зеркало из https://github.com/golang/tools.git
go/ast/inspector: add support for the new IndexListExpr node
IndexListExpr nodes were being skipped by go/ast/inspector, due to not having a type value. Add this value, along with a test that we can inspect the new constructs in generic code. Use a type alias in the typeparams package to achieve this, following the pattern for new go/types nodes. Change-Id: I894a9415a93806cc6dbb92cf190b2bdab368d5df Reviewed-on: https://go-review.googlesource.com/c/tools/+/352896 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:
Родитель
58ad7eb1ab
Коммит
13c407cf48
|
@ -12,10 +12,12 @@ import (
|
|||
"log"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/tools/go/ast/inspector"
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
)
|
||||
|
||||
var netFiles []*ast.File
|
||||
|
@ -69,6 +71,72 @@ func TestInspectAllNodes(t *testing.T) {
|
|||
compare(t, nodesA, nodesB)
|
||||
}
|
||||
|
||||
func TestInspectGenericNodes(t *testing.T) {
|
||||
if !typeparams.Enabled {
|
||||
t.Skip("type parameters are not supported at this Go version")
|
||||
}
|
||||
|
||||
// src is using the 16 identifiers i0, i1, ... i15 so
|
||||
// we can easily verify that we've found all of them.
|
||||
const src = `package a
|
||||
|
||||
type I interface { ~i0|i1 }
|
||||
|
||||
type T[i2, i3 interface{ ~i4 }] struct {}
|
||||
|
||||
func f[i5, i6 any]() {
|
||||
_ = f[i7, i8]
|
||||
var x T[i9, i10]
|
||||
}
|
||||
|
||||
func (*T[i11, i12]) m()
|
||||
|
||||
var _ i13[i14, i15]
|
||||
`
|
||||
fset := token.NewFileSet()
|
||||
f, _ := parser.ParseFile(fset, "a.go", src, 0)
|
||||
inspect := inspector.New([]*ast.File{f})
|
||||
found := make([]bool, 16)
|
||||
|
||||
indexListExprs := make(map[*typeparams.IndexListExpr]bool)
|
||||
|
||||
// Verify that we reach all i* identifiers, and collect IndexListExpr nodes.
|
||||
inspect.Preorder(nil, func(n ast.Node) {
|
||||
switch n := n.(type) {
|
||||
case *ast.Ident:
|
||||
if n.Name[0] == 'i' {
|
||||
index, err := strconv.Atoi(n.Name[1:])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
found[index] = true
|
||||
}
|
||||
case *typeparams.IndexListExpr:
|
||||
indexListExprs[n] = false
|
||||
}
|
||||
})
|
||||
for i, v := range found {
|
||||
if !v {
|
||||
t.Errorf("missed identifier i%d", i)
|
||||
}
|
||||
}
|
||||
|
||||
// Verify that we can filter to IndexListExprs that we found in the first
|
||||
// step.
|
||||
if len(indexListExprs) == 0 {
|
||||
t.Fatal("no index list exprs found")
|
||||
}
|
||||
inspect.Preorder([]ast.Node{&typeparams.IndexListExpr{}}, func(n ast.Node) {
|
||||
ix := n.(*typeparams.IndexListExpr)
|
||||
indexListExprs[ix] = true
|
||||
})
|
||||
for ix, v := range indexListExprs {
|
||||
if !v {
|
||||
t.Errorf("inspected node %v not filtered", ix)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestPruning compares Inspector against ast.Inspect,
|
||||
// pruning descent within ast.CallExpr nodes.
|
||||
func TestInspectPruning(t *testing.T) {
|
||||
|
|
|
@ -9,7 +9,11 @@ package inspector
|
|||
// The initial map-based implementation was too slow;
|
||||
// see https://go-review.googlesource.com/c/tools/+/135655/1/go/ast/inspector/inspector.go#196
|
||||
|
||||
import "go/ast"
|
||||
import (
|
||||
"go/ast"
|
||||
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
)
|
||||
|
||||
const (
|
||||
nArrayType = iota
|
||||
|
@ -47,6 +51,7 @@ const (
|
|||
nImportSpec
|
||||
nIncDecStmt
|
||||
nIndexExpr
|
||||
nIndexListExpr
|
||||
nInterfaceType
|
||||
nKeyValueExpr
|
||||
nLabeledStmt
|
||||
|
@ -164,6 +169,8 @@ func typeOf(n ast.Node) uint64 {
|
|||
return 1 << nIncDecStmt
|
||||
case *ast.IndexExpr:
|
||||
return 1 << nIndexExpr
|
||||
case *typeparams.IndexListExpr:
|
||||
return 1 << nIndexListExpr
|
||||
case *ast.InterfaceType:
|
||||
return 1 << nInterfaceType
|
||||
case *ast.KeyValueExpr:
|
||||
|
|
|
@ -49,6 +49,12 @@ func PackIndexExpr(x ast.Expr, lbrack token.Pos, indices []ast.Expr, rbrack toke
|
|||
}
|
||||
}
|
||||
|
||||
// IndexListExpr is a placeholder type, as type parameters are not supported at
|
||||
// this Go version. Its methods panic on use.
|
||||
type IndexListExpr struct {
|
||||
ast.Expr
|
||||
}
|
||||
|
||||
// ForTypeSpec returns an empty field list, as type parameters on not supported
|
||||
// at this Go version.
|
||||
func ForTypeSpec(*ast.TypeSpec) *ast.FieldList {
|
||||
|
|
|
@ -22,6 +22,7 @@ import (
|
|||
//
|
||||
// For nodes that don't represent index expressions, GetIndexExprData returns
|
||||
// nil.
|
||||
// TODO(rfindley): remove this function in favor of using the alias below.
|
||||
func GetIndexExprData(n ast.Node) *IndexExprData {
|
||||
switch e := n.(type) {
|
||||
case *ast.IndexExpr:
|
||||
|
@ -61,6 +62,9 @@ func PackIndexExpr(x ast.Expr, lbrack token.Pos, indices []ast.Expr, rbrack toke
|
|||
}
|
||||
}
|
||||
|
||||
// IndexListExpr is an alias for ast.IndexListExpr.
|
||||
type IndexListExpr = ast.IndexListExpr
|
||||
|
||||
// ForTypeSpec returns n.TypeParams.
|
||||
func ForTypeSpec(n *ast.TypeSpec) *ast.FieldList {
|
||||
if n == nil {
|
||||
|
|
Загрузка…
Ссылка в новой задаче