1use super::*;
2
3impl AnalysisSession {
4 pub fn definition_of(
18 &self,
19 symbol: &crate::Name,
20 ) -> Result<mir_types::Location, crate::SymbolLookupError> {
21 match symbol {
23 crate::Name::Class(fqcn) => {
24 let _ = self.load_class(fqcn.as_ref());
25 }
26 crate::Name::Function(fqn) => {
27 let _ = self.load_class(fqn.as_ref());
28 }
29 crate::Name::Method { class, .. }
30 | crate::Name::Property { class, .. }
31 | crate::Name::ClassConstant { class, .. } => {
32 let _ = self.load_class(class.as_ref());
33 }
34 _ => {}
35 }
36 self.definition_of_cached(symbol)
37 }
38
39 pub fn definition_of_cached(
45 &self,
46 symbol: &crate::Name,
47 ) -> Result<mir_types::Location, crate::SymbolLookupError> {
48 let db = self.snapshot_db();
49 match symbol {
50 crate::Name::Class(fqcn) => {
51 let here = crate::db::Fqcn::from_str(&db, fqcn.as_ref());
52 let class = crate::db::find_class_like(&db, here)
53 .ok_or(crate::SymbolLookupError::NotFound)?;
54 class
55 .location()
56 .cloned()
57 .ok_or(crate::SymbolLookupError::NoSourceLocation)
58 }
59 crate::Name::Function(fqn) => {
60 let here = crate::db::Fqcn::from_str(&db, fqn.as_ref());
61 let f = crate::db::find_function(&db, here)
62 .ok_or(crate::SymbolLookupError::NotFound)?;
63 f.location
64 .clone()
65 .ok_or(crate::SymbolLookupError::NoSourceLocation)
66 }
67 crate::Name::Method { class, name }
68 | crate::Name::Property { class, name }
69 | crate::Name::ClassConstant { class, name } => {
70 crate::db::member_location(&db, class, name)
71 .ok_or(crate::SymbolLookupError::NotFound)
72 }
73 crate::Name::GlobalConstant(_) => Err(crate::SymbolLookupError::NoSourceLocation),
74 }
75 }
76
77 pub fn hover(
91 &self,
92 symbol: &crate::Name,
93 ) -> Result<crate::HoverInfo, crate::SymbolLookupError> {
94 match symbol {
98 crate::Name::Class(fqcn) => {
99 self.load_class(fqcn.as_ref());
100 }
101 crate::Name::Method { class, .. }
102 | crate::Name::Property { class, .. }
103 | crate::Name::ClassConstant { class, .. } => {
104 self.load_class(class.as_ref());
108 }
109 _ => {}
110 }
111 self.hover_cached(symbol)
112 }
113
114 pub fn hover_cached(
117 &self,
118 symbol: &crate::Name,
119 ) -> Result<crate::HoverInfo, crate::SymbolLookupError> {
120 use mir_types::{Atomic, Type};
121 let db = self.snapshot_db();
122 match symbol {
123 crate::Name::Function(fqn) => {
124 let here = crate::db::Fqcn::from_str(&db, fqn.as_ref());
125 let f = crate::db::find_function(&db, here)
126 .ok_or(crate::SymbolLookupError::NotFound)?;
127 let ty = f
128 .return_type
129 .as_deref()
130 .cloned()
131 .unwrap_or_else(Type::mixed);
132 let docstring = f.docstring.as_ref().map(|s| s.to_string());
133 Ok(crate::HoverInfo {
134 ty,
135 docstring,
136 definition: f.location.clone(),
137 })
138 }
139 crate::Name::Method { class, name } => {
140 let here = crate::db::Fqcn::from_str(&db, class.as_ref());
141 let (_, m) = crate::db::find_method_in_chain(&db, here, name)
142 .ok_or(crate::SymbolLookupError::NotFound)?;
143 let ty = m
144 .return_type
145 .as_deref()
146 .cloned()
147 .unwrap_or_else(Type::mixed);
148 let docstring = m.docstring.as_ref().map(|s| s.to_string());
149 Ok(crate::HoverInfo {
150 ty,
151 docstring,
152 definition: m.location.clone(),
153 })
154 }
155 crate::Name::Class(fqcn) => {
156 let here = crate::db::Fqcn::from_str(&db, fqcn.as_ref());
157 let class = crate::db::find_class_like(&db, here)
158 .ok_or(crate::SymbolLookupError::NotFound)?;
159 let ty = Type::single(Atomic::TNamedObject {
160 fqcn: mir_types::Name::from(fqcn.as_ref()),
161 type_params: mir_types::union::empty_type_params(),
162 });
163 Ok(crate::HoverInfo {
164 ty,
165 docstring: None,
166 definition: class.location().cloned(),
167 })
168 }
169 crate::Name::Property { class, name } => {
170 let here = crate::db::Fqcn::from_str(&db, class.as_ref());
171 let (_, p) = crate::db::find_property_in_chain(&db, here, name)
172 .ok_or(crate::SymbolLookupError::NotFound)?;
173 let ty = p.ty.as_deref().cloned().unwrap_or_else(Type::mixed);
174 Ok(crate::HoverInfo {
175 ty,
176 docstring: None,
177 definition: p.location.clone(),
178 })
179 }
180 crate::Name::ClassConstant { class, name } => {
181 let here = crate::db::Fqcn::from_str(&db, class.as_ref());
182 let (_, c) = crate::db::find_class_constant_in_chain(&db, here, name)
183 .ok_or(crate::SymbolLookupError::NotFound)?;
184 Ok(crate::HoverInfo {
185 ty: c.ty.clone(),
186 docstring: None,
187 definition: c.location.clone(),
188 })
189 }
190 crate::Name::GlobalConstant(fqn) => {
191 let here = crate::db::Fqcn::from_str(&db, fqn.as_ref());
192 let ty = crate::db::find_global_constant(&db, here)
193 .ok_or(crate::SymbolLookupError::NotFound)?;
194 Ok(crate::HoverInfo {
195 ty: (*ty).clone(),
196 docstring: None,
197 definition: None,
198 })
199 }
200 }
201 }
202
203 #[doc(hidden)]
207 pub fn reference_locations(&self, symbol: &str) -> Vec<(Arc<str>, u32, u16, u16)> {
208 use crate::db::MirDatabase;
209 let db = self.snapshot_db();
210 db.reference_locations(symbol)
211 }
212
213 pub fn references_to(&self, symbol: &crate::Name) -> Vec<(Arc<str>, crate::Range)> {
217 let db = self.snapshot_db();
218 let key = symbol.codebase_key();
219 db.reference_locations(&key)
220 .into_iter()
221 .map(|(file, line, col_start, col_end)| {
222 let range = crate::Range {
223 start: crate::Position {
224 line,
225 column: col_start as u32,
226 },
227 end: crate::Position {
228 line,
229 column: col_end as u32,
230 },
231 };
232 (file, range)
233 })
234 .collect()
235 }
236
237 pub fn class_issues(&self, files: &[Arc<str>]) -> Vec<crate::Issue> {
247 let db = self.snapshot_db();
248 let file_set: HashSet<Arc<str>> = files.iter().cloned().collect();
249 let file_data: Vec<(Arc<str>, Arc<str>)> = files
250 .iter()
251 .filter_map(|f| Some((f.clone(), self.source_of(f)?)))
252 .collect();
253 crate::class::ClassAnalyzer::with_files(&db, file_set, &file_data).analyze_all()
254 }
255
256 pub fn document_symbols(&self, file: &str) -> Vec<crate::symbol::DocumentSymbol> {
262 use crate::symbol::{DeclarationKind, DocumentSymbol};
263
264 let db = self.snapshot_db();
265 let Some(sf) = db.lookup_source_file(file) else {
266 return Vec::new();
267 };
268 let defs = crate::db::collect_file_definitions(&db, sf);
269 let mut out: Vec<DocumentSymbol> = Vec::new();
270
271 let class_children =
272 |methods: &indexmap::IndexMap<Arc<str>, Arc<mir_codebase::storage::MethodDef>>,
273 props: Option<&indexmap::IndexMap<Arc<str>, mir_codebase::storage::PropertyDef>>,
274 consts: &indexmap::IndexMap<Arc<str>, mir_codebase::storage::ConstantDef>,
275 is_enum: bool|
276 -> Vec<DocumentSymbol> {
277 let mut out: Vec<DocumentSymbol> = Vec::new();
278 for (_, m) in methods.iter() {
279 out.push(DocumentSymbol {
280 name: m.name.clone(),
281 kind: DeclarationKind::Method,
282 location: m.location.clone(),
283 children: Vec::new(),
284 });
285 }
286 if let Some(props) = props {
287 for (_, p) in props.iter() {
288 out.push(DocumentSymbol {
289 name: p.name.clone(),
290 kind: DeclarationKind::Property,
291 location: p.location.clone(),
292 children: Vec::new(),
293 });
294 }
295 }
296 let const_kind = if is_enum {
297 DeclarationKind::EnumCase
298 } else {
299 DeclarationKind::Constant
300 };
301 for (_, c) in consts.iter() {
302 out.push(DocumentSymbol {
303 name: c.name.clone(),
304 kind: const_kind,
305 location: c.location.clone(),
306 children: Vec::new(),
307 });
308 }
309 out
310 };
311
312 for c in defs.slice.classes.iter() {
313 out.push(DocumentSymbol {
314 name: c.fqcn.clone(),
315 kind: DeclarationKind::Class,
316 location: c.location.clone(),
317 children: class_children(
318 &c.own_methods,
319 Some(&c.own_properties),
320 &c.own_constants,
321 false,
322 ),
323 });
324 }
325 for i in defs.slice.interfaces.iter() {
326 out.push(DocumentSymbol {
327 name: i.fqcn.clone(),
328 kind: DeclarationKind::Interface,
329 location: i.location.clone(),
330 children: class_children(&i.own_methods, None, &i.own_constants, false),
331 });
332 }
333 for t in defs.slice.traits.iter() {
334 out.push(DocumentSymbol {
335 name: t.fqcn.clone(),
336 kind: DeclarationKind::Trait,
337 location: t.location.clone(),
338 children: class_children(
339 &t.own_methods,
340 Some(&t.own_properties),
341 &t.own_constants,
342 false,
343 ),
344 });
345 }
346 for e in defs.slice.enums.iter() {
347 let mut children = class_children(&e.own_methods, None, &e.own_constants, true);
348 for (_, case) in e.cases.iter() {
349 children.push(DocumentSymbol {
350 name: case.name.clone(),
351 kind: DeclarationKind::EnumCase,
352 location: case.location.clone(),
353 children: Vec::new(),
354 });
355 }
356 out.push(DocumentSymbol {
357 name: e.fqcn.clone(),
358 kind: DeclarationKind::Enum,
359 location: e.location.clone(),
360 children,
361 });
362 }
363 for f in defs.slice.functions.iter() {
364 out.push(DocumentSymbol {
365 name: f.fqn.clone(),
366 kind: DeclarationKind::Function,
367 location: f.location.clone(),
368 children: Vec::new(),
369 });
370 }
371 for (name, _) in defs.slice.constants.iter() {
372 out.push(DocumentSymbol {
373 name: name.clone(),
374 kind: DeclarationKind::Constant,
375 location: None,
376 children: Vec::new(),
377 });
378 }
379 out
380 }
381}