Skip to content

Linter precision: migrate the 3 remaining CI-enforced linters that match stdlib packages by identifier name to astutil.IsPkgSele [Content truncated due to length] #40243

Description

@github-actions

Summary

Three CI-enforced custom linters still identify standard-library package calls by the syntactic identifier name (ident.Name == "<pkg>") instead of by package identity via pass.TypesInfo. The canonical helper astutil.IsPkgSelector(pass, sel, pkgPath) already exists (pkg/linters/internal/astutil/astutil.go:75-94) and is already proven in production — rawloginlib was migrated to it (pkg/linters/rawloginlib/rawloginlib.go:58). Only three holdouts remain; migrating them closes a recurring false-positive/false-negative class across the enforced suite.

The holdouts

Linter Location Current code
osexitinlibrary pkg/linters/osexitinlibrary/osexitinlibrary.go:59 ident.Name == "os" && sel.Sel.Name == "Exit"
fprintlnsprintf pkg/linters/fprintlnsprintf/fprintlnsprintf.go:144 ident.Name == "fmt" && sel.Sel.Name == name
errstringmatch pkg/linters/errstringmatch/errstringmatch.go:85 ident.Name == "strings" && sel.Sel.Name == "Contains"

All three are part of the 14 CI-enforced linters (.github/workflows/cgo.yml LINTER_FLAGS), so any false positive is a build-blocker and any false negative silently lets the targeted anti-pattern ship.

Why syntactic matching is wrong (two failure modes)

  1. Alias-import false negative. import str "strings" then str.Contains(err.Error(), "x")ident.Name is "str", so the call escapes the linter. Same for import xos "os" / import xfmt "fmt".
  2. Shadowing false positive (build-blocker). A local variable/parameter/field named os, fmt, or strings with a matching method/field name (e.g. os.Exit) matches by name even though it is not the stdlib package. CI-enforced ⇒ a spurious diagnostic fails the build.

The established correct approach resolves the selector base to a *types.PkgName and compares the imported path:

obj := pass.TypesInfo.ObjectOf(pkgIdent)
pkgName, ok := obj.(*types.PkgName)
return ok && pkgName.Imported().Path() == pkgPath

This is exactly what astutil.IsPkgSelector (and astutil.IsFmtErrorf, astutil.go:51-73) already do.

Current impact

Latent today (no aliased strings/os/fmt imports in pkg/, and these identifiers are rarely shadowed), but this is the same class already accepted and fixed for sortslice (#38029, landed), rawloginlib (#39981, fix landed in code), and regexpcompileinfunction (#39733). The helper and precedent now exist, so finishing the migration is cheap and removes the class entirely.

Recommendation

Replace each syntactic check with the existing helper, mirroring rawloginlib.go:58:

  • osexitinlibrary.go:59
if astutil.IsPkgSelector(pass, sel, "os") && sel.Sel.Name == "Exit" {
  • fprintlnsprintf.go:144 (isFmtFunc)
return astutil.IsPkgSelector(pass, sel, "fmt") && sel.Sel.Name == name
  • errstringmatch.go:85 (isStringsContains)
return astutil.IsPkgSelector(pass, sel, "strings") && sel.Sel.Name == "Contains"

Validation checklist

  • Add a testdata case per linter for an aliased import (e.g. str "strings") — confirm it is now flagged (FN closed).
  • Add a testdata case with a shadowing local named os/fmt/strings — confirm it is NOT flagged (FP closed).
  • Existing testdata expectations unchanged for the normal os.Exit / fmt.Fprintln / strings.Contains cases.
  • go test ./pkg/linters/... green; CI linter pass over pkg/ produces no new diagnostics.

Effort

Small — one-line change per linter plus two testdata cases each; the helper already exists. Single PR.

Related

Same syntactic-package-identity class: #38029 (sortslice, landed), #39981 (rawloginlib, landed in code), #39733 (regexpcompileinfunction), #38789 (ctxbackground). This issue finishes the migration for the last three holdouts.

Generated by 🤖 Sergo - Serena Go Expert · 339.2 AIC · ⌖ 14.7 AIC · ⊞ 5.8K ·

  • expires on Jun 25, 2026, 9:36 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