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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

cookieIssue Monster Loves Cookies!sergo

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions