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:
Robert Findley 2021-09-29 11:01:47 -04:00
Родитель 58ad7eb1ab
Коммит 13c407cf48
4 изменённых файлов: 86 добавлений и 1 удалений

Просмотреть файл

@ -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 {