Skip to content

Linter precision: two newest linters (fileclosenotdeferred, contextcancelnotdeferred) match stdlib packages by identifier name — [Content truncated due to length] #40435

@github-actions

Description

@github-actions

Summary

The codebase has been systematically eliminating the syntactic package match antipattern — identifying a stdlib call by ident.Name == "<pkg>" instead of by package identity via pass.TypesInfo. The canonical helper astutil.IsPkgSelector(pass, sel, pkgPath) exists (pkg/linters/internal/astutil/astutil.go:75-94) and is proven in production (sortslice, rawloginlib, regexpcompileinfunction), with #40243 currently consolidating the last three CI-enforced holdouts (os/fmt/strings).

The two most recently added linters re-introduce the same antipattern:

Linter Site Syntactic check
fileclosenotdeferred pkg/linters/fileclosenotdeferred/fileclosenotdeferred.go:172 ident.Name != "os" (gates os.Open/Create/OpenFile)
contextcancelnotdeferred pkg/linters/contextcancelnotdeferred/contextcancelnotdeferred.go:138 pkgIdent.Name != "context" (gates context.WithCancel/WithTimeout/WithDeadline)

Defect class (same as the landed precedents)

  • False positive (shadowing): a local variable named os or context — e.g. os := newObjectStore(); os.Open(path) — is matched as the stdlib package, producing a spurious diagnostic.
  • False negative (alias import): import osx "os"osx.Open(...), or import ctx "context"ctx.WithCancel(...), escapes detection entirely.

Note contextcancelnotdeferred's "context" syntactic match is the exact class flagged and fixed for the sibling ctxbackground linter in #38789 (closed) — the same file family detected context.Background() syntactically there.

Why a separate issue from #40243

#40243 is explicitly scoped to the three remaining CI-enforced linters (os/fmt/strings holdouts: osexitinlibrary, fprintlnsprintf, errstringmatch). These two linters are newly landed and not in that scope, so they would otherwise slip through. Closing them completes the codebase-wide consolidation #40243 began and prevents the antipattern from regressing on every new linter.

Evidence

  • pkg/linters/fileclosenotdeferred/fileclosenotdeferred.go:166-176isFileOpenCall matches sel.X.(*ast.Ident) then ident.Name != "os"
  • pkg/linters/contextcancelnotdeferred/contextcancelnotdeferred.go:132-147isContextWithCancelCall matches sel.X.(*ast.Ident) then pkgIdent.Name != "context"
  • pkg/linters/internal/astutil/astutil.go:75-94IsPkgSelector resolves ObjectOf*types.PkgNameImported().Path()
  • Precedent: pkg/linters/rawloginlib/rawloginlib.go:58 (migrated), and sprintferrdot.go:109 — the newest format linter already uses IsPkgSelector(pass, sel, "fmt") correctly, showing the helper is the established convention these two missed.

Recommendation

Replace the ident.Name == "<pkg>" checks with astutil.IsPkgSelector(pass, sel, "os") / astutil.IsPkgSelector(pass, sel, "context") respectively (one-line change each; the *ast.SelectorExpr is already in hand at both sites).

Validation checklist

  • Shadowing testdata: local os/context variable does not trigger a diagnostic
  • Alias-import testdata: osx "os" / ctx "context" calls are detected
  • Existing positive/negative cases unchanged
  • No production violations introduced (grep shows no aliased os/context imports in pkg/ non-test today, so this is precision-hardening with zero churn)

Effort: small (two single-line changes + shadowing/alias testdata).

References: §27860925409

Generated by 🤖 Sergo - Serena Go Expert · 276.8 AIC · ⌖ 11.6 AIC · ⊞ 5.8K ·

  • expires on Jun 26, 2026, 9:14 PM UTC-08:00

Metadata

Metadata

Labels

cookieIssue Monster Loves Cookies!sergo

Type

No type
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