mago_names/
lib.rs

1use std::collections::HashSet;
2
3use ahash::HashMap;
4use serde::Serialize;
5
6use mago_span::HasPosition;
7use mago_span::Position;
8
9pub mod kind;
10pub mod resolver;
11pub mod scope;
12
13mod internal;
14
15/// Stores the results of a name resolution pass over a PHP program.
16///
17/// Maps source code positions (specifically, the starting byte offset of identifiers)
18/// to their resolved fully qualified name (`StringIdentifier`) and a flag indicating
19/// whether the resolution involved an explicit `use` alias or construct.
20#[derive(Debug, Clone, Eq, PartialEq, Serialize, Default)]
21pub struct ResolvedNames<'arena> {
22    /// Internal map storing: position (byte offset) -> (Resolved Name ID, Was Imported Flag)
23    names: HashMap<u32, (&'arena str, bool)>,
24}
25
26impl<'arena> ResolvedNames<'arena> {
27    /// Returns the total number of resolved names stored.
28    pub fn len(&self) -> usize {
29        self.names.len()
30    }
31
32    /// Returns `true` if no resolved names are stored.
33    pub fn is_empty(&self) -> bool {
34        self.names.is_empty()
35    }
36
37    /// Checks if a resolved name exists for the given source `Position`.
38    pub fn contains(&self, position: &Position) -> bool {
39        self.names.contains_key(&position.offset)
40    }
41
42    /// Gets the resolved name identifier for the given source position.
43    ///
44    /// # Panics
45    ///
46    /// Panics if no resolved name is found at the specified `position`.
47    /// Use `contains` first if unsure.
48    pub fn get<T: HasPosition>(&self, position: &T) -> &'arena str {
49        self.names.get(&position.offset()).map(|(name, _)| name).expect("resolved name not found at position")
50    }
51
52    /// Checks if the name resolved at the given position originated from an explicit `use` alias or construct.
53    ///
54    /// Returns `false` if the name was resolved relative to the namespace, is a definition,
55    /// or if no name is found at the position.
56    pub fn is_imported<T: HasPosition>(&self, position: &T) -> bool {
57        self.names
58            .get(&position.offset()) // Get Option<(StringIdentifier, bool)>
59            .map(|(_, imported)| *imported) // Extract the bool flag
60            .unwrap_or(false) // Default to false if position not found
61    }
62
63    /// Inserts a resolution result into the map (intended for internal use).
64    ///
65    /// Associates the resolved `name` identifier and its `imported` status with the
66    /// given `position` (byte offset).
67    pub(crate) fn insert_at<T: HasPosition>(&mut self, position: &T, name: &'arena str, imported: bool) {
68        self.names.insert(position.offset(), (name, imported));
69    }
70
71    /// Returns a `HashSet` containing references to all stored resolution results.
72    ///
73    /// Each element in the set is a reference to a tuple: `(&usize, &(StringIdentifier, bool))`,
74    /// representing `(&position, &(resolved_name_id, was_imported_flag))`.
75    pub fn all(&self) -> HashSet<(&u32, &(&'arena str, bool))> {
76        HashSet::from_iter(self.names.iter())
77    }
78}