Source file src/cmd/compile/internal/types2/resolver_test.go

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

View as plain text