mago_reference/
lib.rs

1use serde::Deserialize;
2use serde::Serialize;
3
4use mago_interner::StringIdentifier;
5use mago_interner::ThreadedInterner;
6use mago_project::module::Module;
7use mago_span::HasSpan;
8use mago_span::Span;
9use mago_syntax::ast::Program;
10use mago_syntax::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}