Repository navigation
[duplicate-code] strings.Index/Count Comparison Analyzers Share Duplicated Match+Report Logic #65438
Description
🔍 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
-
Introduce a table-driven comparison analyzer helper
- Add
astutilsupport 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.
- Add
-
Extract the shared report tail
- Factor the
sText/subText/pkgTextextraction + message/fix/Report block into one helper takingnegatedand a label.
- Factor the
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
Activity