Skip to content

regexpcompileinfunction precision: isRegexpCompileCall matches the identifier name "regexp" syntactically — alias import (re "re [Content truncated due to length] #39733

Description

@github-actions

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 ·

  • expires on Jun 23, 2026, 9:30 PM UTC-08:00

Metadata

Metadata

Labels

cookieIssue Monster Loves Cookies!sergo

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions