Problem
regexpcompileinfunction identifies regexp.MustCompile / regexp.Compile calls by comparing the package identifier's name to the literal string "regexp", with no use of pass.TypesInfo:
// pkg/linters/regexpcompileinfunction/regexpcompileinfunction.go:72-82
func isRegexpCompileCall(call *ast.CallExpr) bool {
sel, ok := call.Fun.(*ast.SelectorExpr)
if !ok { return false }
ident, ok := sel.X.(*ast.Ident)
if !ok { return false }
return ident.Name == "regexp" && (sel.Sel.Name == "MustCompile" || sel.Sel.Name == "Compile")
}
This is the same syntactic-vs-package-identity defect already fixed in sortslice (#38029, merged) and filed for ctxbackground (#38789). Matching on the identifier text alone produces both directions of error:
- False negative (alias import):
import re "regexp" then re.MustCompile("...") → ident.Name == "re" ≠ "regexp" → the in-function compile is missed.
- False positive (shadowing): a local/param/field named
regexp of an unrelated type with a Compile/MustCompile method (e.g. a wrapper) → flagged as a stdlib regexp compile it is not.
This linter is CI-enforced (.github/workflows/cgo.yml:1123, LINTER_FLAGS="... -regexpcompileinfunction ..."), so the FP path can block a build on code that never touches regexp, and the FN path silently drops a real performance finding.
Locations
Impact
Medium. FN: aliased-import call sites escape an enforced linter (latent — grep finds no aliased regexp import in pkg/ today, but nothing prevents one). FP: a future identifier named regexp falsely fails CI. Both are correctness gaps in an enforced linter; the FP is a build-blocker.
Recommendation
Resolve package identity via the type checker instead of the identifier text, exactly as sortslice does:
// after — gate on the imported package path, not the identifier spelling
func isRegexpCompileCall(pass *analysis.Pass, call *ast.CallExpr) bool {
sel, ok := call.Fun.(*ast.SelectorExpr)
if !ok { return false }
if sel.Sel.Name != "MustCompile" && sel.Sel.Name != "Compile" { return false }
ident, ok := sel.X.(*ast.Ident)
if !ok || pass.TypesInfo == nil { return false }
pkgName, ok := pass.TypesInfo.ObjectOf(ident).(*types.PkgName)
return ok && pkgName.Imported().Path() == "regexp"
}
(sortslice.go:58-67 is the merged template; pkg/linters/internal/astutil already does the equivalent Imported().Path() check for "fmt" at astutil.go:72 if a shared helper is preferred.)
Validation checklist
- testdata FN:
import re "regexp"; func f(){ re.MustCompile("x") } → now flagged.
- testdata FP:
type T struct{}; func (T) MustCompile(string){}; func f(){ var regexp T; regexp.MustCompile("x") } → not flagged.
- Existing in-function
regexp.MustCompile("literal") cases still flagged; package-level still skipped.
make golint-custom clean on pkg/; spec_test.go still 29 analyzers.
Effort
Small — single function, thread pass into isRegexpCompileCall, add go/types import; copy of the merged sortslice fix.
Generated by 🤖 Sergo - Serena Go Expert · ◷
Problem
regexpcompileinfunctionidentifiesregexp.MustCompile/regexp.Compilecalls by comparing the package identifier's name to the literal string"regexp", with no use ofpass.TypesInfo:This is the same syntactic-vs-package-identity defect already fixed in
sortslice(#38029, merged) and filed forctxbackground(#38789). Matching on the identifier text alone produces both directions of error:import re "regexp"thenre.MustCompile("...")→ident.Name == "re"≠"regexp"→ the in-function compile is missed.regexpof an unrelated type with aCompile/MustCompilemethod (e.g. a wrapper) → flagged as a stdlib regexp compile it is not.This linter is CI-enforced (
.github/workflows/cgo.yml:1123,LINTER_FLAGS="... -regexpcompileinfunction ..."), so the FP path can block a build on code that never touchesregexp, and the FN path silently drops a real performance finding.Locations
pkg/linters/regexpcompileinfunction/regexpcompileinfunction.go:72-82—isRegexpCompileCall(syntacticident.Name == "regexp").github/workflows/cgo.yml:1123— CI enforcementpkg/linters/sortslice/sortslice.go:58-67(merged via sortslice precision: match sort.Slice/SliceStable via package identity (pass.TypesInfo), not the syntactic identifier name "sort [Content truncated due to length] #38029)Impact
Medium. FN: aliased-import call sites escape an enforced linter (latent — grep finds no aliased
regexpimport inpkg/today, but nothing prevents one). FP: a future identifier namedregexpfalsely fails CI. Both are correctness gaps in an enforced linter; the FP is a build-blocker.Recommendation
Resolve package identity via the type checker instead of the identifier text, exactly as
sortslicedoes:(
sortslice.go:58-67is the merged template;pkg/linters/internal/astutilalready does the equivalentImported().Path()check for"fmt"atastutil.go:72if a shared helper is preferred.)Validation checklist
import re "regexp"; func f(){ re.MustCompile("x") }→ now flagged.type T struct{}; func (T) MustCompile(string){}; func f(){ var regexp T; regexp.MustCompile("x") }→ not flagged.regexp.MustCompile("literal")cases still flagged; package-level still skipped.make golint-customclean onpkg/;spec_test.gostill 29 analyzers.Effort
Small — single function, thread
passintoisRegexpCompileCall, addgo/typesimport; copy of the merged sortslice fix.