From 01cad7e596bddb41a0d09847cbf1639e7f87e7a8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Jun 2026 12:18:50 +0000 Subject: [PATCH 1/4] Initial plan From 979edab34dc5faa116be73a824375b2939c786f5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Jun 2026 12:23:52 +0000 Subject: [PATCH 2/4] Plan: fix isRegexpCompileCall to use type-checker identity Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .github/workflows/grumpy-reviewer.lock.yml | 2 +- .github/workflows/mattpocock-skills-reviewer.lock.yml | 2 +- .github/workflows/pr-code-quality-reviewer.lock.yml | 2 +- .github/workflows/pr-nitpick-reviewer.lock.yml | 2 +- .github/workflows/pr-triage-agent.lock.yml | 2 +- .github/workflows/refiner.lock.yml | 2 +- .github/workflows/security-review.lock.yml | 2 +- .github/workflows/smoke-claude.lock.yml | 2 +- .github/workflows/smoke-copilot-aoai-apikey.lock.yml | 2 +- .github/workflows/smoke-copilot-aoai-entra.lock.yml | 2 +- .github/workflows/smoke-copilot-arm.lock.yml | 2 +- .github/workflows/smoke-copilot.lock.yml | 2 +- .github/workflows/test-quality-sentinel.lock.yml | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/grumpy-reviewer.lock.yml b/.github/workflows/grumpy-reviewer.lock.yml index f0767b939c0..235620f694d 100644 --- a/.github/workflows/grumpy-reviewer.lock.yml +++ b/.github/workflows/grumpy-reviewer.lock.yml @@ -742,7 +742,7 @@ jobs: ] }, "pull_request_number": { - "optionalPositiveInteger": true + "issueOrPRNumber": true }, "repo": { "type": "string", diff --git a/.github/workflows/mattpocock-skills-reviewer.lock.yml b/.github/workflows/mattpocock-skills-reviewer.lock.yml index 630293ffdf3..700ecf36ac1 100644 --- a/.github/workflows/mattpocock-skills-reviewer.lock.yml +++ b/.github/workflows/mattpocock-skills-reviewer.lock.yml @@ -772,7 +772,7 @@ jobs: ] }, "pull_request_number": { - "optionalPositiveInteger": true + "issueOrPRNumber": true }, "repo": { "type": "string", diff --git a/.github/workflows/pr-code-quality-reviewer.lock.yml b/.github/workflows/pr-code-quality-reviewer.lock.yml index c54b67124fe..d45a2313870 100644 --- a/.github/workflows/pr-code-quality-reviewer.lock.yml +++ b/.github/workflows/pr-code-quality-reviewer.lock.yml @@ -736,7 +736,7 @@ jobs: ] }, "pull_request_number": { - "optionalPositiveInteger": true + "issueOrPRNumber": true }, "repo": { "type": "string", diff --git a/.github/workflows/pr-nitpick-reviewer.lock.yml b/.github/workflows/pr-nitpick-reviewer.lock.yml index 8c2646e811d..6130f10bf6c 100644 --- a/.github/workflows/pr-nitpick-reviewer.lock.yml +++ b/.github/workflows/pr-nitpick-reviewer.lock.yml @@ -771,7 +771,7 @@ jobs: ] }, "pull_request_number": { - "optionalPositiveInteger": true + "issueOrPRNumber": true }, "repo": { "type": "string", diff --git a/.github/workflows/pr-triage-agent.lock.yml b/.github/workflows/pr-triage-agent.lock.yml index a5f1b83fdef..36618b1e0ce 100644 --- a/.github/workflows/pr-triage-agent.lock.yml +++ b/.github/workflows/pr-triage-agent.lock.yml @@ -790,7 +790,7 @@ jobs: ] }, "pull_request_number": { - "optionalPositiveInteger": true + "issueOrPRNumber": true }, "repo": { "type": "string", diff --git a/.github/workflows/refiner.lock.yml b/.github/workflows/refiner.lock.yml index e316b50c6a2..b9c4c472934 100644 --- a/.github/workflows/refiner.lock.yml +++ b/.github/workflows/refiner.lock.yml @@ -784,7 +784,7 @@ jobs: ] }, "pull_request_number": { - "optionalPositiveInteger": true + "issueOrPRNumber": true }, "repo": { "type": "string", diff --git a/.github/workflows/security-review.lock.yml b/.github/workflows/security-review.lock.yml index cc0487ee1b3..813428b8085 100644 --- a/.github/workflows/security-review.lock.yml +++ b/.github/workflows/security-review.lock.yml @@ -802,7 +802,7 @@ jobs: ] }, "pull_request_number": { - "optionalPositiveInteger": true + "issueOrPRNumber": true }, "repo": { "type": "string", diff --git a/.github/workflows/smoke-claude.lock.yml b/.github/workflows/smoke-claude.lock.yml index 09e2304f27e..0b49593d1c6 100644 --- a/.github/workflows/smoke-claude.lock.yml +++ b/.github/workflows/smoke-claude.lock.yml @@ -1252,7 +1252,7 @@ jobs: ] }, "pull_request_number": { - "optionalPositiveInteger": true + "issueOrPRNumber": true }, "repo": { "type": "string", diff --git a/.github/workflows/smoke-copilot-aoai-apikey.lock.yml b/.github/workflows/smoke-copilot-aoai-apikey.lock.yml index 05fca4ab840..90d951b7862 100644 --- a/.github/workflows/smoke-copilot-aoai-apikey.lock.yml +++ b/.github/workflows/smoke-copilot-aoai-apikey.lock.yml @@ -1168,7 +1168,7 @@ jobs: ] }, "pull_request_number": { - "optionalPositiveInteger": true + "issueOrPRNumber": true }, "repo": { "type": "string", diff --git a/.github/workflows/smoke-copilot-aoai-entra.lock.yml b/.github/workflows/smoke-copilot-aoai-entra.lock.yml index b956d54065f..2dd7ce15d8b 100644 --- a/.github/workflows/smoke-copilot-aoai-entra.lock.yml +++ b/.github/workflows/smoke-copilot-aoai-entra.lock.yml @@ -1169,7 +1169,7 @@ jobs: ] }, "pull_request_number": { - "optionalPositiveInteger": true + "issueOrPRNumber": true }, "repo": { "type": "string", diff --git a/.github/workflows/smoke-copilot-arm.lock.yml b/.github/workflows/smoke-copilot-arm.lock.yml index a84512ac19f..838dc591aa4 100644 --- a/.github/workflows/smoke-copilot-arm.lock.yml +++ b/.github/workflows/smoke-copilot-arm.lock.yml @@ -1037,7 +1037,7 @@ jobs: ] }, "pull_request_number": { - "optionalPositiveInteger": true + "issueOrPRNumber": true }, "repo": { "type": "string", diff --git a/.github/workflows/smoke-copilot.lock.yml b/.github/workflows/smoke-copilot.lock.yml index 6ec9501f68a..568e58f5714 100644 --- a/.github/workflows/smoke-copilot.lock.yml +++ b/.github/workflows/smoke-copilot.lock.yml @@ -1174,7 +1174,7 @@ jobs: ] }, "pull_request_number": { - "optionalPositiveInteger": true + "issueOrPRNumber": true }, "repo": { "type": "string", diff --git a/.github/workflows/test-quality-sentinel.lock.yml b/.github/workflows/test-quality-sentinel.lock.yml index 416ffad3543..c87faeb4013 100644 --- a/.github/workflows/test-quality-sentinel.lock.yml +++ b/.github/workflows/test-quality-sentinel.lock.yml @@ -731,7 +731,7 @@ jobs: ] }, "pull_request_number": { - "optionalPositiveInteger": true + "issueOrPRNumber": true }, "repo": { "type": "string", From 44be2f8235e2cd58661e38f8a4c8a5f56eb9cf31 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Jun 2026 12:31:41 +0000 Subject: [PATCH 3/4] fix: resolve regexp package identity via type checker in regexpcompileinfunction linter Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .../regexpcompileinfunction.go | 20 ++++++++++++++----- .../regexpcompileinfunction/alias_import.go | 20 +++++++++++++++++++ .../shadowed_identifier.go | 14 +++++++++++++ 3 files changed, 49 insertions(+), 5 deletions(-) create mode 100644 pkg/linters/regexpcompileinfunction/testdata/src/regexpcompileinfunction/alias_import.go create mode 100644 pkg/linters/regexpcompileinfunction/testdata/src/regexpcompileinfunction/shadowed_identifier.go diff --git a/pkg/linters/regexpcompileinfunction/regexpcompileinfunction.go b/pkg/linters/regexpcompileinfunction/regexpcompileinfunction.go index 49ed2c5defb..98918cb90a0 100644 --- a/pkg/linters/regexpcompileinfunction/regexpcompileinfunction.go +++ b/pkg/linters/regexpcompileinfunction/regexpcompileinfunction.go @@ -34,7 +34,7 @@ func run(pass *analysis.Pass) (any, error) { for cur := range insp.Root().Preorder((*ast.CallExpr)(nil)) { call, ok := cur.Node().(*ast.CallExpr) - if !ok || !isRegexpCompileCall(call) { + if !ok || !isRegexpCompileCall(pass, call) { continue } if !hasConstantStringPattern(pass, call) { @@ -68,17 +68,27 @@ func run(pass *analysis.Pass) (any, error) { return nil, nil } -// isRegexpCompileCall checks if the call is to regexp.MustCompile or regexp.Compile. -func isRegexpCompileCall(call *ast.CallExpr) bool { +// isRegexpCompileCall checks if the call is to regexp.MustCompile or regexp.Compile, +// resolving the package identity via the type checker to handle aliased imports +// and avoid false positives from local identifiers named "regexp". +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 { + if !ok || pass.TypesInfo == nil { + return false + } + obj := pass.TypesInfo.ObjectOf(ident) + if obj == nil { return false } - return ident.Name == "regexp" && (sel.Sel.Name == "MustCompile" || sel.Sel.Name == "Compile") + pkgName, ok := obj.(*types.PkgName) + return ok && pkgName.Imported().Path() == "regexp" } // hasConstantStringPattern checks whether the regexp pattern is a compile-time constant string, diff --git a/pkg/linters/regexpcompileinfunction/testdata/src/regexpcompileinfunction/alias_import.go b/pkg/linters/regexpcompileinfunction/testdata/src/regexpcompileinfunction/alias_import.go new file mode 100644 index 00000000000..c78ccb8f650 --- /dev/null +++ b/pkg/linters/regexpcompileinfunction/testdata/src/regexpcompileinfunction/alias_import.go @@ -0,0 +1,20 @@ +package regexpcompileinfunction + +import re "regexp" + +// flagged: aliased import of regexp — alias must not cause a false negative. +func ProcessWithAlias(s string) bool { + r := re.MustCompile(`^[a-z]+$`) // want `regexp compilation inside function should be moved to package-level variable` + return r.MatchString(s) +} + +func ValidateWithAlias(input string) (bool, error) { + r, err := re.Compile(`\d+`) // want `regexp compilation inside function should be moved to package-level variable` + if err != nil { + return false, err + } + return r.MatchString(input), nil +} + +// not flagged: aliased import at package level is fine. +var packageLevelAliasRegexp = re.MustCompile(`^[a-z]+$`) diff --git a/pkg/linters/regexpcompileinfunction/testdata/src/regexpcompileinfunction/shadowed_identifier.go b/pkg/linters/regexpcompileinfunction/testdata/src/regexpcompileinfunction/shadowed_identifier.go new file mode 100644 index 00000000000..90833379715 --- /dev/null +++ b/pkg/linters/regexpcompileinfunction/testdata/src/regexpcompileinfunction/shadowed_identifier.go @@ -0,0 +1,14 @@ +package regexpcompileinfunction + +// customRegexp is an unrelated type that happens to have Compile/MustCompile methods. +type customRegexp struct{} + +func (customRegexp) Compile(_ string) (*customRegexp, error) { return &customRegexp{}, nil } +func (customRegexp) MustCompile(_ string) *customRegexp { return &customRegexp{} } + +// not flagged: local variable named "regexp" is not the stdlib regexp package. +func GoodShadowedRegexpIdentifier(s string) bool { + regexp := customRegexp{} + _ = regexp.MustCompile(s) + return true +} From e16e2a51c092355ea079da6f5429c51116b8a13e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Jun 2026 13:49:13 +0000 Subject: [PATCH 4/4] fix: address review feedback on regexpcompileinfunction linter - Guard pkgName.Imported() against nil before calling .Path() - Fix shadowed_identifier.go fixture to use constant string pattern - Add dot_import.go fixture documenting dot-import known limitation - Revert unrelated lock.yml changes (optionalPositiveInteger -> issueOrPRNumber) Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .github/workflows/grumpy-reviewer.lock.yml | 2 +- .github/workflows/mattpocock-skills-reviewer.lock.yml | 2 +- .github/workflows/pr-code-quality-reviewer.lock.yml | 2 +- .github/workflows/pr-nitpick-reviewer.lock.yml | 2 +- .github/workflows/pr-triage-agent.lock.yml | 2 +- .github/workflows/refiner.lock.yml | 2 +- .github/workflows/security-review.lock.yml | 2 +- .github/workflows/smoke-claude.lock.yml | 2 +- .github/workflows/smoke-copilot-aoai-apikey.lock.yml | 2 +- .github/workflows/smoke-copilot-aoai-entra.lock.yml | 2 +- .github/workflows/smoke-copilot-arm.lock.yml | 2 +- .github/workflows/smoke-copilot.lock.yml | 2 +- .github/workflows/test-quality-sentinel.lock.yml | 2 +- .../regexpcompileinfunction.go | 5 ++++- .../src/regexpcompileinfunction/dot_import.go | 11 +++++++++++ .../regexpcompileinfunction/shadowed_identifier.go | 4 ++-- 16 files changed, 30 insertions(+), 16 deletions(-) create mode 100644 pkg/linters/regexpcompileinfunction/testdata/src/regexpcompileinfunction/dot_import.go diff --git a/.github/workflows/grumpy-reviewer.lock.yml b/.github/workflows/grumpy-reviewer.lock.yml index 235620f694d..f0767b939c0 100644 --- a/.github/workflows/grumpy-reviewer.lock.yml +++ b/.github/workflows/grumpy-reviewer.lock.yml @@ -742,7 +742,7 @@ jobs: ] }, "pull_request_number": { - "issueOrPRNumber": true + "optionalPositiveInteger": true }, "repo": { "type": "string", diff --git a/.github/workflows/mattpocock-skills-reviewer.lock.yml b/.github/workflows/mattpocock-skills-reviewer.lock.yml index 700ecf36ac1..630293ffdf3 100644 --- a/.github/workflows/mattpocock-skills-reviewer.lock.yml +++ b/.github/workflows/mattpocock-skills-reviewer.lock.yml @@ -772,7 +772,7 @@ jobs: ] }, "pull_request_number": { - "issueOrPRNumber": true + "optionalPositiveInteger": true }, "repo": { "type": "string", diff --git a/.github/workflows/pr-code-quality-reviewer.lock.yml b/.github/workflows/pr-code-quality-reviewer.lock.yml index d45a2313870..c54b67124fe 100644 --- a/.github/workflows/pr-code-quality-reviewer.lock.yml +++ b/.github/workflows/pr-code-quality-reviewer.lock.yml @@ -736,7 +736,7 @@ jobs: ] }, "pull_request_number": { - "issueOrPRNumber": true + "optionalPositiveInteger": true }, "repo": { "type": "string", diff --git a/.github/workflows/pr-nitpick-reviewer.lock.yml b/.github/workflows/pr-nitpick-reviewer.lock.yml index 6130f10bf6c..8c2646e811d 100644 --- a/.github/workflows/pr-nitpick-reviewer.lock.yml +++ b/.github/workflows/pr-nitpick-reviewer.lock.yml @@ -771,7 +771,7 @@ jobs: ] }, "pull_request_number": { - "issueOrPRNumber": true + "optionalPositiveInteger": true }, "repo": { "type": "string", diff --git a/.github/workflows/pr-triage-agent.lock.yml b/.github/workflows/pr-triage-agent.lock.yml index 36618b1e0ce..a5f1b83fdef 100644 --- a/.github/workflows/pr-triage-agent.lock.yml +++ b/.github/workflows/pr-triage-agent.lock.yml @@ -790,7 +790,7 @@ jobs: ] }, "pull_request_number": { - "issueOrPRNumber": true + "optionalPositiveInteger": true }, "repo": { "type": "string", diff --git a/.github/workflows/refiner.lock.yml b/.github/workflows/refiner.lock.yml index b9c4c472934..e316b50c6a2 100644 --- a/.github/workflows/refiner.lock.yml +++ b/.github/workflows/refiner.lock.yml @@ -784,7 +784,7 @@ jobs: ] }, "pull_request_number": { - "issueOrPRNumber": true + "optionalPositiveInteger": true }, "repo": { "type": "string", diff --git a/.github/workflows/security-review.lock.yml b/.github/workflows/security-review.lock.yml index 813428b8085..cc0487ee1b3 100644 --- a/.github/workflows/security-review.lock.yml +++ b/.github/workflows/security-review.lock.yml @@ -802,7 +802,7 @@ jobs: ] }, "pull_request_number": { - "issueOrPRNumber": true + "optionalPositiveInteger": true }, "repo": { "type": "string", diff --git a/.github/workflows/smoke-claude.lock.yml b/.github/workflows/smoke-claude.lock.yml index 0b49593d1c6..09e2304f27e 100644 --- a/.github/workflows/smoke-claude.lock.yml +++ b/.github/workflows/smoke-claude.lock.yml @@ -1252,7 +1252,7 @@ jobs: ] }, "pull_request_number": { - "issueOrPRNumber": true + "optionalPositiveInteger": true }, "repo": { "type": "string", diff --git a/.github/workflows/smoke-copilot-aoai-apikey.lock.yml b/.github/workflows/smoke-copilot-aoai-apikey.lock.yml index 90d951b7862..05fca4ab840 100644 --- a/.github/workflows/smoke-copilot-aoai-apikey.lock.yml +++ b/.github/workflows/smoke-copilot-aoai-apikey.lock.yml @@ -1168,7 +1168,7 @@ jobs: ] }, "pull_request_number": { - "issueOrPRNumber": true + "optionalPositiveInteger": true }, "repo": { "type": "string", diff --git a/.github/workflows/smoke-copilot-aoai-entra.lock.yml b/.github/workflows/smoke-copilot-aoai-entra.lock.yml index 2dd7ce15d8b..b956d54065f 100644 --- a/.github/workflows/smoke-copilot-aoai-entra.lock.yml +++ b/.github/workflows/smoke-copilot-aoai-entra.lock.yml @@ -1169,7 +1169,7 @@ jobs: ] }, "pull_request_number": { - "issueOrPRNumber": true + "optionalPositiveInteger": true }, "repo": { "type": "string", diff --git a/.github/workflows/smoke-copilot-arm.lock.yml b/.github/workflows/smoke-copilot-arm.lock.yml index 838dc591aa4..a84512ac19f 100644 --- a/.github/workflows/smoke-copilot-arm.lock.yml +++ b/.github/workflows/smoke-copilot-arm.lock.yml @@ -1037,7 +1037,7 @@ jobs: ] }, "pull_request_number": { - "issueOrPRNumber": true + "optionalPositiveInteger": true }, "repo": { "type": "string", diff --git a/.github/workflows/smoke-copilot.lock.yml b/.github/workflows/smoke-copilot.lock.yml index 568e58f5714..6ec9501f68a 100644 --- a/.github/workflows/smoke-copilot.lock.yml +++ b/.github/workflows/smoke-copilot.lock.yml @@ -1174,7 +1174,7 @@ jobs: ] }, "pull_request_number": { - "issueOrPRNumber": true + "optionalPositiveInteger": true }, "repo": { "type": "string", diff --git a/.github/workflows/test-quality-sentinel.lock.yml b/.github/workflows/test-quality-sentinel.lock.yml index c87faeb4013..416ffad3543 100644 --- a/.github/workflows/test-quality-sentinel.lock.yml +++ b/.github/workflows/test-quality-sentinel.lock.yml @@ -731,7 +731,7 @@ jobs: ] }, "pull_request_number": { - "issueOrPRNumber": true + "optionalPositiveInteger": true }, "repo": { "type": "string", diff --git a/pkg/linters/regexpcompileinfunction/regexpcompileinfunction.go b/pkg/linters/regexpcompileinfunction/regexpcompileinfunction.go index 98918cb90a0..01362d544dc 100644 --- a/pkg/linters/regexpcompileinfunction/regexpcompileinfunction.go +++ b/pkg/linters/regexpcompileinfunction/regexpcompileinfunction.go @@ -88,7 +88,10 @@ func isRegexpCompileCall(pass *analysis.Pass, call *ast.CallExpr) bool { return false } pkgName, ok := obj.(*types.PkgName) - return ok && pkgName.Imported().Path() == "regexp" + if !ok || pkgName.Imported() == nil { + return false + } + return pkgName.Imported().Path() == "regexp" } // hasConstantStringPattern checks whether the regexp pattern is a compile-time constant string, diff --git a/pkg/linters/regexpcompileinfunction/testdata/src/regexpcompileinfunction/dot_import.go b/pkg/linters/regexpcompileinfunction/testdata/src/regexpcompileinfunction/dot_import.go new file mode 100644 index 00000000000..a39e6163267 --- /dev/null +++ b/pkg/linters/regexpcompileinfunction/testdata/src/regexpcompileinfunction/dot_import.go @@ -0,0 +1,11 @@ +package regexpcompileinfunction + +import . "regexp" + +// NOT flagged: dot imports produce bare identifier calls, not selector expressions, +// so isRegexpCompileCall exits early at the *ast.SelectorExpr guard. +// This is a known limitation of the linter. +func DotImportExample() bool { + r := MustCompile(`^[a-z]+$`) // not flagged: dot-import calls are not selector expressions + return r.MatchString("abc") +} diff --git a/pkg/linters/regexpcompileinfunction/testdata/src/regexpcompileinfunction/shadowed_identifier.go b/pkg/linters/regexpcompileinfunction/testdata/src/regexpcompileinfunction/shadowed_identifier.go index 90833379715..f051ddec67f 100644 --- a/pkg/linters/regexpcompileinfunction/testdata/src/regexpcompileinfunction/shadowed_identifier.go +++ b/pkg/linters/regexpcompileinfunction/testdata/src/regexpcompileinfunction/shadowed_identifier.go @@ -7,8 +7,8 @@ func (customRegexp) Compile(_ string) (*customRegexp, error) { return &customReg func (customRegexp) MustCompile(_ string) *customRegexp { return &customRegexp{} } // not flagged: local variable named "regexp" is not the stdlib regexp package. -func GoodShadowedRegexpIdentifier(s string) bool { +func GoodShadowedRegexpIdentifier() bool { regexp := customRegexp{} - _ = regexp.MustCompile(s) + _ = regexp.MustCompile(`^[a-z]+$`) return true }