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