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  }