internal/astutil: add EqualSyntax, moved from modernize
Change-Id: Ia08518c031dce2f82d17049f911946fc03356014
Reviewed-on: https://go-review.googlesource.com/c/tools/+/708915
Reviewed-by: Robert Findley <rfindley@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
diff --git a/go/analysis/passes/modernize/bloop.go b/go/analysis/passes/modernize/bloop.go
index 5d7c9e5..9578468 100644
--- a/go/analysis/passes/modernize/bloop.go
+++ b/go/analysis/passes/modernize/bloop.go
@@ -18,6 +18,7 @@
"golang.org/x/tools/internal/analysisinternal"
"golang.org/x/tools/internal/analysisinternal/generated"
typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
+ "golang.org/x/tools/internal/astutil"
"golang.org/x/tools/internal/moreiters"
"golang.org/x/tools/internal/typesinternal/typeindex"
)
@@ -241,7 +242,7 @@
isZeroIntLiteral(info, assign.Rhs[0]) &&
is[*ast.IncDecStmt](loop.Post) &&
loop.Post.(*ast.IncDecStmt).Tok == token.INC &&
- equalSyntax(loop.Post.(*ast.IncDecStmt).X, assign.Lhs[0]) {
+ astutil.EqualSyntax(loop.Post.(*ast.IncDecStmt).X, assign.Lhs[0]) {
return info.Defs[assign.Lhs[0].(*ast.Ident)].(*types.Var)
}
return nil
diff --git a/go/analysis/passes/modernize/forvar.go b/go/analysis/passes/modernize/forvar.go
index 2c3cd29..9a24856 100644
--- a/go/analysis/passes/modernize/forvar.go
+++ b/go/analysis/passes/modernize/forvar.go
@@ -13,6 +13,7 @@
"golang.org/x/tools/go/ast/inspector"
"golang.org/x/tools/internal/analysisinternal"
"golang.org/x/tools/internal/analysisinternal/generated"
+ "golang.org/x/tools/internal/astutil"
)
var ForVarAnalyzer = &analysis.Analyzer{
@@ -52,8 +53,8 @@
}
isLoopVarRedecl := func(assign *ast.AssignStmt) bool {
for i, lhs := range assign.Lhs {
- if !(equalSyntax(lhs, assign.Rhs[i]) &&
- (equalSyntax(lhs, loop.Key) || equalSyntax(lhs, loop.Value))) {
+ if !(astutil.EqualSyntax(lhs, assign.Rhs[i]) &&
+ (astutil.EqualSyntax(lhs, loop.Key) || astutil.EqualSyntax(lhs, loop.Value))) {
return false
}
}
diff --git a/go/analysis/passes/modernize/maps.go b/go/analysis/passes/modernize/maps.go
index 16747ed..d6a77c4 100644
--- a/go/analysis/passes/modernize/maps.go
+++ b/go/analysis/passes/modernize/maps.go
@@ -17,6 +17,7 @@
"golang.org/x/tools/go/ast/inspector"
"golang.org/x/tools/internal/analysisinternal"
"golang.org/x/tools/internal/analysisinternal/generated"
+ "golang.org/x/tools/internal/astutil"
"golang.org/x/tools/internal/typeparams"
)
@@ -99,7 +100,7 @@
if assign, ok := curPrev.Node().(*ast.AssignStmt); ok &&
len(assign.Lhs) == 1 &&
len(assign.Rhs) == 1 &&
- equalSyntax(assign.Lhs[0], m) {
+ astutil.EqualSyntax(assign.Lhs[0], m) {
// Have: m = rhs; for k, v := range x { m[k] = v }
var newMap bool
@@ -235,8 +236,8 @@
assign := rng.Body.List[0].(*ast.AssignStmt)
if index, ok := assign.Lhs[0].(*ast.IndexExpr); ok &&
- equalSyntax(rng.Key, index.Index) &&
- equalSyntax(rng.Value, assign.Rhs[0]) &&
+ astutil.EqualSyntax(rng.Key, index.Index) &&
+ astutil.EqualSyntax(rng.Value, assign.Rhs[0]) &&
is[*types.Map](typeparams.CoreType(info.TypeOf(index.X))) &&
types.Identical(info.TypeOf(index), info.TypeOf(rng.Value)) { // m[k], v
diff --git a/go/analysis/passes/modernize/minmax.go b/go/analysis/passes/modernize/minmax.go
index 350a3c4..3896b28 100644
--- a/go/analysis/passes/modernize/minmax.go
+++ b/go/analysis/passes/modernize/minmax.go
@@ -18,6 +18,7 @@
"golang.org/x/tools/internal/analysisinternal"
"golang.org/x/tools/internal/analysisinternal/generated"
typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
+ "golang.org/x/tools/internal/astutil"
"golang.org/x/tools/internal/typeparams"
"golang.org/x/tools/internal/typesinternal/typeindex"
)
@@ -92,10 +93,10 @@
// For pattern 1, check that:
// - lhs = lhs2
// - {rhs,rhs2} = {a,b}
- if equalSyntax(lhs, lhs2) {
- if equalSyntax(rhs, a) && equalSyntax(rhs2, b) {
+ if astutil.EqualSyntax(lhs, lhs2) {
+ if astutil.EqualSyntax(rhs, a) && astutil.EqualSyntax(rhs2, b) {
sign = +sign
- } else if equalSyntax(rhs2, a) && equalSyntax(rhs, b) {
+ } else if astutil.EqualSyntax(rhs2, a) && astutil.EqualSyntax(rhs, b) {
sign = -sign
} else {
return
@@ -149,10 +150,10 @@
lhs0 := fassign.Lhs[0]
rhs0 := fassign.Rhs[0]
- if equalSyntax(lhs, lhs0) {
- if equalSyntax(rhs, a) && (equalSyntax(rhs0, b) || equalSyntax(lhs0, b)) {
+ if astutil.EqualSyntax(lhs, lhs0) {
+ if astutil.EqualSyntax(rhs, a) && (astutil.EqualSyntax(rhs0, b) || astutil.EqualSyntax(lhs0, b)) {
sign = +sign
- } else if (equalSyntax(rhs0, a) || equalSyntax(lhs0, a)) && equalSyntax(rhs, b) {
+ } else if (astutil.EqualSyntax(rhs0, a) || astutil.EqualSyntax(lhs0, a)) && astutil.EqualSyntax(rhs, b) {
sign = -sign
} else {
return
@@ -166,9 +167,9 @@
// Permit lhs0 to stand for rhs0 in the matching,
// but don't actually reduce to lhs0 = min(lhs0, rhs)
// since the "=" could be a ":=". Use min(rhs0, rhs).
- if equalSyntax(lhs0, a) {
+ if astutil.EqualSyntax(lhs0, a) {
a = rhs0
- } else if equalSyntax(lhs0, b) {
+ } else if astutil.EqualSyntax(lhs0, b) {
b = rhs0
}
@@ -411,9 +412,9 @@
y := cmp.Y // right operand
// Check operand order and adjust sign accordingly
- if equalSyntax(t, x) && equalSyntax(f, y) {
+ if astutil.EqualSyntax(t, x) && astutil.EqualSyntax(f, y) {
sign = +sign
- } else if equalSyntax(t, y) && equalSyntax(f, x) {
+ } else if astutil.EqualSyntax(t, y) && astutil.EqualSyntax(f, x) {
sign = -sign
} else {
return false
diff --git a/go/analysis/passes/modernize/modernize.go b/go/analysis/passes/modernize/modernize.go
index 58814f0..6367012 100644
--- a/go/analysis/passes/modernize/modernize.go
+++ b/go/analysis/passes/modernize/modernize.go
@@ -20,7 +20,6 @@
"golang.org/x/tools/go/ast/inspector"
"golang.org/x/tools/internal/analysisinternal"
"golang.org/x/tools/internal/analysisinternal/generated"
- "golang.org/x/tools/internal/astutil"
"golang.org/x/tools/internal/moreiters"
"golang.org/x/tools/internal/stdlib"
"golang.org/x/tools/internal/versions"
@@ -67,12 +66,6 @@
}
}
-// equalSyntax reports whether x and y are syntactically equal (ignoring comments).
-func equalSyntax(x, y ast.Expr) bool {
- sameName := func(x, y *ast.Ident) bool { return x.Name == y.Name }
- return astutil.Equal(x, y, sameName)
-}
-
// formatExprs formats a comma-separated list of expressions.
func formatExprs(fset *token.FileSet, exprs []ast.Expr) string {
var buf strings.Builder
diff --git a/go/analysis/passes/modernize/rangeint.go b/go/analysis/passes/modernize/rangeint.go
index 3e07f7b..62c9740 100644
--- a/go/analysis/passes/modernize/rangeint.go
+++ b/go/analysis/passes/modernize/rangeint.go
@@ -18,6 +18,7 @@
"golang.org/x/tools/internal/analysisinternal"
"golang.org/x/tools/internal/analysisinternal/generated"
typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
+ "golang.org/x/tools/internal/astutil"
"golang.org/x/tools/internal/typesinternal"
"golang.org/x/tools/internal/typesinternal/typeindex"
)
@@ -85,7 +86,7 @@
if compare, ok := loop.Cond.(*ast.BinaryExpr); ok &&
compare.Op == token.LSS &&
- equalSyntax(compare.X, init.Lhs[0]) {
+ astutil.EqualSyntax(compare.X, init.Lhs[0]) {
// Have: for i = 0; i < limit; ... {}
limit := compare.Y
@@ -126,7 +127,7 @@
if inc, ok := loop.Post.(*ast.IncDecStmt); ok &&
inc.Tok == token.INC &&
- equalSyntax(compare.X, inc.X) {
+ astutil.EqualSyntax(compare.X, inc.X) {
// Have: for i = 0; i < limit; i++ {}
// Find references to i within the loop body.
diff --git a/go/analysis/passes/modernize/slices.go b/go/analysis/passes/modernize/slices.go
index e2dc6f8..42b01d2 100644
--- a/go/analysis/passes/modernize/slices.go
+++ b/go/analysis/passes/modernize/slices.go
@@ -17,6 +17,7 @@
"golang.org/x/tools/go/types/typeutil"
"golang.org/x/tools/internal/analysisinternal"
"golang.org/x/tools/internal/analysisinternal/generated"
+ "golang.org/x/tools/internal/astutil"
)
// Warning: this analyzer is not safe to enable by default.
@@ -261,12 +262,12 @@
switch e := e.(type) {
case *ast.SliceExpr:
// x[:0:0], x[:len(x):len(x)], x[:k:k]
- if e.Slice3 && e.High != nil && e.Max != nil && equalSyntax(e.High, e.Max) { // x[:k:k]
+ if e.Slice3 && e.High != nil && e.Max != nil && astutil.EqualSyntax(e.High, e.Max) { // x[:k:k]
res = e
empty = isZeroIntLiteral(info, e.High) // x[:0:0]
if call, ok := e.High.(*ast.CallExpr); ok &&
typeutil.Callee(info, call) == builtinLen &&
- equalSyntax(call.Args[0], e.X) {
+ astutil.EqualSyntax(call.Args[0], e.X) {
res = e.X // x[:len(x):len(x)] -> x
}
return
diff --git a/go/analysis/passes/modernize/slicescontains.go b/go/analysis/passes/modernize/slicescontains.go
index 447e30b..5480cd9 100644
--- a/go/analysis/passes/modernize/slicescontains.go
+++ b/go/analysis/passes/modernize/slicescontains.go
@@ -17,6 +17,7 @@
"golang.org/x/tools/internal/analysisinternal"
"golang.org/x/tools/internal/analysisinternal/generated"
typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
+ "golang.org/x/tools/internal/astutil"
"golang.org/x/tools/internal/typeparams"
"golang.org/x/tools/internal/typesinternal/typeindex"
)
@@ -87,12 +88,12 @@
// isSliceElem reports whether e denotes the
// current slice element (elem or s[i]).
isSliceElem := func(e ast.Expr) bool {
- if rng.Value != nil && equalSyntax(e, rng.Value) {
+ if rng.Value != nil && astutil.EqualSyntax(e, rng.Value) {
return true // "elem"
}
if x, ok := e.(*ast.IndexExpr); ok &&
- equalSyntax(x.X, rng.X) &&
- equalSyntax(x.Index, rng.Key) {
+ astutil.EqualSyntax(x.X, rng.X) &&
+ astutil.EqualSyntax(x.Index, rng.Key) {
return true // "s[i]"
}
return false
@@ -322,7 +323,7 @@
if prevAssign, ok := prevStmt.(*ast.AssignStmt); ok &&
len(prevAssign.Lhs) == 1 &&
len(prevAssign.Rhs) == 1 &&
- equalSyntax(prevAssign.Lhs[0], assign.Lhs[0]) &&
+ astutil.EqualSyntax(prevAssign.Lhs[0], assign.Lhs[0]) &&
is[*ast.Ident](assign.Rhs[0]) &&
info.Uses[assign.Rhs[0].(*ast.Ident)] == builtinTrue {
diff --git a/go/analysis/passes/modernize/slicesdelete.go b/go/analysis/passes/modernize/slicesdelete.go
index f3c5504..6310372 100644
--- a/go/analysis/passes/modernize/slicesdelete.go
+++ b/go/analysis/passes/modernize/slicesdelete.go
@@ -15,6 +15,7 @@
"golang.org/x/tools/go/ast/inspector"
"golang.org/x/tools/internal/analysisinternal"
"golang.org/x/tools/internal/analysisinternal/generated"
+ "golang.org/x/tools/internal/astutil"
)
// Warning: this analyzer is not safe to enable by default (not nil-preserving).
@@ -140,7 +141,7 @@
slice2, ok2 := call.Args[1].(*ast.SliceExpr)
if ok1 && slice1.Low == nil && !slice1.Slice3 &&
ok2 && slice2.High == nil && !slice2.Slice3 &&
- equalSyntax(slice1.X, slice2.X) && noEffects(info, slice1.X) &&
+ astutil.EqualSyntax(slice1.X, slice2.X) && noEffects(info, slice1.X) &&
increasingSliceIndices(info, slice1.High, slice2.Low) {
// Have append(s[:a], s[b:]...) where we can verify a < b.
report(file, call, slice1, slice2)
@@ -176,5 +177,5 @@
ai, ak := split(a)
bi, bk := split(b)
- return equalSyntax(ai, bi) && constant.Compare(ak, token.LSS, bk)
+ return astutil.EqualSyntax(ai, bi) && constant.Compare(ak, token.LSS, bk)
}
diff --git a/go/analysis/passes/modernize/sortslice.go b/go/analysis/passes/modernize/sortslice.go
index 3950fc9..3b6b8da 100644
--- a/go/analysis/passes/modernize/sortslice.go
+++ b/go/analysis/passes/modernize/sortslice.go
@@ -14,6 +14,7 @@
"golang.org/x/tools/internal/analysisinternal"
"golang.org/x/tools/internal/analysisinternal/generated"
typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
+ "golang.org/x/tools/internal/astutil"
"golang.org/x/tools/internal/typesinternal/typeindex"
)
@@ -79,7 +80,7 @@
isIndex := func(e ast.Expr, v *types.Var) bool {
index, ok := e.(*ast.IndexExpr)
return ok &&
- equalSyntax(index.X, s) &&
+ astutil.EqualSyntax(index.X, s) &&
is[*ast.Ident](index.Index) &&
info.Uses[index.Index.(*ast.Ident)] == v
}
diff --git a/go/analysis/passes/modernize/stditerators.go b/go/analysis/passes/modernize/stditerators.go
index 1af3a59..e32c297 100644
--- a/go/analysis/passes/modernize/stditerators.go
+++ b/go/analysis/passes/modernize/stditerators.go
@@ -17,6 +17,7 @@
"golang.org/x/tools/internal/analysisinternal"
"golang.org/x/tools/internal/analysisinternal/generated"
typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
+ "golang.org/x/tools/internal/astutil"
"golang.org/x/tools/internal/goplsexport"
"golang.org/x/tools/internal/stdlib"
"golang.org/x/tools/internal/typesinternal/typeindex"
@@ -133,7 +134,7 @@
// call to x.At(i)?
if call, ok := assign.Rhs[0].(*ast.CallExpr); ok &&
typeutil.Callee(info, call) == atMethod &&
- equalSyntax(ast.Unparen(call.Fun).(*ast.SelectorExpr).X, x) &&
+ astutil.EqualSyntax(ast.Unparen(call.Fun).(*ast.SelectorExpr).X, x) &&
is[*ast.Ident](call.Args[0]) &&
info.Uses[call.Args[0].(*ast.Ident)] == i {
// Have: { elem := x.At(i); ... }
@@ -282,7 +283,7 @@
atSel := ast.Unparen(atCall.Fun).(*ast.SelectorExpr)
// Check receivers of Len, At calls match (syntactically).
- if !equalSyntax(lenSel.X, atSel.X) {
+ if !astutil.EqualSyntax(lenSel.X, atSel.X) {
continue nextCall
}
diff --git a/go/analysis/passes/modernize/stringscutprefix.go b/go/analysis/passes/modernize/stringscutprefix.go
index 199c0b5..4422bdd 100644
--- a/go/analysis/passes/modernize/stringscutprefix.go
+++ b/go/analysis/passes/modernize/stringscutprefix.go
@@ -17,6 +17,7 @@
"golang.org/x/tools/internal/analysisinternal"
"golang.org/x/tools/internal/analysisinternal/generated"
typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
+ "golang.org/x/tools/internal/astutil"
"golang.org/x/tools/internal/typesinternal/typeindex"
)
@@ -123,7 +124,7 @@
// check whether the obj1 uses the exact the same argument with strings.HasPrefix
// shadow variables won't be valid because we only access the first statement (ditto Suffix).
- if equalSyntax(s0, s) && equalSyntax(pre0, pre) {
+ if astutil.EqualSyntax(s0, s) && astutil.EqualSyntax(pre0, pre) {
after := analysisinternal.FreshName(info.Scopes[ifStmt], ifStmt.Pos(), varName)
_, prefix, importEdits := analysisinternal.AddImport(
info,
@@ -201,8 +202,8 @@
fixMessage = "Replace TrimSuffix with CutSuffix"
}
- if equalSyntax(lhs, bin.X) && equalSyntax(call.Args[0], bin.Y) ||
- (equalSyntax(lhs, bin.Y) && equalSyntax(call.Args[0], bin.X)) {
+ if astutil.EqualSyntax(lhs, bin.X) && astutil.EqualSyntax(call.Args[0], bin.Y) ||
+ (astutil.EqualSyntax(lhs, bin.Y) && astutil.EqualSyntax(call.Args[0], bin.X)) {
okVarName := analysisinternal.FreshName(info.Scopes[ifStmt], ifStmt.Pos(), "ok")
// Have one of:
// if rest := TrimPrefix(s, prefix); rest != s { (ditto Suffix)
diff --git a/go/analysis/passes/modernize/waitgroup.go b/go/analysis/passes/modernize/waitgroup.go
index d7290ae..bbae38a 100644
--- a/go/analysis/passes/modernize/waitgroup.go
+++ b/go/analysis/passes/modernize/waitgroup.go
@@ -17,6 +17,7 @@
"golang.org/x/tools/internal/analysisinternal"
"golang.org/x/tools/internal/analysisinternal/generated"
typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
+ "golang.org/x/tools/internal/astutil"
"golang.org/x/tools/internal/typesinternal/typeindex"
)
@@ -107,13 +108,13 @@
var doneStmt ast.Stmt
if deferStmt, ok := list[0].(*ast.DeferStmt); ok &&
typeutil.Callee(info, deferStmt.Call) == syncWaitGroupDone &&
- equalSyntax(ast.Unparen(deferStmt.Call.Fun).(*ast.SelectorExpr).X, addCallRecv) {
+ astutil.EqualSyntax(ast.Unparen(deferStmt.Call.Fun).(*ast.SelectorExpr).X, addCallRecv) {
doneStmt = deferStmt // "defer wg.Done()"
} else if lastStmt, ok := list[len(list)-1].(*ast.ExprStmt); ok {
if doneCall, ok := lastStmt.X.(*ast.CallExpr); ok &&
typeutil.Callee(info, doneCall) == syncWaitGroupDone &&
- equalSyntax(ast.Unparen(doneCall.Fun).(*ast.SelectorExpr).X, addCallRecv) {
+ astutil.EqualSyntax(ast.Unparen(doneCall.Fun).(*ast.SelectorExpr).X, addCallRecv) {
doneStmt = lastStmt // "wg.Done()"
}
}
diff --git a/internal/astutil/equal.go b/internal/astutil/equal.go
index c945de0..210f392 100644
--- a/internal/astutil/equal.go
+++ b/internal/astutil/equal.go
@@ -26,6 +26,14 @@
return equal(reflect.ValueOf(x), reflect.ValueOf(y), identical)
}
+// EqualSyntax reports whether x and y are equal.
+// Identifiers are considered equal if they are spelled the same.
+// Comments are ignored.
+func EqualSyntax(x, y ast.Expr) bool {
+ sameName := func(x, y *ast.Ident) bool { return x.Name == y.Name }
+ return Equal(x, y, sameName)
+}
+
func equal(x, y reflect.Value, identical func(x, y *ast.Ident) bool) bool {
// Ensure types are the same
if x.Type() != y.Type() {