internal/analysisinternal: export EnclosingFile

...and use it throughout modernize.

Change-Id: I8d9b94ed474750e00c94cc963745340cd7fb2348
Reviewed-on: https://go-review.googlesource.com/c/tools/+/708956
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Robert Findley <rfindley@google.com>
diff --git a/go/analysis/passes/modernize/errorsastype.go b/go/analysis/passes/modernize/errorsastype.go
index ef8ce8b..a3ed611 100644
--- a/go/analysis/passes/modernize/errorsastype.go
+++ b/go/analysis/passes/modernize/errorsastype.go
@@ -94,7 +94,7 @@
 			continue
 		}
 
-		file := enclosingFile(curDeclStmt)
+		file := analysisinternal.EnclosingFile(curDeclStmt)
 		if !fileUses(info, file, "go1.26") {
 			continue // errors.AsType is too new
 		}
diff --git a/go/analysis/passes/modernize/fmtappendf.go b/go/analysis/passes/modernize/fmtappendf.go
index 4313902..4e6a254 100644
--- a/go/analysis/passes/modernize/fmtappendf.go
+++ b/go/analysis/passes/modernize/fmtappendf.go
@@ -49,7 +49,7 @@
 				conv := curCall.Parent().Node().(*ast.CallExpr)
 				tv := pass.TypesInfo.Types[conv.Fun]
 				if tv.IsType() && types.Identical(tv.Type, byteSliceType) &&
-					fileUses(pass.TypesInfo, enclosingFile(curCall), "go1.19") {
+					fileUses(pass.TypesInfo, analysisinternal.EnclosingFile(curCall), "go1.19") {
 					// Have: []byte(fmt.SprintX(...))
 
 					// Find "Sprint" identifier.
diff --git a/go/analysis/passes/modernize/modernize.go b/go/analysis/passes/modernize/modernize.go
index 6367012..e51e4a5 100644
--- a/go/analysis/passes/modernize/modernize.go
+++ b/go/analysis/passes/modernize/modernize.go
@@ -118,12 +118,6 @@
 	return !versions.Before(info.FileVersions[file], version)
 }
 
-// enclosingFile returns the syntax tree for the file enclosing c.
-func enclosingFile(c inspector.Cursor) *ast.File {
-	c, _ = moreiters.First(c.Enclosing((*ast.File)(nil)))
-	return c.Node().(*ast.File)
-}
-
 // within reports whether the current pass is analyzing one of the
 // specified standard packages or their dependencies.
 func within(pass *analysis.Pass, pkgs ...string) bool {
diff --git a/go/analysis/passes/modernize/newexpr.go b/go/analysis/passes/modernize/newexpr.go
index 08bc71d..2522cf2 100644
--- a/go/analysis/passes/modernize/newexpr.go
+++ b/go/analysis/passes/modernize/newexpr.go
@@ -58,7 +58,7 @@
 								pass.ExportObjectFact(fn, &newLike{})
 
 								// Check file version.
-								file := enclosingFile(curFuncDecl)
+								file := analysisinternal.EnclosingFile(curFuncDecl)
 								if !fileUses(info, file, "go1.26") {
 									continue // new(expr) not available in this file
 								}
@@ -138,7 +138,7 @@
 			pass.ImportObjectFact(fn, &fact) {
 
 			// Check file version.
-			file := enclosingFile(curCall)
+			file := analysisinternal.EnclosingFile(curCall)
 			if !fileUses(info, file, "go1.26") {
 				continue // new(expr) not available in this file
 			}
diff --git a/go/analysis/passes/modernize/reflect.go b/go/analysis/passes/modernize/reflect.go
index 1ddf0f9..28a13c4 100644
--- a/go/analysis/passes/modernize/reflect.go
+++ b/go/analysis/passes/modernize/reflect.go
@@ -87,7 +87,7 @@
 			continue
 		}
 
-		file := enclosingFile(curCall)
+		file := analysisinternal.EnclosingFile(curCall)
 		if versions.Before(info.FileVersions[file], "go1.22") {
 			continue // TypeFor requires go1.22
 		}
diff --git a/go/analysis/passes/modernize/sortslice.go b/go/analysis/passes/modernize/sortslice.go
index 3b6b8da..c216aab 100644
--- a/go/analysis/passes/modernize/sortslice.go
+++ b/go/analysis/passes/modernize/sortslice.go
@@ -84,7 +84,7 @@
 							is[*ast.Ident](index.Index) &&
 							info.Uses[index.Index.(*ast.Ident)] == v
 					}
-					file := enclosingFile(curCall)
+					file := analysisinternal.EnclosingFile(curCall)
 					if isIndex(compare.X, i) && isIndex(compare.Y, j) &&
 						fileUses(info, file, "go1.21") {
 						// Have: sort.Slice(s, func(i, j int) bool { return s[i] < s[j] })
diff --git a/go/analysis/passes/modernize/stditerators.go b/go/analysis/passes/modernize/stditerators.go
index e32c297..0569b33 100644
--- a/go/analysis/passes/modernize/stditerators.go
+++ b/go/analysis/passes/modernize/stditerators.go
@@ -314,7 +314,7 @@
 			// may be somewhat expensive.)
 			if v, ok := methodGoVersion(row.pkgpath, row.typename, row.itermethod); !ok {
 				panic("no version found")
-			} else if file := enclosingFile(curLenCall); !fileUses(info, file, v.String()) {
+			} else if file := analysisinternal.EnclosingFile(curLenCall); !fileUses(info, file, v.String()) {
 				continue nextCall
 			}
 
diff --git a/go/analysis/passes/modernize/stringsbuilder.go b/go/analysis/passes/modernize/stringsbuilder.go
index aa07900..7cbda73 100644
--- a/go/analysis/passes/modernize/stringsbuilder.go
+++ b/go/analysis/passes/modernize/stringsbuilder.go
@@ -101,7 +101,7 @@
 
 			// Add strings import.
 			_, prefix, importEdits := analysisinternal.AddImport(
-				pass.TypesInfo, enclosingFile(def), "strings", "strings", "Builder", v.Pos())
+				pass.TypesInfo, analysisinternal.EnclosingFile(def), "strings", "strings", "Builder", v.Pos())
 			edits = append(edits, importEdits...)
 
 			if isEmptyString(pass.TypesInfo, assign.Rhs[0]) {
@@ -140,7 +140,7 @@
 
 			// Add strings import.
 			_, prefix, importEdits := analysisinternal.AddImport(
-				pass.TypesInfo, enclosingFile(def), "strings", "strings", "Builder", v.Pos())
+				pass.TypesInfo, analysisinternal.EnclosingFile(def), "strings", "strings", "Builder", v.Pos())
 			edits = append(edits, importEdits...)
 
 			spec := def.Parent().Node().(*ast.ValueSpec)
diff --git a/go/analysis/passes/modernize/testingcontext.go b/go/analysis/passes/modernize/testingcontext.go
index 10a7ad6..d14bf97 100644
--- a/go/analysis/passes/modernize/testingcontext.go
+++ b/go/analysis/passes/modernize/testingcontext.go
@@ -135,7 +135,7 @@
 				testObj = isTestFn(info, n)
 			}
 		}
-		if testObj != nil && fileUses(info, enclosingFile(cur), "go1.24") {
+		if testObj != nil && fileUses(info, analysisinternal.EnclosingFile(cur), "go1.24") {
 			// Have a test function. Check that we can resolve the relevant
 			// testing.{T,B,F} at the current position.
 			if _, obj := lhs[0].Parent().LookupParent(testObj.Name(), lhs[0].Pos()); obj == testObj {
diff --git a/go/analysis/passes/modernize/waitgroup.go b/go/analysis/passes/modernize/waitgroup.go
index bbae38a..b8de5f6 100644
--- a/go/analysis/passes/modernize/waitgroup.go
+++ b/go/analysis/passes/modernize/waitgroup.go
@@ -126,7 +126,7 @@
 			panic("can't find Cursor for 'done' statement")
 		}
 
-		file := enclosingFile(curAddCall)
+		file := analysisinternal.EnclosingFile(curAddCall)
 		if !fileUses(info, file, "go1.25") {
 			continue
 		}
diff --git a/internal/analysisinternal/analysis.go b/internal/analysisinternal/analysis.go
index 57ec1a9..e4e893a 100644
--- a/internal/analysisinternal/analysis.go
+++ b/internal/analysisinternal/analysis.go
@@ -585,7 +585,7 @@
 	}
 	// and now for the comments
 Outer:
-	for _, cg := range enclosingFile(curStmt).Comments {
+	for _, cg := range EnclosingFile(curStmt).Comments {
 		for _, co := range cg.List {
 			if lineOf(co.End()) < stmtStartLine {
 				continue
@@ -673,8 +673,10 @@
 func (r tokenRange) Pos() token.Pos { return r.StartPos }
 func (r tokenRange) End() token.Pos { return r.EndPos }
 
-// enclosingFile returns the syntax tree for the file enclosing c.
-func enclosingFile(c inspector.Cursor) *ast.File {
+// EnclosingFile returns the syntax tree for the file enclosing c.
+//
+// TODO(adonovan): promote this to a method of Cursor.
+func EnclosingFile(c inspector.Cursor) *ast.File {
 	c, _ = moreiters.First(c.Enclosing((*ast.File)(nil)))
 	return c.Node().(*ast.File)
 }