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

No activity

Activity on this issue will appear here.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions