Skip to content

[refactor] Consolidate duplicated byte/string AST predicates into linters astutilΒ #46104

Description

@github-actions

πŸ”§ Semantic Function Clustering Analysis

Analysis of repository: github/gh-aw

Executive Summary

Analyzed ~1,094 non-test Go files (~7,100 functions) across pkg/. Most high-frequency function names cluster cleanly and are not problems β€” they are engine-interface implementations (GetInstallationSteps, RenderMCPConfig, ResolveLLMProvider, GetExecutionSteps, ..., each implemented ~8Γ— across the claude/codex/copilot/custom engines) or build-tag variants (findGitRoot in git_helpers.go vs git_helpers_wasm.go). These are correct Go idioms and should be left alone.

One genuinely actionable duplication cluster stands out: three static-analysis linter packages carry byte-for-byte identical AST type predicates that were never promoted into the shared helper package that already exists and is already imported by all three.

Identified Issue: Duplicate AST helpers across linter packages

Cluster: byte/string type predicates for go/analysis passes.

A shared package pkg/linters/internal/astutil already exists (with IsStringLiteral, ConstIntValue, ImplementsError, ContextContextType, ...) and is already imported by all three packages below. These predicates were simply never moved there.

Function Copies Locations Status
isByteSlice(pass, expr) bool 3 appendbytestring/appendbytestring.go:107, writebytestring/writebytestring.go:159, bytescomparestring/bytescomparestring.go:287 identical
isStringType(pass, expr) bool 2 appendbytestring/appendbytestring.go:131, writebytestring/writebytestring.go:173 identical
isByteSliceConversion(pass, conv) bool 2 appendbytestring/appendbytestring.go:121, writebytestring/writebytestring.go:150 identical
Code comparison β€” isByteSlice (identical in all three files)
func isByteSlice(pass *analysis.Pass, expr ast.Expr) bool {
	t := pass.TypesInfo.TypeOf(expr)
	if t == nil {
		return false
	}
	sl, ok := t.Underlying().(*types.Slice)
	if !ok {
		return false
	}
	elem, ok := sl.Elem().(*types.Basic)
	return ok && elem.Kind() == types.Byte
}

isByteSliceConversion and isStringType are likewise verbatim copies (the only diff is a comment on one copy).

Recommendation

Promote the three predicates into pkg/linters/internal/astutil as exported IsByteSlice, IsStringType, IsByteSliceConversion, then delete the 7 local copies and update call sites (all three packages already import astutil).

  • Impact: removes ~7 duplicated function bodies; single source of truth for byte/string type checks, consistent with how the rest of the linters already share AST helpers.
  • Risk: very low β€” pure move of identical code into a package that is already a dependency; covered by existing linter _test.go suites.
  • Effort: ~30–45 min.

Implementation Checklist

  • Add IsByteSlice, IsStringType, IsByteSliceConversion to pkg/linters/internal/astutil/astutil.go
  • Replace local calls in appendbytestring, writebytestring, bytescomparestring with the astutil.* versions
  • Delete the 7 now-unused local copies
  • Run the linters' test suites to confirm no behavior change

Analysis Metadata

  • Total Go files analyzed: ~1,094 (non-test, pkg/)
  • Total functions cataloged: ~7,100
  • Duplicates confirmed (byte-for-byte): 3 predicates / 7 copies
  • False-positive clusters ruled out: engine-interface methods, ToMap/String/Error interface impls, build-tag _wasm variants, distinct sanitize* functions
  • Detection method: cross-file name clustering + manual source verification
  • Analysis date: 2026-07-17

Generated by πŸ”§ Semantic Function Refactoring Β· 117.8 AIC Β· βŒ– 8.03 AIC Β· ⊞ 9.4K Β· β—·

  • expires on Jul 18, 2026, 4:12 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