зеркало из https://github.com/golang/tools.git
go/ast/astutil: update PathEnclosingInterval to handle type parameters
Add support for the new generic syntax to PathEnclosingInterval, notably the new IndexListExpr node and FuncDecl.Type.TypeParams. Change-Id: I013a916a1617e5f08c8d1cb30501bf2bf253c742 Reviewed-on: https://go-review.googlesource.com/c/tools/+/353150 Trust: Robert Findley <rfindley@google.com> Run-TryBot: Robert Findley <rfindley@google.com> gopls-CI: kokoro <noreply+kokoro@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
Родитель
942994fc75
Коммит
0ebff1a957
|
@ -11,6 +11,8 @@ import (
|
|||
"go/ast"
|
||||
"go/token"
|
||||
"sort"
|
||||
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
)
|
||||
|
||||
// PathEnclosingInterval returns the node that encloses the source
|
||||
|
@ -294,8 +296,8 @@ func childrenOf(n ast.Node) []ast.Node {
|
|||
|
||||
case *ast.FieldList:
|
||||
children = append(children,
|
||||
tok(n.Opening, len("(")),
|
||||
tok(n.Closing, len(")")))
|
||||
tok(n.Opening, len("(")), // or len("[")
|
||||
tok(n.Closing, len(")"))) // or len("]")
|
||||
|
||||
case *ast.File:
|
||||
// TODO test: Doc
|
||||
|
@ -322,6 +324,9 @@ func childrenOf(n ast.Node) []ast.Node {
|
|||
children = append(children, n.Recv)
|
||||
}
|
||||
children = append(children, n.Name)
|
||||
if tparams := typeparams.ForFuncType(n.Type); tparams != nil {
|
||||
children = append(children, tparams)
|
||||
}
|
||||
if n.Type.Params != nil {
|
||||
children = append(children, n.Type.Params)
|
||||
}
|
||||
|
@ -371,8 +376,13 @@ func childrenOf(n ast.Node) []ast.Node {
|
|||
|
||||
case *ast.IndexExpr:
|
||||
children = append(children,
|
||||
tok(n.Lbrack, len("{")),
|
||||
tok(n.Rbrack, len("}")))
|
||||
tok(n.Lbrack, len("[")),
|
||||
tok(n.Rbrack, len("]")))
|
||||
|
||||
case *typeparams.IndexListExpr:
|
||||
children = append(children,
|
||||
tok(n.Lbrack, len("[")),
|
||||
tok(n.Rbrack, len("]")))
|
||||
|
||||
case *ast.InterfaceType:
|
||||
children = append(children,
|
||||
|
@ -581,6 +591,8 @@ func NodeDescription(n ast.Node) string {
|
|||
return "decrement statement"
|
||||
case *ast.IndexExpr:
|
||||
return "index expression"
|
||||
case *typeparams.IndexListExpr:
|
||||
return "index list expression"
|
||||
case *ast.InterfaceType:
|
||||
return "interface type"
|
||||
case *ast.KeyValueExpr:
|
||||
|
|
|
@ -19,6 +19,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"golang.org/x/tools/go/ast/astutil"
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
)
|
||||
|
||||
// pathToString returns a string containing the concrete types of the
|
||||
|
@ -59,7 +60,10 @@ func findInterval(t *testing.T, fset *token.FileSet, input, substr string) (f *a
|
|||
}
|
||||
|
||||
// Common input for following tests.
|
||||
const input = `
|
||||
var input = makeInput()
|
||||
|
||||
func makeInput() string {
|
||||
src := `
|
||||
// Hello.
|
||||
package main
|
||||
import "fmt"
|
||||
|
@ -70,52 +74,88 @@ func main() {
|
|||
}
|
||||
`
|
||||
|
||||
if typeparams.Enabled {
|
||||
src += `
|
||||
func g[A any, P interface{ctype1| ~ctype2}](a1 A, p1 P) {}
|
||||
|
||||
type PT[T constraint] struct{ t T }
|
||||
|
||||
var v GT[targ1]
|
||||
|
||||
var h = g[ targ2, targ3]
|
||||
`
|
||||
}
|
||||
return src
|
||||
}
|
||||
|
||||
func TestPathEnclosingInterval_Exact(t *testing.T) {
|
||||
// For the exact tests, we check that a substring is mapped to
|
||||
// the canonical string for the node it denotes.
|
||||
tests := []struct {
|
||||
type testCase struct {
|
||||
substr string // first occurrence of this string indicates interval
|
||||
node string // complete text of expected containing node
|
||||
}{
|
||||
}
|
||||
|
||||
dup := func(s string) testCase { return testCase{s, s} }
|
||||
// For the exact tests, we check that a substring is mapped to
|
||||
// the canonical string for the node it denotes.
|
||||
tests := []testCase{
|
||||
{"package",
|
||||
input[11 : len(input)-1]},
|
||||
{"\npack",
|
||||
input[11 : len(input)-1]},
|
||||
{"main",
|
||||
"main"},
|
||||
dup("main"),
|
||||
{"import",
|
||||
"import \"fmt\""},
|
||||
{"\"fmt\"",
|
||||
"\"fmt\""},
|
||||
dup("\"fmt\""),
|
||||
{"\nfunc f() {}\n",
|
||||
"func f() {}"},
|
||||
{"x ",
|
||||
"x"},
|
||||
{" y",
|
||||
"y"},
|
||||
{"z",
|
||||
"z"},
|
||||
dup("z"),
|
||||
{" + ",
|
||||
"x + y"},
|
||||
{" :=",
|
||||
"z := (x + y)"},
|
||||
{"x + y",
|
||||
"x + y"},
|
||||
{"(x + y)",
|
||||
"(x + y)"},
|
||||
dup("x + y"),
|
||||
dup("(x + y)"),
|
||||
{" (x + y) ",
|
||||
"(x + y)"},
|
||||
{" (x + y) // add",
|
||||
"(x + y)"},
|
||||
{"func",
|
||||
"func f() {}"},
|
||||
{"func f() {}",
|
||||
"func f() {}"},
|
||||
dup("func f() {}"),
|
||||
{"\nfun",
|
||||
"func f() {}"},
|
||||
{" f",
|
||||
"f"},
|
||||
}
|
||||
if typeparams.Enabled {
|
||||
tests = append(tests, []testCase{
|
||||
dup("[A any, P interface{ctype1| ~ctype2}]"),
|
||||
{"[", "[A any, P interface{ctype1| ~ctype2}]"},
|
||||
dup("A"),
|
||||
{" any", "any"},
|
||||
dup("ctype1"),
|
||||
{"|", "ctype1| ~ctype2"},
|
||||
dup("ctype2"),
|
||||
{"~", "~ctype2"},
|
||||
dup("~ctype2"),
|
||||
{" ~ctype2", "~ctype2"},
|
||||
{"]", "[A any, P interface{ctype1| ~ctype2}]"},
|
||||
dup("a1"),
|
||||
dup("a1 A"),
|
||||
dup("(a1 A, p1 P)"),
|
||||
dup("type PT[T constraint] struct{ t T }"),
|
||||
dup("PT"),
|
||||
dup("[T constraint]"),
|
||||
dup("constraint"),
|
||||
dup("targ1"),
|
||||
{" targ2", "targ2"},
|
||||
dup("g[ targ2, targ3]"),
|
||||
}...)
|
||||
}
|
||||
for _, test := range tests {
|
||||
f, start, end := findInterval(t, new(token.FileSet), input, test.substr)
|
||||
if f == nil {
|
||||
|
@ -145,13 +185,14 @@ func TestPathEnclosingInterval_Exact(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestPathEnclosingInterval_Paths(t *testing.T) {
|
||||
type testCase struct {
|
||||
substr string // first occurrence of this string indicates interval
|
||||
path string // the pathToString(),exact of the expected path
|
||||
}
|
||||
// For these tests, we check only the path of the enclosing
|
||||
// node, but not its complete text because it's often quite
|
||||
// large when !exact.
|
||||
tests := []struct {
|
||||
substr string // first occurrence of this string indicates interval
|
||||
path string // the pathToString(),exact of the expected path
|
||||
}{
|
||||
tests := []testCase{
|
||||
{"// add",
|
||||
"[BlockStmt FuncDecl File],false"},
|
||||
{"(x + y",
|
||||
|
@ -179,6 +220,18 @@ func TestPathEnclosingInterval_Paths(t *testing.T) {
|
|||
{"f() // NB",
|
||||
"[CallExpr ExprStmt BlockStmt FuncDecl File],true"},
|
||||
}
|
||||
if typeparams.Enabled {
|
||||
tests = append(tests, []testCase{
|
||||
{" any", "[Ident Field FieldList FuncDecl File],true"},
|
||||
{"|", "[BinaryExpr Field FieldList InterfaceType Field FieldList FuncDecl File],true"},
|
||||
{"ctype2",
|
||||
"[Ident UnaryExpr BinaryExpr Field FieldList InterfaceType Field FieldList FuncDecl File],true"},
|
||||
{"a1", "[Ident Field FieldList FuncDecl File],true"},
|
||||
{"PT[T constraint]", "[TypeSpec GenDecl File],false"},
|
||||
{"[T constraint]", "[FieldList TypeSpec GenDecl File],true"},
|
||||
{"targ2", "[Ident IndexListExpr ValueSpec GenDecl File],true"},
|
||||
}...)
|
||||
}
|
||||
for _, test := range tests {
|
||||
f, start, end := findInterval(t, new(token.FileSet), input, test.substr)
|
||||
if f == nil {
|
||||
|
|
Загрузка…
Ссылка в новой задаче