use std::collections::BTreeMap;
use std::sync::Arc;
use pedant_types::{
CapabilityAnalysis, CapabilityFinding, CapabilityProfile, CapabilitySymbol,
CapabilitySymbolKind, Language, SourceLocation, SymbolAttributionStatus,
SymbolCapabilityProfile,
};
use crate::ir::FileIr;
use crate::ir::facts::FnFact;
use super::draft::{CapabilityDraft, DraftedFinding};
pub(crate) fn project_analysis(ir: &FileIr, draft: CapabilityDraft) -> CapabilityAnalysis {
let entries = draft.into_entries();
let symbols = symbol_profiles(ir, &entries);
let findings: Box<[CapabilityFinding]> =
entries.into_iter().map(|entry| entry.finding).collect();
CapabilityAnalysis {
profile: CapabilityProfile { findings },
symbol_attribution: SymbolAttributionStatus::Complete,
symbols,
}
}
fn symbol_profiles(ir: &FileIr, entries: &[DraftedFinding]) -> Box<[SymbolCapabilityProfile]> {
grouped_by_callable(entries)
.into_iter()
.filter_map(|(index, positions)| profile_for(ir, entries, index, &positions))
.collect()
}
fn grouped_by_callable(entries: &[DraftedFinding]) -> BTreeMap<usize, Vec<usize>> {
let mut grouped: BTreeMap<usize, Vec<usize>> = BTreeMap::new();
for (position, entry) in entries.iter().enumerate() {
if let Some(index) = entry.containing_fn {
grouped.entry(index).or_default().push(position);
}
}
grouped
}
fn profile_for(
ir: &FileIr,
entries: &[DraftedFinding],
index: usize,
positions: &[usize],
) -> Option<SymbolCapabilityProfile> {
let declared = ir.functions.get(index)?;
let findings = positions
.iter()
.map(|&position| entries[position].finding.clone())
.collect();
Some(SymbolCapabilityProfile {
symbol: symbol(&ir.file_path, declared),
profile: CapabilityProfile { findings },
})
}
fn symbol(file: &Arc<str>, declared: &FnFact) -> CapabilitySymbol {
CapabilitySymbol {
language: Language::Rust,
kind: match declared.is_associated {
true => CapabilitySymbolKind::Method,
false => CapabilitySymbolKind::Function,
},
name: declared.name.clone(),
declaration: SourceLocation {
file: Arc::clone(file),
line: declared.span.line,
column: declared.span.column + 1,
},
}
}