ownsight_core/
analysis.rs1use crate::model::*;
2use crate::graph::*;
3use anyhow::Result;
4
5pub struct Analyzer {
6 pub analysis: ProgramAnalysis,
7}
8
9impl Analyzer {
10 pub fn new(mode: AnalysisMode) -> Self {
11 Self {
12 analysis: ProgramAnalysis::new(mode),
13 }
14 }
15
16 pub fn analyze_snippet(&mut self, code: &str, filename: &str) -> Result<()> {
17 let source_file = SourceFile::new(filename.to_string(), code.to_string());
18 self.analysis.files.push(source_file);
19
20 Ok(())
21 }
22
23 pub fn build_ownership_graph(&mut self) {
24 for event in &self.analysis.events {
25 let var_node = GraphNode::Variable(event.variable_id);
26 self.analysis.ownership_graph.add_node(var_node.clone());
27
28 match event.kind {
29 EventKind::MoveOut => {
30 if let Some(related_id) = event.related_variable_id {
31 let target_node = GraphNode::Variable(related_id);
32 self.analysis.ownership_graph.add_node(target_node.clone());
33 self.analysis.ownership_graph.add_edge(
34 GraphEdge::new(var_node, target_node, EdgeKind::MovesTo)
35 );
36 }
37 }
38 EventKind::BorrowShared => {
39 if let Some(related_id) = event.related_variable_id {
40 let ref_node = GraphNode::Reference(related_id);
41 self.analysis.ownership_graph.add_node(ref_node.clone());
42 self.analysis.ownership_graph.add_edge(
43 GraphEdge::new(ref_node, var_node, EdgeKind::Borrows)
44 );
45 }
46 }
47 EventKind::BorrowMut => {
48 if let Some(related_id) = event.related_variable_id {
49 let ref_node = GraphNode::Reference(related_id);
50 self.analysis.ownership_graph.add_node(ref_node.clone());
51 self.analysis.ownership_graph.add_edge(
52 GraphEdge::new(ref_node, var_node, EdgeKind::MutablyBorrows)
53 );
54 }
55 }
56 _ => {}
57 }
58 }
59 }
60
61 pub fn query_why_cant_use(&self, var_id: VariableId, line: usize) -> Option<String> {
62 let state = self.analysis.get_ownership_state_at_line(line);
63
64 if state.is_moved(var_id) {
65 let move_events: Vec<_> = self.analysis.events.iter()
66 .filter(|e| e.variable_id == var_id && e.kind == EventKind::MoveOut && e.line_number < line)
67 .collect();
68
69 if let Some(move_event) = move_events.last() {
70 let var = self.analysis.get_variable(var_id)?;
71 return Some(format!(
72 "Cannot use `{}` because it was moved at line {}. {}",
73 var.name, move_event.line_number, move_event.explanation
74 ));
75 }
76 }
77
78 None
79 }
80
81 pub fn query_where_moved(&self, var_id: VariableId) -> Vec<usize> {
82 self.analysis.events.iter()
83 .filter(|e| e.variable_id == var_id && e.kind == EventKind::MoveOut)
84 .map(|e| e.line_number)
85 .collect()
86 }
87
88 pub fn query_what_borrows(&self, var_id: VariableId, line: usize) -> Vec<String> {
89 let state = self.analysis.get_ownership_state_at_line(line);
90 let mut results = Vec::new();
91
92 for borrow in &state.active_borrows {
93 if borrow.borrowed_var == var_id {
94 if let Some(borrow_var_id) = borrow.borrow_var {
95 if let Some(var) = self.analysis.get_variable(borrow_var_id) {
96 let borrow_type = if borrow.is_mutable { "mutably" } else { "immutably" };
97 results.push(format!("`{}` is borrowed {} by `{}`",
98 self.analysis.get_variable(var_id).map(|v| v.name.as_str()).unwrap_or("?"),
99 borrow_type,
100 var.name
101 ));
102 }
103 }
104 }
105 }
106
107 results
108 }
109
110 pub fn finalize(mut self) -> ProgramAnalysis {
111 self.build_ownership_graph();
112 self.analysis
113 }
114}