fn get_qg_violation_summary_rows(results: &QualityGateResults) -> [(&'static str, u64); 9] {
[
(
"Complexity",
results.complexity_violations.try_into().unwrap_or(0),
),
(
"Dead Code",
results.dead_code_violations.try_into().unwrap_or(0),
),
("SATD", results.satd_violations.try_into().unwrap_or(0)),
(
"Entropy",
results.entropy_violations.try_into().unwrap_or(0),
),
(
"Security",
results.security_violations.try_into().unwrap_or(0),
),
(
"Duplicates",
results.duplicate_violations.try_into().unwrap_or(0),
),
(
"Coverage",
results.coverage_violations.try_into().unwrap_or(0),
),
(
"Sections",
results.section_violations.try_into().unwrap_or(0),
),
(
"Provability",
results.provability_violations.try_into().unwrap_or(0),
),
]
}
#[must_use]
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "path_exists")]
pub fn detect_toolchain(path: &Path) -> Option<String> {
super::detect_primary_language(path)
}
#[must_use]
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn build_complexity_thresholds(
max_cyclomatic: Option<u16>,
max_cognitive: Option<u16>,
) -> (u16, u16) {
(max_cyclomatic.unwrap_or(10), max_cognitive.unwrap_or(15))
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "path_exists")]
pub async fn analyze_project_files(
project_path: &Path,
toolchain: Option<&str>,
include: &[String],
cyclomatic_threshold: u16,
cognitive_threshold: u16,
) -> Result<Vec<crate::services::complexity::FileComplexityMetrics>> {
use crate::services::file_discovery::{FileDiscoveryConfig, ProjectFileDiscovery};
let discovery_config = FileDiscoveryConfig {
respect_gitignore: true, ..Default::default()
};
let discovery =
ProjectFileDiscovery::new(project_path.to_path_buf()).with_config(discovery_config);
let discovered_files = discovery.discover_files()?;
let extensions = get_file_extensions(toolchain);
let files_to_analyze: Vec<_> = discovered_files
.into_iter()
.filter(|path| {
let extension = path.extension().and_then(|ext| ext.to_str()).unwrap_or("");
if !extensions.contains(&extension) {
return false;
}
if !include.is_empty() {
matches_include_patterns(path, project_path, include)
} else {
true }
})
.collect();
if files_to_analyze.is_empty() {
return Ok(Vec::new());
}
let batch_size = std::cmp::min(files_to_analyze.len(), 20); let mut results = Vec::new();
for batch in files_to_analyze.chunks(batch_size) {
let batch_futures: Vec<_> = batch
.iter()
.map(|path| analyze_complexity_file(path, cyclomatic_threshold, cognitive_threshold))
.collect();
let batch_results = futures::future::try_join_all(batch_futures).await?;
for metrics in batch_results.into_iter().flatten() {
results.push(metrics);
}
}
Ok(results)
}
#[must_use]
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn get_file_extensions(toolchain: Option<&str>) -> Vec<&'static str> {
match toolchain {
Some("rust") => vec!["rs"],
Some("deno" | "typescript") => vec!["ts", "tsx", "js", "jsx"],
Some("javascript") => vec!["js", "jsx"], Some("python-uv" | "python") => vec!["py"],
Some("c") => vec!["c", "h"], Some("cpp" | "c++") => vec!["cpp", "cc", "cxx", "hpp", "h", "hxx"], Some("go") => vec!["go"],
Some("java") => vec!["java"],
Some("kotlin") => vec!["kt", "kts"],
Some("ruby") => vec!["rb"],
Some("php") => vec!["php"],
Some("swift") => vec!["swift"],
Some("csharp" | "cs") => vec!["cs"],
Some("bash") => vec!["sh", "bash"],
Some("lua") => vec!["lua"],
Some("lean") => vec!["lean"],
Some(_) => vec!["rs"], None => {
vec![
"rs", "py", "ts", "tsx", "js", "jsx", "go", "java", "kt", "kts", "c", "cpp", "cc",
"cxx", "rb", "php", "swift", "cs", "lua", "lean",
]
}
}
}
#[must_use]
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "path_exists")]
pub fn should_analyze_file(
path: &Path,
project_path: &Path,
extensions: &[&str],
include: &[String],
) -> bool {
let extension = path.extension().and_then(|ext| ext.to_str()).unwrap_or("");
if !extensions.contains(&extension) {
return false;
}
if include.is_empty() {
!is_excluded_path(path)
} else {
matches_include_patterns(path, project_path, include)
}
}
fn matches_include_patterns(path: &Path, project_path: &Path, include: &[String]) -> bool {
use glob::Pattern;
let path_str = path.to_string_lossy();
let relative_path = path.strip_prefix(project_path).unwrap_or(path);
let relative_str = relative_path.to_string_lossy();
include.iter().any(|pattern| match Pattern::new(pattern) {
Ok(glob_pattern) => glob_pattern.matches(&relative_str) || glob_pattern.matches(&path_str),
Err(_) => path_str.contains(pattern),
})
}
fn is_excluded_path(path: &Path) -> bool {
let path_str = path.to_string_lossy();
if is_excluded_directory(&path_str) {
return true;
}
if let Some(file_name) = path.file_name() {
let fname = file_name.to_string_lossy();
is_excluded_filename(&fname)
} else {
false
}
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn is_excluded_directory(path_str: &str) -> bool {
let normalized = path_str.replace('\\', "/");
let excluded_dir_names = [
"target",
"build",
"out",
".cargo",
"node_modules",
"dist",
".git",
"vendor",
"generated",
".aws-sam",
"coverage",
"__pycache__",
".pytest_cache",
".cache",
"tmp",
".venv",
"venv",
"ENV",
"env",
".terraform",
"site",
"_site",
".jekyll-cache",
".idea",
".vscode",
];
let excluded_path_patterns = [
"/target/",
"/build/",
"/out/",
"/.cargo/",
"/node_modules/",
"/dist/",
"/.git/",
"/vendor/",
"/generated/",
"/.aws-sam/",
"/coverage/",
"/__pycache__/",
"/.pytest_cache/",
"/.cache/",
"/tmp/",
"/.venv/",
"/venv/",
"/ENV/",
"/env/",
"/.terraform/",
"/site/",
"/_site/",
"/.jekyll-cache/",
"/.idea/",
"/.vscode/",
"/tests/",
"/test/",
"/examples/",
"/benches/",
"/benchmarks/",
"/fixtures/",
"/testdata/",
"/test_data/",
"/debug_test/",
"/test-",
];
if excluded_path_patterns
.iter()
.any(|pattern| normalized.contains(pattern))
{
return true;
}
let path_components: Vec<&str> = normalized.trim_start_matches("./").split('/').collect();
if let Some(first_component) = path_components.first() {
if excluded_dir_names.contains(first_component) {
return true;
}
}
false
}
#[must_use]
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn is_excluded_filename(filename: &str) -> bool {
is_test_file(filename)
|| is_example_or_demo_file(filename)
|| is_benchmark_file(filename)
|| is_mock_or_stub_file(filename)
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn is_test_file(filename: &str) -> bool {
const TEST_SUFFIXES: &[&str] = &["_test.rs", "_tests.rs", "tests.rs"];
const TEST_PREFIXES: &[&str] = &["test_", "tests_"];
const TEST_CONTAINS: &[&str] = &[
"_test_",
"_tests_",
"test_harness",
"test_helpers",
"test_utils",
"_property_test",
"property_tests",
];
TEST_SUFFIXES.iter().any(|s| filename.ends_with(s))
|| TEST_PREFIXES.iter().any(|p| filename.starts_with(p))
|| TEST_CONTAINS.iter().any(|c| filename.contains(c))
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn is_example_or_demo_file(filename: &str) -> bool {
const EXAMPLE_DEMO_PREFIXES: &[&str] = &["example_", "demo_"];
const EXAMPLE_DEMO_CONTAINS: &[&str] = &["_example", "_demo"];
EXAMPLE_DEMO_PREFIXES
.iter()
.any(|p| filename.starts_with(p))
|| EXAMPLE_DEMO_CONTAINS.iter().any(|c| filename.contains(c))
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn is_benchmark_file(filename: &str) -> bool {
const BENCH_SUFFIXES: &[&str] = &["_bench.rs", "_benchmark.rs"];
const BENCH_CONTAINS: &[&str] = &["bench_", "benchmark_"];
BENCH_SUFFIXES.iter().any(|s| filename.ends_with(s))
|| BENCH_CONTAINS.iter().any(|c| filename.contains(c))
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn is_mock_or_stub_file(filename: &str) -> bool {
const MOCK_STUB_PREFIXES: &[&str] = &["mock_", "stub_", "stubs_"];
const MOCK_STUB_CONTAINS: &[&str] = &["_mock", "_stub", "_stubs"];
MOCK_STUB_PREFIXES.iter().any(|p| filename.starts_with(p))
|| MOCK_STUB_CONTAINS.iter().any(|c| filename.contains(c))
}
async fn analyze_complexity_file(
path: &Path,
cyclomatic_threshold: u16,
cognitive_threshold: u16,
) -> Result<Option<crate::services::complexity::FileComplexityMetrics>> {
match tokio::fs::read_to_string(path).await {
Ok(content) => {
let metrics = analyze_file_complexity_async(
path,
&content,
cyclomatic_threshold,
cognitive_threshold,
)
.await?;
Ok(Some(metrics))
}
Err(_) => Ok(None),
}
}
async fn analyze_file_complexity_async(
path: &Path,
content: &str,
_cyclomatic_threshold: u16,
_cognitive_threshold: u16,
) -> Result<crate::services::complexity::FileComplexityMetrics> {
crate::cli::language_analyzer::analyze_file_complexity(path, content).await
}
#[must_use]
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn add_top_files_ranking(
files: Vec<crate::services::complexity::FileComplexityMetrics>,
top_files: usize,
) -> Vec<crate::services::complexity::FileComplexityMetrics> {
if top_files == 0 {
files
} else {
files.into_iter().take(top_files).collect()
}
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "path_exists")]
pub fn format_dead_code_output(
format: DeadCodeOutputFormat,
dead_code_result: &crate::models::dead_code::DeadCodeResult,
_output: Option<PathBuf>,
) -> Result<()> {
crate::cli::dead_code_formatter::format_and_output_dead_code(format, dead_code_result, _output)
}