MCPcopy Create free account
hub / github.com/ParzivalHack/PySpector / run_analysis

Function run_analysis

src/pyspector/_rust_core/src/analysis/mod.rs:33–160  ·  view source on GitHub ↗
(mut context: AnalysisContext)

Source from the content-addressed store, hash-verified

31}
32
33pub fn run_analysis(mut context: AnalysisContext) -> Vec<Issue> {
34 // Apply disabled_rule_ids from [defaults] before scanning
35 if !context.ruleset.defaults.disabled_rule_ids.is_empty() {
36 let disabled: std::collections::HashSet<&str> = context.ruleset.defaults
37 .disabled_rule_ids.iter().map(|s| s.as_str()).collect();
38 let before = context.ruleset.rules.len();
39 context.ruleset.rules.retain(|r| !disabled.contains(r.id.as_str()));
40 let removed = before - context.ruleset.rules.len();
41 if removed > 0 {
42 println!("[*] Disabled {} rules via [defaults].disabled_rule_ids", removed);
43 }
44 }
45 println!("[*] Starting analysis with {} rules", context.ruleset.rules.len());
46
47 let root_path = Path::new(&context.root_path);
48 let mut files_to_scan: Vec<String> = Vec::new();
49
50 // Add common test fixture patterns to exclusions
51 let mut enhanced_exclusions = context.exclusions.clone();
52 enhanced_exclusions.extend(vec![
53 "*/tests/fixtures/*".to_string(),
54 "*/test/fixtures/*".to_string(),
55 "*_test.py".to_string(),
56 "*/test_*.py".to_string(),
57 ]);
58 // Precompile each exclusion pattern once — is_excluded() is called once per
59 // file in the walk below and once per file again in the AST pass, so
60 // re-parsing every glob pattern with WildMatch::new() on every call (and
61 // twice per call, at that) adds up on large codebases.
62 let compiled_exclusions = compile_exclusions(&enhanced_exclusions);
63
64 for entry in WalkDir::new(root_path).into_iter().filter_map(|e| e.ok()) {
65 let path = entry.path();
66 // Collect all files (not just .py) for regex scanning
67 if path.is_file() && !is_excluded(path, &compiled_exclusions) {
68 if let Some(s) = path.to_str() {
69 files_to_scan.push(s.to_string());
70 }
71 }
72 }
73
74 println!("[+] Found {} files to scan ({} non-Python)", files_to_scan.len(),
75 files_to_scan.iter().filter(|f| !f.ends_with(".py")).count());
76
77 // Scan all files with regex patterns
78 let t_config = std::time::Instant::now();
79 let mut issues: Vec<Issue> = files_to_scan
80 .par_iter()
81 .flat_map(|file_path| {
82 if let Ok(content) = fs::read_to_string(file_path) {
83 config_analysis::scan_file(file_path, &content, &context.ruleset)
84 } else {
85 Vec::new()
86 }
87 })
88 .collect();
89 println!("[*] Pattern/config scan: {:.2}s → {} issues", t_config.elapsed().as_secs_f64(), issues.len());
90

Callers 1

run_scan_pyFunction · 0.85

Calls 9

compile_exclusionsFunction · 0.85
is_excludedFunction · 0.85
scan_fileFunction · 0.85
scan_astFunction · 0.85
build_call_graphFunction · 0.85
severity_rankFunction · 0.85
is_emptyMethod · 0.80
get_fingerprintMethod · 0.80

Tested by

no test coverage detected