impl DagBuilder {
#[must_use]
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn new() -> Self {
Self {
graph: DependencyGraph::new(),
function_map: FxHashMap::default(),
type_map: FxHashMap::default(),
namer: SemanticNamer::new(),
}
}
#[must_use]
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn build_from_project(project: &ProjectContext) -> DependencyGraph {
let mut builder = Self::new();
for file in &project.files {
builder.collect_nodes(file);
}
for file in &project.files {
builder.process_relationships(file);
}
builder.finalize_graph()
}
const EDGE_BUDGET: usize = 400;
fn finalize_graph(mut self) -> DependencyGraph {
let valid_nodes: FxHashSet<&String> = self.graph.nodes.keys().collect();
self.graph
.edges
.retain(|edge| valid_nodes.contains(&edge.from) && valid_nodes.contains(&edge.to));
if self.graph.edges.len() > Self::EDGE_BUDGET {
self.prune_edges_by_priority();
}
self.graph
}
fn prune_edges_by_priority(&mut self) {
let priority = |edge_type: &EdgeType| -> u8 {
match edge_type {
EdgeType::Inherits => 0,
EdgeType::Uses => 1,
EdgeType::Implements => 2,
EdgeType::Calls => 3,
EdgeType::Imports => 4,
}
};
self.graph
.edges
.sort_unstable_by_key(|e| priority(&e.edge_type));
self.graph.edges.truncate(Self::EDGE_BUDGET);
let retained_nodes: FxHashSet<String> = self
.graph
.edges
.iter()
.flat_map(|e| [e.from.clone(), e.to.clone()])
.collect();
self.graph.nodes.retain(|id, _| retained_nodes.contains(id));
}
#[must_use]
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn build_from_project_with_limit(
project: &ProjectContext,
max_nodes: usize,
) -> DependencyGraph {
let graph = Self::build_from_project(project);
let graph = add_pagerank_scores(graph);
if graph.edges.len() > 400 {
prune_graph_pagerank(&graph, max_nodes)
} else {
graph
}
}
}
impl Default for DagBuilder {
fn default() -> Self {
Self::new()
}
}