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