[linter-miner] Add slice-make-zero-length linter - #60310
Conversation
This linter reports make([]T, 0) calls without a capacity argument,
which can lead to unnecessary allocations when the final slice length
is known. Providing a capacity upfront reduces the number of allocations
and improves performance.
Example:
result := make([]string, 0) // bad - will reallocate as items added
for _, item := range items {
result = append(result, item)
}
result := make([]string, 0, len(items)) // good - pre-allocates
The linter detects patterns where make([]T, 0) is used on slices
and suggests providing capacity, helping improve the efficiency of
code that builds slices incrementally.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
✅ Ponytail Reviewer completed successfully! Lean already. Ship. Warning Firewall blocked 1 domainThe following domain was blocked by the firewall during workflow execution:
To allow these domains, add them to the network:
allowed:
- defaults
- "ab.chatgpt.com"See Network Configuration for more information.
|
|
Warning Threat Detection Engine Failure — The analysis engine could not complete. This is a tooling failure, not a security finding. What happenedThe threat detection engine failed to produce results. Review the workflow run logs for details.
|
|
✅ Test Quality Sentinel completed test quality analysis. Test Quality Sentinel skipped because pre-fetch PR data was unavailable: unable to fetch test file diff
|
|
|
🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅ Warning Firewall blocked 1 domainThe following domain was blocked by the firewall during workflow execution:
To allow these domains, add them to the network:
allowed:
- defaults
- "github.com"See Network Configuration for more information.
|
🏗️ ADR required for PR #60310I generated a draft ADR and pushed it to this PR branch:
Evidence used
Inferred design decision
Next actionPlease review and refine the draft ADR, especially the decision scope and trade-offs, before treating this PR as ADR-backed.
|
There was a problem hiding this comment.
🟡 Changes recommended
The analyzer produces false positives and its registration leaves required documentation, tests, CI configuration, and existing findings unresolved.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Adds a custom Go analyzer intended to detect zero-length slice allocations without capacity hints.
Changes:
- Implements and registers
slicemakezerolength. - Adds coverage and
nolinthandling. - Adds analyzer fixtures and tests.
File summaries
| File | Description |
|---|---|
pkg/linters/slicemakezerolength/slicemakezerolength.go |
Implements analyzer logic. |
pkg/linters/slicemakezerolength/slicemakezerolength_test.go |
Runs analyzer tests. |
pkg/linters/slicemakezerolength/testdata/src/slicemakezerolength/slicemakezerolength.go |
Provides test fixtures. |
pkg/linters/registry.go |
Registers the analyzer. |
Review details
Suppressed comments (1)
pkg/linters/registry.go:129
- Adding this analyzer to
linters.All()without updating the synchronized surfaces makes the existing linter tests fail.doc_sync_test.go:97-107requires matching entries indoc.go, the README Subpackages table, andspec_test.go'sdocumentedAnalyzers; lines 129-136 also require the analyzer in bothcgo.ymlflag sets or innotYetEnforced. Please update those surfaces together with this registration.
slicemakezerolength.Analyzer,
- Files reviewed: 5/5 changed files
- Comments generated: 2
- Review effort level: Balanced
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
| regexpdynamicpattern.Analyzer, | ||
| ssljson.Analyzer, | ||
| seenmapbool.Analyzer, | ||
| slicemakezerolength.Analyzer, |
There was a problem hiding this comment.
Addressed in 9ca42be. The analyzer now reports only an immediately following known-size range loop that appends exactly one element per iteration, and its isolated repository-wide run passes without findings.
| // The second argument must be a literal 0. | ||
| if !isZeroLiteral(call.Args[1]) { | ||
| return |
There was a problem hiding this comment.
Addressed in 9ca42be. No-growth, conditional-growth, channel-range, multi-append, and self-range cases are now excluded; fixtures cover each case.
There was a problem hiding this comment.
Skills-Based Review 🧠
Applied /codebase-design and /tdd — requesting changes: the new analyzer isn't registered in the repo's enforced documentation surface, which breaks CI.
📋 Key Themes & Highlights
Key Themes
- Blocking:
pkg/linters/registry.goregistersslicemakezerolength.AnalyzerinallAnalyzers, butpkg/linters/README.mdwas not updated (Overview bullets + Public API table). I ran the existing doc-sync tests locally and confirmedTestRegistryMatchesDocumentationandTestDocSurfacesMatchRegistryAndSpecListfail on this branch ("...should have 68 item(s), but has 69"). This will fail CI as-is. - Minor:
isZeroLiteralcompares literal text against"0"only, missing equivalent zero forms (0x0,0_0,00). Low real-world impact, but a small correctness gap worth a follow-up test.
Positive Highlights
- ✅ Correctly follows the coverage-aware perf-gating pattern (
RegisterHotThresholdFlag+coverage.ShouldApply) used by other allocation-related linters likeseenmapbool/mapclearloop. - ✅ Good
nolintdirective support and generated-file skip viafilecheck.ShouldSkipFilename. - ✅ Test fixtures cover both flagged and suppressed cases (capacity given, length given, array types,
nolint).
@copilot please address the review comments above.
Warning
Firewall blocked 1 domain
The following domain was blocked by the firewall during workflow execution:
github.com
To allow these domains, add them to the network.allowed list in your workflow frontmatter:
network:
allowed:
- defaults
- "github.com"See Network Configuration for more information.
🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · copilot · sonnet50 · 55.9 AIC · ⌖ 16.1 AIC · ⊞ 10.4K
Comment /matt to run again
| regexpdynamicpattern.Analyzer, | ||
| ssljson.Analyzer, | ||
| seenmapbool.Analyzer, | ||
| slicemakezerolength.Analyzer, |
There was a problem hiding this comment.
[/codebase-design] This PR registers slicemakezerolength in allAnalyzers but does not add the corresponding entry to pkg/linters/README.md (Overview bullet list + Public API table). The repo enforces this with TestRegistryMatchesDocumentation / TestDocSurfacesMatchRegistryAndSpecList in pkg/linters/spec_test.go and doc_sync_test.go, and I confirmed both fail against this branch (68 item(s), but has 69).
💡 Fix
Add a bullet to the Overview list and a row to the Public API table in pkg/linters/README.md, alphabetically placed near seenmapbool/sortslice, e.g.:
- `slicemakezerolength` — reports `make([]T, 0)` calls without a capacity argument when the final slice length is known, which can be optimized.And in the Public API table:
| `slicemakezerolength` | Custom `go/analysis` analyzer that flags `make([]T, 0)` calls without capacity when the final length is known |Also consider whether this should be added to the coverage-gated linter list in the README (it registers a -hot-threshold flag consistent with other perf linters like mapclearloop/seenmapbool, so it belongs in that enumerated list too).
@copilot please address this.
There was a problem hiding this comment.
Addressed in 9ca42be. README.md, doc.go, spec_test.go, and both native/wasm CI linter flag sets now include slicemakezerolength; synchronization tests pass.
| // isZeroLiteral reports whether expr is the literal 0. | ||
| func isZeroLiteral(expr ast.Expr) bool { | ||
| lit, ok := expr.(*ast.BasicLit) | ||
| if !ok { |
There was a problem hiding this comment.
[/tdd] isZeroLiteral only matches the exact literal text "0", so equivalent zero literals like 0x0, 0_0, or 00 silently bypass the check — a minor false-negative gap, not a blocker.
💡 Suggested test + fix
Parse the literal value instead of comparing raw text, e.g. using strconv.ParseInt(lit.Value, 0, 64) and checking == 0, or go/constant.MakeFromLiteral for correctness across bases/underscores. Add a fixture case:
func badZeroLengthHex() {
s := make([]int, 0x0) // want `make\(\[\]int, 0x0\) without capacity can be optimized`
_ = s
}Low impact since 0x0/0_0 are rare in practice, but worth tightening if this linter graduates into the coverage-gated hot-path set where correctness matters more.
@copilot please address this.
There was a problem hiding this comment.
Addressed in 9ca42be. Zero detection now uses go/constant, with a 0x0 regression fixture.
|
@copilot run pr-finisher skill |
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Ran the |
|
🎉 This pull request is included in a new release. Release: |
Overview
This PR adds a new custom Go analysis linter:
slice-make-zero-lengthWhat the Linter Does
The linter reports
make([]T, 0)calls without a capacity argument, which can lead to unnecessary allocations when the final slice length is known or can be estimated.Example
Why This Matters
Evidence from Codebase
Found 10+ instances in the repository where
make([]T, 0)is used:pkg/github/label_objective_mapping.go:203pkg/workflow/checkout_manager.go:590pkg/workflow/enclaves.go:116pkg/workflow/workflow_errors.go:204pkg/cli/bootstrap_shared.go:27pkg/cli/graders_operational_value_report_history.go:49pkg/cli/deploy_command.go:297Implementation
pkg/linters/slicemakezerolength/(analyzer, tests, fixtures)pkg/linters/registry.go(registration)Validation
✅ All linter tests pass
✅ Linter compiles without errors
✅ Registered in custom linter suite
✅
make golint-customruns successfullyWarning
Firewall blocked 1 domain
The following domain was blocked by the firewall during workflow execution:
github.com/ghapi[!TIP]
github.com/ghapiis blocked because GitHub API access uses the built-in GitHub tools by default. Instead of addinggithub.laiyagushi.com/ghapitonetwork.allowed, usetools.github.mode: gh-proxyfor direct pre-authenticated GitHub CLI access without requiring network access togithub.laiyagushi.com/ghapi:See GitHub Tools for more information on
gh-proxymode.To allow these domains, add them to the
network.allowedlist in your workflow frontmatter:See Network Configuration for more information.