1use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet};
2
3use diagnostics::{PatternIssue, UnusedExpressionKind};
4use syntax::ast::{BindingId, BindingKind, DeadCodeCause, Span};
5
6#[derive(Debug, Default)]
7pub struct Facts {
8 next_id: BindingId,
9 pub bindings: HashMap<BindingId, BindingFact>,
10 pub dead_code: Vec<DeadCodeFact>,
11 pub pattern_issues: Vec<PatternIssue>,
12 pub unused_expressions: Vec<UnusedExpressionFact>,
13 pub discarded_tail_expressions: Vec<DiscardedTailFact>,
14 pub overused_references: Vec<OverusedReferenceFact>,
15 pub unused_type_params: Vec<UnusedTypeParamFact>,
16 pub always_failing_try_blocks: Vec<Span>,
17 pub expression_only_fstrings: Vec<Span>,
18 pub or_pattern_error_spans: HashSet<Span>,
20 pub usages: Vec<Usage>,
22 usage_set: HashSet<(Span, Span)>,
23 pub interface_satisfied_methods: HashMap<(String, String), Vec<Span>>,
26}
27
28impl Facts {
29 pub fn new() -> Self {
30 Self::default()
31 }
32
33 fn new_binding_id(&mut self) -> BindingId {
34 let id = self.next_id;
35 self.next_id += 1;
36 id
37 }
38
39 pub fn add_binding(
40 &mut self,
41 name: String,
42 span: Span,
43 kind: BindingKind,
44 is_typedef: bool,
45 is_struct_field: bool,
46 ) -> BindingId {
47 let id = self.new_binding_id();
48 self.bindings.insert(
49 id,
50 BindingFact {
51 name,
52 span,
53 kind,
54 used: false,
55 mutated: false,
56 is_typedef,
57 is_struct_field,
58 },
59 );
60 id
61 }
62
63 pub fn mark_used(&mut self, id: BindingId) {
64 if let Some(fact) = self.bindings.get_mut(&id) {
65 fact.used = true;
66 }
67 }
68
69 pub fn mark_mutated(&mut self, id: BindingId) {
70 if let Some(fact) = self.bindings.get_mut(&id) {
71 fact.mutated = true;
72 }
73 }
74
75 pub fn binding_checkpoint(&self) -> BindingId {
76 self.next_id
77 }
78
79 pub fn remove_bindings_from(&mut self, checkpoint: BindingId) {
80 self.bindings.retain(|id, _| *id < checkpoint);
81 self.next_id = checkpoint;
82 }
83
84 pub fn add_dead_code(&mut self, span: Span, cause: DeadCodeCause) {
85 self.dead_code.push(DeadCodeFact { span, cause });
86 }
87
88 pub fn add_unused_expression(&mut self, span: Span, kind: UnusedExpressionKind) {
89 self.unused_expressions
90 .push(UnusedExpressionFact { span, kind });
91 }
92
93 pub fn add_discarded_tail(&mut self, span: Span, kind: DiscardedTailKind, return_type: String) {
94 self.discarded_tail_expressions.push(DiscardedTailFact {
95 span,
96 kind,
97 return_type,
98 });
99 }
100
101 pub fn add_overused_reference(&mut self, span: Span, name: Option<String>) {
102 self.overused_references
103 .push(OverusedReferenceFact { span, name });
104 }
105
106 pub fn add_unused_type_param(&mut self, name: String, span: Span, is_typedef: bool) {
107 self.unused_type_params.push(UnusedTypeParamFact {
108 name,
109 span,
110 is_typedef,
111 });
112 }
113
114 pub fn add_always_failing_try_block(&mut self, span: Span) {
115 self.always_failing_try_blocks.push(span);
116 }
117
118 pub fn add_expression_only_fstring(&mut self, span: Span) {
119 self.expression_only_fstrings.push(span);
120 }
121
122 pub fn add_usage(&mut self, usage_span: Span, definition_span: Span) {
123 if self.usage_set.insert((usage_span, definition_span)) {
124 self.usages.push(Usage {
125 usage_span,
126 definition_span,
127 });
128 }
129 }
130
131 pub fn mark_method_used_for_interface(
132 &mut self,
133 module_id: String,
134 method_name: String,
135 usage_span: Span,
136 ) {
137 self.interface_satisfied_methods
138 .entry((module_id, method_name))
139 .or_default()
140 .push(usage_span);
141 }
142}
143
144#[derive(Debug, Clone)]
145pub struct BindingFact {
146 pub name: String,
147 pub span: Span,
148 pub kind: BindingKind,
149 pub used: bool,
150 pub mutated: bool,
151 pub is_typedef: bool,
152 pub is_struct_field: bool,
154}
155
156#[derive(Debug, Clone)]
157pub struct DeadCodeFact {
158 pub span: Span,
159 pub cause: DeadCodeCause,
160}
161
162#[derive(Debug, Clone)]
163pub struct UnusedExpressionFact {
164 pub span: Span,
165 pub kind: UnusedExpressionKind,
166}
167
168#[derive(Debug, Clone, Copy, PartialEq, Eq)]
169pub enum DiscardedTailKind {
170 Result,
171 Option,
172 Partial,
173}
174
175#[derive(Debug, Clone)]
176pub struct DiscardedTailFact {
177 pub span: Span,
178 pub kind: DiscardedTailKind,
179 pub return_type: String,
180}
181
182#[derive(Debug, Clone)]
183pub struct OverusedReferenceFact {
184 pub span: Span,
185 pub name: Option<String>,
186}
187
188#[derive(Debug, Clone)]
189pub struct UnusedTypeParamFact {
190 pub name: String,
191 pub span: Span,
192 pub is_typedef: bool,
193}
194
195#[derive(Debug, Clone)]
198pub struct Usage {
199 pub usage_span: Span,
200 pub definition_span: Span,
201}