1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
//! Position → resolved-type queries backed by mir's body analysis.
//!
//! mir's `FileAnalyzer::analyze` already resolves a [`mir_analyzer::Type`] for
//! every expression it visits and records it as a [`mir_analyzer::ResolvedSymbol`]
//! (see `DocumentStore::cached_analysis`, which retains the result across LSP
//! requests). This module is the thin glue that maps an LSP cursor onto those
//! recorded symbols — replacing the hand-rolled, short-name-only tracker in
//! `type_map` for the variable/expression-type cases.
//!
//! ## Contract callers must respect
//!
//! For variable/identifier symbols, mir spans are **end-exclusive and
//! identifier-only**: the variable `$q` at bytes `76..78` is found by
//! `symbol_at(76)` or `symbol_at(77)` but **not** `symbol_at(78)`. Callers must
//! pass a byte offset that lands strictly inside the token of interest — for a
//! variable, `word_range_at(..).start` (the `$`) is always inside.
//!
//! Call-like symbols (method/static/function calls) additionally carry an
//! `expr_span` covering the whole call node; when an offset misses every
//! identifier token, `symbol_at` falls back to the innermost enclosing call by
//! `expr_span`. Note the convention: for a chain gap that fallback resolves to
//! the *following* call. Consumers wanting a different one (type_definition.rs
//! wants the *preceding* call's return type in `a()$0->b()`) still locate their
//! own in-token offset via the AST.
use ;
use Atomic;
/// The resolved mir type recorded at `offset`, or `None` if no recorded symbol
/// covers it. `offset` is a byte offset that must land strictly inside the
/// token of interest (see the module-level contract).
pub
/// The class/enum FQCN named by a single atomic, if any. Covers object types
/// (`TNamedObject`, `self`/`static`/`parent`) and enum-case literals
/// (`Suit::Hearts` → `Suit`), which is what member/declaration lookups want.
/// The fully-qualified class names named by `ty` — one per named-object atomic,
/// so a union `A|B` yields `["A", "B"]`. Generic parameters are stripped
/// (`Collection<User>` → `Collection`), since callers searching for a class
/// declaration match on the bare FQCN. Scalar/array/callable types yield an
/// empty vec.
///
/// Names are returned exactly as mir produces them: fully qualified with no
/// leading `\` (e.g. `App\Svc\User`), already resolved through the file's
/// namespace and `use` imports.
///
/// **TParent note**: `Atomic::TParent { fqcn }` carries the *containing*
/// class's FQCN (e.g. `"ChildClass"`), not the actual parent. This function
/// returns that fqcn as-is, which is correct for `self`/`static` navigation
/// but wrong for `parent`. type_definition.rs bypasses mir for `parent`-typed
/// parameters to look up the inheritance chain directly via the AST.
pub
/// The single receiver class FQCN for member resolution — the first named
/// object in `ty`. `None` if `ty` names no class.
pub