x/tools: deprecate astutil.Unparen

The go1.22 go/ast package now provides it.

Updates golang/go#60061

Change-Id: I24e201660e3a8752dd505eefc894c7acae4c99f3
Reviewed-on: https://go-review.googlesource.com/c/tools/+/612038
Auto-Submit: Alan Donovan <adonovan@google.com>
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/assign/assign.go b/go/analysis/passes/assign/assign.go
index 3bfd501..0d95fef 100644
--- a/go/analysis/passes/assign/assign.go
+++ b/go/analysis/passes/assign/assign.go
@@ -18,7 +18,6 @@
 	"golang.org/x/tools/go/analysis"
 	"golang.org/x/tools/go/analysis/passes/inspect"
 	"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
-	"golang.org/x/tools/go/ast/astutil"
 	"golang.org/x/tools/go/ast/inspector"
 )
 
@@ -78,7 +77,7 @@
 
 // isMapIndex returns true if e is a map index expression.
 func isMapIndex(info *types.Info, e ast.Expr) bool {
-	if idx, ok := astutil.Unparen(e).(*ast.IndexExpr); ok {
+	if idx, ok := ast.Unparen(e).(*ast.IndexExpr); ok {
 		if typ := info.Types[idx.X].Type; typ != nil {
 			_, ok := typ.Underlying().(*types.Map)
 			return ok
diff --git a/go/analysis/passes/bools/bools.go b/go/analysis/passes/bools/bools.go
index 5643297..8cec6e8 100644
--- a/go/analysis/passes/bools/bools.go
+++ b/go/analysis/passes/bools/bools.go
@@ -14,7 +14,6 @@
 	"golang.org/x/tools/go/analysis"
 	"golang.org/x/tools/go/analysis/passes/inspect"
 	"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
-	"golang.org/x/tools/go/ast/astutil"
 	"golang.org/x/tools/go/ast/inspector"
 )
 
@@ -169,7 +168,7 @@
 // seen[e] is already true; any newly processed exprs are added to seen.
 func (op boolOp) split(e ast.Expr, seen map[*ast.BinaryExpr]bool) (exprs []ast.Expr) {
 	for {
-		e = astutil.Unparen(e)
+		e = ast.Unparen(e)
 		if b, ok := e.(*ast.BinaryExpr); ok && b.Op == op.tok {
 			seen[b] = true
 			exprs = append(exprs, op.split(b.Y, seen)...)
diff --git a/go/analysis/passes/cgocall/cgocall.go b/go/analysis/passes/cgocall/cgocall.go
index 4e86439..26ec068 100644
--- a/go/analysis/passes/cgocall/cgocall.go
+++ b/go/analysis/passes/cgocall/cgocall.go
@@ -19,7 +19,6 @@
 
 	"golang.org/x/tools/go/analysis"
 	"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
-	"golang.org/x/tools/go/ast/astutil"
 )
 
 const debug = false
@@ -65,7 +64,7 @@
 
 		// Is this a C.f() call?
 		var name string
-		if sel, ok := astutil.Unparen(call.Fun).(*ast.SelectorExpr); ok {
+		if sel, ok := ast.Unparen(call.Fun).(*ast.SelectorExpr); ok {
 			if id, ok := sel.X.(*ast.Ident); ok && id.Name == "C" {
 				name = sel.Sel.Name
 			}
diff --git a/go/analysis/passes/copylock/copylock.go b/go/analysis/passes/copylock/copylock.go
index 0d63cd1..3e9a55b 100644
--- a/go/analysis/passes/copylock/copylock.go
+++ b/go/analysis/passes/copylock/copylock.go
@@ -16,7 +16,6 @@
 	"golang.org/x/tools/go/analysis"
 	"golang.org/x/tools/go/analysis/passes/inspect"
 	"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
-	"golang.org/x/tools/go/ast/astutil"
 	"golang.org/x/tools/go/ast/inspector"
 	"golang.org/x/tools/internal/aliases"
 	"golang.org/x/tools/internal/typeparams"
@@ -253,7 +252,7 @@
 }
 
 func lockPathRhs(pass *analysis.Pass, x ast.Expr) typePath {
-	x = astutil.Unparen(x) // ignore parens on rhs
+	x = ast.Unparen(x) // ignore parens on rhs
 
 	if _, ok := x.(*ast.CompositeLit); ok {
 		return nil
@@ -263,7 +262,7 @@
 		return nil
 	}
 	if star, ok := x.(*ast.StarExpr); ok {
-		if _, ok := astutil.Unparen(star.X).(*ast.CallExpr); ok {
+		if _, ok := ast.Unparen(star.X).(*ast.CallExpr); ok {
 			// A call may return a pointer to a zero value.
 			return nil
 		}
diff --git a/go/analysis/passes/testinggoroutine/testinggoroutine.go b/go/analysis/passes/testinggoroutine/testinggoroutine.go
index 828f95b..aaf1c76 100644
--- a/go/analysis/passes/testinggoroutine/testinggoroutine.go
+++ b/go/analysis/passes/testinggoroutine/testinggoroutine.go
@@ -14,7 +14,6 @@
 	"golang.org/x/tools/go/analysis"
 	"golang.org/x/tools/go/analysis/passes/inspect"
 	"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
-	"golang.org/x/tools/go/ast/astutil"
 	"golang.org/x/tools/go/ast/inspector"
 	"golang.org/x/tools/go/types/typeutil"
 	"golang.org/x/tools/internal/aliases"
@@ -186,7 +185,7 @@
 func goAsyncCall(info *types.Info, goStmt *ast.GoStmt, toDecl func(*types.Func) *ast.FuncDecl) *asyncCall {
 	call := goStmt.Call
 
-	fun := astutil.Unparen(call.Fun)
+	fun := ast.Unparen(call.Fun)
 	if id := funcIdent(fun); id != nil {
 		if lit := funcLitInScope(id); lit != nil {
 			return &asyncCall{region: lit, async: goStmt, scope: nil, fun: fun}
@@ -213,7 +212,7 @@
 		return nil
 	}
 
-	fun := astutil.Unparen(call.Args[1])
+	fun := ast.Unparen(call.Args[1])
 	if lit, ok := fun.(*ast.FuncLit); ok { // function lit?
 		return &asyncCall{region: lit, async: call, scope: lit, fun: fun}
 	}
@@ -243,7 +242,7 @@
 // Returns (nil, nil, nil) if call is not of this form.
 func forbiddenMethod(info *types.Info, call *ast.CallExpr) (*types.Var, *types.Selection, *types.Func) {
 	// Compare to typeutil.StaticCallee.
-	fun := astutil.Unparen(call.Fun)
+	fun := ast.Unparen(call.Fun)
 	selExpr, ok := fun.(*ast.SelectorExpr)
 	if !ok {
 		return nil, nil, nil
@@ -254,7 +253,7 @@
 	}
 
 	var x *types.Var
-	if id, ok := astutil.Unparen(selExpr.X).(*ast.Ident); ok {
+	if id, ok := ast.Unparen(selExpr.X).(*ast.Ident); ok {
 		x, _ = info.Uses[id].(*types.Var)
 	}
 	if x == nil {
diff --git a/go/analysis/passes/testinggoroutine/util.go b/go/analysis/passes/testinggoroutine/util.go
index ad815f1..8c7a51c 100644
--- a/go/analysis/passes/testinggoroutine/util.go
+++ b/go/analysis/passes/testinggoroutine/util.go
@@ -8,7 +8,6 @@
 	"go/ast"
 	"go/types"
 
-	"golang.org/x/tools/go/ast/astutil"
 	"golang.org/x/tools/internal/typeparams"
 )
 
@@ -56,7 +55,7 @@
 }
 
 func funcIdent(fun ast.Expr) *ast.Ident {
-	switch fun := astutil.Unparen(fun).(type) {
+	switch fun := ast.Unparen(fun).(type) {
 	case *ast.IndexExpr, *ast.IndexListExpr:
 		x, _, _, _ := typeparams.UnpackIndexExpr(fun) // necessary?
 		id, _ := x.(*ast.Ident)
diff --git a/go/analysis/passes/unsafeptr/unsafeptr.go b/go/analysis/passes/unsafeptr/unsafeptr.go
index 14e4a6c..f4261a6 100644
--- a/go/analysis/passes/unsafeptr/unsafeptr.go
+++ b/go/analysis/passes/unsafeptr/unsafeptr.go
@@ -15,7 +15,6 @@
 	"golang.org/x/tools/go/analysis"
 	"golang.org/x/tools/go/analysis/passes/inspect"
 	"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
-	"golang.org/x/tools/go/ast/astutil"
 	"golang.org/x/tools/go/ast/inspector"
 	"golang.org/x/tools/internal/aliases"
 )
@@ -70,7 +69,7 @@
 	// Check unsafe.Pointer safety rules according to
 	// https://golang.org/pkg/unsafe/#Pointer.
 
-	switch x := astutil.Unparen(x).(type) {
+	switch x := ast.Unparen(x).(type) {
 	case *ast.SelectorExpr:
 		// "(6) Conversion of a reflect.SliceHeader or
 		// reflect.StringHeader Data field to or from Pointer."
@@ -119,7 +118,7 @@
 // isSafeArith reports whether x is a pointer arithmetic expression that is safe
 // to convert to unsafe.Pointer.
 func isSafeArith(info *types.Info, x ast.Expr) bool {
-	switch x := astutil.Unparen(x).(type) {
+	switch x := ast.Unparen(x).(type) {
 	case *ast.CallExpr:
 		// Base case: initial conversion from unsafe.Pointer to uintptr.
 		return len(x.Args) == 1 &&
diff --git a/go/analysis/passes/unusedresult/unusedresult.go b/go/analysis/passes/unusedresult/unusedresult.go
index 76f42b0..c27d26d 100644
--- a/go/analysis/passes/unusedresult/unusedresult.go
+++ b/go/analysis/passes/unusedresult/unusedresult.go
@@ -24,7 +24,6 @@
 	"golang.org/x/tools/go/analysis"
 	"golang.org/x/tools/go/analysis/passes/inspect"
 	"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
-	"golang.org/x/tools/go/ast/astutil"
 	"golang.org/x/tools/go/ast/inspector"
 	"golang.org/x/tools/go/types/typeutil"
 )
@@ -101,7 +100,7 @@
 		(*ast.ExprStmt)(nil),
 	}
 	inspect.Preorder(nodeFilter, func(n ast.Node) {
-		call, ok := astutil.Unparen(n.(*ast.ExprStmt).X).(*ast.CallExpr)
+		call, ok := ast.Unparen(n.(*ast.ExprStmt).X).(*ast.CallExpr)
 		if !ok {
 			return // not a call statement
 		}
diff --git a/go/ast/astutil/util.go b/go/ast/astutil/util.go
index 6bdcf70..ca71e3e 100644
--- a/go/ast/astutil/util.go
+++ b/go/ast/astutil/util.go
@@ -7,13 +7,5 @@
 import "go/ast"
 
 // Unparen returns e with any enclosing parentheses stripped.
-// TODO(adonovan): use go1.22's ast.Unparen.
-func Unparen(e ast.Expr) ast.Expr {
-	for {
-		p, ok := e.(*ast.ParenExpr)
-		if !ok {
-			return e
-		}
-		e = p.X
-	}
-}
+// Deprecated: use [ast.Unparen].
+func Unparen(e ast.Expr) ast.Expr { return ast.Unparen(e) }
diff --git a/go/ssa/util.go b/go/ssa/util.go
index 549c9c8..4ac2b19 100644
--- a/go/ssa/util.go
+++ b/go/ssa/util.go
@@ -15,7 +15,6 @@
 	"os"
 	"sync"
 
-	"golang.org/x/tools/go/ast/astutil"
 	"golang.org/x/tools/go/types/typeutil"
 	"golang.org/x/tools/internal/aliases"
 	"golang.org/x/tools/internal/typeparams"
@@ -36,7 +35,7 @@
 
 //// AST utilities
 
-func unparen(e ast.Expr) ast.Expr { return astutil.Unparen(e) }
+func unparen(e ast.Expr) ast.Expr { return ast.Unparen(e) }
 
 // isBlankIdent returns true iff e is an Ident with name "_".
 // They have no associated types.Object, and thus no type.
diff --git a/go/types/typeutil/callee.go b/go/types/typeutil/callee.go
index 90dc541..7543803 100644
--- a/go/types/typeutil/callee.go
+++ b/go/types/typeutil/callee.go
@@ -8,7 +8,6 @@
 	"go/ast"
 	"go/types"
 
-	"golang.org/x/tools/go/ast/astutil"
 	"golang.org/x/tools/internal/typeparams"
 )
 
@@ -17,7 +16,7 @@
 //
 // Functions and methods may potentially have type parameters.
 func Callee(info *types.Info, call *ast.CallExpr) types.Object {
-	fun := astutil.Unparen(call.Fun)
+	fun := ast.Unparen(call.Fun)
 
 	// Look through type instantiation if necessary.
 	isInstance := false
diff --git a/internal/refactor/inline/callee.go b/internal/refactor/inline/callee.go
index 09deda3..c72699c 100644
--- a/internal/refactor/inline/callee.go
+++ b/internal/refactor/inline/callee.go
@@ -16,7 +16,6 @@
 	"go/types"
 	"strings"
 
-	"golang.org/x/tools/go/ast/astutil"
 	"golang.org/x/tools/go/types/typeutil"
 	"golang.org/x/tools/internal/typeparams"
 )
@@ -242,7 +241,7 @@
 		// not just a return statement
 	} else if ret, ok := decl.Body.List[0].(*ast.ReturnStmt); ok && len(ret.Results) == 1 {
 		validForCallStmt = func() bool {
-			switch expr := astutil.Unparen(ret.Results[0]).(type) {
+			switch expr := ast.Unparen(ret.Results[0]).(type) {
 			case *ast.CallExpr: // f(x)
 				callee := typeutil.Callee(info, expr)
 				if callee == nil {
diff --git a/internal/refactor/inline/inline.go b/internal/refactor/inline/inline.go
index da2d26e..21f3147 100644
--- a/internal/refactor/inline/inline.go
+++ b/internal/refactor/inline/inline.go
@@ -527,7 +527,7 @@
 			// or time.Second.String()) will remain after
 			// inlining, as arguments.
 			if pkgName, ok := existing.(*types.PkgName); ok {
-				if sel, ok := astutil.Unparen(caller.Call.Fun).(*ast.SelectorExpr); ok {
+				if sel, ok := ast.Unparen(caller.Call.Fun).(*ast.SelectorExpr); ok {
 					if sole := soleUse(caller.Info, pkgName); sole == sel.X {
 						for _, spec := range caller.File.Imports {
 							pkgName2, ok := importedPkgName(caller.Info, spec)
@@ -1263,7 +1263,7 @@
 
 	callArgs := caller.Call.Args
 	if calleeDecl.Recv != nil {
-		sel := astutil.Unparen(caller.Call.Fun).(*ast.SelectorExpr)
+		sel := ast.Unparen(caller.Call.Fun).(*ast.SelectorExpr)
 		seln := caller.Info.Selections[sel]
 		var recvArg ast.Expr
 		switch seln.Kind() {
@@ -2227,7 +2227,7 @@
 // be evaluated at any point--though not necessarily at multiple
 // points (consider new, make).
 func callsPureBuiltin(info *types.Info, call *ast.CallExpr) bool {
-	if id, ok := astutil.Unparen(call.Fun).(*ast.Ident); ok {
+	if id, ok := ast.Unparen(call.Fun).(*ast.Ident); ok {
 		if b, ok := info.ObjectOf(id).(*types.Builtin); ok {
 			switch b.Name() {
 			case "len", "cap", "complex", "imag", "real", "make", "new", "max", "min":
diff --git a/refactor/satisfy/find.go b/refactor/satisfy/find.go
index bab0e3c..3d693aa 100644
--- a/refactor/satisfy/find.go
+++ b/refactor/satisfy/find.go
@@ -43,7 +43,6 @@
 	"go/token"
 	"go/types"
 
-	"golang.org/x/tools/go/ast/astutil"
 	"golang.org/x/tools/go/types/typeutil"
 	"golang.org/x/tools/internal/typeparams"
 )
@@ -708,7 +707,7 @@
 
 // -- Plundered from golang.org/x/tools/go/ssa -----------------
 
-func unparen(e ast.Expr) ast.Expr { return astutil.Unparen(e) }
+func unparen(e ast.Expr) ast.Expr { return ast.Unparen(e) }
 
 func isInterface(T types.Type) bool { return types.IsInterface(T) }