gopls/internal/analysis: add skipped analysis simplify on generated code
On generated code, gopls always suggest to simplify code produced literals polluting the "Problems" pane in IDE, while properly refusing to format file on save because it is generated code.
This change will make simplifycompositelit, simplifyrange, simplifyslice skipped on generated code, so it will not polluting the "Problems" pane in IDE.
Fixes golang/go#67733
Change-Id: I99b3f083ce96594f360576f530cfc7f4b77c1cc1
Reviewed-on: https://go-review.googlesource.com/c/tools/+/598835
Reviewed-by: Alan Donovan <adonovan@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Robert Findley <rfindley@google.com>
diff --git a/gopls/doc/analyzers.md b/gopls/doc/analyzers.md
index 45db766..f78f1bd 100644
--- a/gopls/doc/analyzers.md
+++ b/gopls/doc/analyzers.md
@@ -636,6 +636,8 @@
This is one of the simplifications that "gofmt -s" applies.
+This analyzer ignores generated code.
+
Default: on.
Package documentation: [simplifycompositelit](https://pkg.go.dev/golang.org/x/tools/gopls/internal/analysis/simplifycompositelit)
@@ -662,6 +664,8 @@
This is one of the simplifications that "gofmt -s" applies.
+This analyzer ignores generated code.
+
Default: on.
Package documentation: [simplifyrange](https://pkg.go.dev/golang.org/x/tools/gopls/internal/analysis/simplifyrange)
@@ -680,6 +684,8 @@
This is one of the simplifications that "gofmt -s" applies.
+This analyzer ignores generated code.
+
Default: on.
Package documentation: [simplifyslice](https://pkg.go.dev/golang.org/x/tools/gopls/internal/analysis/simplifyslice)
diff --git a/gopls/internal/analysis/simplifycompositelit/doc.go b/gopls/internal/analysis/simplifycompositelit/doc.go
index fe40596..bda74c7 100644
--- a/gopls/internal/analysis/simplifycompositelit/doc.go
+++ b/gopls/internal/analysis/simplifycompositelit/doc.go
@@ -19,4 +19,6 @@
// []T{{}, {}}
//
// This is one of the simplifications that "gofmt -s" applies.
+//
+// This analyzer ignores generated code.
package simplifycompositelit
diff --git a/gopls/internal/analysis/simplifycompositelit/simplifycompositelit.go b/gopls/internal/analysis/simplifycompositelit/simplifycompositelit.go
index c651206..1bdce1d 100644
--- a/gopls/internal/analysis/simplifycompositelit/simplifycompositelit.go
+++ b/gopls/internal/analysis/simplifycompositelit/simplifycompositelit.go
@@ -19,6 +19,7 @@
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
+ "golang.org/x/tools/gopls/internal/util/astutil"
"golang.org/x/tools/internal/analysisinternal"
)
@@ -34,9 +35,21 @@
}
func run(pass *analysis.Pass) (interface{}, error) {
+ // Gather information whether file is generated or not
+ generated := make(map[*token.File]bool)
+ for _, file := range pass.Files {
+ if astutil.IsGenerated(file) {
+ generated[pass.Fset.File(file.Pos())] = true
+ }
+ }
+
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
nodeFilter := []ast.Node{(*ast.CompositeLit)(nil)}
inspect.Preorder(nodeFilter, func(n ast.Node) {
+ if _, ok := generated[pass.Fset.File(n.Pos())]; ok {
+ return // skip checking if it's generated code
+ }
+
expr := n.(*ast.CompositeLit)
outer := expr
diff --git a/gopls/internal/analysis/simplifycompositelit/simplifycompositelit_test.go b/gopls/internal/analysis/simplifycompositelit/simplifycompositelit_test.go
index a355616..4445a0c 100644
--- a/gopls/internal/analysis/simplifycompositelit/simplifycompositelit_test.go
+++ b/gopls/internal/analysis/simplifycompositelit/simplifycompositelit_test.go
@@ -13,5 +13,5 @@
func Test(t *testing.T) {
testdata := analysistest.TestData()
- analysistest.RunWithSuggestedFixes(t, testdata, simplifycompositelit.Analyzer, "a")
+ analysistest.RunWithSuggestedFixes(t, testdata, simplifycompositelit.Analyzer, "a", "generatedcode")
}
diff --git a/gopls/internal/analysis/simplifycompositelit/testdata/src/generatedcode/generatedcode.go b/gopls/internal/analysis/simplifycompositelit/testdata/src/generatedcode/generatedcode.go
new file mode 100644
index 0000000..7b11dc5
--- /dev/null
+++ b/gopls/internal/analysis/simplifycompositelit/testdata/src/generatedcode/generatedcode.go
@@ -0,0 +1,17 @@
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Code generated with somegen DO NOT EDIT.
+
+package testdata
+
+type T struct {
+ x, y int
+}
+
+var _ = [42]T{
+ T{}, // No simplification fix is offered in generated code.
+ T{1, 2}, // No simplification fix is offered in generated code.
+ T{3, 4}, // No simplification fix is offered in generated code.
+}
diff --git a/gopls/internal/analysis/simplifycompositelit/testdata/src/generatedcode/generatedcode.go.golden b/gopls/internal/analysis/simplifycompositelit/testdata/src/generatedcode/generatedcode.go.golden
new file mode 100644
index 0000000..7b11dc5
--- /dev/null
+++ b/gopls/internal/analysis/simplifycompositelit/testdata/src/generatedcode/generatedcode.go.golden
@@ -0,0 +1,17 @@
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Code generated with somegen DO NOT EDIT.
+
+package testdata
+
+type T struct {
+ x, y int
+}
+
+var _ = [42]T{
+ T{}, // No simplification fix is offered in generated code.
+ T{1, 2}, // No simplification fix is offered in generated code.
+ T{3, 4}, // No simplification fix is offered in generated code.
+}
diff --git a/gopls/internal/analysis/simplifyrange/doc.go b/gopls/internal/analysis/simplifyrange/doc.go
index f55ed56..3d1145e 100644
--- a/gopls/internal/analysis/simplifyrange/doc.go
+++ b/gopls/internal/analysis/simplifyrange/doc.go
@@ -27,4 +27,6 @@
// for range v {...}
//
// This is one of the simplifications that "gofmt -s" applies.
+//
+// This analyzer ignores generated code.
package simplifyrange
diff --git a/gopls/internal/analysis/simplifyrange/simplifyrange.go b/gopls/internal/analysis/simplifyrange/simplifyrange.go
index 537e0e9..ce9d450 100644
--- a/gopls/internal/analysis/simplifyrange/simplifyrange.go
+++ b/gopls/internal/analysis/simplifyrange/simplifyrange.go
@@ -14,6 +14,7 @@
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
+ "golang.org/x/tools/gopls/internal/util/astutil"
"golang.org/x/tools/internal/analysisinternal"
)
@@ -29,11 +30,23 @@
}
func run(pass *analysis.Pass) (interface{}, error) {
+ // Gather information whether file is generated or not
+ generated := make(map[*token.File]bool)
+ for _, file := range pass.Files {
+ if astutil.IsGenerated(file) {
+ generated[pass.Fset.File(file.Pos())] = true
+ }
+ }
+
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
nodeFilter := []ast.Node{
(*ast.RangeStmt)(nil),
}
inspect.Preorder(nodeFilter, func(n ast.Node) {
+ if _, ok := generated[pass.Fset.File(n.Pos())]; ok {
+ return // skip checking if it's generated code
+ }
+
var copy *ast.RangeStmt // shallow-copy the AST before modifying
{
x := *n.(*ast.RangeStmt)
diff --git a/gopls/internal/analysis/simplifyrange/simplifyrange_test.go b/gopls/internal/analysis/simplifyrange/simplifyrange_test.go
index fd927c5..973144c 100644
--- a/gopls/internal/analysis/simplifyrange/simplifyrange_test.go
+++ b/gopls/internal/analysis/simplifyrange/simplifyrange_test.go
@@ -15,7 +15,7 @@
func Test(t *testing.T) {
testdata := analysistest.TestData()
- analysistest.RunWithSuggestedFixes(t, testdata, simplifyrange.Analyzer, "a")
+ analysistest.RunWithSuggestedFixes(t, testdata, simplifyrange.Analyzer, "a", "generatedcode")
if slices.Contains(build.Default.ReleaseTags, "go1.23") { // uses iter.Seq
analysistest.RunWithSuggestedFixes(t, testdata, simplifyrange.Analyzer, "rangeoverfunc")
}
diff --git a/gopls/internal/analysis/simplifyrange/testdata/src/generatedcode/generatedcode.go b/gopls/internal/analysis/simplifyrange/testdata/src/generatedcode/generatedcode.go
new file mode 100644
index 0000000..36b935c
--- /dev/null
+++ b/gopls/internal/analysis/simplifyrange/testdata/src/generatedcode/generatedcode.go
@@ -0,0 +1,18 @@
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Code generated with somegen DO NOT EDIT.
+
+package testdata
+
+import "log"
+
+func mgeneratedcode() {
+ maps := make(map[string]string)
+ for k, _ := range maps { // No simplification fix is offered in generated code.
+ log.Println(k)
+ }
+ for _ = range maps { // No simplification fix is offered in generated code.
+ }
+}
diff --git a/gopls/internal/analysis/simplifyrange/testdata/src/generatedcode/generatedcode.go.golden b/gopls/internal/analysis/simplifyrange/testdata/src/generatedcode/generatedcode.go.golden
new file mode 100644
index 0000000..36b935c
--- /dev/null
+++ b/gopls/internal/analysis/simplifyrange/testdata/src/generatedcode/generatedcode.go.golden
@@ -0,0 +1,18 @@
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Code generated with somegen DO NOT EDIT.
+
+package testdata
+
+import "log"
+
+func mgeneratedcode() {
+ maps := make(map[string]string)
+ for k, _ := range maps { // No simplification fix is offered in generated code.
+ log.Println(k)
+ }
+ for _ = range maps { // No simplification fix is offered in generated code.
+ }
+}
diff --git a/gopls/internal/analysis/simplifyslice/doc.go b/gopls/internal/analysis/simplifyslice/doc.go
index 2fb4c46..4c6808a 100644
--- a/gopls/internal/analysis/simplifyslice/doc.go
+++ b/gopls/internal/analysis/simplifyslice/doc.go
@@ -19,4 +19,6 @@
// s[a:]
//
// This is one of the simplifications that "gofmt -s" applies.
+//
+// This analyzer ignores generated code.
package simplifyslice
diff --git a/gopls/internal/analysis/simplifyslice/simplifyslice.go b/gopls/internal/analysis/simplifyslice/simplifyslice.go
index 0c7cc3f..343fca8 100644
--- a/gopls/internal/analysis/simplifyslice/simplifyslice.go
+++ b/gopls/internal/analysis/simplifyslice/simplifyslice.go
@@ -10,10 +10,12 @@
"fmt"
"go/ast"
"go/printer"
+ "go/token"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
+ "golang.org/x/tools/gopls/internal/util/astutil"
"golang.org/x/tools/internal/analysisinternal"
)
@@ -37,11 +39,23 @@
// x, y := b[:n], b[n:]
func run(pass *analysis.Pass) (interface{}, error) {
+ // Gather information whether file is generated or not
+ generated := make(map[*token.File]bool)
+ for _, file := range pass.Files {
+ if astutil.IsGenerated(file) {
+ generated[pass.Fset.File(file.Pos())] = true
+ }
+ }
+
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
nodeFilter := []ast.Node{
(*ast.SliceExpr)(nil),
}
inspect.Preorder(nodeFilter, func(n ast.Node) {
+ if _, ok := generated[pass.Fset.File(n.Pos())]; ok {
+ return // skip checking if it's generated code
+ }
+
expr := n.(*ast.SliceExpr)
// - 3-index slices always require the 2nd and 3rd index
if expr.Max != nil {
diff --git a/gopls/internal/analysis/simplifyslice/simplifyslice_test.go b/gopls/internal/analysis/simplifyslice/simplifyslice_test.go
index 969161e..7fc5f9a 100644
--- a/gopls/internal/analysis/simplifyslice/simplifyslice_test.go
+++ b/gopls/internal/analysis/simplifyslice/simplifyslice_test.go
@@ -13,5 +13,5 @@
func Test(t *testing.T) {
testdata := analysistest.TestData()
- analysistest.RunWithSuggestedFixes(t, testdata, simplifyslice.Analyzer, "a", "typeparams")
+ analysistest.RunWithSuggestedFixes(t, testdata, simplifyslice.Analyzer, "a", "generatedcode", "typeparams")
}
diff --git a/gopls/internal/analysis/simplifyslice/testdata/src/generatedcode/generatedcode.go b/gopls/internal/analysis/simplifyslice/testdata/src/generatedcode/generatedcode.go
new file mode 100644
index 0000000..a291600
--- /dev/null
+++ b/gopls/internal/analysis/simplifyslice/testdata/src/generatedcode/generatedcode.go
@@ -0,0 +1,72 @@
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Code generated with somegen DO NOT EDIT.
+
+package testdata
+
+var (
+ a [10]byte
+ b [20]float32
+ s []int
+ t struct {
+ s []byte
+ }
+
+ _ = a[0:]
+ _ = a[1:10]
+ _ = a[2:len(a)] // No simplification fix is offered in generated code.
+ _ = a[3:(len(a))]
+ _ = a[len(a)-1 : len(a)] // No simplification fix is offered in generated code.
+ _ = a[2:len(a):len(a)]
+
+ _ = a[:]
+ _ = a[:10]
+ _ = a[:len(a)] // No simplification fix is offered in generated code.
+ _ = a[:(len(a))]
+ _ = a[:len(a)-1]
+ _ = a[:len(a):len(a)]
+
+ _ = s[0:]
+ _ = s[1:10]
+ _ = s[2:len(s)] // No simplification fix is offered in generated code.
+ _ = s[3:(len(s))]
+ _ = s[len(a) : len(s)-1]
+ _ = s[0:len(b)]
+ _ = s[2:len(s):len(s)]
+
+ _ = s[:]
+ _ = s[:10]
+ _ = s[:len(s)] // No simplification fix is offered in generated code.
+ _ = s[:(len(s))]
+ _ = s[:len(s)-1]
+ _ = s[:len(b)]
+ _ = s[:len(s):len(s)]
+
+ _ = t.s[0:]
+ _ = t.s[1:10]
+ _ = t.s[2:len(t.s)]
+ _ = t.s[3:(len(t.s))]
+ _ = t.s[len(a) : len(t.s)-1]
+ _ = t.s[0:len(b)]
+ _ = t.s[2:len(t.s):len(t.s)]
+
+ _ = t.s[:]
+ _ = t.s[:10]
+ _ = t.s[:len(t.s)]
+ _ = t.s[:(len(t.s))]
+ _ = t.s[:len(t.s)-1]
+ _ = t.s[:len(b)]
+ _ = t.s[:len(t.s):len(t.s)]
+)
+
+func _() {
+ s := s[0:len(s)] // No simplification fix is offered in generated code.
+ _ = s
+}
+
+func m() {
+ maps := []int{}
+ _ = maps[1:len(maps)] // No simplification fix is offered in generated code.
+}
diff --git a/gopls/internal/analysis/simplifyslice/testdata/src/generatedcode/generatedcode.go.golden b/gopls/internal/analysis/simplifyslice/testdata/src/generatedcode/generatedcode.go.golden
new file mode 100644
index 0000000..a291600
--- /dev/null
+++ b/gopls/internal/analysis/simplifyslice/testdata/src/generatedcode/generatedcode.go.golden
@@ -0,0 +1,72 @@
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Code generated with somegen DO NOT EDIT.
+
+package testdata
+
+var (
+ a [10]byte
+ b [20]float32
+ s []int
+ t struct {
+ s []byte
+ }
+
+ _ = a[0:]
+ _ = a[1:10]
+ _ = a[2:len(a)] // No simplification fix is offered in generated code.
+ _ = a[3:(len(a))]
+ _ = a[len(a)-1 : len(a)] // No simplification fix is offered in generated code.
+ _ = a[2:len(a):len(a)]
+
+ _ = a[:]
+ _ = a[:10]
+ _ = a[:len(a)] // No simplification fix is offered in generated code.
+ _ = a[:(len(a))]
+ _ = a[:len(a)-1]
+ _ = a[:len(a):len(a)]
+
+ _ = s[0:]
+ _ = s[1:10]
+ _ = s[2:len(s)] // No simplification fix is offered in generated code.
+ _ = s[3:(len(s))]
+ _ = s[len(a) : len(s)-1]
+ _ = s[0:len(b)]
+ _ = s[2:len(s):len(s)]
+
+ _ = s[:]
+ _ = s[:10]
+ _ = s[:len(s)] // No simplification fix is offered in generated code.
+ _ = s[:(len(s))]
+ _ = s[:len(s)-1]
+ _ = s[:len(b)]
+ _ = s[:len(s):len(s)]
+
+ _ = t.s[0:]
+ _ = t.s[1:10]
+ _ = t.s[2:len(t.s)]
+ _ = t.s[3:(len(t.s))]
+ _ = t.s[len(a) : len(t.s)-1]
+ _ = t.s[0:len(b)]
+ _ = t.s[2:len(t.s):len(t.s)]
+
+ _ = t.s[:]
+ _ = t.s[:10]
+ _ = t.s[:len(t.s)]
+ _ = t.s[:(len(t.s))]
+ _ = t.s[:len(t.s)-1]
+ _ = t.s[:len(b)]
+ _ = t.s[:len(t.s):len(t.s)]
+)
+
+func _() {
+ s := s[0:len(s)] // No simplification fix is offered in generated code.
+ _ = s
+}
+
+func m() {
+ maps := []int{}
+ _ = maps[1:len(maps)] // No simplification fix is offered in generated code.
+}
diff --git a/gopls/internal/doc/api.json b/gopls/internal/doc/api.json
index 7de6006..322707d 100644
--- a/gopls/internal/doc/api.json
+++ b/gopls/internal/doc/api.json
@@ -524,17 +524,17 @@
},
{
"Name": "\"simplifycompositelit\"",
- "Doc": "check for composite literal simplifications\n\nAn array, slice, or map composite literal of the form:\n\n\t[]T{T{}, T{}}\n\nwill be simplified to:\n\n\t[]T{{}, {}}\n\nThis is one of the simplifications that \"gofmt -s\" applies.",
+ "Doc": "check for composite literal simplifications\n\nAn array, slice, or map composite literal of the form:\n\n\t[]T{T{}, T{}}\n\nwill be simplified to:\n\n\t[]T{{}, {}}\n\nThis is one of the simplifications that \"gofmt -s\" applies.\n\nThis analyzer ignores generated code.",
"Default": "true"
},
{
"Name": "\"simplifyrange\"",
- "Doc": "check for range statement simplifications\n\nA range of the form:\n\n\tfor x, _ = range v {...}\n\nwill be simplified to:\n\n\tfor x = range v {...}\n\nA range of the form:\n\n\tfor _ = range v {...}\n\nwill be simplified to:\n\n\tfor range v {...}\n\nThis is one of the simplifications that \"gofmt -s\" applies.",
+ "Doc": "check for range statement simplifications\n\nA range of the form:\n\n\tfor x, _ = range v {...}\n\nwill be simplified to:\n\n\tfor x = range v {...}\n\nA range of the form:\n\n\tfor _ = range v {...}\n\nwill be simplified to:\n\n\tfor range v {...}\n\nThis is one of the simplifications that \"gofmt -s\" applies.\n\nThis analyzer ignores generated code.",
"Default": "true"
},
{
"Name": "\"simplifyslice\"",
- "Doc": "check for slice simplifications\n\nA slice expression of the form:\n\n\ts[a:len(s)]\n\nwill be simplified to:\n\n\ts[a:]\n\nThis is one of the simplifications that \"gofmt -s\" applies.",
+ "Doc": "check for slice simplifications\n\nA slice expression of the form:\n\n\ts[a:len(s)]\n\nwill be simplified to:\n\n\ts[a:]\n\nThis is one of the simplifications that \"gofmt -s\" applies.\n\nThis analyzer ignores generated code.",
"Default": "true"
},
{
@@ -1186,19 +1186,19 @@
},
{
"Name": "simplifycompositelit",
- "Doc": "check for composite literal simplifications\n\nAn array, slice, or map composite literal of the form:\n\n\t[]T{T{}, T{}}\n\nwill be simplified to:\n\n\t[]T{{}, {}}\n\nThis is one of the simplifications that \"gofmt -s\" applies.",
+ "Doc": "check for composite literal simplifications\n\nAn array, slice, or map composite literal of the form:\n\n\t[]T{T{}, T{}}\n\nwill be simplified to:\n\n\t[]T{{}, {}}\n\nThis is one of the simplifications that \"gofmt -s\" applies.\n\nThis analyzer ignores generated code.",
"URL": "https://pkg.go.dev/golang.org/x/tools/gopls/internal/analysis/simplifycompositelit",
"Default": true
},
{
"Name": "simplifyrange",
- "Doc": "check for range statement simplifications\n\nA range of the form:\n\n\tfor x, _ = range v {...}\n\nwill be simplified to:\n\n\tfor x = range v {...}\n\nA range of the form:\n\n\tfor _ = range v {...}\n\nwill be simplified to:\n\n\tfor range v {...}\n\nThis is one of the simplifications that \"gofmt -s\" applies.",
+ "Doc": "check for range statement simplifications\n\nA range of the form:\n\n\tfor x, _ = range v {...}\n\nwill be simplified to:\n\n\tfor x = range v {...}\n\nA range of the form:\n\n\tfor _ = range v {...}\n\nwill be simplified to:\n\n\tfor range v {...}\n\nThis is one of the simplifications that \"gofmt -s\" applies.\n\nThis analyzer ignores generated code.",
"URL": "https://pkg.go.dev/golang.org/x/tools/gopls/internal/analysis/simplifyrange",
"Default": true
},
{
"Name": "simplifyslice",
- "Doc": "check for slice simplifications\n\nA slice expression of the form:\n\n\ts[a:len(s)]\n\nwill be simplified to:\n\n\ts[a:]\n\nThis is one of the simplifications that \"gofmt -s\" applies.",
+ "Doc": "check for slice simplifications\n\nA slice expression of the form:\n\n\ts[a:len(s)]\n\nwill be simplified to:\n\n\ts[a:]\n\nThis is one of the simplifications that \"gofmt -s\" applies.\n\nThis analyzer ignores generated code.",
"URL": "https://pkg.go.dev/golang.org/x/tools/gopls/internal/analysis/simplifyslice",
"Default": true
},
diff --git a/gopls/internal/util/astutil/util.go b/gopls/internal/util/astutil/util.go
index ac7515d..b9cf9a0 100644
--- a/gopls/internal/util/astutil/util.go
+++ b/gopls/internal/util/astutil/util.go
@@ -7,6 +7,7 @@
import (
"go/ast"
"go/token"
+ "strings"
"golang.org/x/tools/internal/typeparams"
)
@@ -69,3 +70,25 @@
func NodeContains(n ast.Node, pos token.Pos) bool {
return n.Pos() <= pos && pos <= n.End()
}
+
+// IsGenerated check if a file is generated code
+func IsGenerated(file *ast.File) bool {
+ // TODO: replace this implementation with calling function ast.IsGenerated when go1.21 is assured
+ for _, group := range file.Comments {
+ for _, comment := range group.List {
+ if comment.Pos() > file.Package {
+ break // after package declaration
+ }
+ // opt: check Contains first to avoid unnecessary array allocation in Split.
+ const prefix = "// Code generated "
+ if strings.Contains(comment.Text, prefix) {
+ for _, line := range strings.Split(comment.Text, "\n") {
+ if strings.HasPrefix(line, prefix) && strings.HasSuffix(line, " DO NOT EDIT.") {
+ return true
+ }
+ }
+ }
+ }
+ }
+ return false
+}