| // Copyright 2024 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package golang |
| |
| import ( |
| "fmt" |
| "go/ast" |
| "go/parser" |
| "go/token" |
| "reflect" |
| "strings" |
| "testing" |
| |
| "golang.org/x/tools/gopls/internal/cache/parsego" |
| ) |
| |
| func TestSizeClass(t *testing.T) { |
| // See GOROOT/src/runtime/msize.go for details. |
| for _, test := range [...]struct{ size, class int64 }{ |
| {8, 8}, |
| {9, 16}, |
| {16, 16}, |
| {17, 24}, |
| } { |
| got := sizeClass(test.size) |
| if got != test.class { |
| t.Errorf("sizeClass(%d) = %d, want %d", test.size, got, test.class) |
| } |
| } |
| } |
| |
| func TestFindDeclInfo(t *testing.T) { |
| // Each comment names the types of each non-nil component of |
| // the 4-tuple returned by findDeclInfo at that point. |
| for _, src := range []string{ |
| `func /*FuncDecl,-,-,-*/F() {}`, // FuncDecl_Name |
| `type /*GenDecl,TypeSpec,-,-*/T struct{}`, // TypeSpec_Name |
| `var /*GenDecl,ValueSpec,-,-*/x int`, // ValueSpec_Names (simple var) |
| `const /*GenDecl,ValueSpec,-,-*/C = 1`, // ValueSpec_Names (const) |
| `var a, /*GenDecl,ValueSpec,-,-*/b int`, // ValueSpec_Names (multi var) |
| `func f() { /*-,-,-,AssignStmt*/y := 1 }`, // AssignStmt_Lhs |
| `func f() { /*-,-,-,AssignStmt*/x, y := 1, 2 }`, // AssignStmt_Lhs (first of two vars) |
| `func f() { x, /*-,-,-,AssignStmt*/y := 1, 2 }`, // AssignStmt_Lhs (second of two vars) |
| `type T struct { /*GenDecl,TypeSpec,Field,-*/f int }`, // Field_Names (struct field) |
| `func F(/*FuncDecl,-,Field,-*/p int)`, // Field_Names (parameter) |
| `func F(a, /*FuncDecl,-,Field,-*/b, c int)`, // Field_Names (one of many params) |
| `func F() (/*FuncDecl,-,Field,-*/result int)`, // Field_Names (result) |
| `func F() (x, /*FuncDecl,-,Field,-*/y int)`, // Field_Names (one of many results) |
| `func (/*FuncDecl,-,Field,-*/r int) M() {}`, // Field_Names (receiver) |
| `type I interface { /*GenDecl,TypeSpec,Field,-*/f() }`, // Field_Names (interface method) |
| `type T struct { /*GenDecl,TypeSpec,Field,-*/S }; type S struct{}`, // Field_Type (anon struct field) |
| `type T struct { */*GenDecl,TypeSpec,Field,-*/S }; type S struct{}`, // Field_Type (anon struct field pointer) |
| `import "pkg"; type T struct { pkg. /*GenDecl,TypeSpec,Field,-*/S }`, // Field_Type (anon struct field selector) |
| `type T[X any] struct { /*GenDecl,TypeSpec,Field,-*/S[X] }; type S[Y any] struct{}`, // Field_Type (anon generic struct field) |
| `type T[X any] struct { */*GenDecl,TypeSpec,Field,-*/S[X] }; type S[Y any] struct{}`, // Field_Type (anon generic struct field pointer) |
| `import "pkg"; type T[X any] struct { pkg. /*GenDecl,TypeSpec,Field,-*/S[X] }`, // Field_Type (anon generic struct field selector) |
| `import "pkg"; type T[X, Y any] struct { pkg. /*GenDecl,TypeSpec,Field,-*/S[X, Y] }`, // Field_Type (anon generic struct field multiple type args) |
| `import "pkg"; type T[X, Y any] struct { *pkg. /*GenDecl,TypeSpec,Field,-*/S[X, Y] }`, // Field_Type (anon generic struct field pointer multiple type args) |
| `import /*GenDecl,ImportSpec,-,-*/"pkg"`, // ImportSpec_Path |
| `import /*GenDecl,ImportSpec,-,-*/p "pkg"`, // ImportSpec_Name |
| `import p /*GenDecl,ImportSpec,-,-*/"pkg"`, // ImportSpec_Path, with name |
| `func F(/*FuncDecl,-,Field,-*/int) {}`, // Field_Type (anon parameter) |
| `func F() /*FuncDecl,-,Field,-*/int {}`, // Field_Type (anon result) |
| `type T interface { /*GenDecl,TypeSpec,Field,-*/error }`, // Field_Type (interface embedding) |
| `func F(/*FuncDecl,-,Field,-*/...int) {}`, // Field_Type (anon variadic parameter, pos at ...) |
| `func F(... /*FuncDecl,-,Field,-*/int) {}`, // Field_Type (anon variadic parameter, pos at Elt) |
| `func F(/*FuncDecl,-,Field,-*/args ...int) {}`, // Field_Names (named variadic parameter) |
| `func F(args /*-,-,-,-*/...int) {}`, // pos at ... of named variadic parameter |
| `func F(args ... /*-,-,-,-*/int) {}`, // pos at Elt of named variadic parameter |
| `func F[/*FuncDecl,-,Field,-*/T any]() {}`, // Field_Names (type parameter of func) |
| `type T[/*GenDecl,TypeSpec,Field,-*/P any] struct{}`, // Field_Names (type parameter of type) |
| `type I interface { f(/*GenDecl,TypeSpec,Field,-*/int) }`, // Field_Type (parameter of interface method) |
| `var ( a = 1; /*GenDecl,ValueSpec,-,-*/b = 2 )`, // ValueSpec_Names in var block |
| } { |
| t.Run("", func(t *testing.T) { |
| src := "package p; " + src |
| fset := token.NewFileSet() |
| file, err := parser.ParseFile(fset, "test.go", src, parser.ParseComments) |
| if err != nil { |
| t.Fatal(err) |
| } |
| if len(file.Comments) != 1 { |
| t.Fatalf("got %d File.Comments, want exactly 1", len(file.Comments)) |
| } |
| comment := file.Comments[0] |
| |
| pgf := &parsego.File{ |
| File: file, |
| Tok: fset.File(file.Pos()), |
| } |
| decl, spec, field, assign := findDeclInfo(pgf, comment.End()) |
| |
| format := func(n ast.Node) string { |
| if n == nil || reflect.ValueOf(n).IsNil() { |
| return "-" |
| } |
| return strings.TrimPrefix(fmt.Sprintf("%T", n), "*ast.") |
| } |
| |
| got := fmt.Sprintf("%s,%s,%s,%s", format(decl), format(spec), format(field), format(assign)) |
| want := strings.TrimSpace(comment.Text()) |
| if got != want { |
| t.Errorf("%s:\nfindDeclInfo = %s, want %s", src, got, want) |
| } |
| }) |
| } |
| } |