Skip to main content

mir_analyzer/
symbol.rs

1//! Per-expression resolved symbol data, retained from body analysis.
2//!
3//! The static analyzer already resolves types for every expression during
4//! analysis but historically discarded the intermediate state.  This module
5//! exposes that data so that downstream tools can build position indexes for
6//! hover, go-to-definition, and completions.
7
8use std::sync::Arc;
9
10use mir_types::Type;
11use php_ast::Span;
12
13/// A single resolved symbol observed during body analysis.
14#[derive(Debug, Clone)]
15pub struct ResolvedSymbol {
16    /// Absolute path of the file this symbol was found in.
17    pub file: Arc<str>,
18    /// Byte-offset span in the source file.
19    pub span: Span,
20    /// What kind of symbol this is.
21    pub kind: ReferenceKind,
22    /// The resolved type at this location.
23    pub resolved_type: Type,
24}
25
26impl ResolvedSymbol {
27    /// Return the reference-index lookup key, or `None` for kinds that are not
28    /// tracked there (e.g. variables). Delegates to [`ReferenceKind::to_name`].
29    pub fn codebase_key(&self) -> Option<String> {
30        self.kind.to_name().map(|name| name.codebase_key())
31    }
32
33    /// Convert to a typed [`crate::Name`] for use with
34    /// [`crate::AnalysisSession::definition_of`], [`crate::AnalysisSession::references_to`],
35    /// or [`crate::AnalysisSession::hover`]. Delegates to [`ReferenceKind::to_name`].
36    pub fn to_symbol(&self) -> Option<crate::Name> {
37        self.kind.to_name()
38    }
39}
40
41/// One declaration emitted by [`crate::AnalysisSession::document_symbols`].
42/// Tool-agnostic shape for outline / breadcrumb features; consumers map this
43/// onto whatever protocol-specific symbol type they need.
44///
45/// Forms a tree: classes/interfaces/traits/enums have `children` populated
46/// with their methods, properties, and constants. Top-level functions and
47/// constants have empty `children`.
48#[derive(Debug, Clone)]
49pub struct DocumentSymbol {
50    /// FQCN for classes/interfaces/traits/enums; FQN for functions /
51    /// constants; short name for members nested inside a class.
52    pub name: Arc<str>,
53    /// Coarse kind suitable for icon / severity selection in outlines.
54    pub kind: DeclarationKind,
55    /// Source location of the declaration (file + 1-based lines, 0-based
56    /// columns). `None` only for synthetic stub-only definitions that don't
57    /// have a recorded source span.
58    pub location: Option<mir_types::Location>,
59    /// For container symbols (Class, Interface, Trait, Enum), the nested
60    /// methods, properties, and constants declared on this type. Empty for
61    /// leaf kinds (Function, Constant, etc.).
62    pub children: Vec<DocumentSymbol>,
63}
64
65/// Coarse declaration kind used by [`DocumentSymbol`]. Maps onto outline-style
66/// symbol kinds in any consumer protocol.
67#[derive(Debug, Clone, Copy, PartialEq, Eq)]
68pub enum DeclarationKind {
69    Class,
70    Interface,
71    Trait,
72    Enum,
73    Function,
74    Method,
75    Property,
76    Constant,
77    EnumCase,
78}
79
80/// The kind of symbol reference that was resolved.
81#[derive(Debug, Clone)]
82pub enum ReferenceKind {
83    /// A variable reference (`$foo`).
84    Variable(Arc<str>),
85    /// An instance method call (`$obj->method()`).
86    MethodCall { class: Arc<str>, method: Arc<str> },
87    /// A static method call (`Foo::method()`).
88    StaticCall { class: Arc<str>, method: Arc<str> },
89    /// A property access (`$obj->prop`).
90    PropertyAccess { class: Arc<str>, property: Arc<str> },
91    /// A free function call (`foo()`).
92    FunctionCall(Arc<str>),
93    /// A class reference (`new Foo`, `instanceof Foo`, type hints).
94    ClassReference(Arc<str>),
95    /// A class constant access (`Config::VERSION`, `self::CONST`, `parent::CONST`).
96    ConstantAccess { class: Arc<str>, constant: Arc<str> },
97}
98
99impl ReferenceKind {
100    /// Map to a typed [`crate::Name`], or `None` for kinds that don't correspond
101    /// to a codebase-level symbol (currently only `Variable`).
102    pub fn to_name(&self) -> Option<crate::Name> {
103        match self {
104            ReferenceKind::MethodCall { class, method }
105            | ReferenceKind::StaticCall { class, method } => {
106                Some(crate::Name::method(class.clone(), method.as_ref()))
107            }
108            ReferenceKind::PropertyAccess { class, property } => {
109                Some(crate::Name::property(class.clone(), property.clone()))
110            }
111            ReferenceKind::FunctionCall(fqn) => Some(crate::Name::function(fqn.clone())),
112            ReferenceKind::ClassReference(fqcn) => Some(crate::Name::class(fqcn.clone())),
113            ReferenceKind::ConstantAccess { class, constant } => {
114                Some(crate::Name::class_constant(class.clone(), constant.clone()))
115            }
116            ReferenceKind::Variable(_) => None,
117        }
118    }
119}