github.com/lovishpuri/go-40569/src@v0.0.0-20230519171745-f8623e7c56cf/go/types/resolver_test.go (about) 1 // Copyright 2011 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package types_test 6 7 import ( 8 "fmt" 9 "go/ast" 10 "go/importer" 11 "go/token" 12 "internal/testenv" 13 "sort" 14 "testing" 15 16 . "go/types" 17 ) 18 19 type resolveTestImporter struct { 20 importer ImporterFrom 21 imported map[string]bool 22 } 23 24 func (imp *resolveTestImporter) Import(string) (*Package, error) { 25 panic("should not be called") 26 } 27 28 func (imp *resolveTestImporter) ImportFrom(path, srcDir string, mode ImportMode) (*Package, error) { 29 if mode != 0 { 30 panic("mode must be 0") 31 } 32 if imp.importer == nil { 33 imp.importer = importer.Default().(ImporterFrom) 34 imp.imported = make(map[string]bool) 35 } 36 pkg, err := imp.importer.ImportFrom(path, srcDir, mode) 37 if err != nil { 38 return nil, err 39 } 40 imp.imported[path] = true 41 return pkg, nil 42 } 43 44 func TestResolveIdents(t *testing.T) { 45 testenv.MustHaveGoBuild(t) 46 47 sources := []string{ 48 ` 49 package p 50 import "fmt" 51 import "math" 52 const pi = math.Pi 53 func sin(x float64) float64 { 54 return math.Sin(x) 55 } 56 var Println = fmt.Println 57 `, 58 ` 59 package p 60 import "fmt" 61 type errorStringer struct { fmt.Stringer; error } 62 func f() string { 63 _ = "foo" 64 return fmt.Sprintf("%d", g()) 65 } 66 func g() (x int) { return } 67 `, 68 ` 69 package p 70 import . "go/parser" 71 import "sync" 72 func h() Mode { return ImportsOnly } 73 var _, x int = 1, 2 74 func init() {} 75 type T struct{ *sync.Mutex; a, b, c int} 76 type I interface{ m() } 77 var _ = T{a: 1, b: 2, c: 3} 78 func (_ T) m() {} 79 func (T) _() {} 80 var i I 81 var _ = i.m 82 func _(s []int) { for i, x := range s { _, _ = i, x } } 83 func _(x interface{}) { 84 switch x := x.(type) { 85 case int: 86 _ = x 87 } 88 switch {} // implicit 'true' tag 89 } 90 `, 91 ` 92 package p 93 type S struct{} 94 func (T) _() {} 95 func (T) _() {} 96 `, 97 ` 98 package p 99 func _() { 100 L0: 101 L1: 102 goto L0 103 for { 104 goto L1 105 } 106 if true { 107 goto L2 108 } 109 L2: 110 } 111 `, 112 } 113 114 pkgnames := []string{ 115 "fmt", 116 "math", 117 } 118 119 // parse package files 120 fset := token.NewFileSet() 121 var files []*ast.File 122 for _, src := range sources { 123 files = append(files, mustParse(fset, src)) 124 } 125 126 // resolve and type-check package AST 127 importer := new(resolveTestImporter) 128 conf := Config{Importer: importer} 129 uses := make(map[*ast.Ident]Object) 130 defs := make(map[*ast.Ident]Object) 131 _, err := conf.Check("testResolveIdents", fset, files, &Info{Defs: defs, Uses: uses}) 132 if err != nil { 133 t.Fatal(err) 134 } 135 136 // check that all packages were imported 137 for _, name := range pkgnames { 138 if !importer.imported[name] { 139 t.Errorf("package %s not imported", name) 140 } 141 } 142 143 // check that qualified identifiers are resolved 144 for _, f := range files { 145 ast.Inspect(f, func(n ast.Node) bool { 146 if s, ok := n.(*ast.SelectorExpr); ok { 147 if x, ok := s.X.(*ast.Ident); ok { 148 obj := uses[x] 149 if obj == nil { 150 t.Errorf("%s: unresolved qualified identifier %s", fset.Position(x.Pos()), x.Name) 151 return false 152 } 153 if _, ok := obj.(*PkgName); ok && uses[s.Sel] == nil { 154 t.Errorf("%s: unresolved selector %s", fset.Position(s.Sel.Pos()), s.Sel.Name) 155 return false 156 } 157 return false 158 } 159 return true 160 } 161 return true 162 }) 163 } 164 165 for id, obj := range uses { 166 if obj == nil { 167 t.Errorf("%s: Uses[%s] == nil", fset.Position(id.Pos()), id.Name) 168 } 169 } 170 171 // check that each identifier in the source is found in uses or defs or both 172 var both []string 173 for _, f := range files { 174 ast.Inspect(f, func(n ast.Node) bool { 175 if x, ok := n.(*ast.Ident); ok { 176 var objects int 177 if _, found := uses[x]; found { 178 objects |= 1 179 delete(uses, x) 180 } 181 if _, found := defs[x]; found { 182 objects |= 2 183 delete(defs, x) 184 } 185 if objects == 0 { 186 t.Errorf("%s: unresolved identifier %s", fset.Position(x.Pos()), x.Name) 187 } else if objects == 3 { 188 both = append(both, x.Name) 189 } 190 return false 191 } 192 return true 193 }) 194 } 195 196 // check the expected set of idents that are simultaneously uses and defs 197 sort.Strings(both) 198 if got, want := fmt.Sprint(both), "[Mutex Stringer error]"; got != want { 199 t.Errorf("simultaneous uses/defs = %s, want %s", got, want) 200 } 201 202 // any left-over identifiers didn't exist in the source 203 for x := range uses { 204 t.Errorf("%s: identifier %s not present in source", fset.Position(x.Pos()), x.Name) 205 } 206 for x := range defs { 207 t.Errorf("%s: identifier %s not present in source", fset.Position(x.Pos()), x.Name) 208 } 209 210 // TODO(gri) add tests to check ImplicitObj callbacks 211 }