...
Run Format

Source file src/go/types/issues_test.go

Documentation: go/types

     1  // Copyright 2013 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  // This file implements tests for various issues.
     6  
     7  package types_test
     8  
     9  import (
    10  	"fmt"
    11  	"go/ast"
    12  	"go/importer"
    13  	"go/parser"
    14  	"internal/testenv"
    15  	"sort"
    16  	"strings"
    17  	"testing"
    18  
    19  	. "go/types"
    20  )
    21  
    22  func TestIssue5770(t *testing.T) {
    23  	src := `package p; type S struct{T}`
    24  	f, err := parser.ParseFile(fset, "", src, 0)
    25  	if err != nil {
    26  		t.Fatal(err)
    27  	}
    28  
    29  	conf := Config{Importer: importer.Default()}
    30  	_, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, nil) // do not crash
    31  	want := "undeclared name: T"
    32  	if err == nil || !strings.Contains(err.Error(), want) {
    33  		t.Errorf("got: %v; want: %s", err, want)
    34  	}
    35  }
    36  
    37  func TestIssue5849(t *testing.T) {
    38  	src := `
    39  package p
    40  var (
    41  	s uint
    42  	_ = uint8(8)
    43  	_ = uint16(16) << s
    44  	_ = uint32(32 << s)
    45  	_ = uint64(64 << s + s)
    46  	_ = (interface{})("foo")
    47  	_ = (interface{})(nil)
    48  )`
    49  	f, err := parser.ParseFile(fset, "", src, 0)
    50  	if err != nil {
    51  		t.Fatal(err)
    52  	}
    53  
    54  	var conf Config
    55  	types := make(map[ast.Expr]TypeAndValue)
    56  	_, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Types: types})
    57  	if err != nil {
    58  		t.Fatal(err)
    59  	}
    60  
    61  	for x, tv := range types {
    62  		var want Type
    63  		switch x := x.(type) {
    64  		case *ast.BasicLit:
    65  			switch x.Value {
    66  			case `8`:
    67  				want = Typ[Uint8]
    68  			case `16`:
    69  				want = Typ[Uint16]
    70  			case `32`:
    71  				want = Typ[Uint32]
    72  			case `64`:
    73  				want = Typ[Uint] // because of "+ s", s is of type uint
    74  			case `"foo"`:
    75  				want = Typ[String]
    76  			}
    77  		case *ast.Ident:
    78  			if x.Name == "nil" {
    79  				want = Typ[UntypedNil]
    80  			}
    81  		}
    82  		if want != nil && !Identical(tv.Type, want) {
    83  			t.Errorf("got %s; want %s", tv.Type, want)
    84  		}
    85  	}
    86  }
    87  
    88  func TestIssue6413(t *testing.T) {
    89  	src := `
    90  package p
    91  func f() int {
    92  	defer f()
    93  	go f()
    94  	return 0
    95  }
    96  `
    97  	f, err := parser.ParseFile(fset, "", src, 0)
    98  	if err != nil {
    99  		t.Fatal(err)
   100  	}
   101  
   102  	var conf Config
   103  	types := make(map[ast.Expr]TypeAndValue)
   104  	_, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Types: types})
   105  	if err != nil {
   106  		t.Fatal(err)
   107  	}
   108  
   109  	want := Typ[Int]
   110  	n := 0
   111  	for x, tv := range types {
   112  		if _, ok := x.(*ast.CallExpr); ok {
   113  			if tv.Type != want {
   114  				t.Errorf("%s: got %s; want %s", fset.Position(x.Pos()), tv.Type, want)
   115  			}
   116  			n++
   117  		}
   118  	}
   119  
   120  	if n != 2 {
   121  		t.Errorf("got %d CallExprs; want 2", n)
   122  	}
   123  }
   124  
   125  func TestIssue7245(t *testing.T) {
   126  	src := `
   127  package p
   128  func (T) m() (res bool) { return }
   129  type T struct{} // receiver type after method declaration
   130  `
   131  	f, err := parser.ParseFile(fset, "", src, 0)
   132  	if err != nil {
   133  		t.Fatal(err)
   134  	}
   135  
   136  	var conf Config
   137  	defs := make(map[*ast.Ident]Object)
   138  	_, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Defs: defs})
   139  	if err != nil {
   140  		t.Fatal(err)
   141  	}
   142  
   143  	m := f.Decls[0].(*ast.FuncDecl)
   144  	res1 := defs[m.Name].(*Func).Type().(*Signature).Results().At(0)
   145  	res2 := defs[m.Type.Results.List[0].Names[0]].(*Var)
   146  
   147  	if res1 != res2 {
   148  		t.Errorf("got %s (%p) != %s (%p)", res1, res2, res1, res2)
   149  	}
   150  }
   151  
   152  // This tests that uses of existing vars on the LHS of an assignment
   153  // are Uses, not Defs; and also that the (illegal) use of a non-var on
   154  // the LHS of an assignment is a Use nonetheless.
   155  func TestIssue7827(t *testing.T) {
   156  	const src = `
   157  package p
   158  func _() {
   159  	const w = 1        // defs w
   160          x, y := 2, 3       // defs x, y
   161          w, x, z := 4, 5, 6 // uses w, x, defs z; error: cannot assign to w
   162          _, _, _ = x, y, z  // uses x, y, z
   163  }
   164  `
   165  	const want = `L3 defs func p._()
   166  L4 defs const w untyped int
   167  L5 defs var x int
   168  L5 defs var y int
   169  L6 defs var z int
   170  L6 uses const w untyped int
   171  L6 uses var x int
   172  L7 uses var x int
   173  L7 uses var y int
   174  L7 uses var z int`
   175  
   176  	f, err := parser.ParseFile(fset, "", src, 0)
   177  	if err != nil {
   178  		t.Fatal(err)
   179  	}
   180  
   181  	// don't abort at the first error
   182  	conf := Config{Error: func(err error) { t.Log(err) }}
   183  	defs := make(map[*ast.Ident]Object)
   184  	uses := make(map[*ast.Ident]Object)
   185  	_, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Defs: defs, Uses: uses})
   186  	if s := fmt.Sprint(err); !strings.HasSuffix(s, "cannot assign to w") {
   187  		t.Errorf("Check: unexpected error: %s", s)
   188  	}
   189  
   190  	var facts []string
   191  	for id, obj := range defs {
   192  		if obj != nil {
   193  			fact := fmt.Sprintf("L%d defs %s", fset.Position(id.Pos()).Line, obj)
   194  			facts = append(facts, fact)
   195  		}
   196  	}
   197  	for id, obj := range uses {
   198  		fact := fmt.Sprintf("L%d uses %s", fset.Position(id.Pos()).Line, obj)
   199  		facts = append(facts, fact)
   200  	}
   201  	sort.Strings(facts)
   202  
   203  	got := strings.Join(facts, "\n")
   204  	if got != want {
   205  		t.Errorf("Unexpected defs/uses\ngot:\n%s\nwant:\n%s", got, want)
   206  	}
   207  }
   208  
   209  // This tests that the package associated with the types.Object.Pkg method
   210  // is the type's package independent of the order in which the imports are
   211  // listed in the sources src1, src2 below.
   212  // The actual issue is in go/internal/gcimporter which has a corresponding
   213  // test; we leave this test here to verify correct behavior at the go/types
   214  // level.
   215  func TestIssue13898(t *testing.T) {
   216  	testenv.MustHaveGoBuild(t)
   217  
   218  	const src0 = `
   219  package main
   220  
   221  import "go/types"
   222  
   223  func main() {
   224  	var info types.Info
   225  	for _, obj := range info.Uses {
   226  		_ = obj.Pkg()
   227  	}
   228  }
   229  `
   230  	// like src0, but also imports go/importer
   231  	const src1 = `
   232  package main
   233  
   234  import (
   235  	"go/types"
   236  	_ "go/importer"
   237  )
   238  
   239  func main() {
   240  	var info types.Info
   241  	for _, obj := range info.Uses {
   242  		_ = obj.Pkg()
   243  	}
   244  }
   245  `
   246  	// like src1 but with different import order
   247  	// (used to fail with this issue)
   248  	const src2 = `
   249  package main
   250  
   251  import (
   252  	_ "go/importer"
   253  	"go/types"
   254  )
   255  
   256  func main() {
   257  	var info types.Info
   258  	for _, obj := range info.Uses {
   259  		_ = obj.Pkg()
   260  	}
   261  }
   262  `
   263  	f := func(test, src string) {
   264  		f, err := parser.ParseFile(fset, "", src, 0)
   265  		if err != nil {
   266  			t.Fatal(err)
   267  		}
   268  		cfg := Config{Importer: importer.Default()}
   269  		info := Info{Uses: make(map[*ast.Ident]Object)}
   270  		_, err = cfg.Check("main", fset, []*ast.File{f}, &info)
   271  		if err != nil {
   272  			t.Fatal(err)
   273  		}
   274  
   275  		var pkg *Package
   276  		count := 0
   277  		for id, obj := range info.Uses {
   278  			if id.Name == "Pkg" {
   279  				pkg = obj.Pkg()
   280  				count++
   281  			}
   282  		}
   283  		if count != 1 {
   284  			t.Fatalf("%s: got %d entries named Pkg; want 1", test, count)
   285  		}
   286  		if pkg.Name() != "types" {
   287  			t.Fatalf("%s: got %v; want package types", test, pkg)
   288  		}
   289  	}
   290  
   291  	f("src0", src0)
   292  	f("src1", src1)
   293  	f("src2", src2)
   294  }
   295  
   296  func TestIssue22525(t *testing.T) {
   297  	src := `package p; func f() { var a, b, c, d, e int }`
   298  	f, err := parser.ParseFile(fset, "", src, 0)
   299  	if err != nil {
   300  		t.Fatal(err)
   301  	}
   302  
   303  	got := "\n"
   304  	conf := Config{Error: func(err error) { got += err.Error() + "\n" }}
   305  	conf.Check(f.Name.Name, fset, []*ast.File{f}, nil) // do not crash
   306  	want := `
   307  1:27: a declared but not used
   308  1:30: b declared but not used
   309  1:33: c declared but not used
   310  1:36: d declared but not used
   311  1:39: e declared but not used
   312  `
   313  	if got != want {
   314  		t.Errorf("got: %swant: %s", got, want)
   315  	}
   316  }
   317  
   318  func TestIssue25627(t *testing.T) {
   319  	const prefix = `package p; import "unsafe"; type P *struct{}; type I interface{}; type T `
   320  	// The src strings (without prefix) are constructed such that the number of semicolons
   321  	// plus one corresponds to the number of fields expected in the respective struct.
   322  	for _, src := range []string{
   323  		`struct { x Missing }`,
   324  		`struct { Missing }`,
   325  		`struct { *Missing }`,
   326  		`struct { unsafe.Pointer }`,
   327  		`struct { P }`,
   328  		`struct { *I }`,
   329  		`struct { a int; b Missing; *Missing }`,
   330  	} {
   331  		f, err := parser.ParseFile(fset, "", prefix+src, 0)
   332  		if err != nil {
   333  			t.Fatal(err)
   334  		}
   335  
   336  		cfg := Config{Importer: importer.Default(), Error: func(err error) {}}
   337  		info := &Info{Types: make(map[ast.Expr]TypeAndValue)}
   338  		_, err = cfg.Check(f.Name.Name, fset, []*ast.File{f}, info)
   339  		if err != nil {
   340  			if _, ok := err.(Error); !ok {
   341  				t.Fatal(err)
   342  			}
   343  		}
   344  
   345  		ast.Inspect(f, func(n ast.Node) bool {
   346  			if spec, _ := n.(*ast.TypeSpec); spec != nil {
   347  				if tv, ok := info.Types[spec.Type]; ok && spec.Name.Name == "T" {
   348  					want := strings.Count(src, ";") + 1
   349  					if got := tv.Type.(*Struct).NumFields(); got != want {
   350  						t.Errorf("%s: got %d fields; want %d", src, got, want)
   351  					}
   352  				}
   353  			}
   354  			return true
   355  		})
   356  	}
   357  }
   358  

View as plain text