use crate::code_intelligence::*;
use crate::error::Error;
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use std::cell::RefCell;
use std::collections::HashMap;
use std::sync::Arc;
use tracing::{info, instrument};
thread_local! {
static REGEX_CACHE: RefCell<HashMap<String, regex::Regex>> = RefCell::new(HashMap::new());
}
fn get_cached_regex(pattern_str: &str) -> Result<regex::Regex, Error> {
REGEX_CACHE.with(|cache| {
let mut cache = cache.borrow_mut();
if let Some(re) = cache.get(pattern_str) {
return Ok(re.clone());
}
let re = regex::Regex::new(pattern_str).map_err(|e| {
Error::ConfigError(format!("Invalid regex pattern: {} - {}", pattern_str, e))
})?;
cache.insert(pattern_str.to_string(), re.clone());
Ok(re)
})
}
pub struct BugDetectorEngine {
detectors: HashMap<ProgrammingLanguage, Box<dyn LanguageBugDetector + Send + Sync>>,
security_scanner: Arc<SecurityVulnerabilityScanner>,
performance_analyzer: Arc<PerformanceBugAnalyzer>,
concurrency_detector: Arc<ConcurrencyBugDetector>,
}
#[async_trait]
pub trait LanguageBugDetector: Send + Sync {
async fn detect_bugs(
&self,
ast: &UnifiedAST,
code: &str,
analysis_context: &BugAnalysisContext,
) -> Result<Vec<BugFinding>, Error>;
fn get_bug_patterns(&self) -> Vec<BugPattern>;
}
#[derive(Debug)]
pub struct SecurityVulnerabilityScanner {
sql_injection_patterns: Vec<BugPattern>,
xss_patterns: Vec<BugPattern>,
code_injection_patterns: Vec<BugPattern>,
#[allow(dead_code)]
auth_bypass_patterns: Vec<BugPattern>,
}
#[derive(Debug)]
pub struct PerformanceBugAnalyzer {
memory_leak_patterns: Vec<BugPattern>,
infinite_loop_patterns: Vec<BugPattern>,
inefficient_algorithm_patterns: Vec<BugPattern>,
}
#[derive(Debug)]
pub struct ConcurrencyBugDetector {
race_condition_patterns: Vec<BugPattern>,
#[allow(dead_code)]
deadlock_patterns: Vec<BugPattern>,
#[allow(dead_code)]
thread_safety_patterns: Vec<BugPattern>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BugPattern {
pub pattern_id: String,
pub category: BugCategory,
pub severity: BugSeverity,
pub description: String,
pub regex_pattern: String,
pub false_positive_rate: f64,
pub language_specific: Option<ProgrammingLanguage>,
pub explanation: String,
pub mitigation_suggestion: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BugAnalysisContext {
pub focus_areas: Vec<BugCategory>,
pub security_focus: bool,
pub performance_focus: bool,
pub concurrency_focus: bool,
pub analysis_depth: AnalysisDepth,
pub include_false_positives: bool,
pub custom_patterns: Vec<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum AnalysisDepth {
Shallow,
Medium,
Deep,
Comprehensive,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EnhancedBugFinding {
pub bug: BugFinding,
pub confidence_score: f64,
pub detection_method: DetectionMethod,
pub affected_functions: Vec<String>,
pub related_issues: Vec<String>,
pub fix_complexity: FixComplexity,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum DetectionMethod {
StaticAnalysis,
PatternMatching,
SemanticAnalysis,
DataFlowAnalysis,
ControlFlowAnalysis,
SecurityScanner,
PerformanceAnalyzer,
ConcurrencyChecker,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum FixComplexity {
Simple,
Moderate,
Complex,
Architectural,
}
impl Default for BugDetectorEngine {
fn default() -> Self {
Self::new()
}
}
impl BugDetectorEngine {
pub fn new() -> Self {
let mut detectors = HashMap::new();
detectors.insert(
ProgrammingLanguage::Rust,
Box::new(RustBugDetector::new()) as Box<dyn LanguageBugDetector + Send + Sync>,
);
detectors.insert(
ProgrammingLanguage::Java,
Box::new(JavaBugDetector::new()) as Box<dyn LanguageBugDetector + Send + Sync>,
);
detectors.insert(
ProgrammingLanguage::Python,
Box::new(PythonBugDetector::new()) as Box<dyn LanguageBugDetector + Send + Sync>,
);
detectors.insert(
ProgrammingLanguage::Golang,
Box::new(GolangBugDetector::new()) as Box<dyn LanguageBugDetector + Send + Sync>,
);
detectors.insert(
ProgrammingLanguage::Cpp,
Box::new(CppBugDetector::new()) as Box<dyn LanguageBugDetector + Send + Sync>,
);
detectors.insert(
ProgrammingLanguage::TypeScript,
Box::new(TypeScriptBugDetector::new()) as Box<dyn LanguageBugDetector + Send + Sync>,
);
detectors.insert(
ProgrammingLanguage::JavaScript,
Box::new(JavaScriptBugDetector::new()) as Box<dyn LanguageBugDetector + Send + Sync>,
);
detectors.insert(
ProgrammingLanguage::Kotlin,
Box::new(KotlinBugDetector::new()) as Box<dyn LanguageBugDetector + Send + Sync>,
);
detectors.insert(
ProgrammingLanguage::ObjectiveC,
Box::new(ObjectiveCBugDetector::new()) as Box<dyn LanguageBugDetector + Send + Sync>,
);
let security_scanner = Arc::new(SecurityVulnerabilityScanner::new());
let performance_analyzer = Arc::new(PerformanceBugAnalyzer::new());
let concurrency_detector = Arc::new(ConcurrencyBugDetector::new());
Self {
detectors,
security_scanner,
performance_analyzer,
concurrency_detector,
}
}
#[instrument(skip(self, ast, code))]
pub async fn detect_bugs_comprehensive(
&self,
ast: &UnifiedAST,
language: ProgrammingLanguage,
code: &str,
context: &BugAnalysisContext,
) -> Result<Vec<EnhancedBugFinding>, Error> {
info!(
"Running comprehensive bug detection for {:?} code",
language
);
let detector = self.detectors.get(&language).ok_or_else(|| {
Error::ConfigError(format!(
"No bug detector available for language: {:?}",
language
))
})?;
let mut all_findings = Vec::new();
let language_bugs = detector.detect_bugs(ast, code, context).await?;
for bug in language_bugs {
all_findings.push(EnhancedBugFinding {
bug,
confidence_score: 0.8,
detection_method: DetectionMethod::StaticAnalysis,
affected_functions: vec![],
related_issues: vec![],
fix_complexity: FixComplexity::Moderate,
});
}
if context.security_focus || context.focus_areas.contains(&BugCategory::Security) {
let security_bugs = self.security_scanner.scan_vulnerabilities(code, language)?;
for bug in security_bugs {
all_findings.push(EnhancedBugFinding {
bug,
confidence_score: 0.9,
detection_method: DetectionMethod::SecurityScanner,
affected_functions: vec![],
related_issues: vec![],
fix_complexity: FixComplexity::Complex,
});
}
}
if context.performance_focus || context.focus_areas.contains(&BugCategory::Performance) {
let performance_bugs = self
.performance_analyzer
.analyze_performance_issues(ast, code, language)?;
for bug in performance_bugs {
all_findings.push(EnhancedBugFinding {
bug,
confidence_score: 0.7,
detection_method: DetectionMethod::PerformanceAnalyzer,
affected_functions: vec![],
related_issues: vec![],
fix_complexity: FixComplexity::Moderate,
});
}
}
if context.concurrency_focus || context.focus_areas.contains(&BugCategory::Concurrency) {
let concurrency_bugs = self
.concurrency_detector
.detect_concurrency_issues(ast, code, language)?;
for bug in concurrency_bugs {
all_findings.push(EnhancedBugFinding {
bug,
confidence_score: 0.75,
detection_method: DetectionMethod::ConcurrencyChecker,
affected_functions: vec![],
related_issues: vec![],
fix_complexity: FixComplexity::Architectural,
});
}
}
let filtered_findings = self.filter_by_depth(all_findings, context.analysis_depth)?;
let mut sorted_findings = filtered_findings;
sorted_findings.sort_by(|a, b| {
let severity_order = |severity: BugSeverity| match severity {
BugSeverity::Critical => 4,
BugSeverity::High => 3,
BugSeverity::Medium => 2,
BugSeverity::Low => 1,
BugSeverity::Info => 0,
};
let a_score = (severity_order(a.bug.severity) as f64) * 10.0 + a.confidence_score;
let b_score = (severity_order(b.bug.severity) as f64) * 10.0 + b.confidence_score;
b_score
.partial_cmp(&a_score)
.unwrap_or(std::cmp::Ordering::Equal)
});
info!(
"Bug detection completed - Found {} potential issues",
sorted_findings.len()
);
Ok(sorted_findings)
}
fn filter_by_depth(
&self,
findings: Vec<EnhancedBugFinding>,
depth: AnalysisDepth,
) -> Result<Vec<EnhancedBugFinding>, Error> {
let filtered = match depth {
AnalysisDepth::Shallow => findings
.into_iter()
.filter(|f| {
f.bug.severity == BugSeverity::Critical || f.bug.severity == BugSeverity::High
})
.filter(|f| f.confidence_score >= 0.8)
.collect::<Vec<_>>(),
AnalysisDepth::Medium => findings
.into_iter()
.filter(|f| {
matches!(
f.bug.severity,
BugSeverity::Critical | BugSeverity::High | BugSeverity::Medium
)
})
.filter(|f| f.confidence_score >= 0.7)
.collect::<Vec<_>>(),
AnalysisDepth::Deep => findings
.into_iter()
.filter(|f| f.confidence_score >= 0.6)
.collect::<Vec<_>>(),
AnalysisDepth::Comprehensive => findings
.into_iter()
.filter(|f| {
if !f.bug.severity.eq(&BugSeverity::Info) {
true
} else {
f.confidence_score >= 0.9
}
})
.collect::<Vec<_>>(),
};
Ok(filtered)
}
pub fn get_bug_statistics(&self, findings: &[EnhancedBugFinding]) -> BugStatistics {
let mut stats = BugStatistics::default();
for finding in findings {
match finding.bug.severity {
BugSeverity::Critical => stats.critical_bugs += 1,
BugSeverity::High => stats.high_bugs += 1,
BugSeverity::Medium => stats.medium_bugs += 1,
BugSeverity::Low => stats.low_bugs += 1,
BugSeverity::Info => stats.info_bugs += 1,
}
match finding.bug.category {
BugCategory::Security => stats.security_bugs += 1,
BugCategory::Performance => stats.performance_bugs += 1,
BugCategory::Logic => stats.logic_bugs += 1,
BugCategory::Memory => stats.memory_bugs += 1,
BugCategory::Concurrency => stats.concurrency_bugs += 1,
BugCategory::Type => stats.type_bugs += 1,
BugCategory::NullPointer => stats.null_pointer_bugs += 1,
BugCategory::ResourceLeak => stats.resource_leak_bugs += 1,
BugCategory::Deadlock => stats.deadlock_bugs += 1,
BugCategory::RaceCondition => stats.race_condition_bugs += 1,
BugCategory::Accessibility => stats.accessibility_bugs += 1,
}
stats.total_findings += 1;
stats.average_confidence += finding.confidence_score;
}
if stats.total_findings > 0 {
stats.average_confidence /= stats.total_findings as f64;
}
stats
}
}
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub struct BugStatistics {
pub total_findings: u32,
pub critical_bugs: u32,
pub high_bugs: u32,
pub medium_bugs: u32,
pub low_bugs: u32,
pub info_bugs: u32,
pub security_bugs: u32,
pub performance_bugs: u32,
pub logic_bugs: u32,
pub memory_bugs: u32,
pub concurrency_bugs: u32,
pub type_bugs: u32,
pub null_pointer_bugs: u32,
pub resource_leak_bugs: u32,
pub deadlock_bugs: u32,
pub race_condition_bugs: u32,
pub accessibility_bugs: u32,
pub average_confidence: f64,
}
impl Default for SecurityVulnerabilityScanner {
fn default() -> Self {
Self::new()
}
}
impl SecurityVulnerabilityScanner {
pub fn new() -> Self {
Self {
sql_injection_patterns: Self::initialize_sql_injection_patterns(),
xss_patterns: Self::initialize_xss_patterns(),
code_injection_patterns: Self::initialize_code_injection_patterns(),
auth_bypass_patterns: Self::initialize_auth_bypass_patterns(),
}
}
pub fn scan_vulnerabilities(
&self,
code: &str,
_language: ProgrammingLanguage,
) -> Result<Vec<BugFinding>, Error> {
let mut vulnerabilities = Vec::new();
for pattern in &self.sql_injection_patterns {
let re = get_cached_regex(&pattern.regex_pattern)?;
for matches in re.find_iter(code) {
vulnerabilities.push(BugFinding {
severity: pattern.severity,
category: BugCategory::Security,
description: format!("{} - {}", pattern.description, matches.as_str()),
location: CodeLocation {
file_path: "unknown".to_string(),
line_number: None,
column_number: None,
function_name: None,
},
confidence: 1.0 - pattern.false_positive_rate,
suggested_fix: Some(pattern.mitigation_suggestion.clone()),
});
}
}
for pattern in &self.xss_patterns {
let re = get_cached_regex(&pattern.regex_pattern)?;
for matches in re.find_iter(code) {
vulnerabilities.push(BugFinding {
severity: pattern.severity,
category: BugCategory::Security,
description: format!("{} - {}", pattern.description, matches.as_str()),
location: CodeLocation {
file_path: "unknown".to_string(),
line_number: None,
column_number: None,
function_name: None,
},
confidence: 1.0 - pattern.false_positive_rate,
suggested_fix: Some(pattern.mitigation_suggestion.clone()),
});
}
}
for pattern in &self.code_injection_patterns {
let re = get_cached_regex(&pattern.regex_pattern)?;
for matches in re.find_iter(code) {
vulnerabilities.push(BugFinding {
severity: pattern.severity,
category: BugCategory::Security,
description: format!("{} - {}", pattern.description, matches.as_str()),
location: CodeLocation {
file_path: "unknown".to_string(),
line_number: None,
column_number: None,
function_name: None,
},
confidence: 1.0 - pattern.false_positive_rate,
suggested_fix: Some(pattern.mitigation_suggestion.clone()),
});
}
}
Ok(vulnerabilities)
}
fn initialize_sql_injection_patterns() -> Vec<BugPattern> {
vec![
BugPattern {
pattern_id: "sql_001".to_string(),
category: BugCategory::Security,
severity: BugSeverity::Critical,
description: "Potential SQL injection via string concatenation".to_string(),
regex_pattern: r#"["'].*SELECT.*["'].*\+.*["'].*["']|"#.to_string(),
false_positive_rate: 0.1,
language_specific: None,
explanation: "SQL queries built by concatenating strings can be vulnerable to injection attacks".to_string(),
mitigation_suggestion: "Use parameterized queries or prepared statements".to_string(),
},
BugPattern {
pattern_id: "sql_002".to_string(),
category: BugCategory::Security,
severity: BugSeverity::High,
description: "Dynamic SQL construction".to_string(),
regex_pattern: r#"execute\s*\(\s*["'].*["'].*\)|exec\s*\(\s*["'].*["'].*\)"#.to_string(),
false_positive_rate: 0.2,
language_specific: None,
explanation: "Dynamic SQL execution can lead to injection vulnerabilities".to_string(),
mitigation_suggestion: "Use parameterized queries or whitelist input values".to_string(),
},
]
}
fn initialize_xss_patterns() -> Vec<BugPattern> {
vec![
BugPattern {
pattern_id: "xss_001".to_string(),
category: BugCategory::Security,
severity: BugSeverity::High,
description: "Potential XSS via innerHTML".to_string(),
regex_pattern: r#"innerHTML\s*=\s*[^;]+"#.to_string(),
false_positive_rate: 0.1,
language_specific: Some(ProgrammingLanguage::JavaScript),
explanation: "Setting innerHTML directly can execute malicious scripts".to_string(),
mitigation_suggestion: "Use textContent or sanitize HTML content".to_string(),
},
BugPattern {
pattern_id: "xss_002".to_string(),
category: BugCategory::Security,
severity: BugSeverity::High,
description: "Potential XSS via document.write".to_string(),
regex_pattern: r#"document\.write\s*\([^)]*\)"#.to_string(),
false_positive_rate: 0.15,
language_specific: Some(ProgrammingLanguage::JavaScript),
explanation: "document.write can be used to inject malicious content".to_string(),
mitigation_suggestion: "Use DOM manipulation methods or sanitize input".to_string(),
},
]
}
fn initialize_code_injection_patterns() -> Vec<BugPattern> {
vec![
BugPattern {
pattern_id: "code_001".to_string(),
category: BugCategory::Security,
severity: BugSeverity::Critical,
description: "Use of eval() function".to_string(),
regex_pattern: r#"eval\s*\([^)]*\)"#.to_string(),
false_positive_rate: 0.05,
language_specific: None,
explanation: "eval() can execute arbitrary code and is a major security risk"
.to_string(),
mitigation_suggestion: "Use JSON.parse() or safe parsing methods instead of eval()"
.to_string(),
},
BugPattern {
pattern_id: "code_002".to_string(),
category: BugCategory::Security,
severity: BugSeverity::Critical,
description: "Use of exec() function".to_string(),
regex_pattern: r#"exec\s*\([^)]*\)"#.to_string(),
false_positive_rate: 0.05,
language_specific: Some(ProgrammingLanguage::Python),
explanation: "exec() can execute arbitrary code and is a major security risk"
.to_string(),
mitigation_suggestion: "Use safer alternatives like ast.literal_eval()".to_string(),
},
]
}
fn initialize_auth_bypass_patterns() -> Vec<BugPattern> {
vec![BugPattern {
pattern_id: "auth_001".to_string(),
category: BugCategory::Security,
severity: BugSeverity::High,
description: "Authentication bypass via empty check".to_string(),
regex_pattern: r#"if\s*\(\s*[^)]*\)\s*\{[^}]*return\s+true"#.to_string(),
false_positive_rate: 0.3,
language_specific: None,
explanation: "Simple boolean checks for authentication can be bypassed".to_string(),
mitigation_suggestion: "Implement proper authentication and authorization checks"
.to_string(),
}]
}
}
impl Default for PerformanceBugAnalyzer {
fn default() -> Self {
Self::new()
}
}
impl PerformanceBugAnalyzer {
pub fn new() -> Self {
Self {
memory_leak_patterns: Self::initialize_memory_leak_patterns(),
infinite_loop_patterns: Self::initialize_infinite_loop_patterns(),
inefficient_algorithm_patterns: Self::initialize_inefficient_algorithm_patterns(),
}
}
pub fn analyze_performance_issues(
&self,
_ast: &UnifiedAST,
code: &str,
_language: ProgrammingLanguage,
) -> Result<Vec<BugFinding>, Error> {
let mut issues = Vec::new();
for pattern in &self.memory_leak_patterns {
let re = get_cached_regex(&pattern.regex_pattern)?;
for matches in re.find_iter(code) {
issues.push(BugFinding {
severity: pattern.severity,
category: pattern.category,
description: format!("{} - {}", pattern.description, matches.as_str()),
location: CodeLocation {
file_path: "unknown".to_string(),
line_number: None,
column_number: None,
function_name: None,
},
confidence: 1.0 - pattern.false_positive_rate,
suggested_fix: Some(pattern.mitigation_suggestion.clone()),
});
}
}
for pattern in &self.infinite_loop_patterns {
let re = get_cached_regex(&pattern.regex_pattern)?;
for matches in re.find_iter(code) {
issues.push(BugFinding {
severity: pattern.severity,
category: BugCategory::Performance,
description: format!("{} - {}", pattern.description, matches.as_str()),
location: CodeLocation {
file_path: "unknown".to_string(),
line_number: None,
column_number: None,
function_name: None,
},
confidence: 1.0 - pattern.false_positive_rate,
suggested_fix: Some(pattern.mitigation_suggestion.clone()),
});
}
}
for pattern in &self.inefficient_algorithm_patterns {
let re = get_cached_regex(&pattern.regex_pattern)?;
for matches in re.find_iter(code) {
issues.push(BugFinding {
severity: pattern.severity,
category: BugCategory::Performance,
description: format!("{} - {}", pattern.description, matches.as_str()),
location: CodeLocation {
file_path: "unknown".to_string(),
line_number: None,
column_number: None,
function_name: None,
},
confidence: 1.0 - pattern.false_positive_rate,
suggested_fix: Some(pattern.mitigation_suggestion.clone()),
});
}
}
Ok(issues)
}
fn initialize_memory_leak_patterns() -> Vec<BugPattern> {
vec![BugPattern {
pattern_id: "mem_001".to_string(),
category: BugCategory::Memory,
severity: BugSeverity::High,
description: "Potential memory leak - missing cleanup".to_string(),
regex_pattern: r#"new\s+\w+|malloc\s*\(|alloc\s*\(""#.to_string(),
false_positive_rate: 0.2,
language_specific: Some(ProgrammingLanguage::Cpp),
explanation: "Memory allocated without corresponding deallocation".to_string(),
mitigation_suggestion: "Ensure proper memory deallocation or use smart pointers"
.to_string(),
}]
}
fn initialize_infinite_loop_patterns() -> Vec<BugPattern> {
vec![BugPattern {
pattern_id: "loop_001".to_string(),
category: BugCategory::Performance,
severity: BugSeverity::High,
description: "Potential infinite loop".to_string(),
regex_pattern: r#"while\s*\(\s*true\s*\)|for\s*\(\s*;;\s*\)"#.to_string(),
false_positive_rate: 0.1,
language_specific: None,
explanation: "Loop without proper termination condition".to_string(),
mitigation_suggestion: "Add proper break conditions or exit strategies".to_string(),
}]
}
fn initialize_inefficient_algorithm_patterns() -> Vec<BugPattern> {
vec![BugPattern {
pattern_id: "algo_001".to_string(),
category: BugCategory::Performance,
severity: BugSeverity::Medium,
description: "Inefficient O(n²) algorithm detected".to_string(),
regex_pattern: r#"for\s*\([^)]*in[^)]*\)\s*\{[^}]*for\s*\([^)]*in[^)]*\)"#.to_string(),
false_positive_rate: 0.15,
language_specific: None,
explanation: "Nested loops may indicate O(n²) complexity".to_string(),
mitigation_suggestion: "Consider using more efficient algorithms or data structures"
.to_string(),
}]
}
}
impl Default for ConcurrencyBugDetector {
fn default() -> Self {
Self::new()
}
}
impl ConcurrencyBugDetector {
pub fn new() -> Self {
Self {
race_condition_patterns: Self::initialize_race_condition_patterns(),
deadlock_patterns: Self::initialize_deadlock_patterns(),
thread_safety_patterns: Self::initialize_thread_safety_patterns(),
}
}
pub fn detect_concurrency_issues(
&self,
_ast: &UnifiedAST,
code: &str,
_language: ProgrammingLanguage,
) -> Result<Vec<BugFinding>, Error> {
let mut issues = Vec::new();
for pattern in &self.race_condition_patterns {
let re = get_cached_regex(&pattern.regex_pattern)?;
for matches in re.find_iter(code) {
issues.push(BugFinding {
severity: pattern.severity,
category: pattern.category,
description: format!("{} - {}", pattern.description, matches.as_str()),
location: CodeLocation {
file_path: "unknown".to_string(),
line_number: None,
column_number: None,
function_name: None,
},
confidence: 1.0 - pattern.false_positive_rate,
suggested_fix: Some(pattern.mitigation_suggestion.clone()),
});
}
}
Ok(issues)
}
fn initialize_race_condition_patterns() -> Vec<BugPattern> {
vec![BugPattern {
pattern_id: "race_001".to_string(),
category: BugCategory::RaceCondition,
severity: BugSeverity::High,
description: "Shared resource access without synchronization".to_string(),
regex_pattern: r#"global\s+\w+|static\s+\w+"#.to_string(),
false_positive_rate: 0.3,
language_specific: None,
explanation: "Global or static variables accessed without proper synchronization"
.to_string(),
mitigation_suggestion: "Use mutexes, semaphores, or other synchronization primitives"
.to_string(),
}]
}
fn initialize_deadlock_patterns() -> Vec<BugPattern> {
vec![BugPattern {
pattern_id: "deadlock_001".to_string(),
category: BugCategory::Deadlock,
severity: BugSeverity::Critical,
description: "Potential deadlock - nested locks".to_string(),
regex_pattern: r#"lock\s*\([^)]*\)\s*\{[^}]*lock\s*\([^)]*\)"#.to_string(),
false_positive_rate: 0.2,
language_specific: None,
explanation: "Nested lock acquisition can lead to deadlocks".to_string(),
mitigation_suggestion:
"Ensure consistent lock acquisition order or use lock-free algorithms".to_string(),
}]
}
fn initialize_thread_safety_patterns() -> Vec<BugPattern> {
vec![BugPattern {
pattern_id: "thread_001".to_string(),
category: BugCategory::Concurrency,
severity: BugSeverity::Medium,
description: "Non-thread-safe data structure usage".to_string(),
regex_pattern: r#"ArrayList\s*\(|HashMap\s*\(""#.to_string(),
false_positive_rate: 0.4,
language_specific: Some(ProgrammingLanguage::Java),
explanation: "Collection classes that are not thread-safe in multi-threaded context"
.to_string(),
mitigation_suggestion: "Use thread-safe alternatives like Vector or ConcurrentHashMap"
.to_string(),
}]
}
}
macro_rules! implement_language_bug_detector {
($name:ident, $language:ident) => {
pub struct $name;
impl $name {
pub fn new() -> Self {
Self
}
}
impl Default for $name {
fn default() -> Self {
Self::new()
}
}
#[async_trait]
impl LanguageBugDetector for $name {
async fn detect_bugs(
&self,
_ast: &UnifiedAST,
code: &str,
_context: &BugAnalysisContext,
) -> Result<Vec<BugFinding>, Error> {
let mut bugs = Vec::new();
if code.contains("TODO") || code.contains("FIXME") {
bugs.push(BugFinding {
severity: BugSeverity::Low,
category: BugCategory::Logic,
description: "TODO/FIXME comment detected - incomplete implementation"
.to_string(),
location: CodeLocation {
file_path: "unknown".to_string(),
line_number: None,
column_number: None,
function_name: None,
},
confidence: 0.9,
suggested_fix: Some("Complete the TODO/FIXME implementation".to_string()),
});
}
match ProgrammingLanguage::$language {
ProgrammingLanguage::Rust => {
if code.contains("unwrap()") {
bugs.push(BugFinding {
severity: BugSeverity::Medium,
category: BugCategory::Logic,
description: "Use of unwrap() can panic in production".to_string(),
location: CodeLocation {
file_path: "unknown".to_string(),
line_number: None,
column_number: None,
function_name: None,
},
confidence: 0.8,
suggested_fix: Some(
"Use expect() with meaningful message or proper error handling"
.to_string(),
),
});
}
}
ProgrammingLanguage::Java => {
if code.contains("System.out.println") {
bugs.push(BugFinding {
severity: BugSeverity::Low,
category: BugCategory::Logic,
description: "Debug print statement in production code".to_string(),
location: CodeLocation {
file_path: "unknown".to_string(),
line_number: None,
column_number: None,
function_name: None,
},
confidence: 0.9,
suggested_fix: Some(
"Use proper logging framework instead of System.out.println"
.to_string(),
),
});
}
}
ProgrammingLanguage::Python => {
if code.contains("except:") {
bugs.push(BugFinding {
severity: BugSeverity::High,
category: BugCategory::Logic,
description: "Bare except clause catches all exceptions"
.to_string(),
location: CodeLocation {
file_path: "unknown".to_string(),
line_number: None,
column_number: None,
function_name: None,
},
confidence: 0.9,
suggested_fix: Some(
"Catch specific exceptions or use except Exception:"
.to_string(),
),
});
}
}
_ => {}
}
Ok(bugs)
}
fn get_bug_patterns(&self) -> Vec<BugPattern> {
vec![]
}
}
};
}
implement_language_bug_detector!(RustBugDetector, Rust);
implement_language_bug_detector!(JavaBugDetector, Java);
implement_language_bug_detector!(PythonBugDetector, Python);
implement_language_bug_detector!(GolangBugDetector, Golang);
implement_language_bug_detector!(CppBugDetector, Cpp);
implement_language_bug_detector!(TypeScriptBugDetector, TypeScript);
implement_language_bug_detector!(JavaScriptBugDetector, JavaScript);
implement_language_bug_detector!(KotlinBugDetector, Kotlin);
implement_language_bug_detector!(ObjectiveCBugDetector, ObjectiveC);
impl Default for BugAnalysisContext {
fn default() -> Self {
Self {
focus_areas: vec![BugCategory::Security, BugCategory::Logic],
security_focus: false,
performance_focus: false,
concurrency_focus: false,
analysis_depth: AnalysisDepth::Medium,
include_false_positives: false,
custom_patterns: vec![],
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_bug_detector_engine_creation() {
let engine = BugDetectorEngine::new();
assert!(!engine.detectors.is_empty());
}
#[test]
fn test_security_scanner_initialization() {
let scanner = SecurityVulnerabilityScanner::new();
assert!(!scanner.sql_injection_patterns.is_empty());
assert!(!scanner.xss_patterns.is_empty());
}
#[test]
fn test_performance_analyzer_initialization() {
let analyzer = PerformanceBugAnalyzer::new();
assert!(!analyzer.memory_leak_patterns.is_empty());
assert!(!analyzer.infinite_loop_patterns.is_empty());
}
#[test]
fn test_concurrency_detector_initialization() {
let detector = ConcurrencyBugDetector::new();
assert!(!detector.race_condition_patterns.is_empty());
}
#[test]
fn test_bug_statistics() {
let engine = BugDetectorEngine::new();
let findings = vec![EnhancedBugFinding {
bug: BugFinding {
severity: BugSeverity::Critical,
category: BugCategory::Security,
description: "Critical security issue".to_string(),
location: CodeLocation {
file_path: "test".to_string(),
line_number: None,
column_number: None,
function_name: None,
},
confidence: 0.9,
suggested_fix: Some("Fix critical issue".to_string()),
},
confidence_score: 0.9,
detection_method: DetectionMethod::SecurityScanner,
affected_functions: vec![],
related_issues: vec![],
fix_complexity: FixComplexity::Complex,
}];
let stats = engine.get_bug_statistics(&findings);
assert_eq!(stats.total_findings, 1);
assert_eq!(stats.critical_bugs, 1);
assert_eq!(stats.security_bugs, 1);
}
}