зеркало из 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/ast"
|
||||||
"go/token"
|
"go/token"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
|
"golang.org/x/tools/internal/typeparams"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PathEnclosingInterval returns the node that encloses the source
|
// PathEnclosingInterval returns the node that encloses the source
|
||||||
|
@ -294,8 +296,8 @@ func childrenOf(n ast.Node) []ast.Node {
|
||||||
|
|
||||||
case *ast.FieldList:
|
case *ast.FieldList:
|
||||||
children = append(children,
|
children = append(children,
|
||||||
tok(n.Opening, len("(")),
|
tok(n.Opening, len("(")), // or len("[")
|
||||||
tok(n.Closing, len(")")))
|
tok(n.Closing, len(")"))) // or len("]")
|
||||||
|
|
||||||
case *ast.File:
|
case *ast.File:
|
||||||
// TODO test: Doc
|
// TODO test: Doc
|
||||||
|
@ -322,6 +324,9 @@ func childrenOf(n ast.Node) []ast.Node {
|
||||||
children = append(children, n.Recv)
|
children = append(children, n.Recv)
|
||||||
}
|
}
|
||||||
children = append(children, n.Name)
|
children = append(children, n.Name)
|
||||||
|
if tparams := typeparams.ForFuncType(n.Type); tparams != nil {
|
||||||
|
children = append(children, tparams)
|
||||||
|
}
|
||||||
if n.Type.Params != nil {
|
if n.Type.Params != nil {
|
||||||
children = append(children, n.Type.Params)
|
children = append(children, n.Type.Params)
|
||||||
}
|
}
|
||||||
|
@ -371,8 +376,13 @@ func childrenOf(n ast.Node) []ast.Node {
|
||||||
|
|
||||||
case *ast.IndexExpr:
|
case *ast.IndexExpr:
|
||||||
children = append(children,
|
children = append(children,
|
||||||
tok(n.Lbrack, len("{")),
|
tok(n.Lbrack, len("[")),
|
||||||
tok(n.Rbrack, len("}")))
|
tok(n.Rbrack, len("]")))
|
||||||
|
|
||||||
|
case *typeparams.IndexListExpr:
|
||||||
|
children = append(children,
|
||||||
|
tok(n.Lbrack, len("[")),
|
||||||
|
tok(n.Rbrack, len("]")))
|
||||||
|
|
||||||
case *ast.InterfaceType:
|
case *ast.InterfaceType:
|
||||||
children = append(children,
|
children = append(children,
|
||||||
|
@ -581,6 +591,8 @@ func NodeDescription(n ast.Node) string {
|
||||||
return "decrement statement"
|
return "decrement statement"
|
||||||
case *ast.IndexExpr:
|
case *ast.IndexExpr:
|
||||||
return "index expression"
|
return "index expression"
|
||||||
|
case *typeparams.IndexListExpr:
|
||||||
|
return "index list expression"
|
||||||
case *ast.InterfaceType:
|
case *ast.InterfaceType:
|
||||||
return "interface type"
|
return "interface type"
|
||||||
case *ast.KeyValueExpr:
|
case *ast.KeyValueExpr:
|
||||||
|
|
|
@ -19,6 +19,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"golang.org/x/tools/go/ast/astutil"
|
"golang.org/x/tools/go/ast/astutil"
|
||||||
|
"golang.org/x/tools/internal/typeparams"
|
||||||
)
|
)
|
||||||
|
|
||||||
// pathToString returns a string containing the concrete types of the
|
// 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.
|
// Common input for following tests.
|
||||||
const input = `
|
var input = makeInput()
|
||||||
|
|
||||||
|
func makeInput() string {
|
||||||
|
src := `
|
||||||
// Hello.
|
// Hello.
|
||||||
package main
|
package main
|
||||||
import "fmt"
|
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) {
|
func TestPathEnclosingInterval_Exact(t *testing.T) {
|
||||||
// For the exact tests, we check that a substring is mapped to
|
type testCase struct {
|
||||||
// the canonical string for the node it denotes.
|
|
||||||
tests := []struct {
|
|
||||||
substr string // first occurrence of this string indicates interval
|
substr string // first occurrence of this string indicates interval
|
||||||
node string // complete text of expected containing node
|
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",
|
{"package",
|
||||||
input[11 : len(input)-1]},
|
input[11 : len(input)-1]},
|
||||||
{"\npack",
|
{"\npack",
|
||||||
input[11 : len(input)-1]},
|
input[11 : len(input)-1]},
|
||||||
{"main",
|
dup("main"),
|
||||||
"main"},
|
|
||||||
{"import",
|
{"import",
|
||||||
"import \"fmt\""},
|
"import \"fmt\""},
|
||||||
{"\"fmt\"",
|
dup("\"fmt\""),
|
||||||
"\"fmt\""},
|
|
||||||
{"\nfunc f() {}\n",
|
{"\nfunc f() {}\n",
|
||||||
"func f() {}"},
|
"func f() {}"},
|
||||||
{"x ",
|
{"x ",
|
||||||
"x"},
|
"x"},
|
||||||
{" y",
|
{" y",
|
||||||
"y"},
|
"y"},
|
||||||
{"z",
|
dup("z"),
|
||||||
"z"},
|
|
||||||
{" + ",
|
{" + ",
|
||||||
"x + y"},
|
"x + y"},
|
||||||
{" :=",
|
{" :=",
|
||||||
"z := (x + y)"},
|
"z := (x + y)"},
|
||||||
{"x + y",
|
dup("x + y"),
|
||||||
"x + y"},
|
dup("(x + y)"),
|
||||||
{"(x + y)",
|
|
||||||
"(x + y)"},
|
|
||||||
{" (x + y) ",
|
{" (x + y) ",
|
||||||
"(x + y)"},
|
"(x + y)"},
|
||||||
{" (x + y) // add",
|
{" (x + y) // add",
|
||||||
"(x + y)"},
|
"(x + y)"},
|
||||||
{"func",
|
{"func",
|
||||||
"func f() {}"},
|
"func f() {}"},
|
||||||
{"func f() {}",
|
dup("func f() {}"),
|
||||||
"func f() {}"},
|
|
||||||
{"\nfun",
|
{"\nfun",
|
||||||
"func f() {}"},
|
"func f() {}"},
|
||||||
{" f",
|
{" 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 {
|
for _, test := range tests {
|
||||||
f, start, end := findInterval(t, new(token.FileSet), input, test.substr)
|
f, start, end := findInterval(t, new(token.FileSet), input, test.substr)
|
||||||
if f == nil {
|
if f == nil {
|
||||||
|
@ -145,13 +185,14 @@ func TestPathEnclosingInterval_Exact(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPathEnclosingInterval_Paths(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
|
// For these tests, we check only the path of the enclosing
|
||||||
// node, but not its complete text because it's often quite
|
// node, but not its complete text because it's often quite
|
||||||
// large when !exact.
|
// large when !exact.
|
||||||
tests := []struct {
|
tests := []testCase{
|
||||||
substr string // first occurrence of this string indicates interval
|
|
||||||
path string // the pathToString(),exact of the expected path
|
|
||||||
}{
|
|
||||||
{"// add",
|
{"// add",
|
||||||
"[BlockStmt FuncDecl File],false"},
|
"[BlockStmt FuncDecl File],false"},
|
||||||
{"(x + y",
|
{"(x + y",
|
||||||
|
@ -179,6 +220,18 @@ func TestPathEnclosingInterval_Paths(t *testing.T) {
|
||||||
{"f() // NB",
|
{"f() // NB",
|
||||||
"[CallExpr ExprStmt BlockStmt FuncDecl File],true"},
|
"[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 {
|
for _, test := range tests {
|
||||||
f, start, end := findInterval(t, new(token.FileSet), input, test.substr)
|
f, start, end := findInterval(t, new(token.FileSet), input, test.substr)
|
||||||
if f == nil {
|
if f == nil {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче