Skip to content

slicemakezerolength (69th linter): make()-only scope misses the more idiomatic var s []T nil-slice pattern #60367

Description

@github-actions

Problem

slicemakezerolength (added 2026-09-11 via PR #60310, the 69th registered analyzer) flags make([]T, 0) calls that precede an unconditional one-element-per-iteration range+append loop, suggesting capacity len(range-expr). Its entire detection surface requires the slice variable to originate from a two-arg make([]T, 0) call: zeroLengthSliceAssignment (pkg/linters/slicemakezerolength/slicemakezerolength.go:67-122) only matches an AssignStmt or DeclStmt whose right-hand value is a *ast.CallExpr resolving to the builtin make, and the DeclStmt branch additionally requires len(spec.Values) == 1, i.e. an explicit initializer.

Evidence

pkg/parser/content_extractor.go:169-180 has exactly the pattern this linter exists to catch:

var normalizedValue []any
switch v := fieldValue.(type) {
case []string:
    for _, s := range v {
        normalizedValue = append(normalizedValue, s)
    }
}

v is a []string (hasKnownRangeSize accepts string/slice/array/map underlying types) and the loop body is a single unconditional append (appendsOneElement accepts exactly this shape). The only reason this real production site passes undetected is that normalizedValue is declared with var normalizedValue []any, a zero-value nil slice with no initializer, instead of make([]any, 0). Because ValueSpec.Values is empty in that case, zeroLengthSliceAssignment returns false at the len(spec.Values) != 1 check before it ever inspects a make call.

Impact

var x []T is the idiomatic, more common Go spelling for exactly this initialize-then-append-in-a-known-size-loop shape (common Go style guidance prefers the nil-slice form over make([]T, 0) for a var that will only ever grow via append). A linter whose stated goal is finding capacity-preallocation opportunities but whose match rule only recognizes the less-idiomatic make([]T, 0) spelling will have a systematically low real-world hit rate: developers who already reach for the preferred spelling are entirely invisible to it.

Recommendation

Extend zeroLengthSliceAssignment to also accept a DeclStmt ValueSpec with zero Values (a bare var s []T where the type is an *ast.ArrayType with Len nil) as a starting state equivalent to make([]T, 0) — both begin as an empty, zero-capacity slice. Add a testdata case mirroring content_extractor.go (var s []T; for _, x := range known-size-expr { s = append(s, x) }) alongside the existing badZeroLengthNoCapacity case.

Validation checklist

  • New testdata case for the bare var declaration produces a diagnostic.
  • Existing make([]T, 0) and make([]T, 0x0) cases keep passing unchanged.
  • A bare var s []T with no follow-on loop (mirroring goodWithoutGrowth) still produces no diagnostic.

Effort: small — one additional branch in zeroLengthSliceAssignment plus one testdata case.

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • api.anthropic.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "api.anthropic.com"

See Network Configuration for more information.

Generated by 🤖 Sergo - Serena Go Expert · claude · agent · 202 AIC · ⌖ 7.68 AIC · ⊞ 6.8K · ◷

  • expires on Sep 18, 2026, 7:56 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

Assignees

No one assigned

    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