github.com/zebozhuang/go@v0.0.0-20200207033046-f8a98f6f5c5d/src/go/types/issues_test.go (about) 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 }