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>
diff --git a/go/ast/inspector/inspector_test.go b/go/ast/inspector/inspector_test.go
index 3e9d3ba..9e53918 100644
--- a/go/ast/inspector/inspector_test.go
+++ b/go/ast/inspector/inspector_test.go
@@ -12,10 +12,12 @@
"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 @@
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) {
diff --git a/go/ast/inspector/typeof.go b/go/ast/inspector/typeof.go
index b6b00cf..11f4fc3 100644
--- a/go/ast/inspector/typeof.go
+++ b/go/ast/inspector/typeof.go
@@ -9,7 +9,11 @@
// 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 @@
nImportSpec
nIncDecStmt
nIndexExpr
+ nIndexListExpr
nInterfaceType
nKeyValueExpr
nLabeledStmt
@@ -164,6 +169,8 @@
return 1 << nIncDecStmt
case *ast.IndexExpr:
return 1 << nIndexExpr
+ case *typeparams.IndexListExpr:
+ return 1 << nIndexListExpr
case *ast.InterfaceType:
return 1 << nInterfaceType
case *ast.KeyValueExpr:
diff --git a/internal/typeparams/typeparams_go117.go b/internal/typeparams/typeparams_go117.go
index 2145b05..a86d0ea 100644
--- a/internal/typeparams/typeparams_go117.go
+++ b/internal/typeparams/typeparams_go117.go
@@ -49,6 +49,12 @@
}
}
+// 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 {
diff --git a/internal/typeparams/typeparams_go118.go b/internal/typeparams/typeparams_go118.go
index 713efbb..a252183 100644
--- a/internal/typeparams/typeparams_go118.go
+++ b/internal/typeparams/typeparams_go118.go
@@ -22,6 +22,7 @@
//
// 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 @@
}
}
+// 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 {