Skip to content

Enforce-readiness: strings-contains-family linters are clean — add stringsindexcontains to CI (0 violations); stringscountcontai [Content truncated due to length] #45186

Description

@github-actions

Summary

Two strings.Contains-simplification linters are type-resolved, RWSF-verified, and carry full nolint + test-skip parity, but neither is in the CI custom-linter batch (.github/workflows/cgo.yml:1208). One is enforce-ready today; the other becomes ready after a single one-line production fix.

This mirrors previously-accepted enforce-readiness issues (#42644 sprintfint, #42416, #39324, #39016) that landed once zero-violation status was established.

Findings

Linter Prod violations (default build) RWSF golden IsPkgSelector nolint+test-skip Verdict
stringsindexcontains 0 yes (_test.go:15) yes (:184) yes enforce now
stringscountcontains 1 (pkg/cli/compile_update_check.go:302) yes (_test.go:15) yes (:178) yes fix 1 site, then enforce
Audit detail — both linters are correctness-clean

Both use astutil.IsPkgSelector (no syntactic stdlib-name match — avoids the #39981/#40580 shadow/alias class), gate the literal via pass.TypesInfo constant.Int (constIntValue), reuse the actual selector qualifier (indexPkgText/countPkgText, so no alias/import-robustness bug of the #45037 class — the rewrite stays same-package strings.Contains and adds no import), and skip test files + honor nolint. The suggested-fix bodies replace the whole *ast.BinaryExpr with a call/!call (precedence-safe). Empty-substring semantics are consistent in both directions (strings.Index(s,"")==0Contains true; strings.Count(s,"")>=1Contains true), so no false-positive/false-negative edge. Pattern sets are complete for their {-1,0} / {0,1} threshold families and correctly exclude non-presence forms (Index>0, Count>1). No open sergo issue targets either linter.

The single blocking violation for stringscountcontains

// pkg/cli/compile_update_check.go:302
func hasExplicitMinorComponent(version string) bool {
    core := strings.TrimPrefix(version, "v")
    if idx := strings.IndexAny(core, "-+"); idx >= 0 {
        core = core[:idx]
    }
    return strings.Count(core, ".") >= 1   // linter flags this: Count(...) >= 1
}

The linter is working as designed here — strings.Count(core, ".") >= 1 is exactly the "long-way presence check" it targets. The behavior-preserving rewrite:

    return strings.Contains(core, ".")

(Count(x) >= 1 ⟺ at least one occurrence ⟺ Contains(x); same for the empty-substring case since Count(s,"") >= 1 is always true and Contains(s,"") is always true.)

Recommendation

  1. Add -stringsindexcontains to LINTER_FLAGS in .github/workflows/cgo.yml (both the default and the GOOS=js GOARCH=wasm invocations, lines 1208 & 1211) — it has zero violations and full suppression parity.
  2. Apply the one-line rewrite at compile_update_check.go:302, then add -stringscountcontains to the same LINTER_FLAGS.

Validation checklist

  • make golint-custom LINTER_FLAGS="-stringsindexcontains -test=false" reports 0 findings on prod packages.
  • compile_update_check.go:302 rewritten to strings.Contains(core, "."); TestHasExplicitMinorComponent (or equivalent) still passes.
  • make golint-custom LINTER_FLAGS="-stringscountcontains -test=false" reports 0 findings after the fix.
  • Both flags present in the default and wasm cgo.yml runs.

Effort: small (1-line prod change + 2 CI flag additions).

Generated by 🤖 Sergo - Serena Go Expert · 369.4 AIC · ⌖ 14 AIC · ⊞ 5.8K ·

  • expires on Jul 19, 2026, 9:05 PM UTC-08:00

Metadata

Metadata

Assignees

No one assigned

    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