Skip to content

Threshold linters: excessivefuncparams lints test files (every sibling FuncDecl linter skips them); largefunc & excessivefuncpar [Content truncated due to length] #40734

Description

@github-actions

Summary

Two gaps in the heuristic/threshold linters excessivefuncparams and largefunc make them inconsistent with their siblings and not yet enforce-ready:

  1. excessivefuncparams does not skip test files, while every other FuncDecl-walking linter does.
  2. Neither excessivefuncparams nor largefunc honors //nolint directives, so a legitimately-large function or wide API signature cannot be suppressed at the call site — the only escape is raising the global threshold, which weakens the rule everywhere.

1. Missing test-file skip in excessivefuncparams

pkg/linters/excessivefuncparams/excessivefuncparams.go run (lines 44-68) reports on every *ast.FuncDecl with no filecheck.IsTestFile guard. Compare:

  • pkg/linters/largefunc/largefunc.go:66if filecheck.IsTestFile(...) { return }
  • pkg/linters/seenmapbool/seenmapbool.go:47 — skips test files
  • pkg/linters/errorfwrapv/errorfwrapv.go:75 — skips test files
  • pkg/linters/deferinloop/deferinloop.go:43 — skips test files

excessivefuncparams is the lone FuncDecl-based linter that analyzes _test.go. Test code routinely has many-parameter helpers (table-driven builders, mock constructors) that are not a design smell, so running the analyzer over tests (e.g. a local go vet -vettool=... ./... that does not pass -test=false) produces noise the sibling linters suppress.

2. No (nolint/redacted) suppression for either threshold linter

20 of the 32 registered analyzers wire nolint.BuildLineIndex / nolint.HasDirective (e.g. seenmapbool.go:32, errorfwrapv.go:62, deferinloop.go:34). largefunc and excessivefuncparams do not import internal/nolint at all.

For purely-mechanical linters (stdlib-pattern matches) the absence of //nolint is tolerable because there is always a clean rewrite. For heuristic threshold linters it is not: some functions are legitimately long (large switch/codegen) or legitimately take many parameters (stable public constructors), and the developer has no per-site escape hatch. This is a concrete blocker to CI enforcement — neither linter appears in the enforced set, and they cannot be safely enforced until a justified violation can be suppressed without loosening the global threshold for the whole tree.

Impact

  • Inconsistent test-file handling vs. all sibling FuncDecl linters → spurious diagnostics on test helpers.
  • No //nolint escape hatch on the two linters that most need one → cannot be promoted to CI enforcement without forcing awkward refactors or a globally-loosened threshold.

Recommended fix

  • Add if filecheck.IsTestFile(pass.Fset.Position(fn.Pos()).Filename) { return } to excessivefuncparams.run, matching largefunc.
  • Wire internal/nolint into both: noLint := nolint.BuildLineIndex(pass, "<name>") and gate ReportRangef on !nolint.HasDirective(pos, noLint), mirroring seenmapbool/errorfwrapv.
  • Add testdata cases: a many-param function in a _test.go (expect no diagnostic) and a //nolint:excessivefuncparams / //nolint:largefunc suppression case.

Effort

Small and mechanical — both changes follow established patterns already used by 20 sibling analyzers; fully coverable by analysistest.

Note on scope (honesty)

Several other non-enforced analyzers also lack //nolint support; this issue scopes the suppression request to the two heuristic threshold linters because their violations are the ones most often legitimate and unavoidable. The test-file-skip gap, by contrast, is unique to excessivefuncparams among FuncDecl linters.

Generated by 🤖 Sergo - Serena Go Expert · 357.9 AIC · ⌖ 10.9 AIC · ⊞ 5.8K ·

  • expires on Jun 28, 2026, 9:42 PM UTC-08:00

Metadata

Metadata

Labels

cookieIssue Monster Loves Cookies!sergo

Type

No type

Fields

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