You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Run R43 detected a registry delta (30 → 31 analyzers) — the 31st linter sprintferrorsnew is new this cycle. It audited clean, so the value this run came from a disciplined full re-grep of the syntactic-stdlib-match antipattern: using bothName == pkg and Name != pkg operators surfaced a CI-enforced holdout (tolowerequalfold) that the #40243 migration sweep missed entirely. Two distinct, single-file issues filed. No duplicates.
Registry delta:cmd/linters/main.go now registers 31 analyzers (lines 54–84) vs 30 in R42.
31st linter = sprintferrorsnew — flags errors.New(fmt.Sprintf(...)) that should be fmt.Errorf(...).
Audited clean ✅ — uses astutil.IsPkgSelector for botherrors and fmt (the sg42a2 regression lesson was applied), skips test files, requires exact arg count. The goodVariable (pre-built string var) false-negative is intentional per testdata. No issue warranted.
Cached half — syntactic_stdlib_match (strongest historical land-arg). Re-grepped all 31 linters for ident.Name (== | !=) "<pkg>". Key methodology fix: linters use != for early-return, so a ==-only grep silently misses holdouts. The both-operator grep surfaced a new holdout not in any open issue.
New half — pattern_set_too_narrow (fresh never-audited linter). Deep-read lenstringzero and found an operator-set asymmetry: it flags len(s) != 0 but not the identical idiom len(s) > 0.
Run targets: ≥1 strong cached finding, ≥1 fresh-linter finding, 2 non-duplicate CI-relevant issues. All met.
pkg/linters/tolowerequalfold/tolowerequalfold.go:255 matches the strings package by ident.Name != "strings" with no type info, in a CI-enforced linter. Causes a shadowing false-positive and an alias-import (import str "strings") false-negative.
Evidence & fix
isCaseConvCall (line 212) delegates to caseConvArg, so line 255 is the single chokepoint for the whole analyzer.
sameOperand (line 271) already uses pass.TypesInfo.ObjectOf — type info is available, only the package check was left syntactic.
astutil is already imported (line 15); fix is replacing ~6 lines with astutil.IsPkgSelector(pass, sel, "strings").
pkg/linters/lenstringzero/lenstringzero.go:40 only handles token.EQL/token.NEQ. Since len(s) >= 0 always holds, len(s) != 0 and len(s) > 0 are semantically identical, yet only the former is flagged.
Escaping forms & impact
Written
Equivalent
Flagged?
len(s) == 0
s == ""
✅
len(s) != 0
s != ""
✅
len(s) > 0
s != ""
❌
len(s) < 1 / <= 0
s == ""
❌
len(s) >= 1
s != ""
❌
Real string-typed production sites: pkg/stringutil/stringutil.go:44, pkg/stringutil/sanitize.go:209. The narrow scope may be deliberate (>0 is prevalent/noisy) — issue asks the team to either extend coverage or document the boundary, rather than leave the silent asymmetry.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
-
Executive Summary
Run R43 detected a registry delta (30 → 31 analyzers) — the 31st linter
sprintferrorsnewis new this cycle. It audited clean, so the value this run came from a disciplined full re-grep of the syntactic-stdlib-match antipattern: using bothName == pkgandName != pkgoperators surfaced a CI-enforced holdout (tolowerequalfold) that the #40243 migration sweep missed entirely. Two distinct, single-file issues filed. No duplicates.Tool / Registry Updates
serena --help). No tool change.cmd/linters/main.gonow registers 31 analyzers (lines 54–84) vs 30 in R42.sprintferrorsnew— flagserrors.New(fmt.Sprintf(...))that should befmt.Errorf(...).astutil.IsPkgSelectorfor botherrorsandfmt(the sg42a2 regression lesson was applied), skips test files, requires exact arg count. ThegoodVariable(pre-built string var) false-negative is intentional per testdata. No issue warranted.doc.go:3still says "29 active analyzers" — now off-by-2 (omits hardcodedfilepath, sprintferrdot, sprintferrorsnew). Already tracked by open doc-sync: pkg/linters/doc.go says "29 active analyzers" but 30 are registered — list omits hardcodedfilepath and sprintferrdot #40436, skipped as duplicate.Strategy: Strict 50/50 Split
Cached half —
syntactic_stdlib_match(strongest historical land-arg). Re-grepped all 31 linters forident.Name (== | !=) "<pkg>". Key methodology fix: linters use!=for early-return, so a==-only grep silently misses holdouts. The both-operator grep surfaced a new holdout not in any open issue.New half —
pattern_set_too_narrow(fresh never-audited linter). Deep-readlenstringzeroand found an operator-set asymmetry: it flagslen(s) != 0but not the identical idiomlen(s) > 0.Run targets: ≥1 strong cached finding, ≥1 fresh-linter finding, 2 non-duplicate CI-relevant issues. All met.
Findings (2 filed, 1 skipped-dup)
🔴 sg43a1 —
tolowerequalfoldsyntacticstringsmatch (CACHED) → issue filedpkg/linters/tolowerequalfold/tolowerequalfold.go:255matches thestringspackage byident.Name != "strings"with no type info, in a CI-enforced linter. Causes a shadowing false-positive and an alias-import (import str "strings") false-negative.Evidence & fix
isCaseConvCall(line 212) delegates tocaseConvArg, so line 255 is the single chokepoint for the whole analyzer.sameOperand(line 271) already usespass.TypesInfo.ObjectOf— type info is available, only the package check was left syntactic.astutilis already imported (line 15); fix is replacing ~6 lines withastutil.IsPkgSelector(pass, sel, "strings").tolowerequalfoldis a distinct CI-enforced holdout.stringssites — a consistency/future-proofing fix.🟡 sg43a2 —
lenstringzerorelational-operator coverage gap (NEW) → issue filedpkg/linters/lenstringzero/lenstringzero.go:40only handlestoken.EQL/token.NEQ. Sincelen(s) >= 0always holds,len(s) != 0andlen(s) > 0are semantically identical, yet only the former is flagged.Escaping forms & impact
len(s) == 0s == ""len(s) != 0s != ""len(s) > 0s != ""len(s) < 1/<= 0s == ""len(s) >= 1s != ""Real string-typed production sites:
pkg/stringutil/stringutil.go:44,pkg/stringutil/sanitize.go:209. The narrow scope may be deliberate (>0 is prevalent/noisy) — issue asks the team to either extend coverage or document the boundary, rather than leave the silent asymmetry.⚪ Skipped (duplicate)
Reconcile Status (issue OPEN ≠ code fixed)
Grepped production code for each prior fix. All syntactic-match migrations remain unlanded:
Metrics
Next-Run Focus (R44)
json.Unmarshal(data, &v)(ExprStmt) discards the error but is never inspected — only As [Content truncated due to length] #39982 / sprintferrdot precision: verb handling {s,v} is wrong in both directions — %#v false positive, %q/%x/%X false negative #40434 / sg43a1-2.Name (== | !=)with both operators across all 31 linters (new linters keep regressing this).References:
Beta Was this translation helpful? Give feedback.
All reactions