diff options
Diffstat (limited to 'crates/ra_ide_db/src/defs.rs')
-rw-r--r-- | crates/ra_ide_db/src/defs.rs | 349 |
1 files changed, 0 insertions, 349 deletions
diff --git a/crates/ra_ide_db/src/defs.rs b/crates/ra_ide_db/src/defs.rs deleted file mode 100644 index 9bb95277d..000000000 --- a/crates/ra_ide_db/src/defs.rs +++ /dev/null | |||
@@ -1,349 +0,0 @@ | |||
1 | //! `NameDefinition` keeps information about the element we want to search references for. | ||
2 | //! The element is represented by `NameKind`. It's located inside some `container` and | ||
3 | //! has a `visibility`, which defines a search scope. | ||
4 | //! Note that the reference search is possible for not all of the classified items. | ||
5 | |||
6 | // FIXME: this badly needs rename/rewrite (matklad, 2020-02-06). | ||
7 | |||
8 | use hir::{ | ||
9 | db::HirDatabase, Crate, Field, HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef, | ||
10 | Name, PathResolution, Semantics, TypeParam, Visibility, | ||
11 | }; | ||
12 | use ra_prof::profile; | ||
13 | use ra_syntax::{ | ||
14 | ast::{self, AstNode}, | ||
15 | match_ast, SyntaxNode, | ||
16 | }; | ||
17 | |||
18 | use crate::RootDatabase; | ||
19 | |||
20 | // FIXME: a more precise name would probably be `Symbol`? | ||
21 | #[derive(Debug, PartialEq, Eq, Copy, Clone)] | ||
22 | pub enum Definition { | ||
23 | Macro(MacroDef), | ||
24 | Field(Field), | ||
25 | ModuleDef(ModuleDef), | ||
26 | SelfType(ImplDef), | ||
27 | Local(Local), | ||
28 | TypeParam(TypeParam), | ||
29 | } | ||
30 | |||
31 | impl Definition { | ||
32 | pub fn module(&self, db: &RootDatabase) -> Option<Module> { | ||
33 | match self { | ||
34 | Definition::Macro(it) => it.module(db), | ||
35 | Definition::Field(it) => Some(it.parent_def(db).module(db)), | ||
36 | Definition::ModuleDef(it) => it.module(db), | ||
37 | Definition::SelfType(it) => Some(it.module(db)), | ||
38 | Definition::Local(it) => Some(it.module(db)), | ||
39 | Definition::TypeParam(it) => Some(it.module(db)), | ||
40 | } | ||
41 | } | ||
42 | |||
43 | pub fn visibility(&self, db: &RootDatabase) -> Option<Visibility> { | ||
44 | match self { | ||
45 | Definition::Macro(_) => None, | ||
46 | Definition::Field(sf) => Some(sf.visibility(db)), | ||
47 | Definition::ModuleDef(def) => def.definition_visibility(db), | ||
48 | Definition::SelfType(_) => None, | ||
49 | Definition::Local(_) => None, | ||
50 | Definition::TypeParam(_) => None, | ||
51 | } | ||
52 | } | ||
53 | |||
54 | pub fn name(&self, db: &RootDatabase) -> Option<Name> { | ||
55 | let name = match self { | ||
56 | Definition::Macro(it) => it.name(db)?, | ||
57 | Definition::Field(it) => it.name(db), | ||
58 | Definition::ModuleDef(def) => match def { | ||
59 | hir::ModuleDef::Module(it) => it.name(db)?, | ||
60 | hir::ModuleDef::Function(it) => it.name(db), | ||
61 | hir::ModuleDef::Adt(def) => match def { | ||
62 | hir::Adt::Struct(it) => it.name(db), | ||
63 | hir::Adt::Union(it) => it.name(db), | ||
64 | hir::Adt::Enum(it) => it.name(db), | ||
65 | }, | ||
66 | hir::ModuleDef::EnumVariant(it) => it.name(db), | ||
67 | hir::ModuleDef::Const(it) => it.name(db)?, | ||
68 | hir::ModuleDef::Static(it) => it.name(db)?, | ||
69 | hir::ModuleDef::Trait(it) => it.name(db), | ||
70 | hir::ModuleDef::TypeAlias(it) => it.name(db), | ||
71 | hir::ModuleDef::BuiltinType(_) => return None, | ||
72 | }, | ||
73 | Definition::SelfType(_) => return None, | ||
74 | Definition::Local(it) => it.name(db)?, | ||
75 | Definition::TypeParam(it) => it.name(db), | ||
76 | }; | ||
77 | Some(name) | ||
78 | } | ||
79 | } | ||
80 | |||
81 | #[derive(Debug)] | ||
82 | pub enum NameClass { | ||
83 | ExternCrate(Crate), | ||
84 | Definition(Definition), | ||
85 | /// `None` in `if let None = Some(82) {}` | ||
86 | ConstReference(Definition), | ||
87 | FieldShorthand { | ||
88 | local: Local, | ||
89 | field: Definition, | ||
90 | }, | ||
91 | } | ||
92 | |||
93 | impl NameClass { | ||
94 | pub fn into_definition(self, db: &dyn HirDatabase) -> Option<Definition> { | ||
95 | Some(match self { | ||
96 | NameClass::ExternCrate(krate) => Definition::ModuleDef(krate.root_module(db).into()), | ||
97 | NameClass::Definition(it) => it, | ||
98 | NameClass::ConstReference(_) => return None, | ||
99 | NameClass::FieldShorthand { local, field: _ } => Definition::Local(local), | ||
100 | }) | ||
101 | } | ||
102 | |||
103 | pub fn definition(self, db: &dyn HirDatabase) -> Definition { | ||
104 | match self { | ||
105 | NameClass::ExternCrate(krate) => Definition::ModuleDef(krate.root_module(db).into()), | ||
106 | NameClass::Definition(it) | NameClass::ConstReference(it) => it, | ||
107 | NameClass::FieldShorthand { local: _, field } => field, | ||
108 | } | ||
109 | } | ||
110 | } | ||
111 | |||
112 | pub fn classify_name(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option<NameClass> { | ||
113 | let _p = profile("classify_name"); | ||
114 | |||
115 | let parent = name.syntax().parent()?; | ||
116 | |||
117 | if let Some(bind_pat) = ast::IdentPat::cast(parent.clone()) { | ||
118 | if let Some(def) = sema.resolve_bind_pat_to_const(&bind_pat) { | ||
119 | return Some(NameClass::ConstReference(Definition::ModuleDef(def))); | ||
120 | } | ||
121 | } | ||
122 | |||
123 | match_ast! { | ||
124 | match parent { | ||
125 | ast::Rename(it) => { | ||
126 | if let Some(use_tree) = it.syntax().parent().and_then(ast::UseTree::cast) { | ||
127 | let path = use_tree.path()?; | ||
128 | let path_segment = path.segment()?; | ||
129 | let name_ref_class = path_segment | ||
130 | .name_ref() | ||
131 | // The rename might be from a `self` token, so fallback to the name higher | ||
132 | // in the use tree. | ||
133 | .or_else(||{ | ||
134 | if path_segment.self_token().is_none() { | ||
135 | return None; | ||
136 | } | ||
137 | |||
138 | let use_tree = use_tree | ||
139 | .syntax() | ||
140 | .parent() | ||
141 | .as_ref() | ||
142 | // Skip over UseTreeList | ||
143 | .and_then(SyntaxNode::parent) | ||
144 | .and_then(ast::UseTree::cast)?; | ||
145 | let path = use_tree.path()?; | ||
146 | let path_segment = path.segment()?; | ||
147 | path_segment.name_ref() | ||
148 | }) | ||
149 | .and_then(|name_ref| classify_name_ref(sema, &name_ref))?; | ||
150 | |||
151 | Some(NameClass::Definition(name_ref_class.definition(sema.db))) | ||
152 | } else { | ||
153 | let extern_crate = it.syntax().parent().and_then(ast::ExternCrate::cast)?; | ||
154 | let resolved = sema.resolve_extern_crate(&extern_crate)?; | ||
155 | Some(NameClass::ExternCrate(resolved)) | ||
156 | } | ||
157 | }, | ||
158 | ast::IdentPat(it) => { | ||
159 | let local = sema.to_def(&it)?; | ||
160 | |||
161 | if let Some(record_field_pat) = it.syntax().parent().and_then(ast::RecordPatField::cast) { | ||
162 | if record_field_pat.name_ref().is_none() { | ||
163 | if let Some(field) = sema.resolve_record_field_pat(&record_field_pat) { | ||
164 | let field = Definition::Field(field); | ||
165 | return Some(NameClass::FieldShorthand { local, field }); | ||
166 | } | ||
167 | } | ||
168 | } | ||
169 | |||
170 | Some(NameClass::Definition(Definition::Local(local))) | ||
171 | }, | ||
172 | ast::RecordField(it) => { | ||
173 | let field: hir::Field = sema.to_def(&it)?; | ||
174 | Some(NameClass::Definition(Definition::Field(field))) | ||
175 | }, | ||
176 | ast::Module(it) => { | ||
177 | let def = sema.to_def(&it)?; | ||
178 | Some(NameClass::Definition(Definition::ModuleDef(def.into()))) | ||
179 | }, | ||
180 | ast::Struct(it) => { | ||
181 | let def: hir::Struct = sema.to_def(&it)?; | ||
182 | Some(NameClass::Definition(Definition::ModuleDef(def.into()))) | ||
183 | }, | ||
184 | ast::Union(it) => { | ||
185 | let def: hir::Union = sema.to_def(&it)?; | ||
186 | Some(NameClass::Definition(Definition::ModuleDef(def.into()))) | ||
187 | }, | ||
188 | ast::Enum(it) => { | ||
189 | let def: hir::Enum = sema.to_def(&it)?; | ||
190 | Some(NameClass::Definition(Definition::ModuleDef(def.into()))) | ||
191 | }, | ||
192 | ast::Trait(it) => { | ||
193 | let def: hir::Trait = sema.to_def(&it)?; | ||
194 | Some(NameClass::Definition(Definition::ModuleDef(def.into()))) | ||
195 | }, | ||
196 | ast::Static(it) => { | ||
197 | let def: hir::Static = sema.to_def(&it)?; | ||
198 | Some(NameClass::Definition(Definition::ModuleDef(def.into()))) | ||
199 | }, | ||
200 | ast::Variant(it) => { | ||
201 | let def: hir::EnumVariant = sema.to_def(&it)?; | ||
202 | Some(NameClass::Definition(Definition::ModuleDef(def.into()))) | ||
203 | }, | ||
204 | ast::Fn(it) => { | ||
205 | let def: hir::Function = sema.to_def(&it)?; | ||
206 | Some(NameClass::Definition(Definition::ModuleDef(def.into()))) | ||
207 | }, | ||
208 | ast::Const(it) => { | ||
209 | let def: hir::Const = sema.to_def(&it)?; | ||
210 | Some(NameClass::Definition(Definition::ModuleDef(def.into()))) | ||
211 | }, | ||
212 | ast::TypeAlias(it) => { | ||
213 | let def: hir::TypeAlias = sema.to_def(&it)?; | ||
214 | Some(NameClass::Definition(Definition::ModuleDef(def.into()))) | ||
215 | }, | ||
216 | ast::MacroCall(it) => { | ||
217 | let def = sema.to_def(&it)?; | ||
218 | Some(NameClass::Definition(Definition::Macro(def))) | ||
219 | }, | ||
220 | ast::TypeParam(it) => { | ||
221 | let def = sema.to_def(&it)?; | ||
222 | Some(NameClass::Definition(Definition::TypeParam(def))) | ||
223 | }, | ||
224 | _ => None, | ||
225 | } | ||
226 | } | ||
227 | } | ||
228 | |||
229 | #[derive(Debug)] | ||
230 | pub enum NameRefClass { | ||
231 | ExternCrate(Crate), | ||
232 | Definition(Definition), | ||
233 | FieldShorthand { local: Local, field: Definition }, | ||
234 | } | ||
235 | |||
236 | impl NameRefClass { | ||
237 | pub fn definition(self, db: &dyn HirDatabase) -> Definition { | ||
238 | match self { | ||
239 | NameRefClass::ExternCrate(krate) => Definition::ModuleDef(krate.root_module(db).into()), | ||
240 | NameRefClass::Definition(def) => def, | ||
241 | NameRefClass::FieldShorthand { local, field: _ } => Definition::Local(local), | ||
242 | } | ||
243 | } | ||
244 | } | ||
245 | |||
246 | // Note: we don't have unit-tests for this rather important function. | ||
247 | // It is primarily exercised via goto definition tests in `ra_ide`. | ||
248 | pub fn classify_name_ref( | ||
249 | sema: &Semantics<RootDatabase>, | ||
250 | name_ref: &ast::NameRef, | ||
251 | ) -> Option<NameRefClass> { | ||
252 | let _p = profile("classify_name_ref"); | ||
253 | |||
254 | let parent = name_ref.syntax().parent()?; | ||
255 | |||
256 | if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) { | ||
257 | if let Some(func) = sema.resolve_method_call(&method_call) { | ||
258 | return Some(NameRefClass::Definition(Definition::ModuleDef(func.into()))); | ||
259 | } | ||
260 | } | ||
261 | |||
262 | if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) { | ||
263 | if let Some(field) = sema.resolve_field(&field_expr) { | ||
264 | return Some(NameRefClass::Definition(Definition::Field(field))); | ||
265 | } | ||
266 | } | ||
267 | |||
268 | if let Some(record_field) = ast::RecordExprField::for_field_name(name_ref) { | ||
269 | if let Some((field, local)) = sema.resolve_record_field(&record_field) { | ||
270 | let field = Definition::Field(field); | ||
271 | let res = match local { | ||
272 | None => NameRefClass::Definition(field), | ||
273 | Some(local) => NameRefClass::FieldShorthand { field, local }, | ||
274 | }; | ||
275 | return Some(res); | ||
276 | } | ||
277 | } | ||
278 | |||
279 | if let Some(record_field_pat) = ast::RecordPatField::cast(parent.clone()) { | ||
280 | if let Some(field) = sema.resolve_record_field_pat(&record_field_pat) { | ||
281 | let field = Definition::Field(field); | ||
282 | return Some(NameRefClass::Definition(field)); | ||
283 | } | ||
284 | } | ||
285 | |||
286 | if ast::AssocTypeArg::cast(parent.clone()).is_some() { | ||
287 | // `Trait<Assoc = Ty>` | ||
288 | // ^^^^^ | ||
289 | let path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?; | ||
290 | let resolved = sema.resolve_path(&path)?; | ||
291 | if let PathResolution::Def(ModuleDef::Trait(tr)) = resolved { | ||
292 | if let Some(ty) = tr | ||
293 | .items(sema.db) | ||
294 | .iter() | ||
295 | .filter_map(|assoc| match assoc { | ||
296 | hir::AssocItem::TypeAlias(it) => Some(*it), | ||
297 | _ => None, | ||
298 | }) | ||
299 | .find(|alias| alias.name(sema.db).to_string() == **name_ref.text()) | ||
300 | { | ||
301 | return Some(NameRefClass::Definition(Definition::ModuleDef( | ||
302 | ModuleDef::TypeAlias(ty), | ||
303 | ))); | ||
304 | } | ||
305 | } | ||
306 | } | ||
307 | |||
308 | if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) { | ||
309 | if let Some(path) = macro_call.path() { | ||
310 | if path.qualifier().is_none() { | ||
311 | // Only use this to resolve single-segment macro calls like `foo!()`. Multi-segment | ||
312 | // paths are handled below (allowing `log<|>::info!` to resolve to the log crate). | ||
313 | if let Some(macro_def) = sema.resolve_macro_call(¯o_call) { | ||
314 | return Some(NameRefClass::Definition(Definition::Macro(macro_def))); | ||
315 | } | ||
316 | } | ||
317 | } | ||
318 | } | ||
319 | |||
320 | if let Some(path) = name_ref.syntax().ancestors().find_map(ast::Path::cast) { | ||
321 | if let Some(resolved) = sema.resolve_path(&path) { | ||
322 | return Some(NameRefClass::Definition(resolved.into())); | ||
323 | } | ||
324 | } | ||
325 | |||
326 | let extern_crate = ast::ExternCrate::cast(parent)?; | ||
327 | let resolved = sema.resolve_extern_crate(&extern_crate)?; | ||
328 | Some(NameRefClass::ExternCrate(resolved)) | ||
329 | } | ||
330 | |||
331 | impl From<PathResolution> for Definition { | ||
332 | fn from(path_resolution: PathResolution) -> Self { | ||
333 | match path_resolution { | ||
334 | PathResolution::Def(def) => Definition::ModuleDef(def), | ||
335 | PathResolution::AssocItem(item) => { | ||
336 | let def = match item { | ||
337 | hir::AssocItem::Function(it) => it.into(), | ||
338 | hir::AssocItem::Const(it) => it.into(), | ||
339 | hir::AssocItem::TypeAlias(it) => it.into(), | ||
340 | }; | ||
341 | Definition::ModuleDef(def) | ||
342 | } | ||
343 | PathResolution::Local(local) => Definition::Local(local), | ||
344 | PathResolution::TypeParam(par) => Definition::TypeParam(par), | ||
345 | PathResolution::Macro(def) => Definition::Macro(def), | ||
346 | PathResolution::SelfType(impl_def) => Definition::SelfType(impl_def), | ||
347 | } | ||
348 | } | ||
349 | } | ||