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