Documentation
¶
Overview ¶
Package patterns provides design pattern and anti-pattern detection for Trace.
Description ¶
This package detects design patterns (Singleton, Factory, Builder, etc.), code smells (long functions, god objects), structural issues (circular deps), and coding conventions. Pattern detection is heuristic-based with confidence scores indicating certainty.
Thread Safety ¶
All detector types are safe for concurrent use.
Index ¶
- Constants
- Variables
- func DefaultMatchers() map[PatternType]*PatternMatcher
- type CRSBridge
- type CRSRecorder
- type CircularDep
- type CircularDepFinder
- func (c *CircularDepFinder) BuildPackageGraph(ctx context.Context) error
- func (c *CircularDepFinder) FindCircularDeps(ctx context.Context, scope string, depType CircularDepType) ([]CircularDep, error)
- func (c *CircularDepFinder) GetPackageGraph() *PackageGraph
- func (c *CircularDepFinder) SetCRS(recorder CRSRecorder)
- func (c *CircularDepFinder) Summary(deps []CircularDep) string
- type CircularDepType
- type CodeFingerprint
- type CodeSmell
- type Convention
- type ConventionExtractor
- type ConventionOptions
- type ConventionType
- type DeadCode
- type DeadCodeExclusions
- type DeadCodeFinder
- type DeadCodeOptions
- type DetectedPattern
- type DetectionOptions
- type DupLocation
- type DuplicatePair
- type Duplication
- type DuplicationFinder
- func (d *DuplicationFinder) BuildIndex(ctx context.Context, opts *DuplicationOptions) (int, error)
- func (d *DuplicationFinder) FindDuplicatesOf(ctx context.Context, symbolID string, opts *DuplicationOptions) ([]Duplication, error)
- func (d *DuplicationFinder) FindDuplication(ctx context.Context, scope string, opts *DuplicationOptions) ([]Duplication, error)
- func (d *DuplicationFinder) SetCRS(recorder CRSRecorder)
- func (d *DuplicationFinder) Stats() DuplicationStats
- func (d *DuplicationFinder) Summary(duplications []Duplication) string
- type DuplicationOptions
- type DuplicationStats
- type DuplicationType
- type FileReader
- type FingerprintConfig
- type Fingerprinter
- type LSHIndex
- func (l *LSHIndex) Add(fp *CodeFingerprint)
- func (l *LSHIndex) FindAllDuplicates(threshold float64) []DuplicatePair
- func (l *LSHIndex) GetFingerprint(symbolID string) (*CodeFingerprint, bool)
- func (l *LSHIndex) Query(fp *CodeFingerprint) []string
- func (l *LSHIndex) QueryWithThreshold(fp *CodeFingerprint, threshold float64) []LSHMatch
- func (l *LSHIndex) Remove(symbolID string)
- func (l *LSHIndex) Size() int
- func (l *LSHIndex) Stats() LSHStats
- type LSHMatch
- type LSHStats
- type NopCRSRecorder
- type PackageGraph
- func (pg *PackageGraph) Dependencies(path string) []string
- func (pg *PackageGraph) Dependents(path string) []string
- func (pg *PackageGraph) FindCycles() [][]string
- func (pg *PackageGraph) FindShortestCycle(pkgPath string) []string
- func (pg *PackageGraph) GetPackage(path string) (*PackageNode, bool)
- func (pg *PackageGraph) Packages() []string
- func (pg *PackageGraph) Stats() PackageGraphStats
- func (pg *PackageGraph) TopologicalSort() []string
- type PackageGraphStats
- type PackageNode
- type PatternCandidate
- type PatternDetector
- func (d *PatternDetector) DetectPattern(ctx context.Context, scope string, patternType PatternType) ([]DetectedPattern, error)
- func (d *PatternDetector) DetectPatterns(ctx context.Context, scope string, opts *DetectionOptions) ([]DetectedPattern, error)
- func (d *PatternDetector) GetMatcher(patternType PatternType) (*PatternMatcher, bool)
- func (d *PatternDetector) ListPatterns() []PatternType
- func (d *PatternDetector) RegisterMatcher(matcher *PatternMatcher)
- func (d *PatternDetector) Summary(patterns []DetectedPattern) string
- type PatternMatcher
- type PatternType
- type Severity
- type SmellFinder
- type SmellOptions
- type SmellThresholds
- type SmellType
Constants ¶
const ( // StructuralMatchBase is confidence when only structure matches. StructuralMatchBase = 0.6 // IdiomaticMatchBase is confidence for idiomatic implementations. IdiomaticMatchBase = 0.9 // HeuristicMatchBase is confidence for threshold-based detection. HeuristicMatchBase = 0.5 )
Confidence base values for calibration.
const ( // MultipleExamplesBoost increases confidence for repeated patterns. MultipleExamplesBoost = 1.2 // SingleExamplePenalty decreases confidence for single occurrences. SingleExamplePenalty = 0.8 // PartialMatchPenalty decreases confidence for incomplete matches. PartialMatchPenalty = 0.7 )
Confidence adjustments.
Variables ¶
var ( // ErrInvalidInput indicates invalid input parameters. ErrInvalidInput = errors.New("invalid input") // ErrGraphNotReady indicates the graph is not frozen. ErrGraphNotReady = errors.New("graph not ready") // ErrContextCanceled indicates the context was canceled. ErrContextCanceled = errors.New("context canceled") // ErrPatternNotFound indicates no patterns were detected. ErrPatternNotFound = errors.New("pattern not found") // ErrUnsupportedLanguage indicates the language isn't supported. ErrUnsupportedLanguage = errors.New("unsupported language") )
Sentinel errors for the patterns package.
var BuilderMatcher = &PatternMatcher{ Name: PatternBuilder, Description: "Constructs complex objects step by step", Languages: []string{"go"}, StructuralCheck: func(ctx context.Context, g *graph.Graph, idx *index.SymbolIndex, scope string) []PatternCandidate { candidates := make([]PatternCandidate, 0) structs := idx.GetByKind(ast.SymbolKindStruct) for _, s := range structs { if ctx.Err() != nil { break } if scope != "" && !strings.HasPrefix(s.FilePath, scope) { continue } if !strings.HasSuffix(s.Name, "Builder") && !strings.HasSuffix(s.Name, "Config") { continue } methods := findMethodsForType(idx, s.Name) withMethods := make([]string, 0) hasBuild := false chainable := 0 for _, m := range methods { if strings.HasPrefix(m.Name, "With") || strings.HasPrefix(m.Name, "Set") { withMethods = append(withMethods, m.ID) if strings.Contains(m.Signature, "*"+s.Name) { chainable++ } } if m.Name == "Build" { hasBuild = true } } if len(withMethods) >= 2 { symbolIDs := append([]string{s.ID}, withMethods...) candidates = append(candidates, PatternCandidate{ SymbolIDs: symbolIDs, Location: s.FilePath, Metadata: map[string]interface{}{ "type": s.ID, "type_name": s.Name, "with_count": len(withMethods), "chainable": chainable, "has_build": hasBuild, "with_methods": withMethods, }, }) } } return candidates }, IdiomaticCheck: func(candidate PatternCandidate, idx *index.SymbolIndex) (bool, []string) { warnings := make([]string, 0) hasBuild, ok := candidate.Metadata["has_build"].(bool) if ok && !hasBuild { warnings = append(warnings, "Builder lacks Build() method - validation point missing") } chainable, ok := candidate.Metadata["chainable"].(int) withCount, ok2 := candidate.Metadata["with_count"].(int) if ok && ok2 && chainable < withCount { warnings = append(warnings, "Some With* methods aren't chainable (don't return *Builder)") } return len(warnings) == 0, warnings }, }
BuilderMatcher detects builder patterns.
Structural Indicators ¶
- Type with method chaining (methods return same type) - With* or Set* methods - Build() method that returns final type
Idiomatic Check ¶
- Build() validates before returning - With* methods are chainable
var FactoryMatcher = &PatternMatcher{ Name: PatternFactory, Description: "Creates objects without exposing instantiation logic", Languages: []string{"go"}, StructuralCheck: func(ctx context.Context, g *graph.Graph, idx *index.SymbolIndex, scope string) []PatternCandidate { candidates := make([]PatternCandidate, 0) functions := idx.GetByKind(ast.SymbolKindFunction) for _, fn := range functions { if ctx.Err() != nil { break } if scope != "" && !strings.HasPrefix(fn.FilePath, scope) { continue } if strings.HasPrefix(fn.Name, "New") || strings.HasPrefix(fn.Name, "Create") { if strings.Contains(fn.FilePath, "_test.go") { continue } candidates = append(candidates, PatternCandidate{ SymbolIDs: []string{fn.ID}, Location: fn.FilePath, Metadata: map[string]interface{}{ "function": fn.ID, "function_name": fn.Name, "function_file": fn.FilePath, "signature": fn.Signature, "returns_pointer": strings.Contains(fn.Signature, "*"), "returns_error": strings.Contains(fn.Signature, "error"), }, }) } } return candidates }, IdiomaticCheck: func(candidate PatternCandidate, idx *index.SymbolIndex) (bool, []string) { warnings := make([]string, 0) sig, ok := candidate.Metadata["signature"].(string) if !ok { return false, []string{"Could not validate signature"} } returnsError, ok := candidate.Metadata["returns_error"].(bool) if !ok { returnsError = false } if !returnsError { warnings = append(warnings, "Factory doesn't return error - no validation possible") } if !strings.Contains(sig, "*") && !strings.Contains(sig, "interface") { warnings = append(warnings, "Consider returning pointer or interface for flexibility") } return len(warnings) == 0, warnings }, }
FactoryMatcher detects factory patterns.
Structural Indicators ¶
- Function named New* or Create* - Returns a concrete type or interface - May include validation or configuration
Idiomatic Check ¶
- Better: returns interface, not concrete type - Better: includes validation
var MiddlewareMatcher = &PatternMatcher{ Name: PatternMiddleware, Description: "Handler chain pattern for HTTP or similar", Languages: []string{"go"}, StructuralCheck: func(ctx context.Context, g *graph.Graph, idx *index.SymbolIndex, scope string) []PatternCandidate { candidates := make([]PatternCandidate, 0) functions := idx.GetByKind(ast.SymbolKindFunction) for _, fn := range functions { if ctx.Err() != nil { break } if scope != "" && !strings.HasPrefix(fn.FilePath, scope) { continue } sig := fn.Signature if (strings.Contains(sig, "Handler") || strings.Contains(sig, "HandlerFunc")) && strings.Count(sig, "Handler") >= 2 { candidates = append(candidates, PatternCandidate{ SymbolIDs: []string{fn.ID}, Location: fn.FilePath, Metadata: map[string]interface{}{ "function": fn.ID, "name": fn.Name, "signature": sig, }, }) } } return candidates }, IdiomaticCheck: func(candidate PatternCandidate, idx *index.SymbolIndex) (bool, []string) { return true, nil }, }
MiddlewareMatcher detects middleware patterns.
Structural Indicators ¶
- Function signature: func(Handler) Handler - http.Handler or similar handler types
var OptionsMatcher = &PatternMatcher{ Name: PatternOptions, Description: "Functional options for configuration", Languages: []string{"go"}, StructuralCheck: func(ctx context.Context, g *graph.Graph, idx *index.SymbolIndex, scope string) []PatternCandidate { candidates := make([]PatternCandidate, 0) types := idx.GetByKind(ast.SymbolKindType) for _, t := range types { if ctx.Err() != nil { break } if scope != "" && !strings.HasPrefix(t.FilePath, scope) { continue } if !strings.Contains(t.Name, "Option") && !strings.Contains(t.Name, "Opt") { continue } if !strings.Contains(t.Signature, "func") { continue } functions := idx.GetByKind(ast.SymbolKindFunction) withFuncs := make([]string, 0) for _, fn := range functions { if strings.HasPrefix(fn.Name, "With") && strings.Contains(fn.Signature, t.Name) { withFuncs = append(withFuncs, fn.ID) } } if len(withFuncs) >= 2 { symbolIDs := append([]string{t.ID}, withFuncs...) candidates = append(candidates, PatternCandidate{ SymbolIDs: symbolIDs, Location: t.FilePath, Metadata: map[string]interface{}{ "option_type": t.ID, "option_name": t.Name, "with_count": len(withFuncs), "with_funcs": withFuncs, }, }) } } return candidates }, IdiomaticCheck: func(candidate PatternCandidate, idx *index.SymbolIndex) (bool, []string) { withCount, ok := candidate.Metadata["with_count"].(int) if ok && withCount < 3 { return true, []string{"Options pattern with few options - might be over-engineering"} } return true, nil }, }
OptionsMatcher detects functional options pattern.
Structural Indicators ¶
- Type alias: type Option func(*Config) - Multiple With* functions returning Option - Constructor accepting ...Option
var SingletonMatcher = &PatternMatcher{ Name: PatternSingleton, Description: "Single instance pattern with thread-safe lazy initialization", Languages: []string{"go"}, StructuralCheck: func(ctx context.Context, g *graph.Graph, idx *index.SymbolIndex, scope string) []PatternCandidate { candidates := make([]PatternCandidate, 0) variables := idx.GetByKind(ast.SymbolKindVariable) for _, v := range variables { if ctx.Err() != nil { break } if scope != "" && !strings.HasPrefix(v.FilePath, scope) { continue } accessorNames := []string{ "Get" + v.Name, v.Name + "Instance", "Instance", "Get" + strings.TrimPrefix(v.Name, "default"), } for _, name := range accessorNames { functions := idx.GetByName(name) for _, fn := range functions { if fn.Kind == ast.SymbolKindFunction && strings.HasPrefix(fn.FilePath, strings.TrimSuffix(v.FilePath, ".go")) { candidates = append(candidates, PatternCandidate{ SymbolIDs: []string{v.ID, fn.ID}, Location: v.FilePath, Metadata: map[string]interface{}{ "variable": v.ID, "accessor": fn.ID, "variable_name": v.Name, "variable_file": v.FilePath, "accessor_name": fn.Name, "accessor_file": fn.FilePath, "accessor_start": fn.StartLine, "accessor_end": fn.EndLine, }, }) } } } } return candidates }, IdiomaticCheck: func(candidate PatternCandidate, idx *index.SymbolIndex) (bool, []string) { warnings := make([]string, 0) accessorID, ok := candidate.Metadata["accessor"].(string) if !ok { return false, []string{"Could not validate accessor function"} } sym, found := idx.GetByID(accessorID) if !found { return false, []string{"Accessor function not found"} } hasSyncOnce := strings.Contains(sym.Signature, "sync.Once") || strings.Contains(sym.Signature, "sync.Mutex") if !hasSyncOnce { warnings = append(warnings, "Singleton without sync.Once is not thread-safe") return false, warnings } return true, warnings }, }
SingletonMatcher detects singleton patterns.
Structural Indicators ¶
- Package-level variable of a type - sync.Once or mutex for initialization - Accessor function (GetInstance, Instance, etc.)
Idiomatic Check ¶
- MUST use sync.Once or mutex for thread-safety - Non-idiomatic: no synchronization mechanism
Functions ¶
func DefaultMatchers ¶
func DefaultMatchers() map[PatternType]*PatternMatcher
DefaultMatchers returns the standard set of pattern matchers.
Types ¶
type CRSBridge ¶
type CRSBridge struct {
// contains filtered or unexported fields
}
CRSBridge implements CRSRecorder using a real CRS instance.
Description ¶
CRSBridge wraps a CRS instance to record tool executions and generate CDCL clauses on error or degraded results. It uses ActorSystem since tool executions are system-level actions.
Thread Safety ¶
This type is safe for concurrent use (delegates to thread-safe CRS).
func NewCRSBridge ¶
NewCRSBridge creates a CRS bridge for tool step recording.
Inputs ¶
- crsInstance: The CRS to record steps in.
- sessionID: Session ID for step attribution.
Outputs ¶
- *CRSBridge: Configured bridge.
func (*CRSBridge) RecordToolStep ¶
func (b *CRSBridge) RecordToolStep(ctx context.Context, toolName string, resultCount int, duration time.Duration, err error)
RecordToolStep records a tool execution step and generates clauses as needed.
Description ¶
Records the step in the CRS step history. On error, generates a session-scoped CDCL clause with FailureType=ToolError. On empty results, generates a soft signal clause indicating the parameters may be wrong.
Inputs ¶
- ctx: Context for cancellation.
- toolName: Name of the tool that executed.
- resultCount: Number of results returned.
- duration: Execution duration.
- err: Error from tool execution (nil on success).
type CRSRecorder ¶
type CRSRecorder interface {
// RecordToolStep records a tool execution step in the CRS.
RecordToolStep(ctx context.Context, toolName string, resultCount int, duration time.Duration, err error)
}
CRSRecorder abstracts CRS step recording for tool implementations.
Description ¶
CRSRecorder provides a simplified interface for pattern analysis tools to record their executions in the CRS. Tool executions are recorded as system-level actions using ActorSystem.
Thread Safety ¶
Implementations must be safe for concurrent use.
type CircularDep ¶
type CircularDep struct {
// Cycle is the dependency chain [A, B, C, A].
Cycle []string `json:"cycle"`
// Type is package, type, or function.
Type string `json:"type"`
// Severity indicates importance.
Severity Severity `json:"severity"`
// Suggestion explains how to fix.
Suggestion string `json:"suggestion"`
// BreakPoints are recommended places to break the cycle.
BreakPoints []string `json:"break_points"`
}
CircularDep represents a circular dependency.
type CircularDepFinder ¶
type CircularDepFinder struct {
// contains filtered or unexported fields
}
CircularDepFinder finds circular dependencies in code.
Description ¶
CircularDepFinder detects circular dependencies at package, type, and function levels. It uses Tarjan's algorithm for efficient strongly connected component detection.
Thread Safety ¶
This type is safe for concurrent use.
func NewCircularDepFinder ¶
func NewCircularDepFinder(g *graph.Graph, projectModule string) *CircularDepFinder
NewCircularDepFinder creates a new circular dependency finder.
Description ¶
Creates a finder that analyzes the code graph for circular dependencies. The package graph is built lazily on first query.
Inputs ¶
- g: The code graph to analyze.
- projectModule: The module path (e.g., "github.com/user/repo").
Outputs ¶
- *CircularDepFinder: Configured finder.
func (*CircularDepFinder) BuildPackageGraph ¶
func (c *CircularDepFinder) BuildPackageGraph(ctx context.Context) error
BuildPackageGraph builds the package-level dependency graph.
Description ¶
Derives package dependencies from file imports. Called automatically on first query but can be called explicitly for better control.
Inputs ¶
- ctx: Context for cancellation.
Outputs ¶
- error: Non-nil on failure.
func (*CircularDepFinder) FindCircularDeps ¶
func (c *CircularDepFinder) FindCircularDeps( ctx context.Context, scope string, depType CircularDepType, ) ([]CircularDep, error)
FindCircularDeps finds circular dependencies.
Description ¶
Finds all circular dependencies in the specified scope. Supports package, type, and function level detection.
Inputs ¶
- ctx: Context for cancellation.
- scope: Package path prefix to filter (empty = all).
- depType: Type of circular dependency to find.
Outputs ¶
- []CircularDep: Found circular dependencies.
- error: Non-nil on failure.
Example ¶
finder := NewCircularDepFinder(graph, "github.com/user/repo") deps, err := finder.FindCircularDeps(ctx, "pkg/", CircularDepPackage)
func (*CircularDepFinder) GetPackageGraph ¶
func (c *CircularDepFinder) GetPackageGraph() *PackageGraph
GetPackageGraph returns the underlying package graph.
func (*CircularDepFinder) SetCRS ¶
func (c *CircularDepFinder) SetCRS(recorder CRSRecorder)
SetCRS configures CRS recording for this finder.
func (*CircularDepFinder) Summary ¶
func (c *CircularDepFinder) Summary(deps []CircularDep) string
Summary generates a summary of circular dependency findings.
type CircularDepType ¶
type CircularDepType string
CircularDepType categorizes circular dependencies.
const ( // CircularDepPackage is a package-level circular dependency. CircularDepPackage CircularDepType = "package" // CircularDepType represents a type-level circular dependency. CircularDepTypeLevel CircularDepType = "type" // CircularDepFunction is a function-level circular dependency. CircularDepFunction CircularDepType = "function" )
type CodeFingerprint ¶
type CodeFingerprint struct {
// SymbolID is the identifier of the source symbol.
SymbolID string
// FilePath is the source file path.
FilePath string
// LineStart is the starting line of the code.
LineStart int
// LineEnd is the ending line of the code.
LineEnd int
// TokenHashes contains k-gram hashes of normalized tokens.
TokenHashes []uint64
// MinHashSig is the MinHash signature for LSH.
MinHashSig []uint64
// ASTStructure is an abstracted AST pattern string.
ASTStructure string
// TokenCount is the number of tokens in the code.
TokenCount int
// LineCount is the number of lines in the code.
LineCount int
// Complexity is a cyclomatic complexity estimate.
Complexity int
}
CodeFingerprint represents a fingerprint for duplication detection.
Description ¶
CodeFingerprint captures the structural essence of code for efficient similarity comparison. It uses k-gram hashing for exact matching and MinHash signatures for locality-sensitive hashing.
Thread Safety ¶
This type is immutable after creation.
func (*CodeFingerprint) EstimatedJaccard ¶
func (fp *CodeFingerprint) EstimatedJaccard(other *CodeFingerprint) float64
EstimatedJaccard estimates Jaccard similarity using MinHash signatures.
Description ¶
Uses MinHash signatures for O(1) similarity estimation. Less accurate than exact Jaccard but much faster for large codebases.
Inputs ¶
- other: The fingerprint to compare against.
Outputs ¶
- float64: Estimated similarity score (0.0 - 1.0).
func (*CodeFingerprint) JaccardSimilarity ¶
func (fp *CodeFingerprint) JaccardSimilarity(other *CodeFingerprint) float64
JaccardSimilarity computes the Jaccard similarity between two fingerprints.
Description ¶
Computes set intersection / set union of token hashes. Returns a value between 0.0 and 1.0.
Inputs ¶
- other: The fingerprint to compare against.
Outputs ¶
- float64: Similarity score (0.0 - 1.0).
type CodeSmell ¶
type CodeSmell struct {
// Type categorizes the smell.
Type SmellType `json:"type"`
// Severity indicates importance.
Severity Severity `json:"severity"`
// Location is the file and symbol.
Location string `json:"location"`
// Description explains the issue.
Description string `json:"description"`
// Suggestion provides a fix recommendation.
Suggestion string `json:"suggestion"`
// Code is the relevant code snippet.
Code string `json:"code,omitempty"`
// Value is the measured value (e.g., line count).
Value int `json:"value,omitempty"`
// Threshold is what triggered the smell.
Threshold int `json:"threshold,omitempty"`
}
CodeSmell represents a potential code quality issue.
type Convention ¶
type Convention struct {
// Type categorizes the convention (naming, error_handling, etc.).
Type string `json:"type"`
// Pattern describes the convention pattern.
Pattern string `json:"pattern"`
// Examples shows instances of the convention.
Examples []string `json:"examples"`
// Frequency is how often the convention is followed (0.0 - 1.0).
Frequency float64 `json:"frequency"`
// Description explains the convention.
Description string `json:"description"`
}
Convention represents an observed coding convention.
type ConventionExtractor ¶
type ConventionExtractor struct {
// contains filtered or unexported fields
}
ConventionExtractor extracts coding conventions from a codebase.
Description ¶
ConventionExtractor analyzes the codebase to infer coding conventions. This helps new code follow existing patterns and maintains consistency.
Thread Safety ¶
This type is safe for concurrent use.
func NewConventionExtractor ¶
func NewConventionExtractor(idx *index.SymbolIndex, projectRoot string) *ConventionExtractor
NewConventionExtractor creates a new convention extractor.
Inputs ¶
- idx: Symbol index for lookups.
- projectRoot: Project root for reading source files.
Outputs ¶
- *ConventionExtractor: Configured extractor.
func NewConventionExtractorWithReader ¶
func NewConventionExtractorWithReader(idx *index.SymbolIndex, reader *FileReader) *ConventionExtractor
NewConventionExtractorWithReader creates a convention extractor with a shared FileReader.
Inputs ¶
- idx: Symbol index for lookups.
- reader: Shared cached file reader.
Outputs ¶
- *ConventionExtractor: Configured extractor.
func (*ConventionExtractor) ExtractConventions ¶
func (c *ConventionExtractor) ExtractConventions( ctx context.Context, scope string, opts *ConventionOptions, ) ([]Convention, error)
ExtractConventions extracts coding conventions from the specified scope.
Description ¶
Analyzes the codebase to identify common patterns in: - Naming (camelCase, snake_case, prefixes, suffixes) - Error handling (return patterns, wrapping) - File organization (one type per file, grouping) - Testing (table-driven, subtests) - Documentation (format, coverage)
Inputs ¶
- ctx: Context for cancellation.
- scope: Package or file path prefix (empty = all).
- opts: Extraction options.
Outputs ¶
- []Convention: Extracted conventions.
- error: Non-nil on failure.
func (*ConventionExtractor) SetCRS ¶
func (c *ConventionExtractor) SetCRS(recorder CRSRecorder)
SetCRS configures CRS recording for this extractor.
func (*ConventionExtractor) Summary ¶
func (c *ConventionExtractor) Summary(conventions []Convention) string
Summary generates a summary of extracted conventions.
type ConventionOptions ¶
type ConventionOptions struct {
// SampleSize is the max symbols to sample per type (0 = all).
SampleSize int
// MinFrequency is the minimum frequency to report (0.0 - 1.0).
MinFrequency float64
// Types filters which convention categories to extract.
// Valid values: "naming", "error_handling", "file_organization", "testing", "documentation", "imports".
// Empty slice means all types.
Types []string
// IncludeTests includes test files in analysis.
IncludeTests bool
}
ConventionOptions configures convention extraction.
func DefaultConventionOptions ¶
func DefaultConventionOptions() ConventionOptions
DefaultConventionOptions returns sensible defaults.
type ConventionType ¶
type ConventionType string
ConventionType categorizes conventions.
const ( // ConventionNaming is a naming convention. ConventionNaming ConventionType = "naming" // ConventionErrorHandling is an error handling convention. ConventionErrorHandling ConventionType = "error_handling" // ConventionFileOrganization is a file organization convention. ConventionFileOrganization ConventionType = "file_organization" // ConventionTesting is a testing convention. ConventionTesting ConventionType = "testing" // ConventionDocumentation is a documentation convention. ConventionDocumentation ConventionType = "documentation" // ConventionImports is an import organization convention. ConventionImports ConventionType = "imports" )
type DeadCode ¶
type DeadCode struct {
// Type is function, type, variable, or constant.
Type string `json:"type"`
// Name is the symbol name.
Name string `json:"name"`
// FilePath is the source file.
FilePath string `json:"file_path"`
// Line is the 1-indexed line number.
Line int `json:"line"`
// Reason explains why it's considered dead.
Reason string `json:"reason"`
// Confidence indicates certainty (lower for edge cases).
Confidence float64 `json:"confidence"`
}
DeadCode represents unreferenced code.
type DeadCodeExclusions ¶
type DeadCodeExclusions struct {
// EntryPoints lists function patterns that are always excluded.
// Supports wildcards: "main", "init", "Test*", "Benchmark*", "Example*"
EntryPoints []string
// ExportedSymbols excludes exported symbols (may be external API).
ExportedSymbols bool
// InterfaceImpls excludes methods that implement interfaces.
InterfaceImpls bool
// ReflectionPatterns lists patterns suggesting reflection usage.
ReflectionPatterns []string
// BuildTaggedFiles excludes files with build tags.
BuildTaggedFiles bool
// AnnotationPatterns lists comment annotations that exclude symbols.
// Examples: "@used-by", "@implements", "nolint:deadcode"
AnnotationPatterns []string
}
DeadCodeExclusions configures what to exclude from dead code detection.
Description ¶
Dead code detection is inherently imprecise due to reflection, build tags, and external API contracts. These exclusions help reduce false positives.
func DefaultExclusions ¶
func DefaultExclusions() *DeadCodeExclusions
DefaultExclusions returns conservative default exclusions.
IT-08 H-1: Extended from Go-only to cross-language entry point patterns.
func (*DeadCodeExclusions) IsExcluded ¶
IsExcluded is a public wrapper for exclusion checking.
Inputs ¶
- symbol: The symbol to check.
- g: The code graph.
Outputs ¶
- bool: True if the symbol should be excluded.
- string: The reason for exclusion.
type DeadCodeFinder ¶
type DeadCodeFinder struct {
// contains filtered or unexported fields
}
DeadCodeFinder finds unreferenced code.
Description ¶
DeadCodeFinder detects code that appears to be unused. It is conservative by default, preferring false negatives over false positives because: - Reflection can invoke code without static references - Build tags may exclude code from normal builds - Exported symbols may be part of a public API
Thread Safety ¶
This type is safe for concurrent use.
func NewDeadCodeFinder ¶
func NewDeadCodeFinder(g *graph.Graph, idx *index.SymbolIndex, projectRoot string) *DeadCodeFinder
NewDeadCodeFinder creates a new dead code finder.
Inputs ¶
- g: Code graph for reference analysis.
- idx: Symbol index for lookups.
- projectRoot: Project root for reading source files.
Outputs ¶
- *DeadCodeFinder: Configured finder.
func (*DeadCodeFinder) FindDeadCode ¶
func (d *DeadCodeFinder) FindDeadCode( ctx context.Context, scope string, opts *DeadCodeOptions, ) ([]DeadCode, error)
FindDeadCode finds unreferenced code in the specified scope.
Description ¶
Analyzes the code graph to find symbols with no incoming references. Uses a conservative approach to avoid false positives.
Inputs ¶
- ctx: Context for cancellation.
- scope: Package or file path prefix (empty = all).
- opts: Detection options.
Outputs ¶
- []DeadCode: Found dead code.
- error: Non-nil on failure.
Example ¶
finder := NewDeadCodeFinder(graph, index, "/project") dead, err := finder.FindDeadCode(ctx, "pkg/internal", nil)
func (*DeadCodeFinder) SetCRS ¶
func (d *DeadCodeFinder) SetCRS(recorder CRSRecorder)
SetCRS configures CRS recording for this finder.
func (*DeadCodeFinder) Summary ¶
func (d *DeadCodeFinder) Summary(deadCode []DeadCode) string
Summary generates a summary of dead code findings.
type DeadCodeOptions ¶
type DeadCodeOptions struct {
// Exclusions configures what to exclude.
Exclusions *DeadCodeExclusions
// IncludeExported includes exported symbols in results.
IncludeExported bool
// IncludeTests includes test files in analysis.
IncludeTests bool
// MaxResults limits the number of results (0 = unlimited).
MaxResults int
}
DeadCodeOptions configures dead code detection.
func DefaultDeadCodeOptions ¶
func DefaultDeadCodeOptions() DeadCodeOptions
DefaultDeadCodeOptions returns sensible defaults.
type DetectedPattern ¶
type DetectedPattern struct {
// Type identifies the pattern (singleton, factory, etc.).
Type PatternType `json:"type"`
// Location is the package or file where the pattern is found.
Location string `json:"location"`
// Components lists the symbols that form the pattern.
Components []string `json:"components"`
// Confidence is how certain we are (0.0 - 1.0).
Confidence float64 `json:"confidence"`
// Example shows a code snippet illustrating the pattern.
Example string `json:"example,omitempty"`
// Idiomatic indicates if this is the recommended implementation.
Idiomatic bool `json:"idiomatic"`
// Warnings lists issues with the implementation.
Warnings []string `json:"warnings,omitempty"`
}
DetectedPattern represents a design pattern found in code.
type DetectionOptions ¶
type DetectionOptions struct {
// Patterns limits detection to specific patterns (empty = all).
Patterns []PatternType
// MinConfidence filters results below this threshold.
MinConfidence float64
// IncludeNonIdiomatic includes non-idiomatic implementations.
IncludeNonIdiomatic bool
}
DetectionOptions configures pattern detection.
type DupLocation ¶
type DupLocation struct {
// FilePath is the source file.
FilePath string `json:"file_path"`
// LineStart is the 1-indexed starting line.
LineStart int `json:"line_start"`
// LineEnd is the 1-indexed ending line.
LineEnd int `json:"line_end"`
// SymbolID is the containing symbol (if applicable).
SymbolID string `json:"symbol_id,omitempty"`
}
DupLocation is a location of duplicated code.
type DuplicatePair ¶
type DuplicatePair struct {
// SymbolID1 is the first symbol's ID.
SymbolID1 string
// SymbolID2 is the second symbol's ID.
SymbolID2 string
// Similarity is the estimated Jaccard similarity.
Similarity float64
}
DuplicatePair represents a pair of similar fingerprints.
type Duplication ¶
type Duplication struct {
// Type is exact, near, or structural.
Type string `json:"type"`
// Similarity is the match percentage (0.0 - 1.0).
Similarity float64 `json:"similarity"`
// Locations are where the duplicates exist.
Locations []DupLocation `json:"locations"`
// Code is a representative sample.
Code string `json:"code,omitempty"`
// Suggestion recommends extraction or refactoring.
Suggestion string `json:"suggestion"`
// Confidence in the duplication detection.
Confidence float64 `json:"confidence"`
}
Duplication represents duplicate or similar code.
type DuplicationFinder ¶
type DuplicationFinder struct {
// contains filtered or unexported fields
}
DuplicationFinder finds duplicate code blocks.
Description ¶
DuplicationFinder uses LSH-based fingerprinting to efficiently find duplicate and near-duplicate code. It operates in O(n log n) time instead of O(n²) for large codebases.
Thread Safety ¶
This type is safe for concurrent use.
func NewDuplicationFinder ¶
func NewDuplicationFinder(idx *index.SymbolIndex, projectRoot string) *DuplicationFinder
NewDuplicationFinder creates a new duplication finder.
Description ¶
Creates a finder with pre-configured fingerprinting and LSH index. The index is built lazily on first query.
Inputs ¶
- idx: Symbol index for lookups.
- projectRoot: Project root directory for reading source files.
Outputs ¶
- *DuplicationFinder: Configured finder.
func NewDuplicationFinderWithReader ¶
func NewDuplicationFinderWithReader(idx *index.SymbolIndex, reader *FileReader) *DuplicationFinder
NewDuplicationFinderWithReader creates a duplication finder with a shared FileReader.
Inputs ¶
- idx: Symbol index for lookups.
- reader: Shared cached file reader.
Outputs ¶
- *DuplicationFinder: Configured finder.
func (*DuplicationFinder) BuildIndex ¶
func (d *DuplicationFinder) BuildIndex(ctx context.Context, opts *DuplicationOptions) (int, error)
BuildIndex builds the fingerprint index for the codebase.
Description ¶
Scans all functions/methods in the index, computes fingerprints, and adds them to the LSH index. This is called automatically on first query but can be called explicitly for better control.
Inputs ¶
- ctx: Context for cancellation.
- opts: Options controlling what to index.
Outputs ¶
- int: Number of symbols indexed.
- error: Non-nil on failure.
func (*DuplicationFinder) FindDuplicatesOf ¶
func (d *DuplicationFinder) FindDuplicatesOf( ctx context.Context, symbolID string, opts *DuplicationOptions, ) ([]Duplication, error)
FindDuplicatesOf finds code similar to a specific symbol.
Description ¶
Finds all code blocks similar to the specified symbol.
Inputs ¶
- ctx: Context for cancellation.
- symbolID: The symbol to find duplicates of.
- opts: Detection options.
Outputs ¶
- []Duplication: Found duplications.
- error: Non-nil on failure.
func (*DuplicationFinder) FindDuplication ¶
func (d *DuplicationFinder) FindDuplication( ctx context.Context, scope string, opts *DuplicationOptions, ) ([]Duplication, error)
FindDuplication finds duplicate code blocks.
Description ¶
Finds all pairs of duplicate code blocks in the specified scope. Uses LSH for efficient near-duplicate detection.
Inputs ¶
- ctx: Context for cancellation.
- scope: Package or file path prefix (empty = all).
- opts: Detection options.
Outputs ¶
- []Duplication: Found duplications.
- error: Non-nil on failure.
Example ¶
finder := NewDuplicationFinder(index, "/project") dups, err := finder.FindDuplication(ctx, "pkg/auth", nil)
func (*DuplicationFinder) SetCRS ¶
func (d *DuplicationFinder) SetCRS(recorder CRSRecorder)
SetCRS configures CRS recording for this finder.
func (*DuplicationFinder) Stats ¶
func (d *DuplicationFinder) Stats() DuplicationStats
Stats returns statistics about the duplication finder.
func (*DuplicationFinder) Summary ¶
func (d *DuplicationFinder) Summary(duplications []Duplication) string
Summary generates a summary of duplication findings.
type DuplicationOptions ¶
type DuplicationOptions struct {
// MinLines is the minimum lines to consider (default: 5).
MinLines int
// SimilarityThreshold is the minimum similarity (default: 0.8).
SimilarityThreshold float64
// Type filters results by duplication type ("exact", "near", "structural").
// Empty string means all types.
Type string
// IncludeTests includes test files in analysis.
IncludeTests bool
// MaxResults limits the number of results (0 = unlimited).
MaxResults int
}
DuplicationOptions configures duplication detection.
func DefaultDuplicationOptions ¶
func DefaultDuplicationOptions() DuplicationOptions
DefaultDuplicationOptions returns sensible defaults.
type DuplicationStats ¶
type DuplicationStats struct {
// Indexed indicates if the index has been built.
Indexed bool
// IndexedSymbols is the number of indexed symbols.
IndexedSymbols int
// NumBands is the LSH band count.
NumBands int
// RowsPerBand is the LSH rows per band.
RowsPerBand int
// TotalBuckets is the total non-empty buckets.
TotalBuckets int
// MaxBucketSize is the largest bucket size.
MaxBucketSize int
}
DuplicationStats contains statistics about duplication detection.
type DuplicationType ¶
type DuplicationType string
DuplicationType categorizes duplicates.
const ( // DuplicationExact is byte-for-byte identical code. DuplicationExact DuplicationType = "exact" // DuplicationNear is structurally similar code with minor differences. DuplicationNear DuplicationType = "near" // DuplicationStructural is same control flow with different names. DuplicationStructural DuplicationType = "structural" )
type FileReader ¶
type FileReader struct {
// contains filtered or unexported fields
}
FileReader provides cached file reading for pattern analysis tools.
Description ¶
FileReader caches file contents (split into lines) to avoid repeated I/O when multiple tools analyze the same files. This replaces the three duplicate readSymbolCode implementations in smells.go, duplication.go, and conventions.go.
Thread Safety ¶
This type is safe for concurrent use via sync.RWMutex.
func NewFileReader ¶
func NewFileReader(projectRoot string) *FileReader
NewFileReader creates a new cached file reader.
Inputs ¶
- projectRoot: Base directory for resolving relative file paths.
Outputs ¶
- *FileReader: Configured reader with empty cache.
func (*FileReader) CacheSize ¶
func (r *FileReader) CacheSize() int
CacheSize returns the number of cached files.
func (*FileReader) ReadLines ¶
func (r *FileReader) ReadLines(filePath string) ([]string, error)
ReadLines reads file contents as lines, using cache on subsequent calls.
Inputs ¶
- filePath: Relative file path (joined with projectRoot).
Outputs ¶
- []string: File lines.
- error: Non-nil on I/O failure.
func (*FileReader) ReadSymbolCode ¶
func (r *FileReader) ReadSymbolCode(sym *ast.Symbol) (string, error)
ReadSymbolCode reads the source code for a symbol, using cache.
Description ¶
Replaces the 3 duplicate readSymbolCode implementations that existed in SmellFinder, DuplicationFinder, and ConventionExtractor.
Inputs ¶
- sym: The symbol to read code for.
Outputs ¶
- string: Source code of the symbol.
- error: Non-nil if symbol is nil, lines are out of bounds, or I/O fails.
type FingerprintConfig ¶
type FingerprintConfig struct {
// KGramSize is the size of k-grams for token hashing.
KGramSize int
// NumHashFuncs is the number of hash functions for MinHash.
NumHashFuncs int
// NormalizeIdentifiers removes identifier differences.
NormalizeIdentifiers bool
}
FingerprintConfig configures code fingerprinting behavior.
func DefaultFingerprintConfig ¶
func DefaultFingerprintConfig() FingerprintConfig
DefaultFingerprintConfig returns sensible defaults.
type Fingerprinter ¶
type Fingerprinter struct {
// contains filtered or unexported fields
}
Fingerprinter creates code fingerprints from symbols.
Description ¶
Fingerprinter processes code symbols to create fingerprints suitable for duplication detection. It normalizes code, extracts k-grams, and computes MinHash signatures.
Thread Safety ¶
This type is safe for concurrent use.
func NewFingerprinter ¶
func NewFingerprinter(config FingerprintConfig) *Fingerprinter
NewFingerprinter creates a new fingerprinter with the given config.
Description ¶
Creates a fingerprinter with pre-computed hash seeds for MinHash.
Inputs ¶
- config: Fingerprinting configuration.
Outputs ¶
- *Fingerprinter: Configured fingerprinter.
func (*Fingerprinter) Fingerprint ¶
func (f *Fingerprinter) Fingerprint(symbol *ast.Symbol, code string) *CodeFingerprint
Fingerprint creates a fingerprint for a symbol's code.
Description ¶
Extracts code from the symbol, normalizes it, and computes k-gram hashes and MinHash signature.
Inputs ¶
- symbol: The symbol to fingerprint.
- code: The source code content for the symbol.
Outputs ¶
- *CodeFingerprint: The computed fingerprint.
type LSHIndex ¶
type LSHIndex struct {
// contains filtered or unexported fields
}
LSHIndex provides O(n log n) near-duplicate detection using locality-sensitive hashing.
Description ¶
LSHIndex uses banded MinHash for approximate nearest neighbor search. Instead of comparing every pair of fingerprints (O(n²)), it hashes fingerprints into buckets where similar items are likely to collide.
The index divides MinHash signatures into bands. Two fingerprints are candidates if they share at least one band. More bands mean higher recall but more false positives.
Thread Safety ¶
This type is safe for concurrent use.
func NewLSHIndex ¶
NewLSHIndex creates an LSH index with the specified parameters.
Description ¶
Creates an index configured for the desired similarity threshold. Higher numBands increases recall (finds more similar pairs) but also increases false positives. A good rule of thumb:
- For 80% similarity threshold: numBands=20, rowsPerBand=5
- For 90% similarity threshold: numBands=50, rowsPerBand=2
The signature length must be numBands * rowsPerBand.
Inputs ¶
- numBands: Number of hash bands.
- rowsPerBand: Rows per band.
Outputs ¶
- *LSHIndex: The configured index.
Example ¶
index := NewLSHIndex(20, 5) // For 100-element MinHash signatures index.Add(fingerprint) candidates := index.Query(queryFingerprint)
func (*LSHIndex) Add ¶
func (l *LSHIndex) Add(fp *CodeFingerprint)
Add adds a fingerprint to the index.
Description ¶
Hashes the fingerprint's MinHash signature into band buckets. If a fingerprint with the same SymbolID already exists, it is replaced.
Inputs ¶
- fp: The fingerprint to add.
Errors ¶
Silently ignores nil fingerprints or those with empty signatures.
func (*LSHIndex) FindAllDuplicates ¶
func (l *LSHIndex) FindAllDuplicates(threshold float64) []DuplicatePair
FindAllDuplicates finds all pairs of similar fingerprints.
Description ¶
Efficiently finds all pairs of fingerprints with similarity above the threshold. Uses LSH to avoid O(n²) comparisons.
Inputs ¶
- threshold: Minimum similarity (0.0 - 1.0).
Outputs ¶
- []DuplicatePair: All pairs above the threshold.
func (*LSHIndex) GetFingerprint ¶
func (l *LSHIndex) GetFingerprint(symbolID string) (*CodeFingerprint, bool)
GetFingerprint retrieves a fingerprint by symbol ID.
Outputs ¶
- *CodeFingerprint: The fingerprint, or nil if not found.
- bool: True if found.
func (*LSHIndex) Query ¶
func (l *LSHIndex) Query(fp *CodeFingerprint) []string
Query finds candidate matches for a fingerprint.
Description ¶
Returns symbol IDs of fingerprints that share at least one band with the query fingerprint. These are candidates that should be verified with actual similarity computation.
Inputs ¶
- fp: The query fingerprint.
Outputs ¶
- []string: Symbol IDs of candidate matches.
func (*LSHIndex) QueryWithThreshold ¶
func (l *LSHIndex) QueryWithThreshold(fp *CodeFingerprint, threshold float64) []LSHMatch
QueryWithThreshold finds matches above a similarity threshold.
Description ¶
Uses LSH to find candidates, then verifies each candidate using estimated Jaccard similarity. Returns only matches above the threshold.
Inputs ¶
- fp: The query fingerprint.
- threshold: Minimum similarity (0.0 - 1.0).
Outputs ¶
- []LSHMatch: Matches above the threshold.
func (*LSHIndex) Remove ¶
Remove removes a fingerprint from the index.
Inputs ¶
- symbolID: The ID of the fingerprint to remove.
type LSHMatch ¶
type LSHMatch struct {
// SymbolID is the matched symbol's ID.
SymbolID string
// Similarity is the estimated Jaccard similarity.
Similarity float64
}
LSHMatch represents a similarity match from the LSH index.
type LSHStats ¶
type LSHStats struct {
// NumFingerprints is the number of indexed fingerprints.
NumFingerprints int
// NumBands is the number of bands.
NumBands int
// RowsPerBand is the number of rows per band.
RowsPerBand int
// TotalBuckets is the total number of non-empty buckets.
TotalBuckets int
// MaxBucketSize is the size of the largest bucket.
MaxBucketSize int
}
LSHStats contains statistics about the LSH index.
type NopCRSRecorder ¶
type NopCRSRecorder struct{}
NopCRSRecorder is a no-op implementation for tests and standalone usage.
Description ¶
NopCRSRecorder discards all step recordings without error. Use this when CRS integration is not needed (tests, standalone tool usage).
Thread Safety ¶
This type is safe for concurrent use (stateless).
func (*NopCRSRecorder) RecordToolStep ¶
func (n *NopCRSRecorder) RecordToolStep(_ context.Context, _ string, _ int, _ time.Duration, _ error)
RecordToolStep is a no-op.
type PackageGraph ¶
type PackageGraph struct {
// contains filtered or unexported fields
}
PackageGraph provides package-level dependency tracking.
Description ¶
Our code graph has file and symbol nodes, but not package nodes. PackageGraph aggregates file imports into package-level dependencies, enabling circular dependency detection at the package level.
Thread Safety ¶
This type is NOT safe for concurrent modification. It is designed to be built once and then queried concurrently.
func BuildPackageGraph ¶
func BuildPackageGraph(g *graph.Graph, projectModule string) *PackageGraph
BuildPackageGraph derives package dependencies from file imports.
Description ¶
Scans all file nodes in the code graph and aggregates their imports into package-level dependencies. Internal packages are identified by the "internal" path segment.
Inputs ¶
- g: The code graph to analyze.
- projectModule: The module path (e.g., "github.com/user/repo").
Outputs ¶
- *PackageGraph: The constructed package dependency graph.
func NewPackageGraph ¶
func NewPackageGraph() *PackageGraph
NewPackageGraph creates an empty package graph.
func (*PackageGraph) Dependencies ¶
func (pg *PackageGraph) Dependencies(path string) []string
Dependencies returns the direct dependencies of a package.
func (*PackageGraph) Dependents ¶
func (pg *PackageGraph) Dependents(path string) []string
Dependents returns packages that depend on the given package.
func (*PackageGraph) FindCycles ¶
func (pg *PackageGraph) FindCycles() [][]string
FindCycles finds all strongly connected components (cycles) using Tarjan's algorithm.
Description ¶
Implements Tarjan's algorithm for finding strongly connected components. Returns all cycles (SCCs with more than one node).
Outputs ¶
- [][]string: Each element is a cycle of package paths.
func (*PackageGraph) FindShortestCycle ¶
func (pg *PackageGraph) FindShortestCycle(pkgPath string) []string
FindShortestCycle finds the shortest cycle containing a package.
Description ¶
Uses BFS to find the shortest cycle that includes the specified package. Returns nil if no cycle exists.
Inputs ¶
- pkgPath: The package to find cycles for.
Outputs ¶
- []string: The cycle path, or nil if no cycle exists.
func (*PackageGraph) GetPackage ¶
func (pg *PackageGraph) GetPackage(path string) (*PackageNode, bool)
GetPackage retrieves a package node by path.
func (*PackageGraph) Packages ¶
func (pg *PackageGraph) Packages() []string
Packages returns all package paths.
func (*PackageGraph) Stats ¶
func (pg *PackageGraph) Stats() PackageGraphStats
Stats returns statistics about the package graph.
func (*PackageGraph) TopologicalSort ¶
func (pg *PackageGraph) TopologicalSort() []string
TopologicalSort returns packages in topological order.
Description ¶
Returns packages such that if A depends on B, B comes before A. Returns nil if cycles exist (no valid topological order).
Outputs ¶
- []string: Packages in topological order, or nil if cycles exist.
type PackageGraphStats ¶
type PackageGraphStats struct {
// PackageCount is the number of packages.
PackageCount int
// EdgeCount is the number of import edges.
EdgeCount int
// MaxDeps is the maximum dependencies for any package.
MaxDeps int
// MaxDependents is the maximum dependents for any package.
MaxDependents int
// InternalCount is the number of internal packages.
InternalCount int
// StdLibCount is the number of std lib packages.
StdLibCount int
}
PackageGraphStats contains statistics about the package graph.
type PackageNode ¶
type PackageNode struct {
// Path is the package import path.
Path string
// Files lists the source files in this package.
Files []string
// Imports lists packages this package imports.
Imports []string
// ImportedBy lists packages that import this package.
ImportedBy []string
// IsInternal indicates if this is an internal package.
IsInternal bool
// IsStdLib indicates if this is a standard library package.
IsStdLib bool
}
PackageNode represents a package in the dependency graph.
type PatternCandidate ¶
type PatternCandidate struct {
// SymbolIDs are the symbols that may form the pattern.
SymbolIDs []string
// Location is where the pattern was found.
Location string
// Metadata contains pattern-specific detection data.
Metadata map[string]interface{}
}
PatternCandidate is a potential pattern match before validation.
type PatternDetector ¶
type PatternDetector struct {
// contains filtered or unexported fields
}
PatternDetector finds design patterns in code.
Description ¶
PatternDetector scans code using configurable matchers to find design patterns. It supports both structural detection (finding code that looks like a pattern) and idiomatic validation (checking if it's implemented correctly).
Thread Safety ¶
This type is safe for concurrent use.
func NewPatternDetector ¶
func NewPatternDetector(g *graph.Graph, idx *index.SymbolIndex) *PatternDetector
NewPatternDetector creates a new detector with default matchers.
Description ¶
Creates a detector that uses the provided graph and index with the standard set of pattern matchers.
Inputs ¶
- g: Code graph. Must be frozen before DetectPatterns().
- idx: Symbol index for lookups.
Outputs ¶
- *PatternDetector: Configured detector.
Example ¶
detector := NewPatternDetector(graph, index) patterns, err := detector.DetectPatterns(ctx, "pkg/service", nil)
func (*PatternDetector) DetectPattern ¶
func (d *PatternDetector) DetectPattern( ctx context.Context, scope string, patternType PatternType, ) ([]DetectedPattern, error)
DetectPattern detects a specific pattern type.
Description ¶
Shorthand for detecting a single pattern type.
Inputs ¶
- ctx: Context for cancellation.
- scope: Package or file path prefix to scan.
- patternType: The specific pattern to look for.
Outputs ¶
- []DetectedPattern: Found patterns.
- error: Non-nil on failure.
func (*PatternDetector) DetectPatterns ¶
func (d *PatternDetector) DetectPatterns( ctx context.Context, scope string, opts *DetectionOptions, ) ([]DetectedPattern, error)
DetectPatterns finds design patterns in the specified scope.
Description ¶
Scans the specified scope (package or file path prefix) for design patterns. Returns all detected patterns with confidence scores and idiomatic validation results.
Inputs ¶
- ctx: Context for cancellation.
- scope: Package or file path prefix to scan (empty = all).
- opts: Optional detection options.
Outputs ¶
- []DetectedPattern: Found patterns with confidence and warnings.
- error: Non-nil on failure.
Example ¶
// Detect all patterns in a package
patterns, err := detector.DetectPatterns(ctx, "pkg/auth", nil)
// Detect only factory patterns
patterns, err := detector.DetectPatterns(ctx, "pkg/auth", &DetectionOptions{
Patterns: []PatternType{PatternFactory},
})
func (*PatternDetector) GetMatcher ¶
func (d *PatternDetector) GetMatcher(patternType PatternType) (*PatternMatcher, bool)
GetMatcher returns a registered matcher by pattern type.
func (*PatternDetector) ListPatterns ¶
func (d *PatternDetector) ListPatterns() []PatternType
ListPatterns returns all registered pattern types.
func (*PatternDetector) RegisterMatcher ¶
func (d *PatternDetector) RegisterMatcher(matcher *PatternMatcher)
RegisterMatcher adds a custom pattern matcher.
Description ¶
Registers a custom pattern matcher. If a matcher for the pattern type already exists, it is replaced.
Inputs ¶
- matcher: The pattern matcher to register.
Example ¶
detector.RegisterMatcher(&PatternMatcher{
Name: "custom_pattern",
StructuralCheck: func(...) []PatternCandidate { ... },
})
func (*PatternDetector) Summary ¶
func (d *PatternDetector) Summary(patterns []DetectedPattern) string
Summary generates a summary of detected patterns.
type PatternMatcher ¶
type PatternMatcher struct {
// Name is the pattern name (singleton, factory, etc.).
Name PatternType
// Description explains the pattern.
Description string
// Languages supported (empty = all).
Languages []string
// StructuralCheck finds candidates based on code structure.
StructuralCheck func(ctx context.Context, g *graph.Graph, idx *index.SymbolIndex, scope string) []PatternCandidate
// IdiomaticCheck validates if a candidate is idiomatically implemented.
// Returns (isIdiomatic, warnings).
IdiomaticCheck func(candidate PatternCandidate, idx *index.SymbolIndex) (bool, []string)
}
PatternMatcher defines how to detect a specific design pattern.
Description ¶
PatternMatcher contains the logic for detecting one design pattern. It has two phases: structural detection (find candidates based on shape) and idiomatic validation (check if the implementation follows best practices).
func (*PatternMatcher) Match ¶
func (m *PatternMatcher) Match( ctx context.Context, g *graph.Graph, idx *index.SymbolIndex, scope string, ) []DetectedPattern
Match runs the pattern matcher and returns detected patterns.
type PatternType ¶
type PatternType string
PatternType identifies the design pattern.
const ( // PatternSingleton is a single instance pattern with thread-safety. PatternSingleton PatternType = "singleton" // PatternFactory creates objects without exposing instantiation logic. PatternFactory PatternType = "factory" // PatternBuilder constructs complex objects step by step. PatternBuilder PatternType = "builder" // PatternOptions uses functional options for configuration. PatternOptions PatternType = "options" // PatternMiddleware chains handlers. PatternMiddleware PatternType = "middleware" // PatternStrategy defines interchangeable algorithms. PatternStrategy PatternType = "strategy" // PatternObserver notifies observers of state changes. PatternObserver PatternType = "observer" // PatternRepository abstracts data access. PatternRepository PatternType = "repository" )
type SmellFinder ¶
type SmellFinder struct {
// contains filtered or unexported fields
}
SmellFinder finds code smells in the codebase.
Description ¶
SmellFinder detects potential code quality issues like long functions, god objects, error swallowing, and more. All detections are configurable via thresholds.
Thread Safety ¶
This type is safe for concurrent use.
func NewSmellFinder ¶
func NewSmellFinder(idx *index.SymbolIndex, projectRoot string) *SmellFinder
NewSmellFinder creates a new code smell finder.
Inputs ¶
- idx: Symbol index for lookups.
- projectRoot: Project root for reading source files.
Outputs ¶
- *SmellFinder: Configured finder.
func NewSmellFinderWithReader ¶
func NewSmellFinderWithReader(idx *index.SymbolIndex, reader *FileReader) *SmellFinder
NewSmellFinderWithReader creates a smell finder with a shared FileReader.
Inputs ¶
- idx: Symbol index for lookups.
- reader: Shared cached file reader.
Outputs ¶
- *SmellFinder: Configured finder.
func (*SmellFinder) FindCodeSmells ¶
func (s *SmellFinder) FindCodeSmells( ctx context.Context, scope string, opts *SmellOptions, ) ([]CodeSmell, error)
FindCodeSmells finds code smells in the specified scope.
Description ¶
Scans the codebase for various code smells including: - Long functions (exceeds line threshold) - Long parameter lists (exceeds param threshold) - God objects (types with too many methods) - Error swallowing (empty error handling) - Magic numbers (unexplained numeric literals) - Deep nesting (excessive indentation)
Inputs ¶
- ctx: Context for cancellation.
- scope: Package or file path prefix (empty = all).
- opts: Detection options.
Outputs ¶
- []CodeSmell: Found code smells.
- error: Non-nil on failure.
func (*SmellFinder) SetCRS ¶
func (s *SmellFinder) SetCRS(recorder CRSRecorder)
SetCRS configures CRS recording for this finder.
Inputs ¶
- recorder: CRS recorder for step tracking.
func (*SmellFinder) Summary ¶
func (s *SmellFinder) Summary(smells []CodeSmell) string
Summary generates a summary of code smell findings.
type SmellOptions ¶
type SmellOptions struct {
// Thresholds configures detection thresholds.
Thresholds SmellThresholds
// MinSeverity filters results by minimum severity.
MinSeverity Severity
// ContextLines controls how many lines of surrounding code to include
// in the Code field of each CodeSmell result (0 = no code context).
ContextLines int
// IncludeTests includes test files in analysis.
IncludeTests bool
// MaxResults limits the number of results (0 = unlimited).
MaxResults int
}
SmellOptions configures code smell detection.
func DefaultSmellOptions ¶
func DefaultSmellOptions() SmellOptions
DefaultSmellOptions returns sensible defaults.
type SmellThresholds ¶
type SmellThresholds struct {
// MaxFunctionLines triggers long_function smell.
MaxFunctionLines int
// MaxParameters triggers long_parameter_list smell.
MaxParameters int
// MaxMethodCount triggers god_object smell.
MaxMethodCount int
// MaxNestingDepth triggers deep_nesting smell.
MaxNestingDepth int
}
SmellThresholds configures code smell detection.
func DefaultSmellThresholds ¶
func DefaultSmellThresholds() SmellThresholds
DefaultSmellThresholds returns standard thresholds.
type SmellType ¶
type SmellType string
SmellType identifies the code smell category.
const ( // SmellLongFunction is a function with too many lines. SmellLongFunction SmellType = "long_function" // SmellLongParameterList is a function with too many parameters. SmellLongParameterList SmellType = "long_parameter_list" // SmellGodObject is a type with too many methods. SmellGodObject SmellType = "god_object" // SmellFeatureEnvy is excessive cross-package dependencies. SmellFeatureEnvy SmellType = "feature_envy" // SmellEmptyInterface is overuse of interface{}. SmellEmptyInterface SmellType = "empty_interface" // SmellErrorSwallowing is ignoring errors. SmellErrorSwallowing SmellType = "error_swallowing" // SmellMagicNumber is unexplained numeric literals. SmellMagicNumber SmellType = "magic_number" // SmellDeepNesting is excessive nesting depth. SmellDeepNesting SmellType = "deep_nesting" )