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  }