...

Source file src/go/types/resolver_test.go

Documentation: go/types

		 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  }
	 217  

View as plain text