Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Control Flow Analysis

The control flow analysis system analyzes method control flow to calculate complexity metrics, detect control flow smells, and identify potential issues.


Overview

Location: src/bsharp_analysis/src/passes/control_flow.rs, src/bsharp_analysis/src/artifacts/cfg.rs

Control flow analysis provides:

  • Cyclomatic complexity calculation
  • Maximum nesting depth tracking
  • Exit point counting
  • Statement counting
  • Control flow smell detection

Control Flow Metrics

Cyclomatic Complexity

Definition: Number of linearly independent paths through a method

Calculation: CC = 1 + number of decision points

Decision Points:

  • if statements
  • case labels in switch
  • Loop statements (for, foreach, while, do-while)
  • catch clauses
  • Logical operators (&&, ||) in conditions
  • Ternary operators (?:)
  • Null-coalescing operators (??)

Example:

public void ProcessOrder(Order order) {  // CC = 1 (base)
    if (order == null) {                 // +1 = 2
        throw new ArgumentNullException();
    }
    
    if (order.IsValid) {                 // +1 = 3
        if (order.Amount > 1000) {       // +1 = 4
            ApplyDiscount(order);
        }
        SaveOrder(order);
    }
}
// Total CC = 4

Maximum Nesting Depth

Definition: Deepest level of nested control structures

Example:

public void Example() {
    if (condition1) {              // Depth 1
        while (condition2) {       // Depth 2
            if (condition3) {      // Depth 3
                DoSomething();
            }
        }
    }
}
// Max Nesting Depth = 3

Exit Points

Definition: Number of points where method can return

Counted:

  • return statements
  • throw statements
  • End of void method

Example:

public int Calculate(int x) {
    if (x < 0) {
        return -1;        // Exit point 1
    }
    if (x == 0) {
        return 0;         // Exit point 2
    }
    return x * 2;         // Exit point 3
}
// Total Exit Points = 3

Statement Count

Definition: Total number of statements in method body

Includes all statement types:

  • Expression statements
  • Declaration statements
  • Control flow statements
  • Jump statements

Control Flow Artifacts

MethodControlFlowStats

#![allow(unused)]
fn main() {
pub struct MethodControlFlowStats {
    pub complexity: usize,
    pub max_nesting: usize,
    pub exit_points: usize,
    pub statement_count: usize,
}
}

ControlFlowIndex

#![allow(unused)]
fn main() {
pub struct ControlFlowIndex {
    // Method identifier -> stats
    methods: HashMap<String, MethodControlFlowStats>,
}
}

CfgSummary

#![allow(unused)]
fn main() {
pub struct CfgSummary {
    pub total_methods: usize,
    pub high_complexity_count: usize,
    pub deep_nesting_count: usize,
}
}

Control Flow Smells

High Complexity

Threshold: Configurable (default: 10)

Detection:

#![allow(unused)]
fn main() {
if stats.complexity > config.cf_high_complexity_threshold {
    session.diagnostics.add(
        DiagnosticCode::HighComplexity,
        format!("Method complexity {} exceeds threshold {}", 
               stats.complexity, threshold)
    );
}
}

Diagnostic:

warning[CF002]: High cyclomatic complexity
  --> src/OrderProcessor.cs:42:17
   |
42 |     public void ProcessOrder(Order order) {
   |                 ^^^^^^^^^^^^ complexity = 15 (threshold: 10)
   |
   = help: Consider breaking this method into smaller methods

Deep Nesting

Threshold: Configurable (default: 4)

Detection:

#![allow(unused)]
fn main() {
if stats.max_nesting > config.cf_deep_nesting_threshold {
    session.diagnostics.add(
        DiagnosticCode::DeepNesting,
        format!("Maximum nesting depth {} exceeds threshold {}", 
               stats.max_nesting, threshold)
    );
}
}

Diagnostic:

warning[CF003]: Deep nesting detected
  --> src/Validator.cs:15:9
   |
15 |         if (condition1) {
   |         ^^ nesting depth = 5 (threshold: 4)
   |
   = help: Consider extracting nested logic into separate methods

Implementation

Analysis Pass

Location: src/bsharp_analysis/src/passes/control_flow.rs

#![allow(unused)]
fn main() {
pub struct ControlFlowPass;

impl AnalyzerPass for ControlFlowPass {
    fn id(&self) -> &'static str { "control_flow" }
    fn phase(&self) -> Phase { Phase::Semantic }
    
    fn run(&self, cu: &CompilationUnit, session: &mut AnalysisSession) {
        let mut index = ControlFlowIndex::new();
        
        // Analyze all methods in compilation unit
        for decl in &cu.declarations {
            analyze_declaration(decl, &mut index, session);
        }
        
        session.artifacts.cfg = Some(index);
    }
}
}

Method Analysis

#![allow(unused)]
fn main() {
fn analyze_method(
    method: &MethodDeclaration,
    index: &mut ControlFlowIndex,
    session: &mut AnalysisSession
) {
    let stats = calculate_stats(method.body.as_ref());
    
    // Check thresholds
    if stats.complexity > session.config.cf_high_complexity_threshold {
        session.diagnostics.add(/* high complexity diagnostic */);
    }
    
    if stats.max_nesting > session.config.cf_deep_nesting_threshold {
        session.diagnostics.add(/* deep nesting diagnostic */);
    }
    
    // Store in index
    index.add_method(&method.identifier.name, stats);
}
}

Stats Calculation

#![allow(unused)]
fn main() {
fn calculate_stats(body: Option<&Statement>) -> MethodControlFlowStats {
    let complexity = match body {
        Some(stmt) => 1 + count_decision_points(stmt),
        None => 1,
    };
    
    let max_nesting = calculate_max_nesting(body, 0);
    let exit_points = count_exit_points(body);
    let statement_count = count_statements(body);
    
    MethodControlFlowStats {
        complexity,
        max_nesting,
        exit_points,
        statement_count,
    }
}
}

Configuration

Thresholds

[analysis.control_flow]
cf_high_complexity_threshold = 10
cf_deep_nesting_threshold = 4

CLI Usage

# Analyze with custom thresholds
bsharp analyze MyProject.csproj --config .bsharp.toml

# Enable control flow pass
bsharp analyze MyProject.csproj --enable-pass control_flow

Integration with Pipeline

Phase: Semantic

Control flow analysis runs in the Semantic phase after symbol indexing:

Phase::Index    -> Build SymbolIndex
Phase::Local    -> Collect metrics
Phase::Semantic -> Control flow analysis

Artifacts

Results stored in AnalysisSession:

#![allow(unused)]
fn main() {
session.artifacts.cfg = Some(ControlFlowIndex { ... });
}

Summarized in AnalysisReport:

#![allow(unused)]
fn main() {
report.cfg = Some(CfgSummary {
    total_methods: 87,
    high_complexity_count: 5,
    deep_nesting_count: 3,
});
}


References

  • Implementation: src/bsharp_analysis/src/passes/control_flow.rs
  • Artifacts: src/bsharp_analysis/src/artifacts/cfg.rs
  • Tests: src/bsharp_tests/src/analysis/control_flow/ (planned)
2025-11-17 15:18:26 • commit: 03a4e25