Documentation
¶
Index ¶
- func SortLineFindings(findings []*LineFinding)
- type BasicBlock
- type CFG
- func (c *CFG) AddBlock(block *BasicBlock)
- func (c *CFG) BreadthFirstWalk(visitor Visitor)
- func (c *CFG) ConnectBlocks(from, to *BasicBlock, edgeType EdgeType) *Edge
- func (c *CFG) CreateBlock(label string) *BasicBlock
- func (c *CFG) GetBlock(id string) *BasicBlock
- func (c *CFG) RemoveBlock(block *BasicBlock)
- func (c *CFG) Size() int
- func (c *CFG) String() string
- func (c *CFG) Walk(visitor Visitor)
- type ComplexityConfig
- type ComplexityContribution
- type ComplexityContributor
- type ComplexityResult
- type DeadCodeConfig
- type DeadCodeFinding
- type DeadCodeResult
- type DeadCodeSeverity
- type Edge
- type EdgeType
- type LineFinding
- type NoOpClassifier
- type ReachabilityConfig
- type ReachabilityResult
- type StatementClassifier
- type Visitor
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func SortLineFindings ¶
func SortLineFindings(findings []*LineFinding)
SortLineFindings sorts findings by start line, then end line, for consistent output and as the precondition of MergeContiguousFindings.
Types ¶
type BasicBlock ¶
type BasicBlock struct {
ID string
Label string
// Statements contains the AST nodes in this block.
// Each element is a language-specific AST node stored as any.
// Language adapters recover the concrete type via type assertion:
//
// for _, stmt := range block.Statements {
// node := stmt.(*parser.Node) // pyscn or jscan
// }
Statements []any
Predecessors []*Edge
Successors []*Edge
IsEntry bool
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 any)
AddStatement adds a statement 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 CFG ¶
type CFG struct {
Entry *BasicBlock
Exit *BasicBlock
Blocks map[string]*BasicBlock
Name string
// FunctionNode is the original AST node for the function.
// This field is opaque to polyscan core; language adapters store their
// own function node type here and recover it via type assertion:
//
// fnNode := cfg.FunctionNode.(*parser.Node)
FunctionNode any
// contains filtered or unexported fields
}
CFG represents a control flow graph.
func (*CFG) AddBlock ¶
func (c *CFG) AddBlock(block *BasicBlock)
AddBlock adds an existing block to the graph.
func (*CFG) BreadthFirstWalk ¶
BreadthFirstWalk performs a breadth-first traversal of the CFG.
func (*CFG) ConnectBlocks ¶
func (c *CFG) ConnectBlocks(from, to *BasicBlock, edgeType EdgeType) *Edge
ConnectBlocks creates an edge between two blocks.
func (*CFG) CreateBlock ¶
func (c *CFG) CreateBlock(label string) *BasicBlock
CreateBlock creates a new basic block and adds it to the graph.
func (*CFG) GetBlock ¶
func (c *CFG) GetBlock(id string) *BasicBlock
GetBlock retrieves a block by its ID.
func (*CFG) RemoveBlock ¶
func (c *CFG) RemoveBlock(block *BasicBlock)
RemoveBlock removes a block from the graph.
type ComplexityConfig ¶
type ComplexityConfig struct {
// Contributor provides language-specific extra complexity contributions.
// If nil, no extra contributions are added.
Contributor ComplexityContributor
}
ComplexityConfig configures complexity computation.
type ComplexityContribution ¶
type ComplexityContribution struct {
Count int
Description string // e.g. "logical_and", "ternary", "null_coalescing"
}
ComplexityContribution represents a single language-specific complexity contribution.
type ComplexityContributor ¶
type ComplexityContributor interface {
ContributeComplexity(block *BasicBlock) ([]ComplexityContribution, error)
}
ComplexityContributor provides language-specific additional complexity counts. For example, jscan counts logical operators (&&, ||, ??) and ternary expressions.
type ComplexityResult ¶
type ComplexityResult struct {
McCabe int
DecisionPoints int
ExtraContributions int
Contributions []ComplexityContribution
EdgeBreakdown map[EdgeType]int
}
ComplexityResult holds McCabe cyclomatic complexity analysis results.
func ComputeComplexity ¶
func ComputeComplexity(c *CFG, config ComplexityConfig) (*ComplexityResult, error)
ComputeComplexity computes McCabe cyclomatic complexity for a CFG. A decision point is a block that has at least one outgoing edge of type EdgeCondTrue, EdgeCondFalse, or EdgeException. Each such block counts as exactly one decision point regardless of how many decision edges it has (e.g. an if-else has both EdgeCondTrue and EdgeCondFalse but is one decision point). EdgeLoop is a back-edge and does not count as a decision point; loop headers should use EdgeCondTrue/EdgeCondFalse for the loop-body vs exit branch. McCabe = DecisionPoints + ExtraContributions + 1.
type DeadCodeConfig ¶
type DeadCodeConfig struct {
// Classifier provides language-specific statement classification.
// If nil, only structural analysis (unreachable blocks) is performed.
Classifier StatementClassifier
}
DeadCodeConfig configures dead code detection.
type DeadCodeFinding ¶
type DeadCodeFinding struct {
BlockID string
Severity DeadCodeSeverity
Reason string // "after_return", "after_break", "after_continue", "after_throw", "unreachable"
}
DeadCodeFinding represents a single dead code detection result.
type DeadCodeResult ¶
type DeadCodeResult struct {
Findings []*DeadCodeFinding
TotalBlocks int
DeadBlocks int
}
DeadCodeResult holds all dead code findings for a CFG.
func DetectDeadCode ¶
func DetectDeadCode(c *CFG, config DeadCodeConfig) *DeadCodeResult
DetectDeadCode identifies dead code in a CFG. It uses AnalyzeReachability to find unreachable blocks, then examines reachable blocks for code after terminators (return/break/continue/throw).
type DeadCodeSeverity ¶
type DeadCodeSeverity int
DeadCodeSeverity indicates the severity of a dead code finding.
const ( SeverityInfo DeadCodeSeverity = iota // after_break, after_continue SeverityWarning // after_return, after_throw SeverityCritical // unreachable )
type Edge ¶
type Edge struct {
From *BasicBlock
To *BasicBlock
Type EdgeType
Label string // Language-specific flow description (e.g. switch case value, yield, await).
Data any // Optional language-specific edge metadata.
}
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 EdgeType = iota // Normal sequential flow EdgeCondTrue // Conditional true branch EdgeCondFalse // Conditional false branch EdgeException // Exception flow EdgeLoop // Loop back edge EdgeBreak // Break statement flow EdgeContinue // Continue statement flow EdgeReturn // Return statement flow )
type LineFinding ¶
type LineFinding struct {
StartLine int
EndLine int
Reason string
Severity DeadCodeSeverity
Description string
Code string
}
LineFinding is the language-independent, line-level slice of a dead code finding used by post-processing passes. Language adapters convert their richer finding types to and from this representation (or embed it).
func MergeContiguousFindings ¶
func MergeContiguousFindings(findings []*LineFinding) []*LineFinding
MergeContiguousFindings collapses findings whose line ranges overlap or are directly adjacent (no reachable line between them) and that share the same reason into a single finding. Findings must be pre-sorted by StartLine (then EndLine); use SortLineFindings. This removes the overlapping/duplicate ranges that arise because a compound statement's finding spans its body while the body's block emits its own nested finding.
type NoOpClassifier ¶
NoOpClassifier is an optional StatementClassifier extension reporting statements with no actionable content (e.g. a bare `;` in JS/TS or `pass` in Python). Unreachable blocks consisting solely of no-op statements are technically dead but carry no signal for the user, so they are not reported as findings.
type ReachabilityConfig ¶
type ReachabilityConfig struct {
// Classifier provides language-specific statement classification.
// If nil, only structural reachability (DFS from entry) is computed.
Classifier StatementClassifier
}
ReachabilityConfig configures reachability analysis.
type ReachabilityResult ¶
type ReachabilityResult struct {
Reachable map[string]bool // blockID -> reachable from entry
ReachableCount int
UnreachableCount int
}
ReachabilityResult holds the result of reachability analysis.
func AnalyzeReachability ¶
func AnalyzeReachability(c *CFG, config ReachabilityConfig) *ReachabilityResult
AnalyzeReachability performs reachability analysis on a CFG. If config.Classifier is nil, only structural reachability (DFS from entry) is computed, following all edges. If config.Classifier is non-nil, blocks whose last statement is a terminator (return/break/continue/throw) will not have their successors visited via normal DFS traversal. Successors are still reachable if another non-terminating path leads to them.
type StatementClassifier ¶
type StatementClassifier interface {
IsReturn(stmt any) bool
IsBreak(stmt any) bool
IsContinue(stmt any) bool
IsThrow(stmt any) bool
}
StatementClassifier classifies statements in a BasicBlock. Language-specific implementations check for terminator statements: e.g. pyscn checks parser.NodeReturn, jscan checks parser.NodeReturnStatement, etc.