Repository navigation
[duplicate-code] Duplicate Code: type-assertion linter run/visit scaffold duplicated across analyzers #69118
Copy link
Copy link
Open
Labels
Description
🔍 Duplicate Code Detected: go/analysis Type-Assertion Linter Scaffold
Analysis of commit 5bf0b44 (github/gh-aw)
Assignee: @copilot
Summary
The type-assertion linters in pkg/linters/ duplicate a near-identical run scaffold and the opening of their visitor: analyzerutil.Indexes(pass) -> build a per-file parent map with astutil.BuildParentMap -> nodeFilter := []ast.Node{(*ast.TypeAssertExpr)(nil)} -> analyzerutil.Preorder(...), followed by the same typeAssert, ok := n.(*ast.TypeAssertExpr) / if typeAssert.Type == nil { return } / ShouldSkipFilename guard block.
Duplication Details
Pattern: parent-map + Preorder + type-assert guard
- Severity: Medium
- Occurrences: 3 analyzers share the full parent-map form (~45 duplicated lines); the broader
analyzerutil.Indexes(pass)run scaffold appears in 78 linter files - Locations:
pkg/linters/typeassertionnil/typeassertionnil.go(run: 21-39; guard: 44-60)pkg/linters/uncheckedtypeassertion/uncheckedtypeassertion.go(run: 23-41; guard: 46-62)pkg/linters/typeassertionokdiscarded/typeassertionokdiscarded.go(run: 20-37; guard: 42-56)
- Code Sample:
func run(pass *analysis.Pass) (any, error) { noLintIndex, generatedFiles, err := analyzerutil.Indexes(pass) if err != nil { return nil, err } fileParents := make(map[*ast.File]map[ast.Node]ast.Node) for _, f := range pass.Files { fileParents[f] = astutil.BuildParentMap(f) } nodeFilter := []ast.Node{(*ast.TypeAssertExpr)(nil)} return analyzerutil.Preorder(pass, nodeFilter, func(n ast.Node) { ... }) }
Impact Analysis
- Maintainability: Changes to parent-map construction or skip logic must be mirrored across the type-assertion analyzers.
- Bug Risk: Divergence already present (one builds parent map eagerly, another looks it up lazily via
astutil.FileForPos). - Code Bloat: Repeated scaffold across analyzers that
analyzerutilwas created to reduce.
Refactoring Recommendations
- Add a parent-map-aware runner to
pkg/linters/internal/analyzerutil, e.g.RunTypeAssertVisitor(pass, func(pass, ta *ast.TypeAssertExpr, parents map[ast.Node]ast.Node, skip ...) )that performs Indexes + parent-map build + Preorder + the commonType == nil/ShouldSkipFilename/ nolint guards.- Estimated effort: medium (3-5h)
- Benefits: each type-assertion linter keeps only its unique predicate/diagnostic; consistent skip behavior.
- Consider a broader
analyzerutil.Run(pass, nodeFilter, visit)helper to collapse the 78-fileIndexesscaffold where a parent map is not needed.
Implementation Checklist
- Review duplication findings
- Add shared runner in analyzerutil
- Migrate typeassertionnil / uncheckedtypeassertion / typeassertionokdiscarded
- Verify linter testdata still passes
Analysis Metadata
- Analyzed Files: pkg/linters//.go (excluding testdata)
- Detection Method: Serena activation + normalized block hashing + grep cross-reference
- Commit: 5bf0b44
Generated by 🔍 Duplicate Code Detector · pi · opus48 · 139.4 AIC · ⌖ 42.8 AIC · ⊞ 1.6K · ◷
- expires on Oct 17, 2026, 1:56 PM UTC-08:00
Reactions are currently unavailable
Activity