Skip to content

[duplicate-code] strings.Index/Count Comparison Analyzers Share Duplicated Match+Report Logic #65438

Description

@github-actions

🔍 Duplicate Code Detected: strings.Index/Count Comparison Analyzers

Analysis of commit 31e5fda

Assignee: @copilot

Summary

The analyzers stringsindexcontains, stringscountcontains, and stringsindexhasprefix in pkg/linters/ share a near-identical structure: a BinaryExpr preorder walk, the same skip/nolint guards, a match*Comparison function that normalizes operands and matches a comparison operator against a sentinel literal (-1/0/1), and the same diagnostic-building/BuildContainsFix tail. Only the operator/literal table and the replacement function name differ.

Duplication Details

Pattern: Comparison-to-sentinel analyzer + reporting

  • Severity: Medium
  • Occurrences: 3 analyzers
  • Locations:
    • pkg/linters/stringsindexcontains/stringsindexcontains.go (lines 35-145)
    • pkg/linters/stringscountcontains/stringscountcontains.go (lines 35-146)
    • pkg/linters/stringsindexhasprefix/stringsindexhasprefix.go (lines 35-120)
  • Code Sample (shared analyze/report body):
expr, ok := n.(*ast.BinaryExpr)
if !ok { return }
pos := pass.Fset.PositionFor(expr.Pos(), false)
if filecheck.ShouldSkipFilename(pos.Filename, generatedFiles) { return }
if nolint.HasDirectiveForLinter(pos, noLintIndex, "<name>") { return }
call, negated, matched := match<X>Comparison(pass, expr)
if !matched { return }
// ... extract sText/subText/pkgText via astutil.NodeText/CallQualifierText ...
// build "use [!]strings.Contains(...)" message
fix := astutil.BuildContainsFix(pass.Files, expr, pkgText, sText, subText, negated, "...")
pass.Report(analysis.Diagnostic{Pos: expr.Pos(), End: expr.End(), Message: msg, SuggestedFixes: fix})

Each match*Comparison uses the same NormalizeComparisonOperands → AsStringsMethodCall → FlipComparisonOp → ConstIntValue → operator switch skeleton.

Impact Analysis

  • Maintainability: Changes to operand normalization, yoda-order handling, or diagnostic wording must be repeated in three analyzers.
  • Bug Risk: Subtle inconsistencies in supported operator/literal combinations are easy to introduce when copy-editing one file.
  • Code Bloat: ~100 lines of duplicated analyze/report scaffolding.

Refactoring Recommendations

  1. Introduce a table-driven comparison analyzer helper

    • Add astutil support for "comparison of strings.(Method)(...) against sentinel literals → suggested replacement", parameterized by method name, an operator/literal → negated table, and the replacement builder.
    • Estimated effort: 4-5 hours
    • Benefits: the three analyzers become small declarations of their operator tables and messages.
  2. Extract the shared report tail

    • Factor the sText/subText/pkgText extraction + message/fix/Report block into one helper taking negated and a label.

Implementation Checklist

  • Review duplication findings
  • Prioritize refactoring tasks
  • Create refactoring plan
  • Implement table-driven helper in astutil
  • Migrate the three analyzers
  • Update tests
  • Verify no functionality broken
Analysis Metadata
  • Analyzed Files: pkg/linters (77 analyzer packages)
  • Detection Method: Serena semantic code analysis
  • Commit: 31e5fda
  • Analysis Date: 2026-10-03T22:48:41.609Z

Generated by 🔍 Duplicate Code Detector · pi · opus48 · 361.7 AIC · ⌖ 46.9 AIC · ⊞ 4.4K · ◷

  • expires on Oct 5, 2026, 2:50 PM UTC-08:00

Metadata

Metadata

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions