mago_reference/lib.rs
1use serde::Deserialize;
2use serde::Serialize;
3
4use mago_ast::Program;
5use mago_interner::StringIdentifier;
6use mago_interner::ThreadedInterner;
7use mago_project::module::Module;
8use mago_span::HasSpan;
9use mago_span::Span;
10use mago_walker::Walker;
11
12use crate::internal::context::Context;
13use crate::internal::walker::ReferenceFindingWalker;
14use crate::query::Query;
15
16pub mod query;
17
18mod internal;
19
20/// Represents the kind of reference that is found in code.
21///
22/// Each variant corresponds to a specific way in which a symbol might be
23/// referred to in code. For instance, an import statement, a usage, or
24/// a definition site.
25#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
26pub enum ReferenceKind {
27 /// Indicates where a symbol is imported into a scope.
28 Import,
29
30 /// Refers to places in code where the symbol is used.
31 Usage,
32
33 /// Points to the definition site(s) of the symbol.
34 Definition,
35
36 /// Identifies where a symbol (like an interface) is
37 /// implemented, or where a trait is applied.
38 Implementation,
39
40 /// Tracks places where a class is extended.
41 Extension,
42}
43
44/// Describes a single reference to a symbol in the source code.
45#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
46pub struct Reference {
47 /// The identifier for the referenced symbol, as stored in the interner.
48 pub value: StringIdentifier,
49
50 /// The kind of reference—import, usage, definition, etc. (see [`ReferenceKind`]).
51 pub kind: ReferenceKind,
52
53 /// The [`Span`] in the source code where this reference appears.
54 pub span: Span,
55}
56
57/// Provides functionality for discovering references (imports, usages, definitions, etc.)
58/// of a symbol within a module.
59///
60/// The [`ReferenceFinder`] can locate references by walking through the AST
61/// (via a [`Walker`]) and collecting relevant `Reference` items.
62#[derive(Debug, Clone)]
63pub struct ReferenceFinder<'a> {
64 /// The interner used to resolve symbol names (e.g., function names, class names, etc.).
65 interner: &'a ThreadedInterner,
66}
67
68impl<'a> ReferenceFinder<'a> {
69 /// Creates a new `ReferenceFinder` that uses the given [`ThreadedInterner`]
70 /// for string lookups and resolutions.
71 pub fn new(interner: &'a ThreadedInterner) -> Self {
72 Self { interner }
73 }
74
75 /// Finds all references that match the given [`Query`] within the provided [`Module`].
76 ///
77 /// This method:
78 ///
79 /// 1. Creates a [`Context`] that holds the interner, the query, and the current module.
80 /// 2. Uses a specialized [`Walker`] (`ReferenceFindingWalker`) to traverse the AST of the program.
81 /// 3. Gathers references (e.g., [`ReferenceKind::Usage`], [`ReferenceKind::Definition`]) in the context.
82 /// 4. Returns all discovered references as a `Vec<Reference>`.
83 ///
84 /// A list of [`Reference`] objects describing where and how the symbol is referenced
85 /// in the code.
86 pub fn find(&self, module: &Module, program: &Program, query: Query) -> Vec<Reference> {
87 let mut context = Context::new(self.interner, &query, module);
88
89 ReferenceFindingWalker.walk_program(program, &mut context);
90
91 context.take_references()
92 }
93}
94
95impl HasSpan for Reference {
96 fn span(&self) -> Span {
97 self.span
98 }
99}