analyzer

package
v0.6.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 18, 2026 License: MIT Imports: 19 Imported by: 0

Documentation

Index

Constants

View Source
const (
	LabelFunctionBody = "func_body"
	LabelClassBody    = "class_body"
	LabelUnreachable  = "unreachable"
	LabelMainModule   = "main"
	LabelEntry        = "ENTRY"
	LabelExit         = "EXIT"

	// Loop-related labels
	LabelLoopHeader = "loop_header"
	LabelLoopBody   = "loop_body"
	LabelLoopExit   = "loop_exit"

	// Exception-related labels
	LabelTryBlock     = "try_block"
	LabelCatchBlock   = "catch_block"
	LabelFinallyBlock = "finally_block"

	// Switch-related labels
	LabelSwitchCase  = "switch_case"
	LabelSwitchMerge = "switch_merge"
)

Block label constants

Variables

This section is empty.

Functions

func CalculateNestingDepth

func CalculateNestingDepth(node *parser.Node) int

CalculateNestingDepth calculates the maximum nesting depth of a function

func ComputeKeyRoots

func ComputeKeyRoots(root *TreeNode) []int

ComputeKeyRoots identifies key roots for path decomposition

func ComputeLeftMostLeaves

func ComputeLeftMostLeaves(root *TreeNode)

ComputeLeftMostLeaves computes left-most leaf descendants for all nodes

func DetectAll

func DetectAll(cfgs map[string]*CFG, filePath string) map[string]*DeadCodeResult

DetectAll analyzes dead code for all functions in a file

func PostOrderTraversal

func PostOrderTraversal(root *TreeNode)

PostOrderTraversal performs post-order traversal and assigns post-order IDs

func PrepareTreeForAPTED

func PrepareTreeForAPTED(root *TreeNode) []int

PrepareTreeForAPTED prepares a tree for APTED algorithm by computing all necessary indices

Types

type APTEDAnalyzer

type APTEDAnalyzer struct {
	// contains filtered or unexported fields
}

APTEDAnalyzer implements the APTED (All Path Tree Edit Distance) algorithm Based on Pawlik & Augsten's optimal O(n² log n) algorithm

func NewAPTEDAnalyzer

func NewAPTEDAnalyzer(costModel CostModel) *APTEDAnalyzer

NewAPTEDAnalyzer creates a new APTED analyzer with the given cost model

func (*APTEDAnalyzer) BatchComputeDistances

func (a *APTEDAnalyzer) BatchComputeDistances(pairs [][2]*TreeNode) []float64

BatchComputeDistances computes distances between multiple tree pairs efficiently

func (*APTEDAnalyzer) ClusterSimilarTrees

func (a *APTEDAnalyzer) ClusterSimilarTrees(trees []*TreeNode, similarityThreshold float64) *ClusterResult

ClusterSimilarTrees clusters trees based on similarity threshold

func (*APTEDAnalyzer) ComputeDetailedDistance

func (a *APTEDAnalyzer) ComputeDetailedDistance(tree1, tree2 *TreeNode) *TreeEditResult

ComputeDetailedDistance computes detailed tree edit distance information

func (*APTEDAnalyzer) ComputeDistance

func (a *APTEDAnalyzer) ComputeDistance(tree1, tree2 *TreeNode) float64

ComputeDistance computes the tree edit distance between two trees

func (*APTEDAnalyzer) ComputeSimilarity

func (a *APTEDAnalyzer) ComputeSimilarity(tree1, tree2 *TreeNode) float64

ComputeSimilarity computes similarity score between two trees (0.0 to 1.0)

type ASTFeatureExtractor

type ASTFeatureExtractor struct {
	// contains filtered or unexported fields
}

ASTFeatureExtractor implements FeatureExtractor for TreeNode

func NewASTFeatureExtractor

func NewASTFeatureExtractor() *ASTFeatureExtractor

NewASTFeatureExtractor creates a feature extractor with sensible defaults

func (*ASTFeatureExtractor) ExtractFeatures

func (a *ASTFeatureExtractor) ExtractFeatures(ast *TreeNode) ([]string, error)

ExtractFeatures builds a mixed set of features from the tree - Subtree hashes (bottom-up) up to maxSubtreeHeight - k-grams from pre-order traversal labels - Node type presence and lightweight distribution markers - Structural pattern tokens

func (*ASTFeatureExtractor) ExtractNodeSequences

func (a *ASTFeatureExtractor) ExtractNodeSequences(ast *TreeNode, k int) []string

ExtractNodeSequences returns k-grams from pre-order traversal labels

func (*ASTFeatureExtractor) ExtractSubtreeHashes

func (a *ASTFeatureExtractor) ExtractSubtreeHashes(ast *TreeNode, maxHeight int) []string

ExtractSubtreeHashes computes bottom-up hashes of subtrees up to maxHeight

func (*ASTFeatureExtractor) WithOptions

func (a *ASTFeatureExtractor) WithOptions(maxHeight, k int, includeTypes, includeLiterals bool) *ASTFeatureExtractor

WithOptions allows overriding defaults

type BasicBlock

type BasicBlock struct {
	// ID is the unique identifier for this block
	ID string

	// Statements contains the AST nodes in this block
	Statements []*parser.Node

	// Predecessors are blocks that can flow into this block
	Predecessors []*Edge

	// Successors are blocks that this block can flow to
	Successors []*Edge

	// Label is an optional human-readable label
	Label string

	// IsEntry indicates if this is an entry block
	IsEntry bool

	// IsExit indicates if this is an exit block
	IsExit bool
}

BasicBlock represents a basic block in the control flow graph

func NewBasicBlock

func NewBasicBlock(id string) *BasicBlock

NewBasicBlock creates a new basic block with the given ID

func (*BasicBlock) AddStatement

func (bb *BasicBlock) AddStatement(stmt *parser.Node)

AddStatement adds an AST node to this block

func (*BasicBlock) AddSuccessor

func (bb *BasicBlock) AddSuccessor(to *BasicBlock, edgeType EdgeType) *Edge

AddSuccessor adds an outgoing edge to another block

func (*BasicBlock) IsEmpty

func (bb *BasicBlock) IsEmpty() bool

IsEmpty returns true if the block has no statements

func (*BasicBlock) RemoveSuccessor

func (bb *BasicBlock) RemoveSuccessor(to *BasicBlock)

RemoveSuccessor removes an edge to the specified block

func (*BasicBlock) String

func (bb *BasicBlock) String() string

String returns a string representation of the basic block

type CBOAnalyzer

type CBOAnalyzer struct {
	// contains filtered or unexported fields
}

CBOAnalyzer analyzes Coupling Between Objects for JavaScript/TypeScript modules

func NewCBOAnalyzer

func NewCBOAnalyzer(config *CBOAnalyzerConfig) *CBOAnalyzer

NewCBOAnalyzer creates a new CBO analyzer with the given configuration

func (*CBOAnalyzer) AnalyzeFile

func (ca *CBOAnalyzer) AnalyzeFile(ast *parser.Node, filePath string) (*domain.ClassCoupling, error)

AnalyzeFile analyzes a single file and returns its CBO metrics

type CBOAnalyzerConfig

type CBOAnalyzerConfig struct {
	// IncludeBuiltins includes Node.js builtin modules in coupling count
	IncludeBuiltins bool

	// IncludeTypeImports includes TypeScript type imports in coupling count
	IncludeTypeImports bool

	// LowThreshold is the CBO threshold for low risk (CBO <= LowThreshold)
	LowThreshold int

	// MediumThreshold is the CBO threshold for medium risk (LowThreshold < CBO <= MediumThreshold)
	MediumThreshold int
}

CBOAnalyzerConfig holds configuration for the CBO analyzer

func DefaultCBOAnalyzerConfig

func DefaultCBOAnalyzerConfig() *CBOAnalyzerConfig

DefaultCBOAnalyzerConfig returns the default configuration

type CFG

type CFG struct {
	// Entry is the entry point of the graph
	Entry *BasicBlock

	// Exit is the exit point of the graph
	Exit *BasicBlock

	// Blocks contains all blocks in the graph, indexed by ID
	Blocks map[string]*BasicBlock

	// Name is the name of the CFG (e.g., function name)
	Name string

	// FunctionNode is the original AST node for the function
	FunctionNode *parser.Node
	// contains filtered or unexported fields
}

CFG represents a control flow graph

func NewCFG

func NewCFG(name string) *CFG

NewCFG creates a new control flow graph

func (*CFG) AddBlock

func (cfg *CFG) AddBlock(block *BasicBlock)

AddBlock adds an existing block to the graph

func (*CFG) BreadthFirstWalk

func (cfg *CFG) BreadthFirstWalk(visitor CFGVisitor)

BreadthFirstWalk performs a breadth-first traversal of the CFG

func (*CFG) ConnectBlocks

func (cfg *CFG) ConnectBlocks(from, to *BasicBlock, edgeType EdgeType) *Edge

ConnectBlocks creates an edge between two blocks

func (*CFG) CreateBlock

func (cfg *CFG) CreateBlock(label string) *BasicBlock

CreateBlock creates a new basic block and adds it to the graph

func (*CFG) GetBlock

func (cfg *CFG) GetBlock(id string) *BasicBlock

GetBlock retrieves a block by its ID

func (*CFG) RemoveBlock

func (cfg *CFG) RemoveBlock(block *BasicBlock)

RemoveBlock removes a block from the graph

func (*CFG) Size

func (cfg *CFG) Size() int

Size returns the number of blocks in the graph

func (*CFG) String

func (cfg *CFG) String() string

String returns a string representation of the CFG

func (*CFG) Walk

func (cfg *CFG) Walk(visitor CFGVisitor)

Walk performs a depth-first traversal of the CFG

type CFGBuilder

type CFGBuilder struct {
	// contains filtered or unexported fields
}

CFGBuilder builds control flow graphs from AST nodes

func NewCFGBuilder

func NewCFGBuilder() *CFGBuilder

NewCFGBuilder creates a new CFG builder

func (*CFGBuilder) Build

func (b *CFGBuilder) Build(node *parser.Node) (*CFG, error)

Build constructs a CFG from an AST node

func (*CFGBuilder) BuildAll

func (b *CFGBuilder) BuildAll(node *parser.Node) (map[string]*CFG, error)

BuildAll builds CFGs for all functions in the AST

func (*CFGBuilder) SetLogger

func (b *CFGBuilder) SetLogger(logger *log.Logger)

SetLogger sets an optional logger for error reporting

type CFGVisitor

type CFGVisitor interface {
	// VisitBlock is called for each basic block
	// Returns false to stop traversal
	VisitBlock(block *BasicBlock) bool

	// VisitEdge is called for each edge
	// Returns false to stop traversal
	VisitEdge(edge *Edge) bool
}

CFGVisitor defines the interface for visiting CFG nodes

type CentroidGrouping

type CentroidGrouping struct {
	// contains filtered or unexported fields
}

CentroidGrouping uses BFS expansion with strict similarity to all existing members

func NewCentroidGrouping

func NewCentroidGrouping(threshold float64) *CentroidGrouping

func (*CentroidGrouping) GetName

func (cg *CentroidGrouping) GetName() string

func (*CentroidGrouping) GroupClones

func (cg *CentroidGrouping) GroupClones(pairs []*domain.ClonePair) []*domain.CloneGroup

type CircularDependencyDetector

type CircularDependencyDetector struct {
	// contains filtered or unexported fields
}

CircularDependencyDetector detects circular dependencies using Tarjan's algorithm

func NewCircularDependencyDetector

func NewCircularDependencyDetector() *CircularDependencyDetector

NewCircularDependencyDetector creates a new CircularDependencyDetector

func (*CircularDependencyDetector) DetectCycles

DetectCycles finds all cycles in the dependency graph using Tarjan's SCC algorithm

func (*CircularDependencyDetector) FindCyclePath

func (d *CircularDependencyDetector) FindCyclePath(from, to string, graph *domain.DependencyGraph) []string

FindCyclePath finds a path from one module to another within a cycle

type ClassDependencies

type ClassDependencies struct {
	// Unique modules/classes this class depends on
	DependentClasses map[string]bool

	// Breakdown by type
	ImportDependencies          map[string]bool
	InstantiationDependencies   map[string]bool
	TypeHintDependencies        map[string]bool
	AttributeAccessDependencies map[string]bool
}

ClassDependencies holds all dependencies for a class/module

func NewClassDependencies

func NewClassDependencies() *ClassDependencies

NewClassDependencies creates a new ClassDependencies instance

type CloneDetector

type CloneDetector struct {
	// contains filtered or unexported fields
}

CloneDetector detects code clones using APTED algorithm

func NewCloneDetector

func NewCloneDetector(config *CloneDetectorConfig) *CloneDetector

NewCloneDetector creates a new clone detector with the given configuration

func (*CloneDetector) DetectClones

func (cd *CloneDetector) DetectClones(fragments []*CodeFragment) ([]*domain.ClonePair, []*domain.CloneGroup)

DetectClones detects clones in the given code fragments

func (*CloneDetector) DetectClonesWithContext

func (cd *CloneDetector) DetectClonesWithContext(ctx context.Context, fragments []*CodeFragment) ([]*domain.ClonePair, []*domain.CloneGroup)

DetectClonesWithContext detects clones with context support for cancellation

func (*CloneDetector) DetectClonesWithLSH

func (cd *CloneDetector) DetectClonesWithLSH(ctx context.Context, fragments []*CodeFragment) ([]*domain.ClonePair, []*domain.CloneGroup)

DetectClonesWithLSH runs a two-stage pipeline using LSH for candidate generation, followed by APTED verification on candidates only. Falls back to exhaustive if misconfigured.

func (*CloneDetector) ExtractFragments

func (cd *CloneDetector) ExtractFragments(astNodes []*parser.Node, filePath string) []*CodeFragment

ExtractFragments extracts code fragments from AST nodes

func (*CloneDetector) GetStatistics

func (cd *CloneDetector) GetStatistics() map[string]interface{}

GetStatistics returns clone detection statistics

func (*CloneDetector) SetBatchSizeLarge

func (cd *CloneDetector) SetBatchSizeLarge(size int)

SetBatchSizeLarge sets the batch size for normal projects (used in testing)

func (*CloneDetector) SetUseLSH

func (cd *CloneDetector) SetUseLSH(enabled bool)

SetUseLSH enables or disables LSH acceleration for clone detection

type CloneDetectorConfig

type CloneDetectorConfig struct {
	// Minimum number of lines for a code fragment to be considered
	MinLines int

	// Minimum number of AST nodes for a code fragment
	MinNodes int

	// Similarity thresholds for different clone types
	Type1Threshold float64
	Type2Threshold float64
	Type3Threshold float64
	Type4Threshold float64

	// Maximum edit distance allowed
	MaxEditDistance float64

	// Whether to ignore differences in literals
	IgnoreLiterals bool

	// Whether to ignore differences in identifiers
	IgnoreIdentifiers bool

	// Cost model to use for APTED
	CostModelType string // "default", "javascript", "weighted"

	// Performance tuning parameters
	MaxClonePairs      int // Maximum pairs to keep in memory
	BatchSizeThreshold int // Minimum fragments to trigger batching
	BatchSizeLarge     int // Batch size for normal projects
	BatchSizeSmall     int // Batch size for large projects
	LargeProjectSize   int // Fragment count threshold for large projects

	// Grouping configuration
	GroupingMode      GroupingMode // Default: GroupingModeConnected
	GroupingThreshold float64      // Default: Type3Threshold
	KCoreK            int          // Default: 2

	// LSH Configuration (optional, opt-in)
	UseLSH                 bool    // Enable LSH acceleration
	LSHSimilarityThreshold float64 // Candidate threshold using MinHash similarity
	LSHBands               int     // Number of LSH bands (default: 32)
	LSHRows                int     // Rows per band (default: 4)
	LSHMinHashCount        int     // Number of MinHash functions (default: 128)
}

CloneDetectorConfig holds configuration for clone detection

func DefaultCloneDetectorConfig

func DefaultCloneDetectorConfig() *CloneDetectorConfig

DefaultCloneDetectorConfig returns default configuration

type ClusterResult

type ClusterResult struct {
	Groups    [][]int     // Groups of tree indices that are similar
	Distances [][]float64 // Distance matrix between all trees
	Threshold float64     // Similarity threshold used
}

ClusterResult represents the result of tree clustering

type CodeFragment

type CodeFragment struct {
	Location   *CodeLocation
	ASTNode    *parser.Node
	TreeNode   *TreeNode
	Content    string // Original source code content
	Hash       string // Hash for quick comparison
	Size       int    // Number of AST nodes
	LineCount  int    // Number of source lines
	Complexity int    // Cyclomatic complexity (if applicable)
}

CodeFragment represents a fragment of code

func NewCodeFragment

func NewCodeFragment(location *CodeLocation, astNode *parser.Node, content string) *CodeFragment

NewCodeFragment creates a new code fragment

type CodeLocation

type CodeLocation struct {
	FilePath  string
	StartLine int
	EndLine   int
	StartCol  int
	EndCol    int
}

CodeLocation represents a location in source code

func (*CodeLocation) String

func (cl *CodeLocation) String() string

String returns string representation of CodeLocation

type CompleteLinkageGrouping

type CompleteLinkageGrouping struct {
	// contains filtered or unexported fields
}

CompleteLinkageGrouping ensures all pairs within a group have similarity above threshold

func NewCompleteLinkageGrouping

func NewCompleteLinkageGrouping(threshold float64) *CompleteLinkageGrouping

func (*CompleteLinkageGrouping) GetName

func (c *CompleteLinkageGrouping) GetName() string

func (*CompleteLinkageGrouping) GroupClones

func (c *CompleteLinkageGrouping) GroupClones(pairs []*domain.ClonePair) []*domain.CloneGroup

type ComplexityAnalyzer

type ComplexityAnalyzer struct {
	// contains filtered or unexported fields
}

ComplexityAnalyzer analyzes complexity for multiple functions

func NewComplexityAnalyzer

func NewComplexityAnalyzer(cfg *config.ComplexityConfig) *ComplexityAnalyzer

NewComplexityAnalyzer creates a new complexity analyzer

func (*ComplexityAnalyzer) AnalyzeFile

func (ca *ComplexityAnalyzer) AnalyzeFile(ast *parser.Node) ([]*ComplexityResult, error)

AnalyzeFile analyzes complexity for all functions in a file

type ComplexityResult

type ComplexityResult struct {
	// McCabe cyclomatic complexity
	Complexity int

	// Raw CFG metrics
	Edges               int
	Nodes               int
	ConnectedComponents int

	// Function/method information
	FunctionName string
	StartLine    int
	StartCol     int
	EndLine      int

	// Nesting depth
	NestingDepth int

	// Decision points breakdown
	IfStatements      int
	LoopStatements    int
	ExceptionHandlers int
	SwitchCases       int
	LogicalOperators  int // JavaScript-specific: &&, ||, ??
	TernaryOperators  int // JavaScript-specific: ? :

	// Risk assessment based on complexity thresholds
	RiskLevel string // "low", "medium", "high"
}

ComplexityResult holds cyclomatic complexity metrics for a function or method

func CalculateComplexity

func CalculateComplexity(cfg *CFG) *ComplexityResult

CalculateComplexity computes McCabe cyclomatic complexity for a CFG using default thresholds

func CalculateComplexityWithConfig

func CalculateComplexityWithConfig(cfg *CFG, complexityConfig *config.ComplexityConfig) *ComplexityResult

CalculateComplexityWithConfig computes McCabe cyclomatic complexity using provided configuration

func (*ComplexityResult) GetComplexity

func (cr *ComplexityResult) GetComplexity() int

func (*ComplexityResult) GetDetailedMetrics

func (cr *ComplexityResult) GetDetailedMetrics() map[string]int

func (*ComplexityResult) GetFunctionName

func (cr *ComplexityResult) GetFunctionName() string

func (*ComplexityResult) GetRiskLevel

func (cr *ComplexityResult) GetRiskLevel() string

func (*ComplexityResult) String

func (cr *ComplexityResult) String() string

String returns a human-readable representation of the complexity result

type ConnectedGrouping

type ConnectedGrouping struct {
	// contains filtered or unexported fields
}

ConnectedGrouping wraps transitive grouping logic using Union-Find

func NewConnectedGrouping

func NewConnectedGrouping(threshold float64) *ConnectedGrouping

func (*ConnectedGrouping) GetName

func (c *ConnectedGrouping) GetName() string

func (*ConnectedGrouping) GroupClones

func (c *ConnectedGrouping) GroupClones(pairs []*domain.ClonePair) []*domain.CloneGroup

type CostModel

type CostModel interface {
	// Insert returns the cost of inserting a node
	Insert(node *TreeNode) float64

	// Delete returns the cost of deleting a node
	Delete(node *TreeNode) float64

	// Rename returns the cost of renaming node1 to node2
	Rename(node1, node2 *TreeNode) float64
}

CostModel defines the interface for calculating edit operation costs

type CouplingMetricsCalculator

type CouplingMetricsCalculator struct {
	// contains filtered or unexported fields
}

CouplingMetricsCalculator calculates coupling metrics for modules

func NewCouplingMetricsCalculator

func NewCouplingMetricsCalculator(config *CouplingMetricsConfig) *CouplingMetricsCalculator

NewCouplingMetricsCalculator creates a new CouplingMetricsCalculator

func (*CouplingMetricsCalculator) CalculateCouplingAnalysis

CalculateCouplingAnalysis generates a comprehensive coupling analysis

func (*CouplingMetricsCalculator) CalculateMaxDepth

func (c *CouplingMetricsCalculator) CalculateMaxDepth(graph *domain.DependencyGraph) int

CalculateMaxDepth calculates the maximum dependency depth in the graph

func (*CouplingMetricsCalculator) CalculateMetrics

CalculateMetrics computes coupling metrics for all modules in the graph

func (*CouplingMetricsCalculator) CalculateTransitiveDependencies

func (c *CouplingMetricsCalculator) CalculateTransitiveDependencies(nodeID string, graph *domain.DependencyGraph) []string

CalculateTransitiveDependencies calculates all transitive dependencies for a module

type CouplingMetricsConfig

type CouplingMetricsConfig struct {
	// InstabilityHighThreshold defines the threshold for high instability (default: 0.8)
	InstabilityHighThreshold float64

	// InstabilityLowThreshold defines the threshold for low instability (default: 0.2)
	InstabilityLowThreshold float64

	// DistanceThreshold defines the threshold for main sequence deviation (default: 0.3)
	DistanceThreshold float64

	// CouplingHighThreshold defines the threshold for high coupling risk (default: 10)
	CouplingHighThreshold int

	// CouplingMediumThreshold defines the threshold for medium coupling risk (default: 5)
	CouplingMediumThreshold int
}

CouplingMetricsConfig configures the CouplingMetricsCalculator

func DefaultCouplingMetricsConfig

func DefaultCouplingMetricsConfig() *CouplingMetricsConfig

DefaultCouplingMetricsConfig returns a config with sensible defaults

type DeadCodeDetector

type DeadCodeDetector struct {
	// contains filtered or unexported fields
}

DeadCodeDetector provides high-level dead code detection functionality

func NewDeadCodeDetector

func NewDeadCodeDetector(cfg *CFG) *DeadCodeDetector

NewDeadCodeDetector creates a new dead code detector for the given CFG

func NewDeadCodeDetectorWithFilePath

func NewDeadCodeDetectorWithFilePath(cfg *CFG, filePath string) *DeadCodeDetector

NewDeadCodeDetectorWithFilePath creates a new dead code detector with file path context

func (*DeadCodeDetector) Detect

func (dcd *DeadCodeDetector) Detect() *DeadCodeResult

Detect performs dead code detection and returns structured findings

type DeadCodeFinding

type DeadCodeFinding struct {
	// Function information
	FunctionName string `json:"function_name"`
	FilePath     string `json:"file_path"`

	// Location information
	StartLine int `json:"start_line"`
	EndLine   int `json:"end_line"`

	// Dead code details
	BlockID     string         `json:"block_id"`
	Code        string         `json:"code"`
	Reason      DeadCodeReason `json:"reason"`
	Severity    SeverityLevel  `json:"severity"`
	Description string         `json:"description"`

	// Context information
	Context []string `json:"context,omitempty"`
}

DeadCodeFinding represents a single dead code detection result

func DetectOrphanFiles added in v0.2.0

func DetectOrphanFiles(allModuleInfos map[string]*domain.ModuleInfo, analyzedFiles map[string]bool) []*DeadCodeFinding

DetectOrphanFiles detects files that are not reachable from any entry point via import chains. Entry points are: index/main/app/server files, and files not imported by any other file. Test files and config files are skipped.

func DetectUnusedExportedFunctions added in v0.2.0

func DetectUnusedExportedFunctions(allModuleInfos map[string]*domain.ModuleInfo, analyzedFiles map[string]bool) []*DeadCodeFinding

DetectUnusedExportedFunctions detects exported functions and classes that are not imported by any other file in the project. Unlike DetectUnusedExports which covers all exports at info severity, this targets only function/class declarations at warning severity.

func DetectUnusedExports added in v0.2.0

func DetectUnusedExports(allModuleInfos map[string]*domain.ModuleInfo, analyzedFiles map[string]bool) []*DeadCodeFinding

DetectUnusedExports detects exported names that are not imported by any other analyzed file. It builds a reverse index of all imports across files and checks each export against it.

func DetectUnusedImports added in v0.2.0

func DetectUnusedImports(ast *parser.Node, moduleInfo *domain.ModuleInfo, filePath string) []*DeadCodeFinding

DetectUnusedImports detects imported names that are never referenced in the file. It walks the AST to collect all identifier references (excluding import/export declarations) and compares them against the locally-bound import names.

type DeadCodeReason

type DeadCodeReason string

DeadCodeReason represents the reason why code is considered dead

const (
	// ReasonUnreachableAfterReturn indicates code after a return statement
	ReasonUnreachableAfterReturn DeadCodeReason = "unreachable_after_return"

	// ReasonUnreachableAfterBreak indicates code after a break statement
	ReasonUnreachableAfterBreak DeadCodeReason = "unreachable_after_break"

	// ReasonUnreachableAfterContinue indicates code after a continue statement
	ReasonUnreachableAfterContinue DeadCodeReason = "unreachable_after_continue"

	// ReasonUnreachableAfterThrow indicates code after a throw statement
	ReasonUnreachableAfterThrow DeadCodeReason = "unreachable_after_throw"

	// ReasonUnreachableBranch indicates an unreachable branch condition
	ReasonUnreachableBranch DeadCodeReason = "unreachable_branch"

	// ReasonUnreachableAfterInfiniteLoop indicates code after an infinite loop
	ReasonUnreachableAfterInfiniteLoop DeadCodeReason = "unreachable_after_infinite_loop"

	// ReasonUnusedImport indicates an imported name that is never referenced
	ReasonUnusedImport DeadCodeReason = "unused_import"

	// ReasonUnusedExport indicates an exported name that is never imported by other files
	ReasonUnusedExport DeadCodeReason = "unused_export"

	// ReasonOrphanFile indicates a file that is not reachable from any entry point via imports
	ReasonOrphanFile DeadCodeReason = "orphan_file"

	// ReasonUnusedExportedFunction indicates an exported function/class that is not imported by any other file
	ReasonUnusedExportedFunction DeadCodeReason = "unused_exported_function"
)

type DeadCodeResult

type DeadCodeResult struct {
	// Function information
	FunctionName string `json:"function_name"`
	FilePath     string `json:"file_path"`

	// Analysis results
	Findings       []*DeadCodeFinding `json:"findings"`
	TotalBlocks    int                `json:"total_blocks"`
	DeadBlocks     int                `json:"dead_blocks"`
	ReachableRatio float64            `json:"reachable_ratio"`

	// Performance metrics
	AnalysisTime time.Duration `json:"analysis_time"`
}

DeadCodeResult contains the results of dead code analysis for a single CFG

func (*DeadCodeResult) GetCriticalFindings

func (dcr *DeadCodeResult) GetCriticalFindings() []*DeadCodeFinding

GetCriticalFindings returns only critical severity findings

func (*DeadCodeResult) GetWarningFindings

func (dcr *DeadCodeResult) GetWarningFindings() []*DeadCodeFinding

GetWarningFindings returns only warning severity findings

func (*DeadCodeResult) HasFindings

func (dcr *DeadCodeResult) HasFindings() bool

HasFindings returns true if there are any dead code findings

type DefaultCostModel

type DefaultCostModel struct{}

DefaultCostModel implements a uniform cost model where all operations cost 1.0

func NewDefaultCostModel

func NewDefaultCostModel() *DefaultCostModel

NewDefaultCostModel creates a new default cost model

func (*DefaultCostModel) Delete

func (c *DefaultCostModel) Delete(node *TreeNode) float64

Delete returns the cost of deleting a node (always 1.0)

func (*DefaultCostModel) Insert

func (c *DefaultCostModel) Insert(node *TreeNode) float64

Insert returns the cost of inserting a node (always 1.0)

func (*DefaultCostModel) Rename

func (c *DefaultCostModel) Rename(node1, node2 *TreeNode) float64

Rename returns the cost of renaming node1 to node2

type DependencyGraphBuilder

type DependencyGraphBuilder struct {
	// contains filtered or unexported fields
}

DependencyGraphBuilder builds a dependency graph from module analysis results

func NewDependencyGraphBuilder

func NewDependencyGraphBuilder(config *DependencyGraphBuilderConfig) *DependencyGraphBuilder

NewDependencyGraphBuilder creates a new DependencyGraphBuilder

func (*DependencyGraphBuilder) BuildGraph

BuildGraph constructs a DependencyGraph from ModuleAnalysisResult

func (*DependencyGraphBuilder) BuildGraphFromASTs

func (b *DependencyGraphBuilder) BuildGraphFromASTs(asts map[string]*parser.Node) (*domain.DependencyGraph, error)

BuildGraphFromASTs constructs a DependencyGraph directly from parsed ASTs

type DependencyGraphBuilderConfig

type DependencyGraphBuilderConfig struct {
	// IncludeExternal includes external modules (node_modules) in the graph
	IncludeExternal bool

	// IncludeTypeImports includes TypeScript type-only imports
	IncludeTypeImports bool

	// ProjectRoot is the root directory for path normalization
	ProjectRoot string
}

DependencyGraphBuilderConfig configures the DependencyGraphBuilder

func DefaultDependencyGraphBuilderConfig

func DefaultDependencyGraphBuilderConfig() *DependencyGraphBuilderConfig

DefaultDependencyGraphBuilderConfig returns a config with sensible defaults

type Edge

type Edge struct {
	From *BasicBlock
	To   *BasicBlock
	Type EdgeType
}

Edge represents a directed edge between two basic blocks

type EdgeType

type EdgeType int

EdgeType represents the type of edge between basic blocks

const (
	// EdgeNormal represents normal sequential flow
	EdgeNormal EdgeType = iota
	// EdgeCondTrue represents conditional true branch
	EdgeCondTrue
	// EdgeCondFalse represents conditional false branch
	EdgeCondFalse
	// EdgeException represents exception flow
	EdgeException
	// EdgeLoop represents loop back edge
	EdgeLoop
	// EdgeBreak represents break statement flow
	EdgeBreak
	// EdgeContinue represents continue statement flow
	EdgeContinue
	// EdgeReturn represents return statement flow
	EdgeReturn
)

func (EdgeType) String

func (e EdgeType) String() string

String returns string representation of EdgeType

type FeatureExtractor

type FeatureExtractor interface {
	ExtractFeatures(ast *TreeNode) ([]string, error)
	ExtractSubtreeHashes(ast *TreeNode, maxHeight int) []string
	ExtractNodeSequences(ast *TreeNode, k int) []string
}

FeatureExtractor converts AST trees into feature sets for Jaccard similarity

type GroupingConfig

type GroupingConfig struct {
	Mode           GroupingMode
	Threshold      float64
	KCoreK         int
	Type1Threshold float64
	Type2Threshold float64
	Type3Threshold float64
	Type4Threshold float64
}

GroupingConfig holds configuration for clone grouping

type GroupingMode

type GroupingMode string

GroupingMode represents the mode of grouping strategy

const (
	GroupingModeConnected       GroupingMode = "connected"
	GroupingModeKCore           GroupingMode = "k_core"
	GroupingModeStarMedoid      GroupingMode = "star_medoid"
	GroupingModeCompleteLinkage GroupingMode = "complete_linkage"
	GroupingModeCentroid        GroupingMode = "centroid"
)

type GroupingStrategy

type GroupingStrategy interface {
	// GroupClones groups the given clone pairs into clone groups.
	GroupClones(pairs []*domain.ClonePair) []*domain.CloneGroup
	// GetName returns the strategy name.
	GetName() string
}

GroupingStrategy defines a strategy for grouping clone pairs into clone groups.

func CreateGroupingStrategy

func CreateGroupingStrategy(config GroupingConfig) GroupingStrategy

CreateGroupingStrategy creates a grouping strategy based on config

type HashFunc

type HashFunc func(uint64) uint64

HashFunc maps a 64-bit base hash to another 64-bit value

type JavaScriptCostModel

type JavaScriptCostModel struct {
	// Base costs for different operations
	BaseInsertCost float64
	BaseDeleteCost float64
	BaseRenameCost float64

	// Whether to ignore differences in literal values
	IgnoreLiterals bool

	// Whether to ignore differences in identifier names
	IgnoreIdentifiers bool
}

JavaScriptCostModel implements a JavaScript-aware cost model with different costs for different node types

func NewJavaScriptCostModel

func NewJavaScriptCostModel() *JavaScriptCostModel

NewJavaScriptCostModel creates a new JavaScript-aware cost model with default settings

func NewJavaScriptCostModelWithConfig

func NewJavaScriptCostModelWithConfig(ignoreLiterals, ignoreIdentifiers bool) *JavaScriptCostModel

NewJavaScriptCostModelWithConfig creates a JavaScript cost model with custom configuration

func (*JavaScriptCostModel) Delete

func (c *JavaScriptCostModel) Delete(node *TreeNode) float64

Delete returns the cost of deleting a node

func (*JavaScriptCostModel) Insert

func (c *JavaScriptCostModel) Insert(node *TreeNode) float64

Insert returns the cost of inserting a node

func (*JavaScriptCostModel) Rename

func (c *JavaScriptCostModel) Rename(node1, node2 *TreeNode) float64

Rename returns the cost of renaming node1 to node2

type KCoreGrouping

type KCoreGrouping struct {
	// contains filtered or unexported fields
}

KCoreGrouping ensures each clone has at least k similar neighbors

func NewKCoreGrouping

func NewKCoreGrouping(threshold float64, k int) *KCoreGrouping

func (*KCoreGrouping) GetName

func (kg *KCoreGrouping) GetName() string

func (*KCoreGrouping) GroupClones

func (kg *KCoreGrouping) GroupClones(pairs []*domain.ClonePair) []*domain.CloneGroup

type LSHIndex

type LSHIndex struct {
	// contains filtered or unexported fields
}

LSHIndex implements MinHash LSH with banding

func NewLSHIndex

func NewLSHIndex(bands, rows int) *LSHIndex

NewLSHIndex creates an index with banding parameters

func (*LSHIndex) AddFragment

func (idx *LSHIndex) AddFragment(id string, signature *MinHashSignature) error

AddFragment inserts a fragment signature into the index

func (*LSHIndex) Bands

func (idx *LSHIndex) Bands() int

Bands returns the number of bands

func (*LSHIndex) BuildIndex

func (idx *LSHIndex) BuildIndex() error

BuildIndex is a no-op for incremental building (kept for API symmetry)

func (*LSHIndex) FindCandidates

func (idx *LSHIndex) FindCandidates(signature *MinHashSignature) []string

FindCandidates retrieves candidate fragment IDs that share at least one band bucket

func (*LSHIndex) GetSignature

func (idx *LSHIndex) GetSignature(id string) *MinHashSignature

GetSignature returns the stored signature for a fragment ID

func (*LSHIndex) Rows

func (idx *LSHIndex) Rows() int

Rows returns the number of rows per band

func (*LSHIndex) Size

func (idx *LSHIndex) Size() int

Size returns the number of fragments in the index

type MinHashSignature

type MinHashSignature struct {
	// contains filtered or unexported fields
}

MinHashSignature holds the signature vector

func (*MinHashSignature) NumHashes

func (s *MinHashSignature) NumHashes() int

NumHashes returns the number of hash functions used

func (*MinHashSignature) Signatures

func (s *MinHashSignature) Signatures() []uint64

Signatures returns the signature slice

type MinHasher

type MinHasher struct {
	// contains filtered or unexported fields
}

MinHasher computes MinHash signatures for feature sets

func NewMinHasher

func NewMinHasher(numHashes int) *MinHasher

NewMinHasher creates a MinHasher with numHashes functions (default 128 if invalid)

func (*MinHasher) ComputeSignature

func (m *MinHasher) ComputeSignature(features []string) *MinHashSignature

ComputeSignature computes the MinHash signature for a set of features

func (*MinHasher) EstimateJaccardSimilarity

func (m *MinHasher) EstimateJaccardSimilarity(sig1, sig2 *MinHashSignature) float64

EstimateJaccardSimilarity estimates Jaccard similarity via signature agreement ratio

func (*MinHasher) NumHashes

func (m *MinHasher) NumHashes() int

NumHashes returns the number of hash functions

type ModuleAnalyzer

type ModuleAnalyzer struct {
	// contains filtered or unexported fields
}

ModuleAnalyzer analyzes JavaScript/TypeScript module imports and exports

func NewModuleAnalyzer

func NewModuleAnalyzer(config *ModuleAnalyzerConfig) *ModuleAnalyzer

NewModuleAnalyzer creates a new module analyzer with the given configuration

func (*ModuleAnalyzer) AnalyzeAll

func (ma *ModuleAnalyzer) AnalyzeAll(asts map[string]*parser.Node) (*domain.ModuleAnalysisResult, error)

AnalyzeAll analyzes multiple files and returns aggregated results

func (*ModuleAnalyzer) AnalyzeFile

func (ma *ModuleAnalyzer) AnalyzeFile(ast *parser.Node, filePath string) (*domain.ModuleInfo, error)

AnalyzeFile analyzes a single file and returns its module info

type ModuleAnalyzerConfig

type ModuleAnalyzerConfig struct {
	// IncludeBuiltins includes Node.js builtin modules in analysis
	IncludeBuiltins bool

	// ResolveRelative enables resolution of relative import paths
	ResolveRelative bool

	// IncludeTypeImports includes TypeScript type imports
	IncludeTypeImports bool

	// AliasPatterns are path alias patterns to recognize (@/, ~/, etc.)
	AliasPatterns []string
}

ModuleAnalyzerConfig holds configuration for the module analyzer

func DefaultModuleAnalyzerConfig

func DefaultModuleAnalyzerConfig() *ModuleAnalyzerConfig

DefaultModuleAnalyzerConfig returns the default configuration

type OptimizedAPTEDAnalyzer

type OptimizedAPTEDAnalyzer struct {
	*APTEDAnalyzer
	// contains filtered or unexported fields
}

OptimizedAPTEDAnalyzer extends APTEDAnalyzer with performance optimizations

func NewOptimizedAPTEDAnalyzer

func NewOptimizedAPTEDAnalyzer(costModel CostModel, maxDistance float64) *OptimizedAPTEDAnalyzer

NewOptimizedAPTEDAnalyzer creates an optimized APTED analyzer

func (*OptimizedAPTEDAnalyzer) ComputeDistance

func (a *OptimizedAPTEDAnalyzer) ComputeDistance(tree1, tree2 *TreeNode) float64

ComputeDistance computes tree edit distance with early stopping optimization

type ReachabilityAnalyzer

type ReachabilityAnalyzer struct {
	// contains filtered or unexported fields
}

ReachabilityAnalyzer performs reachability analysis on CFGs

func NewReachabilityAnalyzer

func NewReachabilityAnalyzer(cfg *CFG) *ReachabilityAnalyzer

NewReachabilityAnalyzer creates a new reachability analyzer for the given CFG

func (*ReachabilityAnalyzer) AnalyzeReachability

func (ra *ReachabilityAnalyzer) AnalyzeReachability() *ReachabilityResult

AnalyzeReachability performs reachability analysis starting from the entry block

func (*ReachabilityAnalyzer) AnalyzeReachabilityFrom

func (ra *ReachabilityAnalyzer) AnalyzeReachabilityFrom(startBlock *BasicBlock) *ReachabilityResult

AnalyzeReachabilityFrom performs reachability analysis from a specific starting block

type ReachabilityResult

type ReachabilityResult struct {
	// ReachableBlocks contains blocks that can be reached from entry
	ReachableBlocks map[string]*BasicBlock

	// UnreachableBlocks contains blocks that cannot be reached from entry
	UnreachableBlocks map[string]*BasicBlock

	// TotalBlocks is the total number of blocks analyzed
	TotalBlocks int

	// ReachableCount is the number of reachable blocks
	ReachableCount int

	// UnreachableCount is the number of unreachable blocks
	UnreachableCount int

	// AnalysisTime is the time taken to perform the analysis
	AnalysisTime time.Duration
}

ReachabilityResult contains the results of reachability analysis

func (*ReachabilityResult) GetReachabilityRatio

func (result *ReachabilityResult) GetReachabilityRatio() float64

GetReachabilityRatio returns the ratio of reachable blocks to total blocks

func (*ReachabilityResult) GetUnreachableBlocksWithStatements

func (result *ReachabilityResult) GetUnreachableBlocksWithStatements() map[string]*BasicBlock

GetUnreachableBlocksWithStatements returns unreachable blocks that contain statements

func (*ReachabilityResult) HasUnreachableCode

func (result *ReachabilityResult) HasUnreachableCode() bool

HasUnreachableCode returns true if there are unreachable blocks with statements

type SeverityLevel

type SeverityLevel string

SeverityLevel represents the severity of a dead code finding

const (
	// SeverityLevelCritical indicates code that is definitely unreachable
	SeverityLevelCritical SeverityLevel = "critical"

	// SeverityLevelWarning indicates code that is likely unreachable
	SeverityLevelWarning SeverityLevel = "warning"

	// SeverityLevelInfo indicates potential optimization opportunities
	SeverityLevelInfo SeverityLevel = "info"
)

type StarMedoidGrouping

type StarMedoidGrouping struct {
	// contains filtered or unexported fields
}

StarMedoidGrouping uses iterative medoid optimization for balanced precision/recall

func NewStarMedoidGrouping

func NewStarMedoidGrouping(threshold float64) *StarMedoidGrouping

func (*StarMedoidGrouping) GetName

func (s *StarMedoidGrouping) GetName() string

func (*StarMedoidGrouping) GroupClones

func (s *StarMedoidGrouping) GroupClones(pairs []*domain.ClonePair) []*domain.CloneGroup

type TreeConverter

type TreeConverter struct {
	// contains filtered or unexported fields
}

TreeConverter converts parser AST nodes to APTED tree nodes

func NewTreeConverter

func NewTreeConverter() *TreeConverter

NewTreeConverter creates a new tree converter

func (*TreeConverter) ConvertAST

func (tc *TreeConverter) ConvertAST(astNode *parser.Node) *TreeNode

ConvertAST converts a parser AST node to an APTED tree

type TreeEditResult

type TreeEditResult struct {
	Distance   float64
	Similarity float64
	Tree1Size  int
	Tree2Size  int
	Operations int // Estimated number of edit operations
}

TreeEditResult holds the result of tree edit distance computation

type TreeNode

type TreeNode struct {
	// Unique identifier for this node
	ID int

	// Label for the node (typically the node type or value)
	Label string

	// Tree structure
	Children []*TreeNode
	Parent   *TreeNode

	// APTED-specific fields for optimization
	PostOrderID  int  // Post-order traversal position
	LeftMostLeaf int  // Left-most leaf descendant
	KeyRoot      bool // Whether this node is a key root

	// Optional metadata from original AST
	OriginalNode *parser.Node
}

TreeNode represents a node in the ordered tree for APTED algorithm

func GetNodeByPostOrderID

func GetNodeByPostOrderID(root *TreeNode, postOrderID int) *TreeNode

GetNodeByPostOrderID finds a node by its post-order ID

func GetSubtreeNodes

func GetSubtreeNodes(root *TreeNode) []*TreeNode

GetSubtreeNodes returns all nodes in the subtree rooted at the given node

func GetSubtreeNodesWithDepthLimit

func GetSubtreeNodesWithDepthLimit(root *TreeNode, maxDepth int) []*TreeNode

GetSubtreeNodesWithDepthLimit returns all nodes with maximum recursion depth limit

func NewTreeNode

func NewTreeNode(id int, label string) *TreeNode

NewTreeNode creates a new tree node with the given ID and label

func (*TreeNode) AddChild

func (t *TreeNode) AddChild(child *TreeNode)

AddChild adds a child node to this node

func (*TreeNode) Height

func (t *TreeNode) Height() int

Height returns the height of the subtree rooted at this node

func (*TreeNode) HeightWithDepthLimit

func (t *TreeNode) HeightWithDepthLimit(maxDepth int) int

HeightWithDepthLimit returns the height with maximum recursion depth limit

func (*TreeNode) IsLeaf

func (t *TreeNode) IsLeaf() bool

IsLeaf returns true if this node has no children

func (*TreeNode) Size

func (t *TreeNode) Size() int

Size returns the size of the subtree rooted at this node

func (*TreeNode) SizeWithDepthLimit

func (t *TreeNode) SizeWithDepthLimit(maxDepth int) int

SizeWithDepthLimit returns the size with maximum recursion depth limit

func (*TreeNode) String

func (t *TreeNode) String() string

String returns a string representation of the node

type WeightedCostModel

type WeightedCostModel struct {
	InsertWeight  float64
	DeleteWeight  float64
	RenameWeight  float64
	BaseCostModel CostModel
}

WeightedCostModel allows custom weights for different operation types

func NewWeightedCostModel

func NewWeightedCostModel(insertWeight, deleteWeight, renameWeight float64, baseCostModel CostModel) *WeightedCostModel

NewWeightedCostModel creates a new weighted cost model

func (*WeightedCostModel) Delete

func (c *WeightedCostModel) Delete(node *TreeNode) float64

Delete returns the weighted cost of deleting a node

func (*WeightedCostModel) Insert

func (c *WeightedCostModel) Insert(node *TreeNode) float64

Insert returns the weighted cost of inserting a node

func (*WeightedCostModel) Rename

func (c *WeightedCostModel) Rename(node1, node2 *TreeNode) float64

Rename returns the weighted cost of renaming node1 to node2

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL