зеркало из 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"
|
"log"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"golang.org/x/tools/go/ast/inspector"
|
"golang.org/x/tools/go/ast/inspector"
|
||||||
|
"golang.org/x/tools/internal/typeparams"
|
||||||
)
|
)
|
||||||
|
|
||||||
var netFiles []*ast.File
|
var netFiles []*ast.File
|
||||||
|
@ -69,6 +71,72 @@ func TestInspectAllNodes(t *testing.T) {
|
||||||
compare(t, nodesA, nodesB)
|
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,
|
// TestPruning compares Inspector against ast.Inspect,
|
||||||
// pruning descent within ast.CallExpr nodes.
|
// pruning descent within ast.CallExpr nodes.
|
||||||
func TestInspectPruning(t *testing.T) {
|
func TestInspectPruning(t *testing.T) {
|
||||||
|
|
|
@ -9,7 +9,11 @@ package inspector
|
||||||
// The initial map-based implementation was too slow;
|
// The initial map-based implementation was too slow;
|
||||||
// see https://go-review.googlesource.com/c/tools/+/135655/1/go/ast/inspector/inspector.go#196
|
// 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 (
|
const (
|
||||||
nArrayType = iota
|
nArrayType = iota
|
||||||
|
@ -47,6 +51,7 @@ const (
|
||||||
nImportSpec
|
nImportSpec
|
||||||
nIncDecStmt
|
nIncDecStmt
|
||||||
nIndexExpr
|
nIndexExpr
|
||||||
|
nIndexListExpr
|
||||||
nInterfaceType
|
nInterfaceType
|
||||||
nKeyValueExpr
|
nKeyValueExpr
|
||||||
nLabeledStmt
|
nLabeledStmt
|
||||||
|
@ -164,6 +169,8 @@ func typeOf(n ast.Node) uint64 {
|
||||||
return 1 << nIncDecStmt
|
return 1 << nIncDecStmt
|
||||||
case *ast.IndexExpr:
|
case *ast.IndexExpr:
|
||||||
return 1 << nIndexExpr
|
return 1 << nIndexExpr
|
||||||
|
case *typeparams.IndexListExpr:
|
||||||
|
return 1 << nIndexListExpr
|
||||||
case *ast.InterfaceType:
|
case *ast.InterfaceType:
|
||||||
return 1 << nInterfaceType
|
return 1 << nInterfaceType
|
||||||
case *ast.KeyValueExpr:
|
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
|
// ForTypeSpec returns an empty field list, as type parameters on not supported
|
||||||
// at this Go version.
|
// at this Go version.
|
||||||
func ForTypeSpec(*ast.TypeSpec) *ast.FieldList {
|
func ForTypeSpec(*ast.TypeSpec) *ast.FieldList {
|
||||||
|
|
|
@ -22,6 +22,7 @@ import (
|
||||||
//
|
//
|
||||||
// For nodes that don't represent index expressions, GetIndexExprData returns
|
// For nodes that don't represent index expressions, GetIndexExprData returns
|
||||||
// nil.
|
// nil.
|
||||||
|
// TODO(rfindley): remove this function in favor of using the alias below.
|
||||||
func GetIndexExprData(n ast.Node) *IndexExprData {
|
func GetIndexExprData(n ast.Node) *IndexExprData {
|
||||||
switch e := n.(type) {
|
switch e := n.(type) {
|
||||||
case *ast.IndexExpr:
|
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.
|
// ForTypeSpec returns n.TypeParams.
|
||||||
func ForTypeSpec(n *ast.TypeSpec) *ast.FieldList {
|
func ForTypeSpec(n *ast.TypeSpec) *ast.FieldList {
|
||||||
if n == nil {
|
if n == nil {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче