normalize_facts_rules_api/relations.rs
1//! Relations (facts) that rules operate on.
2//!
3//! These are the inputs to Datalog rules, extracted from code by normalize-facts.
4//! Each relation type maps to a Datalog predicate:
5//!
6//! - `symbol(file, name, kind, line)` - defined symbols
7//! - `import(from_file, to_module, name)` - import statements
8//! - `call(caller_file, caller_name, callee_name, line)` - function calls
9//! - `visibility(file, name, vis)` - symbol visibility
10//! - `attribute(file, name, attr)` - symbol attributes (one per attribute)
11//! - `parent(file, child_name, parent_name)` - symbol nesting hierarchy
12//! - `qualifier(caller_file, caller_name, callee_name, qual)` - call qualifier
13//! - `symbol_range(file, name, start_line, end_line)` - symbol span
14//! - `implements(file, name, interface)` - interface/trait implementation
15//! - `is_impl(file, name)` - symbol is a trait/interface implementation
16//! - `type_method(file, type_name, method_name)` - method signatures on types
17//!
18//! Cross-file resolution predicates (Phase 0):
19//!
20//! - `resolved_import(from_file, to_file, imported_name, local_alias, kind)` - resolved imports
21//! - `module(file, canonical_module_path)` - canonical module identity of a file
22//! - `export(file, name, kind)` - exported symbols
23//! - `reexport(from_file, original_file, original_name, exported_as)` - re-export chains
24//! - `symbol_use(file, name, line)` - symbol reference/use sites
25//! - `resolved_reference(use_file, use_line, def_file, def_name, def_kind)` - resolved symbol refs
26//! - `resolved_call(caller_file, caller_name, callee_file, callee_name, line)` - resolved calls
27//! - `module_search_path(workspace_root, language, kind, path)` - module search paths
28
29/// A symbol fact: a named entity defined in a file.
30///
31/// Maps to Datalog: `symbol(file, name, kind, line)`
32#[derive(Clone, Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
33#[rkyv(derive(Debug))]
34pub struct SymbolFact {
35 /// File path relative to project root
36 pub file: String,
37 /// Symbol name
38 pub name: String,
39 /// Symbol kind (function, class, method, etc.)
40 pub kind: String,
41 /// Line number where symbol is defined
42 pub line: u32,
43}
44
45/// An import fact: a dependency from one file to another module.
46///
47/// Maps to Datalog: `import(from_file, to_module, name)`
48#[derive(Clone, Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
49#[rkyv(derive(Debug))]
50pub struct ImportFact {
51 /// File containing the import
52 pub from_file: String,
53 /// Raw module specifier as written in the source.
54 ///
55 /// The value depends on the language and import style:
56 ///
57 /// - **Relative or absolute file path** — e.g. `"../foo"`, `"./utils"` (JS/TS, Python
58 /// relative imports). The path is as written in source, not resolved to an absolute path.
59 /// - **Module name** — e.g. `"os"` (Python stdlib), `"std::collections"` (Rust), `"fmt"`
60 /// (Go). These are not file paths and cannot be resolved without a module resolver.
61 /// - **Empty string `""`** — when the grammar does not expose a module path for the
62 /// import, or for star imports that name no explicit module (e.g. some wildcard import
63 /// syntaxes). Callers should treat `""` as "module not known".
64 ///
65 /// Resolved file paths (when available) are stored separately in the index, not here.
66 pub module_specifier: String,
67 /// Name being imported (or "*" for wildcard)
68 pub name: String,
69}
70
71/// A call fact: a function call from one symbol to another.
72///
73/// Maps to Datalog: `call(caller_file, caller_name, callee_name, line)`
74#[derive(Clone, Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
75#[rkyv(derive(Debug))]
76pub struct CallFact {
77 /// File containing the call
78 pub caller_file: String,
79 /// Name of the calling function/method
80 pub caller_name: String,
81 /// Name of the called function/method
82 pub callee_name: String,
83 /// Line number of the call
84 pub line: u32,
85}
86
87/// A visibility fact: the visibility of a symbol.
88///
89/// Maps to Datalog: `visibility(file, name, vis)`
90#[derive(Clone, Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
91#[rkyv(derive(Debug))]
92pub struct VisibilityFact {
93 /// File path relative to project root
94 pub file: String,
95 /// Symbol name
96 pub name: String,
97 /// Visibility: "public", "private", "protected", "internal"
98 pub visibility: String,
99}
100
101/// An attribute fact: one attribute annotation on a symbol.
102///
103/// Maps to Datalog: `attribute(file, name, attr)`
104#[derive(Clone, Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
105#[rkyv(derive(Debug))]
106pub struct AttributeFact {
107 /// File path relative to project root
108 pub file: String,
109 /// Symbol name
110 pub name: String,
111 /// Attribute string (e.g. "#[derive(Debug)]", "@Override")
112 pub attribute: String,
113}
114
115/// A parent fact: symbol nesting hierarchy.
116///
117/// Maps to Datalog: `parent(file, child_name, parent_name)`
118#[derive(Clone, Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
119#[rkyv(derive(Debug))]
120pub struct ParentFact {
121 /// File path relative to project root
122 pub file: String,
123 /// Child symbol name
124 pub child_name: String,
125 /// Parent symbol name
126 pub parent_name: String,
127}
128
129/// A qualifier fact: call qualifier (receiver/module).
130///
131/// Maps to Datalog: `qualifier(caller_file, caller_name, callee_name, qual)`
132#[derive(Clone, Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
133#[rkyv(derive(Debug))]
134pub struct QualifierFact {
135 /// File containing the call
136 pub caller_file: String,
137 /// Name of the calling function/method
138 pub caller_name: String,
139 /// Name of the called function/method
140 pub callee_name: String,
141 /// Qualifier ("self", module name, etc.)
142 pub qualifier: String,
143}
144
145/// A symbol range fact: start and end lines of a symbol.
146///
147/// Maps to Datalog: `symbol_range(file, name, start_line, end_line)`
148#[derive(Clone, Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
149#[rkyv(derive(Debug))]
150pub struct SymbolRangeFact {
151 /// File path relative to project root
152 pub file: String,
153 /// Symbol name
154 pub name: String,
155 /// Start line number
156 pub start_line: u32,
157 /// End line number
158 pub end_line: u32,
159}
160
161/// An implements fact: a symbol implements an interface/trait.
162///
163/// Maps to Datalog: `implements(file, name, interface)`
164#[derive(Clone, Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
165#[rkyv(derive(Debug))]
166pub struct ImplementsFact {
167 /// File path relative to project root
168 pub file: String,
169 /// Symbol name
170 pub name: String,
171 /// Interface/trait name
172 pub interface: String,
173}
174
175/// An is_impl fact: symbol is a trait/interface implementation.
176///
177/// Maps to Datalog: `is_impl(file, name)`
178#[derive(Clone, Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
179#[rkyv(derive(Debug))]
180pub struct IsImplFact {
181 /// File path relative to project root
182 pub file: String,
183 /// Symbol name
184 pub name: String,
185}
186
187/// A type method fact: a method signature on a type.
188///
189/// Maps to Datalog: `type_method(file, type_name, method_name)`
190#[derive(Clone, Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
191#[rkyv(derive(Debug))]
192pub struct TypeMethodFact {
193 /// File path relative to project root
194 pub file: String,
195 /// Type (interface/class) name
196 pub type_name: String,
197 /// Method name
198 pub method_name: String,
199}
200
201/// A resolved import fact: an import statement resolved to a specific file.
202///
203/// Maps to Datalog: `resolved_import(from_file, to_file, imported_name, local_alias, kind)`
204/// kind ∈ {"direct", "glob", "reexport", "unresolved"}
205#[derive(Clone, Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
206#[rkyv(derive(Debug))]
207pub struct ResolvedImportFact {
208 /// File containing the import
209 pub from_file: String,
210 /// Resolved target file
211 pub to_file: String,
212 /// The imported name (e.g. "HashMap", "*" for glob)
213 pub imported_name: String,
214 /// Local alias (same as imported_name if no alias)
215 pub local_alias: String,
216 /// Resolution kind: "direct", "glob", "reexport", or "unresolved"
217 pub kind: String,
218}
219
220/// A module fact: canonical module identity of a file.
221///
222/// Maps to Datalog: `module(file, canonical_module_path)`
223#[derive(Clone, Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
224#[rkyv(derive(Debug))]
225pub struct ModuleFact {
226 /// File path relative to project root
227 pub file: String,
228 /// Canonical module path (e.g. "mycrate::foo::bar")
229 pub canonical_module_path: String,
230}
231
232/// An export fact: a symbol exported from a file.
233///
234/// Maps to Datalog: `export(file, name, kind)`
235/// kind ∈ {"value", "type", "module", "reexport"}
236#[derive(Clone, Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
237#[rkyv(derive(Debug))]
238pub struct ExportFact {
239 /// File path relative to project root
240 pub file: String,
241 /// Exported name
242 pub name: String,
243 /// Export kind: "value", "type", "module", or "reexport"
244 pub kind: String,
245}
246
247/// A reexport fact: a symbol re-exported through an intermediate file.
248///
249/// Maps to Datalog: `reexport(from_file, original_file, original_name, exported_as)`
250#[derive(Clone, Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
251#[rkyv(derive(Debug))]
252pub struct ReexportFact {
253 /// File doing the re-export
254 pub from_file: String,
255 /// File where the symbol is originally defined
256 pub original_file: String,
257 /// Original name of the symbol
258 pub original_name: String,
259 /// Name it is exported as (may differ with `as` alias)
260 pub exported_as: String,
261}
262
263/// A symbol use fact: a reference/use site of a named symbol.
264///
265/// Maps to Datalog: `symbol_use(file, name, line)`
266#[derive(Clone, Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
267#[rkyv(derive(Debug))]
268pub struct SymbolUseFact {
269 /// File containing the use
270 pub file: String,
271 /// Name being used
272 pub name: String,
273 /// Line number of the use
274 pub line: u32,
275}
276
277/// A resolved reference fact: a symbol use resolved to its definition.
278///
279/// Maps to Datalog: `resolved_reference(use_file, use_line, def_file, def_name, def_kind)`
280#[derive(Clone, Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
281#[rkyv(derive(Debug))]
282pub struct ResolvedReferenceFact {
283 /// File containing the use
284 pub use_file: String,
285 /// Line of the use
286 pub use_line: u32,
287 /// File containing the definition
288 pub def_file: String,
289 /// Name of the defined symbol
290 pub def_name: String,
291 /// Kind of the defined symbol
292 pub def_kind: String,
293}
294
295/// A resolved call fact: a function call resolved to its definition file.
296///
297/// Maps to Datalog: `resolved_call(caller_file, caller_name, callee_file, callee_name, line)`
298#[derive(Clone, Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
299#[rkyv(derive(Debug))]
300pub struct ResolvedCallFact {
301 /// File containing the call
302 pub caller_file: String,
303 /// Name of the calling function
304 pub caller_name: String,
305 /// File containing the callee definition
306 pub callee_file: String,
307 /// Name of the called function
308 pub callee_name: String,
309 /// Line number of the call
310 pub line: u32,
311}
312
313/// A module search path fact: a directory to search for modules.
314///
315/// Maps to Datalog: `module_search_path(workspace_root, language, kind, path)`
316#[derive(Clone, Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
317#[rkyv(derive(Debug))]
318pub struct ModuleSearchPathFact {
319 /// Workspace root this path belongs to
320 pub workspace_root: String,
321 /// Language this path applies to (e.g. "rust", "python")
322 pub language: String,
323 /// Kind of search path (e.g. "source", "stdlib", "third-party")
324 pub kind: String,
325 /// The search path
326 pub path: String,
327}
328
329/// A CFG block fact.
330///
331/// Maps to Datalog: `cfg_block(file, func, func_line, block, kind)`
332#[derive(Clone, Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
333#[rkyv(derive(Debug))]
334pub struct CfgBlockFact {
335 /// Source file path
336 pub file: String,
337 /// Qualified function name
338 pub func: String,
339 /// Function start line (1-based)
340 pub func_line: u32,
341 /// Block ID (0-based, unique within function)
342 pub block: u32,
343 /// Block kind (e.g. "entry", "exit", "branch", "loophead")
344 pub kind: String,
345}
346
347/// A CFG edge fact.
348///
349/// Maps to Datalog: `cfg_edge(file, func, func_line, from, to, kind, exception_type)`
350///
351/// `exception_type` is only meaningful for `kind == "exception"` edges:
352/// - Empty string = conservative (type unknown, applies to any exception).
353/// - Non-empty string = the exception type name (e.g. `"IOException"`).
354#[derive(Clone, Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
355#[rkyv(derive(Debug))]
356pub struct CfgEdgeFact {
357 /// Source file path
358 pub file: String,
359 /// Qualified function name
360 pub func: String,
361 /// Function start line (1-based)
362 pub func_line: u32,
363 /// Source block ID
364 pub from: u32,
365 /// Target block ID
366 pub to: u32,
367 /// Edge kind (e.g. "fallthrough", "conditionaltrue", "backedge", "exception")
368 pub kind: String,
369 /// Exception type for `kind == "exception"` edges. Empty string = conservative.
370 pub exception_type: String,
371}
372
373/// A CFG variable definition fact.
374///
375/// Maps to Datalog: `cfg_def(file, func, func_line, block, name)`
376#[derive(Clone, Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
377#[rkyv(derive(Debug))]
378pub struct CfgDefFact {
379 /// Source file path
380 pub file: String,
381 /// Qualified function name
382 pub func: String,
383 /// Function start line (1-based)
384 pub func_line: u32,
385 /// Block ID this def occurs in
386 pub block: u32,
387 /// Name of the variable being defined
388 pub name: String,
389}
390
391/// A CFG variable use fact.
392///
393/// Maps to Datalog: `cfg_use(file, func, func_line, block, name)`
394#[derive(Clone, Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
395#[rkyv(derive(Debug))]
396pub struct CfgUseFact {
397 /// Source file path
398 pub file: String,
399 /// Qualified function name
400 pub func: String,
401 /// Function start line (1-based)
402 pub func_line: u32,
403 /// Block ID this use occurs in
404 pub block: u32,
405 /// Name of the variable being used
406 pub name: String,
407}
408
409/// A CFG side-effect fact.
410///
411/// Maps to Datalog: `cfg_effect(file, func, func_line, block, kind, line, label)`
412///
413/// `kind` is one of: `"await"`, `"defer"`, `"yield"`, `"acquire"`, `"release"`, `"send"`, `"receive"`.
414/// `label` is an optional text label (resource name, expression text, etc.; empty string if absent).
415#[derive(Clone, Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
416#[rkyv(derive(Debug))]
417pub struct CfgEffectFact {
418 /// Source file path
419 pub file: String,
420 /// Qualified function name
421 pub func: String,
422 /// Function start line (1-based)
423 pub func_line: u32,
424 /// Block ID this effect occurs in
425 pub block: u32,
426 /// Effect kind string (e.g. "await", "defer", "yield")
427 pub kind: String,
428 /// Source line of the effect (1-based)
429 pub line: u32,
430 /// Optional label (resource name, expression text). Empty string if absent.
431 pub label: String,
432}
433
434/// All relations (facts) available to rules.
435///
436/// This is the complete set of facts extracted from a codebase.
437/// Rule packs receive this and apply Datalog rules over it.
438#[derive(Clone, Debug, Default, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
439#[rkyv(derive(Debug))]
440pub struct Relations {
441 /// All symbols defined in the codebase
442 pub symbols: Vec<SymbolFact>,
443 /// All imports in the codebase
444 pub imports: Vec<ImportFact>,
445 /// All function calls in the codebase
446 pub calls: Vec<CallFact>,
447 /// Symbol visibility facts
448 pub visibilities: Vec<VisibilityFact>,
449 /// Symbol attribute facts (one per attribute per symbol)
450 pub attributes: Vec<AttributeFact>,
451 /// Symbol parent-child hierarchy
452 pub parents: Vec<ParentFact>,
453 /// Call qualifier facts (receiver/module on calls)
454 pub qualifiers: Vec<QualifierFact>,
455 /// Symbol range facts (start and end lines)
456 pub symbol_ranges: Vec<SymbolRangeFact>,
457 /// Implements facts (symbol implements interface/trait)
458 pub implements: Vec<ImplementsFact>,
459 /// Is-impl facts (symbol is a trait/interface implementation)
460 pub is_impls: Vec<IsImplFact>,
461 /// Type method facts (method signatures on types)
462 pub type_methods: Vec<TypeMethodFact>,
463 /// Resolved import facts (import resolved to a specific file)
464 pub resolved_imports: Vec<ResolvedImportFact>,
465 /// Module identity facts (file → canonical module path)
466 pub modules: Vec<ModuleFact>,
467 /// Export facts (symbol exported from a file)
468 pub exports: Vec<ExportFact>,
469 /// Reexport facts (symbol re-exported through an intermediate)
470 pub reexports: Vec<ReexportFact>,
471 /// Symbol use facts (reference/use sites)
472 pub symbol_uses: Vec<SymbolUseFact>,
473 /// Resolved reference facts (use resolved to definition)
474 pub resolved_references: Vec<ResolvedReferenceFact>,
475 /// Resolved call facts (call resolved to definition file)
476 pub resolved_calls: Vec<ResolvedCallFact>,
477 /// Module search path facts (directories to search for modules)
478 pub module_search_paths: Vec<ModuleSearchPathFact>,
479 /// CFG block facts (one per basic block per function)
480 pub cfg_blocks: Vec<CfgBlockFact>,
481 /// CFG edge facts (one per control-flow edge per function)
482 pub cfg_edges: Vec<CfgEdgeFact>,
483 /// CFG variable definition facts (one per def site per block)
484 pub cfg_defs: Vec<CfgDefFact>,
485 /// CFG variable use facts (one per use site per block)
486 pub cfg_uses: Vec<CfgUseFact>,
487 /// CFG side-effect facts (await, defer, yield, acquire, release, send, receive)
488 pub cfg_effects: Vec<CfgEffectFact>,
489}
490
491impl Relations {
492 /// Create empty relations
493 pub fn new() -> Self {
494 Self::default()
495 }
496
497 /// Add a symbol fact
498 pub fn add_symbol(&mut self, file: &str, name: &str, kind: &str, line: u32) {
499 self.symbols.push(SymbolFact {
500 file: file.into(),
501 name: name.into(),
502 kind: kind.into(),
503 line,
504 });
505 }
506
507 /// Add an import fact
508 pub fn add_import(&mut self, from_file: &str, to_module: &str, name: &str) {
509 self.imports.push(ImportFact {
510 from_file: from_file.into(),
511 module_specifier: to_module.into(),
512 name: name.into(),
513 });
514 }
515
516 /// Add a call fact
517 pub fn add_call(&mut self, caller_file: &str, caller_name: &str, callee_name: &str, line: u32) {
518 self.calls.push(CallFact {
519 caller_file: caller_file.into(),
520 caller_name: caller_name.into(),
521 callee_name: callee_name.into(),
522 line,
523 });
524 }
525
526 /// Add a visibility fact
527 pub fn add_visibility(&mut self, file: &str, name: &str, visibility: &str) {
528 self.visibilities.push(VisibilityFact {
529 file: file.into(),
530 name: name.into(),
531 visibility: visibility.into(),
532 });
533 }
534
535 /// Add an attribute fact
536 pub fn add_attribute(&mut self, file: &str, name: &str, attribute: &str) {
537 self.attributes.push(AttributeFact {
538 file: file.into(),
539 name: name.into(),
540 attribute: attribute.into(),
541 });
542 }
543
544 /// Add a parent fact
545 pub fn add_parent(&mut self, file: &str, child_name: &str, parent_name: &str) {
546 self.parents.push(ParentFact {
547 file: file.into(),
548 child_name: child_name.into(),
549 parent_name: parent_name.into(),
550 });
551 }
552
553 /// Add a qualifier fact
554 pub fn add_qualifier(
555 &mut self,
556 caller_file: &str,
557 caller_name: &str,
558 callee_name: &str,
559 qualifier: &str,
560 ) {
561 self.qualifiers.push(QualifierFact {
562 caller_file: caller_file.into(),
563 caller_name: caller_name.into(),
564 callee_name: callee_name.into(),
565 qualifier: qualifier.into(),
566 });
567 }
568
569 /// Add a symbol range fact
570 pub fn add_symbol_range(&mut self, file: &str, name: &str, start_line: u32, end_line: u32) {
571 self.symbol_ranges.push(SymbolRangeFact {
572 file: file.into(),
573 name: name.into(),
574 start_line,
575 end_line,
576 });
577 }
578
579 /// Add an implements fact
580 pub fn add_implements(&mut self, file: &str, name: &str, interface: &str) {
581 self.implements.push(ImplementsFact {
582 file: file.into(),
583 name: name.into(),
584 interface: interface.into(),
585 });
586 }
587
588 /// Add an is_impl fact
589 pub fn add_is_impl(&mut self, file: &str, name: &str) {
590 self.is_impls.push(IsImplFact {
591 file: file.into(),
592 name: name.into(),
593 });
594 }
595
596 /// Add a type method fact
597 pub fn add_type_method(&mut self, file: &str, type_name: &str, method_name: &str) {
598 self.type_methods.push(TypeMethodFact {
599 file: file.into(),
600 type_name: type_name.into(),
601 method_name: method_name.into(),
602 });
603 }
604
605 /// Add a resolved import fact
606 pub fn add_resolved_import(
607 &mut self,
608 from_file: &str,
609 to_file: &str,
610 imported_name: &str,
611 local_alias: &str,
612 kind: &str,
613 ) {
614 self.resolved_imports.push(ResolvedImportFact {
615 from_file: from_file.into(),
616 to_file: to_file.into(),
617 imported_name: imported_name.into(),
618 local_alias: local_alias.into(),
619 kind: kind.into(),
620 });
621 }
622
623 /// Add a module fact
624 pub fn add_module(&mut self, file: &str, canonical_module_path: &str) {
625 self.modules.push(ModuleFact {
626 file: file.into(),
627 canonical_module_path: canonical_module_path.into(),
628 });
629 }
630
631 /// Add an export fact
632 pub fn add_export(&mut self, file: &str, name: &str, kind: &str) {
633 self.exports.push(ExportFact {
634 file: file.into(),
635 name: name.into(),
636 kind: kind.into(),
637 });
638 }
639
640 /// Add a reexport fact
641 pub fn add_reexport(
642 &mut self,
643 from_file: &str,
644 original_file: &str,
645 original_name: &str,
646 exported_as: &str,
647 ) {
648 self.reexports.push(ReexportFact {
649 from_file: from_file.into(),
650 original_file: original_file.into(),
651 original_name: original_name.into(),
652 exported_as: exported_as.into(),
653 });
654 }
655
656 /// Add a symbol use fact
657 pub fn add_symbol_use(&mut self, file: &str, name: &str, line: u32) {
658 self.symbol_uses.push(SymbolUseFact {
659 file: file.into(),
660 name: name.into(),
661 line,
662 });
663 }
664
665 /// Add a resolved reference fact
666 pub fn add_resolved_reference(
667 &mut self,
668 use_file: &str,
669 use_line: u32,
670 def_file: &str,
671 def_name: &str,
672 def_kind: &str,
673 ) {
674 self.resolved_references.push(ResolvedReferenceFact {
675 use_file: use_file.into(),
676 use_line,
677 def_file: def_file.into(),
678 def_name: def_name.into(),
679 def_kind: def_kind.into(),
680 });
681 }
682
683 /// Add a resolved call fact
684 pub fn add_resolved_call(
685 &mut self,
686 caller_file: &str,
687 caller_name: &str,
688 callee_file: &str,
689 callee_name: &str,
690 line: u32,
691 ) {
692 self.resolved_calls.push(ResolvedCallFact {
693 caller_file: caller_file.into(),
694 caller_name: caller_name.into(),
695 callee_file: callee_file.into(),
696 callee_name: callee_name.into(),
697 line,
698 });
699 }
700
701 /// Add a module search path fact
702 pub fn add_module_search_path(
703 &mut self,
704 workspace_root: &str,
705 language: &str,
706 kind: &str,
707 path: &str,
708 ) {
709 self.module_search_paths.push(ModuleSearchPathFact {
710 workspace_root: workspace_root.into(),
711 language: language.into(),
712 kind: kind.into(),
713 path: path.into(),
714 });
715 }
716
717 /// Add a CFG block fact
718 pub fn add_cfg_block(
719 &mut self,
720 file: &str,
721 func: &str,
722 func_line: u32,
723 block: u32,
724 kind: &str,
725 ) {
726 self.cfg_blocks.push(CfgBlockFact {
727 file: file.into(),
728 func: func.into(),
729 func_line,
730 block,
731 kind: kind.into(),
732 });
733 }
734
735 /// Add a CFG edge fact
736 #[allow(clippy::too_many_arguments)]
737 pub fn add_cfg_edge(
738 &mut self,
739 file: &str,
740 func: &str,
741 func_line: u32,
742 from: u32,
743 to: u32,
744 kind: &str,
745 exception_type: &str,
746 ) {
747 self.cfg_edges.push(CfgEdgeFact {
748 file: file.into(),
749 func: func.into(),
750 func_line,
751 from,
752 to,
753 kind: kind.into(),
754 exception_type: exception_type.into(),
755 });
756 }
757
758 /// Add a CFG variable definition fact
759 pub fn add_cfg_def(&mut self, file: &str, func: &str, func_line: u32, block: u32, name: &str) {
760 self.cfg_defs.push(CfgDefFact {
761 file: file.into(),
762 func: func.into(),
763 func_line,
764 block,
765 name: name.into(),
766 });
767 }
768
769 /// Add a CFG variable use fact
770 pub fn add_cfg_use(&mut self, file: &str, func: &str, func_line: u32, block: u32, name: &str) {
771 self.cfg_uses.push(CfgUseFact {
772 file: file.into(),
773 func: func.into(),
774 func_line,
775 block,
776 name: name.into(),
777 });
778 }
779
780 /// Add a CFG side-effect fact
781 #[allow(clippy::too_many_arguments)]
782 pub fn add_cfg_effect(
783 &mut self,
784 file: &str,
785 func: &str,
786 func_line: u32,
787 block: u32,
788 kind: &str,
789 line: u32,
790 label: &str,
791 ) {
792 self.cfg_effects.push(CfgEffectFact {
793 file: file.into(),
794 func: func.into(),
795 func_line,
796 block,
797 kind: kind.into(),
798 line,
799 label: label.into(),
800 });
801 }
802}