diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-05-23 19:16:46 +0100 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-05-23 19:16:46 +0100 |
commit | afb792acb713442f1ad315354a9edfcdad0a5097 (patch) | |
tree | 68f43512c9c1b3610f11bbebd8dda2d349194a9e /crates/ra_hir/src/code_model.rs | |
parent | 1dc9adc6e27d603f05f794adda91bca8b6dec8ac (diff) | |
parent | ef3169a33a5204c940cc9e0486954b4b35dc3d4d (diff) |
Merge #1316
1316: Simplify code model r=matklad a=matklad
* remove references from types which are now id-based
* remove api/impl separation, as the impl is a tiny fraction of API anyway
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_hir/src/code_model.rs')
-rw-r--r-- | crates/ra_hir/src/code_model.rs | 954 |
1 files changed, 954 insertions, 0 deletions
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs new file mode 100644 index 000000000..49030ce67 --- /dev/null +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -0,0 +1,954 @@ | |||
1 | use std::sync::Arc; | ||
2 | |||
3 | use ra_db::{CrateId, SourceRootId, Edition, FileId}; | ||
4 | use ra_syntax::{ast::{self, NameOwner, TypeAscriptionOwner}, TreeArc}; | ||
5 | |||
6 | use crate::{ | ||
7 | Name, AsName, AstId, Ty, HirFileId, Either, | ||
8 | HirDatabase, DefDatabase, | ||
9 | type_ref::TypeRef, | ||
10 | nameres::{ModuleScope, Namespace, ImportId, CrateModuleId}, | ||
11 | expr::{Body, BodySourceMap, validation::ExprValidator}, | ||
12 | ty::{TraitRef, InferenceResult}, | ||
13 | adt::{EnumVariantId, StructFieldId, VariantDef}, | ||
14 | generics::HasGenericParams, | ||
15 | docs::{Documentation, Docs, docs_from_ast}, | ||
16 | ids::{FunctionId, StructId, EnumId, AstItemDef, ConstId, StaticId, TraitId, TypeAliasId}, | ||
17 | impl_block::ImplBlock, | ||
18 | resolve::Resolver, | ||
19 | diagnostics::{DiagnosticSink}, | ||
20 | traits::{TraitItem, TraitData}, | ||
21 | type_ref::Mutability, | ||
22 | }; | ||
23 | |||
24 | /// hir::Crate describes a single crate. It's the main interface with which | ||
25 | /// a crate's dependencies interact. Mostly, it should be just a proxy for the | ||
26 | /// root module. | ||
27 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
28 | pub struct Crate { | ||
29 | pub(crate) crate_id: CrateId, | ||
30 | } | ||
31 | |||
32 | #[derive(Debug)] | ||
33 | pub struct CrateDependency { | ||
34 | pub krate: Crate, | ||
35 | pub name: Name, | ||
36 | } | ||
37 | |||
38 | impl Crate { | ||
39 | pub fn crate_id(self) -> CrateId { | ||
40 | self.crate_id | ||
41 | } | ||
42 | |||
43 | pub fn dependencies(self, db: &impl DefDatabase) -> Vec<CrateDependency> { | ||
44 | db.crate_graph() | ||
45 | .dependencies(self.crate_id) | ||
46 | .map(|dep| { | ||
47 | let krate = Crate { crate_id: dep.crate_id() }; | ||
48 | let name = dep.as_name(); | ||
49 | CrateDependency { krate, name } | ||
50 | }) | ||
51 | .collect() | ||
52 | } | ||
53 | |||
54 | pub fn root_module(self, db: &impl DefDatabase) -> Option<Module> { | ||
55 | let module_id = db.crate_def_map(self).root(); | ||
56 | let module = Module { krate: self, module_id }; | ||
57 | Some(module) | ||
58 | } | ||
59 | |||
60 | pub fn edition(self, db: &impl DefDatabase) -> Edition { | ||
61 | let crate_graph = db.crate_graph(); | ||
62 | crate_graph.edition(self.crate_id) | ||
63 | } | ||
64 | |||
65 | // FIXME: should this be in source_binder? | ||
66 | pub fn source_root_crates(db: &impl DefDatabase, source_root: SourceRootId) -> Vec<Crate> { | ||
67 | let crate_ids = db.source_root_crates(source_root); | ||
68 | crate_ids.iter().map(|&crate_id| Crate { crate_id }).collect() | ||
69 | } | ||
70 | } | ||
71 | |||
72 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
73 | pub struct Module { | ||
74 | pub(crate) krate: Crate, | ||
75 | pub(crate) module_id: CrateModuleId, | ||
76 | } | ||
77 | |||
78 | /// The defs which can be visible in the module. | ||
79 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
80 | pub enum ModuleDef { | ||
81 | Module(Module), | ||
82 | Function(Function), | ||
83 | Struct(Struct), | ||
84 | Union(Union), | ||
85 | Enum(Enum), | ||
86 | // Can't be directly declared, but can be imported. | ||
87 | EnumVariant(EnumVariant), | ||
88 | Const(Const), | ||
89 | Static(Static), | ||
90 | Trait(Trait), | ||
91 | TypeAlias(TypeAlias), | ||
92 | } | ||
93 | impl_froms!( | ||
94 | ModuleDef: Module, | ||
95 | Function, | ||
96 | Struct, | ||
97 | Union, | ||
98 | Enum, | ||
99 | EnumVariant, | ||
100 | Const, | ||
101 | Static, | ||
102 | Trait, | ||
103 | TypeAlias | ||
104 | ); | ||
105 | |||
106 | pub enum ModuleSource { | ||
107 | SourceFile(TreeArc<ast::SourceFile>), | ||
108 | Module(TreeArc<ast::Module>), | ||
109 | } | ||
110 | |||
111 | impl ModuleSource { | ||
112 | pub(crate) fn new( | ||
113 | db: &impl DefDatabase, | ||
114 | file_id: Option<FileId>, | ||
115 | decl_id: Option<AstId<ast::Module>>, | ||
116 | ) -> ModuleSource { | ||
117 | match (file_id, decl_id) { | ||
118 | (Some(file_id), _) => { | ||
119 | let source_file = db.parse(file_id); | ||
120 | ModuleSource::SourceFile(source_file) | ||
121 | } | ||
122 | (None, Some(item_id)) => { | ||
123 | let module = item_id.to_node(db); | ||
124 | assert!(module.item_list().is_some(), "expected inline module"); | ||
125 | ModuleSource::Module(module.to_owned()) | ||
126 | } | ||
127 | (None, None) => panic!(), | ||
128 | } | ||
129 | } | ||
130 | } | ||
131 | |||
132 | impl Module { | ||
133 | /// Name of this module. | ||
134 | pub fn name(self, db: &impl HirDatabase) -> Option<Name> { | ||
135 | let def_map = db.crate_def_map(self.krate); | ||
136 | let parent = def_map[self.module_id].parent?; | ||
137 | def_map[parent].children.iter().find_map(|(name, module_id)| { | ||
138 | if *module_id == self.module_id { | ||
139 | Some(name.clone()) | ||
140 | } else { | ||
141 | None | ||
142 | } | ||
143 | }) | ||
144 | } | ||
145 | |||
146 | /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items. | ||
147 | pub fn definition_source(self, db: &impl DefDatabase) -> (HirFileId, ModuleSource) { | ||
148 | let def_map = db.crate_def_map(self.krate); | ||
149 | let decl_id = def_map[self.module_id].declaration; | ||
150 | let file_id = def_map[self.module_id].definition; | ||
151 | let module_source = ModuleSource::new(db, file_id, decl_id); | ||
152 | let file_id = file_id.map(HirFileId::from).unwrap_or_else(|| decl_id.unwrap().file_id()); | ||
153 | (file_id, module_source) | ||
154 | } | ||
155 | |||
156 | /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`. | ||
157 | /// `None` for the crate root. | ||
158 | pub fn declaration_source( | ||
159 | self, | ||
160 | db: &impl HirDatabase, | ||
161 | ) -> Option<(HirFileId, TreeArc<ast::Module>)> { | ||
162 | let def_map = db.crate_def_map(self.krate); | ||
163 | let decl = def_map[self.module_id].declaration?; | ||
164 | let ast = decl.to_node(db); | ||
165 | Some((decl.file_id(), ast)) | ||
166 | } | ||
167 | |||
168 | /// Returns the syntax of the last path segment corresponding to this import | ||
169 | pub fn import_source( | ||
170 | self, | ||
171 | db: &impl HirDatabase, | ||
172 | import: ImportId, | ||
173 | ) -> Either<TreeArc<ast::UseTree>, TreeArc<ast::ExternCrateItem>> { | ||
174 | let (file_id, source) = self.definition_source(db); | ||
175 | let (_, source_map) = db.raw_items_with_source_map(file_id); | ||
176 | source_map.get(&source, import) | ||
177 | } | ||
178 | |||
179 | /// Returns the crate this module is part of. | ||
180 | pub fn krate(self, _db: &impl DefDatabase) -> Option<Crate> { | ||
181 | Some(self.krate) | ||
182 | } | ||
183 | |||
184 | /// Topmost parent of this module. Every module has a `crate_root`, but some | ||
185 | /// might be missing `krate`. This can happen if a module's file is not included | ||
186 | /// in the module tree of any target in `Cargo.toml`. | ||
187 | pub fn crate_root(self, db: &impl DefDatabase) -> Module { | ||
188 | let def_map = db.crate_def_map(self.krate); | ||
189 | self.with_module_id(def_map.root()) | ||
190 | } | ||
191 | |||
192 | /// Finds a child module with the specified name. | ||
193 | pub fn child(self, db: &impl HirDatabase, name: &Name) -> Option<Module> { | ||
194 | let def_map = db.crate_def_map(self.krate); | ||
195 | let child_id = def_map[self.module_id].children.get(name)?; | ||
196 | Some(self.with_module_id(*child_id)) | ||
197 | } | ||
198 | |||
199 | /// Iterates over all child modules. | ||
200 | pub fn children(self, db: &impl DefDatabase) -> impl Iterator<Item = Module> { | ||
201 | let def_map = db.crate_def_map(self.krate); | ||
202 | let children = def_map[self.module_id] | ||
203 | .children | ||
204 | .iter() | ||
205 | .map(|(_, module_id)| self.with_module_id(*module_id)) | ||
206 | .collect::<Vec<_>>(); | ||
207 | children.into_iter() | ||
208 | } | ||
209 | |||
210 | /// Finds a parent module. | ||
211 | pub fn parent(self, db: &impl DefDatabase) -> Option<Module> { | ||
212 | let def_map = db.crate_def_map(self.krate); | ||
213 | let parent_id = def_map[self.module_id].parent?; | ||
214 | Some(self.with_module_id(parent_id)) | ||
215 | } | ||
216 | |||
217 | pub fn path_to_root(self, db: &impl HirDatabase) -> Vec<Module> { | ||
218 | let mut res = vec![self.clone()]; | ||
219 | let mut curr = self.clone(); | ||
220 | while let Some(next) = curr.parent(db) { | ||
221 | res.push(next.clone()); | ||
222 | curr = next | ||
223 | } | ||
224 | res | ||
225 | } | ||
226 | |||
227 | /// Returns a `ModuleScope`: a set of items, visible in this module. | ||
228 | pub fn scope(self, db: &impl HirDatabase) -> ModuleScope { | ||
229 | db.crate_def_map(self.krate)[self.module_id].scope.clone() | ||
230 | } | ||
231 | |||
232 | pub fn diagnostics(self, db: &impl HirDatabase, sink: &mut DiagnosticSink) { | ||
233 | db.crate_def_map(self.krate).add_diagnostics(db, self.module_id, sink); | ||
234 | for decl in self.declarations(db) { | ||
235 | match decl { | ||
236 | crate::ModuleDef::Function(f) => f.diagnostics(db, sink), | ||
237 | crate::ModuleDef::Module(f) => f.diagnostics(db, sink), | ||
238 | _ => (), | ||
239 | } | ||
240 | } | ||
241 | |||
242 | for impl_block in self.impl_blocks(db) { | ||
243 | for item in impl_block.items(db) { | ||
244 | match item { | ||
245 | crate::ImplItem::Method(f) => f.diagnostics(db, sink), | ||
246 | _ => (), | ||
247 | } | ||
248 | } | ||
249 | } | ||
250 | } | ||
251 | |||
252 | pub(crate) fn resolver(self, db: &impl DefDatabase) -> Resolver { | ||
253 | let def_map = db.crate_def_map(self.krate); | ||
254 | Resolver::default().push_module_scope(def_map, self.module_id) | ||
255 | } | ||
256 | |||
257 | pub fn declarations(self, db: &impl DefDatabase) -> Vec<ModuleDef> { | ||
258 | let def_map = db.crate_def_map(self.krate); | ||
259 | def_map[self.module_id] | ||
260 | .scope | ||
261 | .entries() | ||
262 | .filter_map(|(_name, res)| if res.import.is_none() { Some(res.def) } else { None }) | ||
263 | .flat_map(|per_ns| { | ||
264 | per_ns.take_types().into_iter().chain(per_ns.take_values().into_iter()) | ||
265 | }) | ||
266 | .collect() | ||
267 | } | ||
268 | |||
269 | pub fn impl_blocks(self, db: &impl HirDatabase) -> Vec<ImplBlock> { | ||
270 | let module_impl_blocks = db.impls_in_module(self); | ||
271 | module_impl_blocks | ||
272 | .impls | ||
273 | .iter() | ||
274 | .map(|(impl_id, _)| ImplBlock::from_id(self, impl_id)) | ||
275 | .collect() | ||
276 | } | ||
277 | |||
278 | fn with_module_id(&self, module_id: CrateModuleId) -> Module { | ||
279 | Module { module_id, krate: self.krate } | ||
280 | } | ||
281 | } | ||
282 | |||
283 | impl Docs for Module { | ||
284 | fn docs(&self, db: &impl HirDatabase) -> Option<Documentation> { | ||
285 | self.declaration_source(db).and_then(|it| docs_from_ast(&*it.1)) | ||
286 | } | ||
287 | } | ||
288 | |||
289 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
290 | pub struct StructField { | ||
291 | pub(crate) parent: VariantDef, | ||
292 | pub(crate) id: StructFieldId, | ||
293 | } | ||
294 | |||
295 | #[derive(Debug)] | ||
296 | pub enum FieldSource { | ||
297 | Named(TreeArc<ast::NamedFieldDef>), | ||
298 | Pos(TreeArc<ast::PosFieldDef>), | ||
299 | } | ||
300 | |||
301 | impl StructField { | ||
302 | pub fn name(&self, db: &impl HirDatabase) -> Name { | ||
303 | self.parent.variant_data(db).fields().unwrap()[self.id].name.clone() | ||
304 | } | ||
305 | |||
306 | pub fn source(&self, db: &impl DefDatabase) -> (HirFileId, FieldSource) { | ||
307 | self.source_impl(db) | ||
308 | } | ||
309 | |||
310 | pub fn ty(&self, db: &impl HirDatabase) -> Ty { | ||
311 | db.type_for_field(*self) | ||
312 | } | ||
313 | |||
314 | pub fn parent_def(&self, _db: &impl HirDatabase) -> VariantDef { | ||
315 | self.parent | ||
316 | } | ||
317 | } | ||
318 | |||
319 | impl Docs for StructField { | ||
320 | fn docs(&self, db: &impl HirDatabase) -> Option<Documentation> { | ||
321 | match self.source(db).1 { | ||
322 | FieldSource::Named(named) => docs_from_ast(&*named), | ||
323 | FieldSource::Pos(..) => return None, | ||
324 | } | ||
325 | } | ||
326 | } | ||
327 | |||
328 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
329 | pub struct Struct { | ||
330 | pub(crate) id: StructId, | ||
331 | } | ||
332 | |||
333 | impl Struct { | ||
334 | pub fn source(self, db: &impl DefDatabase) -> (HirFileId, TreeArc<ast::StructDef>) { | ||
335 | self.id.source(db) | ||
336 | } | ||
337 | |||
338 | pub fn module(self, db: &impl HirDatabase) -> Module { | ||
339 | self.id.module(db) | ||
340 | } | ||
341 | |||
342 | pub fn name(self, db: &impl HirDatabase) -> Option<Name> { | ||
343 | db.struct_data(self).name.clone() | ||
344 | } | ||
345 | |||
346 | pub fn fields(self, db: &impl HirDatabase) -> Vec<StructField> { | ||
347 | db.struct_data(self) | ||
348 | .variant_data | ||
349 | .fields() | ||
350 | .into_iter() | ||
351 | .flat_map(|it| it.iter()) | ||
352 | .map(|(id, _)| StructField { parent: self.into(), id }) | ||
353 | .collect() | ||
354 | } | ||
355 | |||
356 | pub fn field(self, db: &impl HirDatabase, name: &Name) -> Option<StructField> { | ||
357 | db.struct_data(self) | ||
358 | .variant_data | ||
359 | .fields() | ||
360 | .into_iter() | ||
361 | .flat_map(|it| it.iter()) | ||
362 | .find(|(_id, data)| data.name == *name) | ||
363 | .map(|(id, _)| StructField { parent: self.into(), id }) | ||
364 | } | ||
365 | |||
366 | pub fn ty(self, db: &impl HirDatabase) -> Ty { | ||
367 | db.type_for_def(self.into(), Namespace::Types) | ||
368 | } | ||
369 | |||
370 | pub fn constructor_ty(self, db: &impl HirDatabase) -> Ty { | ||
371 | db.type_for_def(self.into(), Namespace::Values) | ||
372 | } | ||
373 | |||
374 | // FIXME move to a more general type | ||
375 | /// Builds a resolver for type references inside this struct. | ||
376 | pub(crate) fn resolver(self, db: &impl HirDatabase) -> Resolver { | ||
377 | // take the outer scope... | ||
378 | let r = self.module(db).resolver(db); | ||
379 | // ...and add generic params, if present | ||
380 | let p = self.generic_params(db); | ||
381 | let r = if !p.params.is_empty() { r.push_generic_params_scope(p) } else { r }; | ||
382 | r | ||
383 | } | ||
384 | } | ||
385 | |||
386 | impl Docs for Struct { | ||
387 | fn docs(&self, db: &impl HirDatabase) -> Option<Documentation> { | ||
388 | docs_from_ast(&*self.source(db).1) | ||
389 | } | ||
390 | } | ||
391 | |||
392 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
393 | pub struct Union { | ||
394 | pub(crate) id: StructId, | ||
395 | } | ||
396 | |||
397 | impl Union { | ||
398 | pub fn source(self, db: &impl DefDatabase) -> (HirFileId, TreeArc<ast::StructDef>) { | ||
399 | self.id.source(db) | ||
400 | } | ||
401 | |||
402 | pub fn name(self, db: &impl HirDatabase) -> Option<Name> { | ||
403 | db.struct_data(Struct { id: self.id }).name.clone() | ||
404 | } | ||
405 | |||
406 | pub fn module(self, db: &impl HirDatabase) -> Module { | ||
407 | self.id.module(db) | ||
408 | } | ||
409 | |||
410 | // FIXME move to a more general type | ||
411 | /// Builds a resolver for type references inside this union. | ||
412 | pub(crate) fn resolver(self, db: &impl HirDatabase) -> Resolver { | ||
413 | // take the outer scope... | ||
414 | let r = self.module(db).resolver(db); | ||
415 | // ...and add generic params, if present | ||
416 | let p = self.generic_params(db); | ||
417 | let r = if !p.params.is_empty() { r.push_generic_params_scope(p) } else { r }; | ||
418 | r | ||
419 | } | ||
420 | } | ||
421 | |||
422 | impl Docs for Union { | ||
423 | fn docs(&self, db: &impl HirDatabase) -> Option<Documentation> { | ||
424 | docs_from_ast(&*self.source(db).1) | ||
425 | } | ||
426 | } | ||
427 | |||
428 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
429 | pub struct Enum { | ||
430 | pub(crate) id: EnumId, | ||
431 | } | ||
432 | |||
433 | impl Enum { | ||
434 | pub fn source(self, db: &impl DefDatabase) -> (HirFileId, TreeArc<ast::EnumDef>) { | ||
435 | self.id.source(db) | ||
436 | } | ||
437 | |||
438 | pub fn module(self, db: &impl HirDatabase) -> Module { | ||
439 | self.id.module(db) | ||
440 | } | ||
441 | |||
442 | pub fn name(self, db: &impl HirDatabase) -> Option<Name> { | ||
443 | db.enum_data(self).name.clone() | ||
444 | } | ||
445 | |||
446 | pub fn variants(self, db: &impl DefDatabase) -> Vec<EnumVariant> { | ||
447 | db.enum_data(self).variants.iter().map(|(id, _)| EnumVariant { parent: self, id }).collect() | ||
448 | } | ||
449 | |||
450 | pub fn variant(self, db: &impl DefDatabase, name: &Name) -> Option<EnumVariant> { | ||
451 | db.enum_data(self) | ||
452 | .variants | ||
453 | .iter() | ||
454 | .find(|(_id, data)| data.name.as_ref() == Some(name)) | ||
455 | .map(|(id, _)| EnumVariant { parent: self, id }) | ||
456 | } | ||
457 | |||
458 | pub fn ty(self, db: &impl HirDatabase) -> Ty { | ||
459 | db.type_for_def(self.into(), Namespace::Types) | ||
460 | } | ||
461 | |||
462 | // FIXME: move to a more general type | ||
463 | /// Builds a resolver for type references inside this struct. | ||
464 | pub(crate) fn resolver(self, db: &impl HirDatabase) -> Resolver { | ||
465 | // take the outer scope... | ||
466 | let r = self.module(db).resolver(db); | ||
467 | // ...and add generic params, if present | ||
468 | let p = self.generic_params(db); | ||
469 | let r = if !p.params.is_empty() { r.push_generic_params_scope(p) } else { r }; | ||
470 | r | ||
471 | } | ||
472 | } | ||
473 | |||
474 | impl Docs for Enum { | ||
475 | fn docs(&self, db: &impl HirDatabase) -> Option<Documentation> { | ||
476 | docs_from_ast(&*self.source(db).1) | ||
477 | } | ||
478 | } | ||
479 | |||
480 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
481 | pub struct EnumVariant { | ||
482 | pub(crate) parent: Enum, | ||
483 | pub(crate) id: EnumVariantId, | ||
484 | } | ||
485 | |||
486 | impl EnumVariant { | ||
487 | pub fn source(&self, db: &impl DefDatabase) -> (HirFileId, TreeArc<ast::EnumVariant>) { | ||
488 | self.source_impl(db) | ||
489 | } | ||
490 | pub fn module(&self, db: &impl HirDatabase) -> Module { | ||
491 | self.parent.module(db) | ||
492 | } | ||
493 | pub fn parent_enum(&self, _db: &impl DefDatabase) -> Enum { | ||
494 | self.parent | ||
495 | } | ||
496 | |||
497 | pub fn name(&self, db: &impl DefDatabase) -> Option<Name> { | ||
498 | db.enum_data(self.parent).variants[self.id].name.clone() | ||
499 | } | ||
500 | |||
501 | pub fn fields(&self, db: &impl HirDatabase) -> Vec<StructField> { | ||
502 | self.variant_data(db) | ||
503 | .fields() | ||
504 | .into_iter() | ||
505 | .flat_map(|it| it.iter()) | ||
506 | .map(|(id, _)| StructField { parent: (*self).into(), id }) | ||
507 | .collect() | ||
508 | } | ||
509 | |||
510 | pub fn field(&self, db: &impl HirDatabase, name: &Name) -> Option<StructField> { | ||
511 | self.variant_data(db) | ||
512 | .fields() | ||
513 | .into_iter() | ||
514 | .flat_map(|it| it.iter()) | ||
515 | .find(|(_id, data)| data.name == *name) | ||
516 | .map(|(id, _)| StructField { parent: (*self).into(), id }) | ||
517 | } | ||
518 | } | ||
519 | |||
520 | impl Docs for EnumVariant { | ||
521 | fn docs(&self, db: &impl HirDatabase) -> Option<Documentation> { | ||
522 | docs_from_ast(&*self.source(db).1) | ||
523 | } | ||
524 | } | ||
525 | |||
526 | /// The defs which have a body. | ||
527 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
528 | pub enum DefWithBody { | ||
529 | Function(Function), | ||
530 | Static(Static), | ||
531 | Const(Const), | ||
532 | } | ||
533 | |||
534 | impl_froms!(DefWithBody: Function, Const, Static); | ||
535 | |||
536 | impl DefWithBody { | ||
537 | pub fn infer(self, db: &impl HirDatabase) -> Arc<InferenceResult> { | ||
538 | db.infer(self) | ||
539 | } | ||
540 | |||
541 | pub fn body(self, db: &impl HirDatabase) -> Arc<Body> { | ||
542 | db.body_hir(self) | ||
543 | } | ||
544 | |||
545 | pub fn body_source_map(self, db: &impl HirDatabase) -> Arc<BodySourceMap> { | ||
546 | db.body_with_source_map(self).1 | ||
547 | } | ||
548 | |||
549 | /// Builds a resolver for code inside this item. | ||
550 | pub(crate) fn resolver(&self, db: &impl HirDatabase) -> Resolver { | ||
551 | match *self { | ||
552 | DefWithBody::Const(ref c) => c.resolver(db), | ||
553 | DefWithBody::Function(ref f) => f.resolver(db), | ||
554 | DefWithBody::Static(ref s) => s.resolver(db), | ||
555 | } | ||
556 | } | ||
557 | } | ||
558 | |||
559 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
560 | pub struct Function { | ||
561 | pub(crate) id: FunctionId, | ||
562 | } | ||
563 | |||
564 | /// The declared signature of a function. | ||
565 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
566 | pub struct FnSignature { | ||
567 | pub(crate) name: Name, | ||
568 | pub(crate) params: Vec<TypeRef>, | ||
569 | pub(crate) ret_type: TypeRef, | ||
570 | /// True if the first param is `self`. This is relevant to decide whether this | ||
571 | /// can be called as a method. | ||
572 | pub(crate) has_self_param: bool, | ||
573 | } | ||
574 | |||
575 | impl FnSignature { | ||
576 | pub(crate) fn fn_signature_query(db: &impl DefDatabase, func: Function) -> Arc<FnSignature> { | ||
577 | let (_, node) = func.source(db); | ||
578 | let name = node.name().map(|n| n.as_name()).unwrap_or_else(Name::missing); | ||
579 | let mut params = Vec::new(); | ||
580 | let mut has_self_param = false; | ||
581 | if let Some(param_list) = node.param_list() { | ||
582 | if let Some(self_param) = param_list.self_param() { | ||
583 | let self_type = if let Some(type_ref) = self_param.ascribed_type() { | ||
584 | TypeRef::from_ast(type_ref) | ||
585 | } else { | ||
586 | let self_type = TypeRef::Path(Name::self_type().into()); | ||
587 | match self_param.kind() { | ||
588 | ast::SelfParamKind::Owned => self_type, | ||
589 | ast::SelfParamKind::Ref => { | ||
590 | TypeRef::Reference(Box::new(self_type), Mutability::Shared) | ||
591 | } | ||
592 | ast::SelfParamKind::MutRef => { | ||
593 | TypeRef::Reference(Box::new(self_type), Mutability::Mut) | ||
594 | } | ||
595 | } | ||
596 | }; | ||
597 | params.push(self_type); | ||
598 | has_self_param = true; | ||
599 | } | ||
600 | for param in param_list.params() { | ||
601 | let type_ref = TypeRef::from_ast_opt(param.ascribed_type()); | ||
602 | params.push(type_ref); | ||
603 | } | ||
604 | } | ||
605 | let ret_type = if let Some(type_ref) = node.ret_type().and_then(|rt| rt.type_ref()) { | ||
606 | TypeRef::from_ast(type_ref) | ||
607 | } else { | ||
608 | TypeRef::unit() | ||
609 | }; | ||
610 | |||
611 | let sig = FnSignature { name, params, ret_type, has_self_param }; | ||
612 | Arc::new(sig) | ||
613 | } | ||
614 | pub fn name(&self) -> &Name { | ||
615 | &self.name | ||
616 | } | ||
617 | |||
618 | pub fn params(&self) -> &[TypeRef] { | ||
619 | &self.params | ||
620 | } | ||
621 | |||
622 | pub fn ret_type(&self) -> &TypeRef { | ||
623 | &self.ret_type | ||
624 | } | ||
625 | |||
626 | /// True if the first arg is `self`. This is relevant to decide whether this | ||
627 | /// can be called as a method. | ||
628 | pub fn has_self_param(&self) -> bool { | ||
629 | self.has_self_param | ||
630 | } | ||
631 | } | ||
632 | |||
633 | impl Function { | ||
634 | pub fn source(self, db: &impl DefDatabase) -> (HirFileId, TreeArc<ast::FnDef>) { | ||
635 | self.id.source(db) | ||
636 | } | ||
637 | |||
638 | pub fn module(self, db: &impl DefDatabase) -> Module { | ||
639 | self.id.module(db) | ||
640 | } | ||
641 | |||
642 | pub fn name(self, db: &impl HirDatabase) -> Name { | ||
643 | self.signature(db).name.clone() | ||
644 | } | ||
645 | |||
646 | pub(crate) fn body_source_map(self, db: &impl HirDatabase) -> Arc<BodySourceMap> { | ||
647 | db.body_with_source_map(self.into()).1 | ||
648 | } | ||
649 | |||
650 | pub fn body(self, db: &impl HirDatabase) -> Arc<Body> { | ||
651 | db.body_hir(self.into()) | ||
652 | } | ||
653 | |||
654 | pub fn ty(self, db: &impl HirDatabase) -> Ty { | ||
655 | db.type_for_def(self.into(), Namespace::Values) | ||
656 | } | ||
657 | |||
658 | pub fn signature(self, db: &impl HirDatabase) -> Arc<FnSignature> { | ||
659 | db.fn_signature(self) | ||
660 | } | ||
661 | |||
662 | pub fn infer(self, db: &impl HirDatabase) -> Arc<InferenceResult> { | ||
663 | db.infer(self.into()) | ||
664 | } | ||
665 | |||
666 | /// The containing impl block, if this is a method. | ||
667 | pub fn impl_block(self, db: &impl DefDatabase) -> Option<ImplBlock> { | ||
668 | let module_impls = db.impls_in_module(self.module(db)); | ||
669 | ImplBlock::containing(module_impls, self.into()) | ||
670 | } | ||
671 | |||
672 | /// The containing trait, if this is a trait method definition. | ||
673 | pub fn parent_trait(self, db: &impl DefDatabase) -> Option<Trait> { | ||
674 | db.trait_items_index(self.module(db)).get_parent_trait(self.into()) | ||
675 | } | ||
676 | |||
677 | pub fn container(self, db: &impl DefDatabase) -> Option<Container> { | ||
678 | if let Some(impl_block) = self.impl_block(db) { | ||
679 | Some(impl_block.into()) | ||
680 | } else if let Some(trait_) = self.parent_trait(db) { | ||
681 | Some(trait_.into()) | ||
682 | } else { | ||
683 | None | ||
684 | } | ||
685 | } | ||
686 | |||
687 | // FIXME: move to a more general type for 'body-having' items | ||
688 | /// Builds a resolver for code inside this item. | ||
689 | pub(crate) fn resolver(self, db: &impl HirDatabase) -> Resolver { | ||
690 | // take the outer scope... | ||
691 | let r = self.container(db).map_or_else(|| self.module(db).resolver(db), |c| c.resolver(db)); | ||
692 | // ...and add generic params, if present | ||
693 | let p = self.generic_params(db); | ||
694 | let r = if !p.params.is_empty() { r.push_generic_params_scope(p) } else { r }; | ||
695 | r | ||
696 | } | ||
697 | |||
698 | pub fn diagnostics(self, db: &impl HirDatabase, sink: &mut DiagnosticSink) { | ||
699 | let infer = self.infer(db); | ||
700 | infer.add_diagnostics(db, self, sink); | ||
701 | let mut validator = ExprValidator::new(self, infer, sink); | ||
702 | validator.validate_body(db); | ||
703 | } | ||
704 | } | ||
705 | |||
706 | impl Docs for Function { | ||
707 | fn docs(&self, db: &impl HirDatabase) -> Option<Documentation> { | ||
708 | docs_from_ast(&*self.source(db).1) | ||
709 | } | ||
710 | } | ||
711 | |||
712 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
713 | pub struct Const { | ||
714 | pub(crate) id: ConstId, | ||
715 | } | ||
716 | |||
717 | impl Const { | ||
718 | pub fn source(self, db: &impl DefDatabase) -> (HirFileId, TreeArc<ast::ConstDef>) { | ||
719 | self.id.source(db) | ||
720 | } | ||
721 | |||
722 | pub fn module(self, db: &impl DefDatabase) -> Module { | ||
723 | self.id.module(db) | ||
724 | } | ||
725 | |||
726 | pub fn signature(self, db: &impl HirDatabase) -> Arc<ConstSignature> { | ||
727 | db.const_signature(self) | ||
728 | } | ||
729 | |||
730 | pub fn infer(self, db: &impl HirDatabase) -> Arc<InferenceResult> { | ||
731 | db.infer(self.into()) | ||
732 | } | ||
733 | |||
734 | /// The containing impl block, if this is a method. | ||
735 | pub fn impl_block(self, db: &impl DefDatabase) -> Option<ImplBlock> { | ||
736 | let module_impls = db.impls_in_module(self.module(db)); | ||
737 | ImplBlock::containing(module_impls, self.into()) | ||
738 | } | ||
739 | |||
740 | // FIXME: move to a more general type for 'body-having' items | ||
741 | /// Builds a resolver for code inside this item. | ||
742 | pub(crate) fn resolver(self, db: &impl HirDatabase) -> Resolver { | ||
743 | // take the outer scope... | ||
744 | let r = self | ||
745 | .impl_block(db) | ||
746 | .map(|ib| ib.resolver(db)) | ||
747 | .unwrap_or_else(|| self.module(db).resolver(db)); | ||
748 | r | ||
749 | } | ||
750 | } | ||
751 | |||
752 | impl Docs for Const { | ||
753 | fn docs(&self, db: &impl HirDatabase) -> Option<Documentation> { | ||
754 | docs_from_ast(&*self.source(db).1) | ||
755 | } | ||
756 | } | ||
757 | |||
758 | /// The declared signature of a const. | ||
759 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
760 | pub struct ConstSignature { | ||
761 | pub(crate) name: Name, | ||
762 | pub(crate) type_ref: TypeRef, | ||
763 | } | ||
764 | |||
765 | impl ConstSignature { | ||
766 | pub fn name(&self) -> &Name { | ||
767 | &self.name | ||
768 | } | ||
769 | |||
770 | pub fn type_ref(&self) -> &TypeRef { | ||
771 | &self.type_ref | ||
772 | } | ||
773 | |||
774 | pub(crate) fn const_signature_query( | ||
775 | db: &impl DefDatabase, | ||
776 | konst: Const, | ||
777 | ) -> Arc<ConstSignature> { | ||
778 | let (_, node) = konst.source(db); | ||
779 | const_signature_for(&*node) | ||
780 | } | ||
781 | |||
782 | pub(crate) fn static_signature_query( | ||
783 | db: &impl DefDatabase, | ||
784 | konst: Static, | ||
785 | ) -> Arc<ConstSignature> { | ||
786 | let (_, node) = konst.source(db); | ||
787 | const_signature_for(&*node) | ||
788 | } | ||
789 | } | ||
790 | |||
791 | fn const_signature_for<N: NameOwner + TypeAscriptionOwner>(node: &N) -> Arc<ConstSignature> { | ||
792 | let name = node.name().map(|n| n.as_name()).unwrap_or_else(Name::missing); | ||
793 | let type_ref = TypeRef::from_ast_opt(node.ascribed_type()); | ||
794 | let sig = ConstSignature { name, type_ref }; | ||
795 | Arc::new(sig) | ||
796 | } | ||
797 | |||
798 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
799 | pub struct Static { | ||
800 | pub(crate) id: StaticId, | ||
801 | } | ||
802 | |||
803 | impl Static { | ||
804 | pub fn source(self, db: &impl DefDatabase) -> (HirFileId, TreeArc<ast::StaticDef>) { | ||
805 | self.id.source(db) | ||
806 | } | ||
807 | |||
808 | pub fn module(self, db: &impl DefDatabase) -> Module { | ||
809 | self.id.module(db) | ||
810 | } | ||
811 | |||
812 | pub fn signature(self, db: &impl HirDatabase) -> Arc<ConstSignature> { | ||
813 | db.static_signature(self) | ||
814 | } | ||
815 | |||
816 | /// Builds a resolver for code inside this item. | ||
817 | pub(crate) fn resolver(self, db: &impl HirDatabase) -> Resolver { | ||
818 | // take the outer scope... | ||
819 | self.module(db).resolver(db) | ||
820 | } | ||
821 | |||
822 | pub fn infer(self, db: &impl HirDatabase) -> Arc<InferenceResult> { | ||
823 | db.infer(self.into()) | ||
824 | } | ||
825 | } | ||
826 | |||
827 | impl Docs for Static { | ||
828 | fn docs(&self, db: &impl HirDatabase) -> Option<Documentation> { | ||
829 | docs_from_ast(&*self.source(db).1) | ||
830 | } | ||
831 | } | ||
832 | |||
833 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
834 | pub struct Trait { | ||
835 | pub(crate) id: TraitId, | ||
836 | } | ||
837 | |||
838 | impl Trait { | ||
839 | pub fn source(self, db: &impl DefDatabase) -> (HirFileId, TreeArc<ast::TraitDef>) { | ||
840 | self.id.source(db) | ||
841 | } | ||
842 | |||
843 | pub fn module(self, db: &impl DefDatabase) -> Module { | ||
844 | self.id.module(db) | ||
845 | } | ||
846 | |||
847 | pub fn name(self, db: &impl DefDatabase) -> Option<Name> { | ||
848 | self.trait_data(db).name().clone() | ||
849 | } | ||
850 | |||
851 | pub fn items(self, db: &impl DefDatabase) -> Vec<TraitItem> { | ||
852 | self.trait_data(db).items().to_vec() | ||
853 | } | ||
854 | |||
855 | pub(crate) fn trait_data(self, db: &impl DefDatabase) -> Arc<TraitData> { | ||
856 | db.trait_data(self) | ||
857 | } | ||
858 | |||
859 | pub fn trait_ref(self, db: &impl HirDatabase) -> TraitRef { | ||
860 | TraitRef::for_trait(db, self) | ||
861 | } | ||
862 | |||
863 | pub fn is_auto(self, db: &impl DefDatabase) -> bool { | ||
864 | self.trait_data(db).is_auto() | ||
865 | } | ||
866 | |||
867 | pub(crate) fn resolver(self, db: &impl DefDatabase) -> Resolver { | ||
868 | let r = self.module(db).resolver(db); | ||
869 | // add generic params, if present | ||
870 | let p = self.generic_params(db); | ||
871 | let r = if !p.params.is_empty() { r.push_generic_params_scope(p) } else { r }; | ||
872 | r | ||
873 | } | ||
874 | } | ||
875 | |||
876 | impl Docs for Trait { | ||
877 | fn docs(&self, db: &impl HirDatabase) -> Option<Documentation> { | ||
878 | docs_from_ast(&*self.source(db).1) | ||
879 | } | ||
880 | } | ||
881 | |||
882 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
883 | pub struct TypeAlias { | ||
884 | pub(crate) id: TypeAliasId, | ||
885 | } | ||
886 | |||
887 | impl TypeAlias { | ||
888 | pub fn source(self, db: &impl DefDatabase) -> (HirFileId, TreeArc<ast::TypeAliasDef>) { | ||
889 | self.id.source(db) | ||
890 | } | ||
891 | |||
892 | pub fn module(self, db: &impl DefDatabase) -> Module { | ||
893 | self.id.module(db) | ||
894 | } | ||
895 | |||
896 | /// The containing impl block, if this is a method. | ||
897 | pub fn impl_block(self, db: &impl DefDatabase) -> Option<ImplBlock> { | ||
898 | let module_impls = db.impls_in_module(self.module(db)); | ||
899 | ImplBlock::containing(module_impls, self.into()) | ||
900 | } | ||
901 | |||
902 | /// The containing trait, if this is a trait method definition. | ||
903 | pub fn parent_trait(self, db: &impl DefDatabase) -> Option<Trait> { | ||
904 | db.trait_items_index(self.module(db)).get_parent_trait(self.into()) | ||
905 | } | ||
906 | |||
907 | pub fn container(self, db: &impl DefDatabase) -> Option<Container> { | ||
908 | if let Some(impl_block) = self.impl_block(db) { | ||
909 | Some(impl_block.into()) | ||
910 | } else if let Some(trait_) = self.parent_trait(db) { | ||
911 | Some(trait_.into()) | ||
912 | } else { | ||
913 | None | ||
914 | } | ||
915 | } | ||
916 | |||
917 | pub fn type_ref(self, db: &impl DefDatabase) -> Arc<TypeRef> { | ||
918 | db.type_alias_ref(self) | ||
919 | } | ||
920 | |||
921 | /// Builds a resolver for the type references in this type alias. | ||
922 | pub(crate) fn resolver(self, db: &impl HirDatabase) -> Resolver { | ||
923 | // take the outer scope... | ||
924 | let r = self | ||
925 | .impl_block(db) | ||
926 | .map(|ib| ib.resolver(db)) | ||
927 | .unwrap_or_else(|| self.module(db).resolver(db)); | ||
928 | // ...and add generic params, if present | ||
929 | let p = self.generic_params(db); | ||
930 | let r = if !p.params.is_empty() { r.push_generic_params_scope(p) } else { r }; | ||
931 | r | ||
932 | } | ||
933 | } | ||
934 | |||
935 | impl Docs for TypeAlias { | ||
936 | fn docs(&self, db: &impl HirDatabase) -> Option<Documentation> { | ||
937 | docs_from_ast(&*self.source(db).1) | ||
938 | } | ||
939 | } | ||
940 | |||
941 | pub enum Container { | ||
942 | Trait(Trait), | ||
943 | ImplBlock(ImplBlock), | ||
944 | } | ||
945 | impl_froms!(Container: Trait, ImplBlock); | ||
946 | |||
947 | impl Container { | ||
948 | pub(crate) fn resolver(self, db: &impl DefDatabase) -> Resolver { | ||
949 | match self { | ||
950 | Container::Trait(trait_) => trait_.resolver(db), | ||
951 | Container::ImplBlock(impl_block) => impl_block.resolver(db), | ||
952 | } | ||
953 | } | ||
954 | } | ||