aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src
diff options
context:
space:
mode:
authorZac Pullar-Strecker <[email protected]>2020-08-24 10:19:53 +0100
committerZac Pullar-Strecker <[email protected]>2020-08-24 10:20:13 +0100
commit7bbca7a1b3f9293d2f5cc5745199bc5f8396f2f0 (patch)
treebdb47765991cb973b2cd5481a088fac636bd326c /crates/ra_hir/src
parentca464650eeaca6195891199a93f4f76cf3e7e697 (diff)
parente65d48d1fb3d4d91d9dc1148a7a836ff5c9a3c87 (diff)
Merge remote-tracking branch 'upstream/master' into 503-hover-doc-links
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r--crates/ra_hir/src/code_model.rs1813
-rw-r--r--crates/ra_hir/src/db.rs28
-rw-r--r--crates/ra_hir/src/diagnostics.rs8
-rw-r--r--crates/ra_hir/src/from_id.rs247
-rw-r--r--crates/ra_hir/src/has_source.rs135
-rw-r--r--crates/ra_hir/src/lib.rs63
-rw-r--r--crates/ra_hir/src/link_rewrite.rs226
-rw-r--r--crates/ra_hir/src/semantics.rs731
-rw-r--r--crates/ra_hir/src/semantics/source_to_def.rs276
-rw-r--r--crates/ra_hir/src/source_analyzer.rs535
10 files changed, 0 insertions, 4062 deletions
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
deleted file mode 100644
index 8154e9bf6..000000000
--- a/crates/ra_hir/src/code_model.rs
+++ /dev/null
@@ -1,1813 +0,0 @@
1//! FIXME: write short doc here
2use std::{iter, sync::Arc};
3
4use arrayvec::ArrayVec;
5use either::Either;
6use hir_def::{
7 adt::StructKind,
8 adt::VariantData,
9 builtin_type::BuiltinType,
10 docs::Documentation,
11 expr::{BindingAnnotation, Pat, PatId},
12 import_map,
13 per_ns::PerNs,
14 resolver::{HasResolver, Resolver},
15 src::HasSource as _,
16 type_ref::{Mutability, TypeRef},
17 AdtId, AssocContainerId, ConstId, DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule,
18 ImplId, LocalEnumVariantId, LocalFieldId, LocalModuleId, Lookup, ModuleId, StaticId, StructId,
19 TraitId, TypeAliasId, TypeParamId, UnionId, VariantId,
20};
21use hir_expand::{
22 diagnostics::DiagnosticSink,
23 name::{name, AsName},
24 MacroDefId, MacroDefKind,
25};
26use hir_ty::{
27 autoderef,
28 display::{HirDisplayError, HirFormatter},
29 method_resolution, ApplicationTy, CallableDefId, Canonical, FnSig, GenericPredicate,
30 InEnvironment, Substs, TraitEnvironment, Ty, TyDefId, TypeCtor,
31};
32use ra_db::{CrateId, Edition, FileId};
33use ra_prof::profile;
34use ra_syntax::{
35 ast::{self, AttrsOwner, NameOwner},
36 AstNode,
37};
38use ra_tt::{Ident, Leaf, Literal, TokenTree};
39use rustc_hash::FxHashSet;
40use stdx::impl_from;
41
42use crate::{
43 db::{DefDatabase, HirDatabase},
44 has_source::HasSource,
45 link_rewrite::Resolvable,
46 HirDisplay, InFile, Name,
47};
48
49/// hir::Crate describes a single crate. It's the main interface with which
50/// a crate's dependencies interact. Mostly, it should be just a proxy for the
51/// root module.
52#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
53pub struct Crate {
54 pub(crate) id: CrateId,
55}
56
57#[derive(Debug)]
58pub struct CrateDependency {
59 pub krate: Crate,
60 pub name: Name,
61}
62
63impl Crate {
64 pub fn dependencies(self, db: &dyn HirDatabase) -> Vec<CrateDependency> {
65 db.crate_graph()[self.id]
66 .dependencies
67 .iter()
68 .map(|dep| {
69 let krate = Crate { id: dep.crate_id };
70 let name = dep.as_name();
71 CrateDependency { krate, name }
72 })
73 .collect()
74 }
75
76 // FIXME: add `transitive_reverse_dependencies`.
77 pub fn reverse_dependencies(self, db: &dyn HirDatabase) -> Vec<Crate> {
78 let crate_graph = db.crate_graph();
79 crate_graph
80 .iter()
81 .filter(|&krate| {
82 crate_graph[krate].dependencies.iter().any(|it| it.crate_id == self.id)
83 })
84 .map(|id| Crate { id })
85 .collect()
86 }
87
88 pub fn root_module(self, db: &dyn HirDatabase) -> Option<Module> {
89 let module_id = db.crate_def_map(self.id).root;
90 Some(Module::new(self, module_id))
91 }
92
93 pub fn root_file(self, db: &dyn HirDatabase) -> FileId {
94 db.crate_graph()[self.id].root_file_id
95 }
96
97 pub fn edition(self, db: &dyn HirDatabase) -> Edition {
98 db.crate_graph()[self.id].edition
99 }
100
101 pub fn display_name(self, db: &dyn HirDatabase) -> Option<String> {
102 db.crate_graph()[self.id].display_name.clone()
103 }
104
105 pub fn query_external_importables(
106 self,
107 db: &dyn DefDatabase,
108 query: &str,
109 ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> {
110 import_map::search_dependencies(
111 db,
112 self.into(),
113 import_map::Query::new(query).anchor_end().case_sensitive().limit(40),
114 )
115 .into_iter()
116 .map(|item| match item {
117 ItemInNs::Types(mod_id) | ItemInNs::Values(mod_id) => Either::Left(mod_id.into()),
118 ItemInNs::Macros(mac_id) => Either::Right(mac_id.into()),
119 })
120 }
121
122 pub fn all(db: &dyn HirDatabase) -> Vec<Crate> {
123 db.crate_graph().iter().map(|id| Crate { id }).collect()
124 }
125
126 /// Try to get the root URL of the documentation of a crate.
127 pub fn get_doc_url(self: &Crate, db: &dyn HirDatabase) -> Option<String> {
128 // Look for #![doc(html_root_url = "...")]
129 let attrs = db.attrs(AttrDef::from(self.root_module(db)?).into());
130 let doc_attr_q = attrs.by_key("doc");
131
132 let doc_url = if doc_attr_q.exists() {
133 doc_attr_q.tt_values().map(|tt| {
134 let name = tt.token_trees.iter()
135 .skip_while(|tt| !matches!(tt, TokenTree::Leaf(Leaf::Ident(Ident{text: ref ident, ..})) if ident == "html_root_url"))
136 .skip(2)
137 .next();
138
139 match name {
140 Some(TokenTree::Leaf(Leaf::Literal(Literal{ref text, ..}))) => Some(text),
141 _ => None
142 }
143 }).flat_map(|t| t).next().map(|s| s.to_string())
144 } else {
145 None
146 };
147
148 doc_url
149 .map(|s| s.trim_matches('"').trim_end_matches("/").to_owned() + "/")
150 .map(|s| s.to_string())
151 }
152}
153
154#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
155pub struct Module {
156 pub(crate) id: ModuleId,
157}
158
159/// The defs which can be visible in the module.
160#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
161pub enum ModuleDef {
162 Module(Module),
163 Function(Function),
164 Adt(Adt),
165 // Can't be directly declared, but can be imported.
166 EnumVariant(EnumVariant),
167 Const(Const),
168 Static(Static),
169 Trait(Trait),
170 TypeAlias(TypeAlias),
171 BuiltinType(BuiltinType),
172}
173impl_from!(
174 Module,
175 Function,
176 Adt(Struct, Enum, Union),
177 EnumVariant,
178 Const,
179 Static,
180 Trait,
181 TypeAlias,
182 BuiltinType
183 for ModuleDef
184);
185
186impl ModuleDef {
187 pub fn module(self, db: &dyn HirDatabase) -> Option<Module> {
188 match self {
189 ModuleDef::Module(it) => it.parent(db),
190 ModuleDef::Function(it) => Some(it.module(db)),
191 ModuleDef::Adt(it) => Some(it.module(db)),
192 ModuleDef::EnumVariant(it) => Some(it.module(db)),
193 ModuleDef::Const(it) => Some(it.module(db)),
194 ModuleDef::Static(it) => Some(it.module(db)),
195 ModuleDef::Trait(it) => Some(it.module(db)),
196 ModuleDef::TypeAlias(it) => Some(it.module(db)),
197 ModuleDef::BuiltinType(_) => None,
198 }
199 }
200
201 pub fn definition_visibility(&self, db: &dyn HirDatabase) -> Option<Visibility> {
202 let module = match self {
203 ModuleDef::Module(it) => it.parent(db)?,
204 ModuleDef::Function(it) => return Some(it.visibility(db)),
205 ModuleDef::Adt(it) => it.module(db),
206 ModuleDef::EnumVariant(it) => {
207 let parent = it.parent_enum(db);
208 let module = it.module(db);
209 return module.visibility_of(db, &ModuleDef::Adt(Adt::Enum(parent)));
210 }
211 ModuleDef::Const(it) => return Some(it.visibility(db)),
212 ModuleDef::Static(it) => it.module(db),
213 ModuleDef::Trait(it) => it.module(db),
214 ModuleDef::TypeAlias(it) => return Some(it.visibility(db)),
215 ModuleDef::BuiltinType(_) => return None,
216 };
217
218 module.visibility_of(db, self)
219 }
220
221 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
222 match self {
223 ModuleDef::Adt(it) => Some(it.name(db)),
224 ModuleDef::Trait(it) => Some(it.name(db)),
225 ModuleDef::Function(it) => Some(it.name(db)),
226 ModuleDef::EnumVariant(it) => Some(it.name(db)),
227 ModuleDef::TypeAlias(it) => Some(it.name(db)),
228 ModuleDef::Module(it) => it.name(db),
229 ModuleDef::Const(it) => it.name(db),
230 ModuleDef::Static(it) => it.name(db),
231
232 ModuleDef::BuiltinType(it) => Some(it.as_name()),
233 }
234 }
235
236 pub fn resolver<D: DefDatabase + HirDatabase>(&self, db: &D) -> Option<Resolver> {
237 Some(match self {
238 ModuleDef::Module(m) => ModuleId::from(m.clone()).resolver(db),
239 ModuleDef::Function(f) => FunctionId::from(f.clone()).resolver(db),
240 ModuleDef::Adt(adt) => AdtId::from(adt.clone()).resolver(db),
241 ModuleDef::EnumVariant(ev) => {
242 GenericDefId::from(GenericDef::from(ev.clone())).resolver(db)
243 }
244 ModuleDef::Const(c) => GenericDefId::from(GenericDef::from(c.clone())).resolver(db),
245 ModuleDef::Static(s) => StaticId::from(s.clone()).resolver(db),
246 ModuleDef::Trait(t) => TraitId::from(t.clone()).resolver(db),
247 ModuleDef::TypeAlias(t) => ModuleId::from(t.module(db)).resolver(db),
248 // FIXME: This should be a resolver relative to `std/core`
249 ModuleDef::BuiltinType(_t) => None?,
250 })
251 }
252}
253
254pub use hir_def::{
255 attr::Attrs, item_scope::ItemInNs, item_tree::ItemTreeNode, visibility::Visibility,
256 AssocItemId, AssocItemLoc,
257};
258
259impl Module {
260 pub(crate) fn new(krate: Crate, crate_module_id: LocalModuleId) -> Module {
261 Module { id: ModuleId { krate: krate.id, local_id: crate_module_id } }
262 }
263
264 /// Name of this module.
265 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
266 let def_map = db.crate_def_map(self.id.krate);
267 let parent = def_map[self.id.local_id].parent?;
268 def_map[parent].children.iter().find_map(|(name, module_id)| {
269 if *module_id == self.id.local_id {
270 Some(name.clone())
271 } else {
272 None
273 }
274 })
275 }
276
277 /// Returns the crate this module is part of.
278 pub fn krate(self) -> Crate {
279 Crate { id: self.id.krate }
280 }
281
282 /// Topmost parent of this module. Every module has a `crate_root`, but some
283 /// might be missing `krate`. This can happen if a module's file is not included
284 /// in the module tree of any target in `Cargo.toml`.
285 pub fn crate_root(self, db: &dyn HirDatabase) -> Module {
286 let def_map = db.crate_def_map(self.id.krate);
287 self.with_module_id(def_map.root)
288 }
289
290 /// Iterates over all child modules.
291 pub fn children(self, db: &dyn HirDatabase) -> impl Iterator<Item = Module> {
292 let def_map = db.crate_def_map(self.id.krate);
293 let children = def_map[self.id.local_id]
294 .children
295 .iter()
296 .map(|(_, module_id)| self.with_module_id(*module_id))
297 .collect::<Vec<_>>();
298 children.into_iter()
299 }
300
301 /// Finds a parent module.
302 pub fn parent(self, db: &dyn HirDatabase) -> Option<Module> {
303 let def_map = db.crate_def_map(self.id.krate);
304 let parent_id = def_map[self.id.local_id].parent?;
305 Some(self.with_module_id(parent_id))
306 }
307
308 pub fn path_to_root(self, db: &dyn HirDatabase) -> Vec<Module> {
309 let mut res = vec![self];
310 let mut curr = self;
311 while let Some(next) = curr.parent(db) {
312 res.push(next);
313 curr = next
314 }
315 res
316 }
317
318 /// Returns a `ModuleScope`: a set of items, visible in this module.
319 pub fn scope(
320 self,
321 db: &dyn HirDatabase,
322 visible_from: Option<Module>,
323 ) -> Vec<(Name, ScopeDef)> {
324 db.crate_def_map(self.id.krate)[self.id.local_id]
325 .scope
326 .entries()
327 .filter_map(|(name, def)| {
328 if let Some(m) = visible_from {
329 let filtered =
330 def.filter_visibility(|vis| vis.is_visible_from(db.upcast(), m.id));
331 if filtered.is_none() && !def.is_none() {
332 None
333 } else {
334 Some((name, filtered))
335 }
336 } else {
337 Some((name, def))
338 }
339 })
340 .flat_map(|(name, def)| {
341 ScopeDef::all_items(def).into_iter().map(move |item| (name.clone(), item))
342 })
343 .collect()
344 }
345
346 pub fn visibility_of(self, db: &dyn HirDatabase, def: &ModuleDef) -> Option<Visibility> {
347 db.crate_def_map(self.id.krate)[self.id.local_id].scope.visibility_of(def.clone().into())
348 }
349
350 pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) {
351 let _p = profile("Module::diagnostics");
352 let crate_def_map = db.crate_def_map(self.id.krate);
353 crate_def_map.add_diagnostics(db.upcast(), self.id.local_id, sink);
354 for decl in self.declarations(db) {
355 match decl {
356 crate::ModuleDef::Function(f) => f.diagnostics(db, sink),
357 crate::ModuleDef::Module(m) => {
358 // Only add diagnostics from inline modules
359 if crate_def_map[m.id.local_id].origin.is_inline() {
360 m.diagnostics(db, sink)
361 }
362 }
363 _ => (),
364 }
365 }
366
367 for impl_def in self.impl_defs(db) {
368 for item in impl_def.items(db) {
369 if let AssocItem::Function(f) = item {
370 f.diagnostics(db, sink);
371 }
372 }
373 }
374 }
375
376 pub fn declarations(self, db: &dyn HirDatabase) -> Vec<ModuleDef> {
377 let def_map = db.crate_def_map(self.id.krate);
378 def_map[self.id.local_id].scope.declarations().map(ModuleDef::from).collect()
379 }
380
381 pub fn impl_defs(self, db: &dyn HirDatabase) -> Vec<ImplDef> {
382 let def_map = db.crate_def_map(self.id.krate);
383 def_map[self.id.local_id].scope.impls().map(ImplDef::from).collect()
384 }
385
386 pub(crate) fn with_module_id(self, module_id: LocalModuleId) -> Module {
387 Module::new(self.krate(), module_id)
388 }
389
390 /// Finds a path that can be used to refer to the given item from within
391 /// this module, if possible.
392 pub fn find_use_path(
393 self,
394 db: &dyn DefDatabase,
395 item: impl Into<ItemInNs>,
396 ) -> Option<hir_def::path::ModPath> {
397 hir_def::find_path::find_path(db, item.into(), self.into())
398 }
399}
400
401#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
402pub struct Field {
403 pub(crate) parent: VariantDef,
404 pub(crate) id: LocalFieldId,
405}
406
407#[derive(Debug, PartialEq, Eq)]
408pub enum FieldSource {
409 Named(ast::RecordField),
410 Pos(ast::TupleField),
411}
412
413impl Field {
414 pub fn name(&self, db: &dyn HirDatabase) -> Name {
415 self.parent.variant_data(db).fields()[self.id].name.clone()
416 }
417
418 /// Returns the type as in the signature of the struct (i.e., with
419 /// placeholder types for type parameters). This is good for showing
420 /// signature help, but not so good to actually get the type of the field
421 /// when you actually have a variable of the struct.
422 pub fn signature_ty(&self, db: &dyn HirDatabase) -> Type {
423 let var_id = self.parent.into();
424 let generic_def_id: GenericDefId = match self.parent {
425 VariantDef::Struct(it) => it.id.into(),
426 VariantDef::Union(it) => it.id.into(),
427 VariantDef::EnumVariant(it) => it.parent.id.into(),
428 };
429 let substs = Substs::type_params(db, generic_def_id);
430 let ty = db.field_types(var_id)[self.id].clone().subst(&substs);
431 Type::new(db, self.parent.module(db).id.krate, var_id, ty)
432 }
433
434 pub fn parent_def(&self, _db: &dyn HirDatabase) -> VariantDef {
435 self.parent
436 }
437}
438
439impl HasVisibility for Field {
440 fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
441 let variant_data = self.parent.variant_data(db);
442 let visibility = &variant_data.fields()[self.id].visibility;
443 let parent_id: hir_def::VariantId = self.parent.into();
444 visibility.resolve(db.upcast(), &parent_id.resolver(db.upcast()))
445 }
446}
447
448#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
449pub struct Struct {
450 pub(crate) id: StructId,
451}
452
453impl Struct {
454 pub fn module(self, db: &dyn HirDatabase) -> Module {
455 Module { id: self.id.lookup(db.upcast()).container.module(db.upcast()) }
456 }
457
458 pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> {
459 Some(self.module(db).krate())
460 }
461
462 pub fn name(self, db: &dyn HirDatabase) -> Name {
463 db.struct_data(self.id).name.clone()
464 }
465
466 pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> {
467 db.struct_data(self.id)
468 .variant_data
469 .fields()
470 .iter()
471 .map(|(id, _)| Field { parent: self.into(), id })
472 .collect()
473 }
474
475 pub fn ty(self, db: &dyn HirDatabase) -> Type {
476 Type::from_def(db, self.id.lookup(db.upcast()).container.module(db.upcast()).krate, self.id)
477 }
478
479 fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
480 db.struct_data(self.id).variant_data.clone()
481 }
482}
483
484#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
485pub struct Union {
486 pub(crate) id: UnionId,
487}
488
489impl Union {
490 pub fn name(self, db: &dyn HirDatabase) -> Name {
491 db.union_data(self.id).name.clone()
492 }
493
494 pub fn module(self, db: &dyn HirDatabase) -> Module {
495 Module { id: self.id.lookup(db.upcast()).container.module(db.upcast()) }
496 }
497
498 pub fn ty(self, db: &dyn HirDatabase) -> Type {
499 Type::from_def(db, self.id.lookup(db.upcast()).container.module(db.upcast()).krate, self.id)
500 }
501
502 pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> {
503 db.union_data(self.id)
504 .variant_data
505 .fields()
506 .iter()
507 .map(|(id, _)| Field { parent: self.into(), id })
508 .collect()
509 }
510
511 fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
512 db.union_data(self.id).variant_data.clone()
513 }
514}
515
516#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
517pub struct Enum {
518 pub(crate) id: EnumId,
519}
520
521impl Enum {
522 pub fn module(self, db: &dyn HirDatabase) -> Module {
523 Module { id: self.id.lookup(db.upcast()).container.module(db.upcast()) }
524 }
525
526 pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> {
527 Some(self.module(db).krate())
528 }
529
530 pub fn name(self, db: &dyn HirDatabase) -> Name {
531 db.enum_data(self.id).name.clone()
532 }
533
534 pub fn variants(self, db: &dyn HirDatabase) -> Vec<EnumVariant> {
535 db.enum_data(self.id)
536 .variants
537 .iter()
538 .map(|(id, _)| EnumVariant { parent: self, id })
539 .collect()
540 }
541
542 pub fn ty(self, db: &dyn HirDatabase) -> Type {
543 Type::from_def(db, self.id.lookup(db.upcast()).container.module(db.upcast()).krate, self.id)
544 }
545}
546
547#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
548pub struct EnumVariant {
549 pub(crate) parent: Enum,
550 pub(crate) id: LocalEnumVariantId,
551}
552
553impl EnumVariant {
554 pub fn module(self, db: &dyn HirDatabase) -> Module {
555 self.parent.module(db)
556 }
557 pub fn parent_enum(self, _db: &dyn HirDatabase) -> Enum {
558 self.parent
559 }
560
561 pub fn name(self, db: &dyn HirDatabase) -> Name {
562 db.enum_data(self.parent.id).variants[self.id].name.clone()
563 }
564
565 pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> {
566 self.variant_data(db)
567 .fields()
568 .iter()
569 .map(|(id, _)| Field { parent: self.into(), id })
570 .collect()
571 }
572
573 pub fn kind(self, db: &dyn HirDatabase) -> StructKind {
574 self.variant_data(db).kind()
575 }
576
577 pub(crate) fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
578 db.enum_data(self.parent.id).variants[self.id].variant_data.clone()
579 }
580}
581
582/// A Data Type
583#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
584pub enum Adt {
585 Struct(Struct),
586 Union(Union),
587 Enum(Enum),
588}
589impl_from!(Struct, Union, Enum for Adt);
590
591impl Adt {
592 pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool {
593 let subst = db.generic_defaults(self.into());
594 subst.iter().any(|ty| &ty.value == &Ty::Unknown)
595 }
596
597 /// Turns this ADT into a type. Any type parameters of the ADT will be
598 /// turned into unknown types, which is good for e.g. finding the most
599 /// general set of completions, but will not look very nice when printed.
600 pub fn ty(self, db: &dyn HirDatabase) -> Type {
601 let id = AdtId::from(self);
602 Type::from_def(db, id.module(db.upcast()).krate, id)
603 }
604
605 pub fn module(self, db: &dyn HirDatabase) -> Module {
606 match self {
607 Adt::Struct(s) => s.module(db),
608 Adt::Union(s) => s.module(db),
609 Adt::Enum(e) => e.module(db),
610 }
611 }
612
613 pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> {
614 Some(self.module(db).krate())
615 }
616
617 pub fn name(self, db: &dyn HirDatabase) -> Name {
618 match self {
619 Adt::Struct(s) => s.name(db),
620 Adt::Union(u) => u.name(db),
621 Adt::Enum(e) => e.name(db),
622 }
623 }
624}
625
626#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
627pub enum VariantDef {
628 Struct(Struct),
629 Union(Union),
630 EnumVariant(EnumVariant),
631}
632impl_from!(Struct, Union, EnumVariant for VariantDef);
633
634impl VariantDef {
635 pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> {
636 match self {
637 VariantDef::Struct(it) => it.fields(db),
638 VariantDef::Union(it) => it.fields(db),
639 VariantDef::EnumVariant(it) => it.fields(db),
640 }
641 }
642
643 pub fn module(self, db: &dyn HirDatabase) -> Module {
644 match self {
645 VariantDef::Struct(it) => it.module(db),
646 VariantDef::Union(it) => it.module(db),
647 VariantDef::EnumVariant(it) => it.module(db),
648 }
649 }
650
651 pub fn name(&self, db: &dyn HirDatabase) -> Name {
652 match self {
653 VariantDef::Struct(s) => s.name(db),
654 VariantDef::Union(u) => u.name(db),
655 VariantDef::EnumVariant(e) => e.name(db),
656 }
657 }
658
659 pub(crate) fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
660 match self {
661 VariantDef::Struct(it) => it.variant_data(db),
662 VariantDef::Union(it) => it.variant_data(db),
663 VariantDef::EnumVariant(it) => it.variant_data(db),
664 }
665 }
666}
667
668/// The defs which have a body.
669#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
670pub enum DefWithBody {
671 Function(Function),
672 Static(Static),
673 Const(Const),
674}
675impl_from!(Function, Const, Static for DefWithBody);
676
677impl DefWithBody {
678 pub fn module(self, db: &dyn HirDatabase) -> Module {
679 match self {
680 DefWithBody::Const(c) => c.module(db),
681 DefWithBody::Function(f) => f.module(db),
682 DefWithBody::Static(s) => s.module(db),
683 }
684 }
685
686 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
687 match self {
688 DefWithBody::Function(f) => Some(f.name(db)),
689 DefWithBody::Static(s) => s.name(db),
690 DefWithBody::Const(c) => c.name(db),
691 }
692 }
693}
694
695#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
696pub struct Function {
697 pub(crate) id: FunctionId,
698}
699
700impl Function {
701 pub fn module(self, db: &dyn HirDatabase) -> Module {
702 self.id.lookup(db.upcast()).module(db.upcast()).into()
703 }
704
705 pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> {
706 Some(self.module(db).krate())
707 }
708
709 pub fn name(self, db: &dyn HirDatabase) -> Name {
710 db.function_data(self.id).name.clone()
711 }
712
713 pub fn has_self_param(self, db: &dyn HirDatabase) -> bool {
714 db.function_data(self.id).has_self_param
715 }
716
717 pub fn params(self, db: &dyn HirDatabase) -> Vec<TypeRef> {
718 db.function_data(self.id).params.clone()
719 }
720
721 pub fn is_unsafe(self, db: &dyn HirDatabase) -> bool {
722 db.function_data(self.id).is_unsafe
723 }
724
725 pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) {
726 hir_ty::diagnostics::validate_body(db, self.id.into(), sink)
727 }
728}
729
730impl HasVisibility for Function {
731 fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
732 let function_data = db.function_data(self.id);
733 let visibility = &function_data.visibility;
734 visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
735 }
736}
737
738#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
739pub struct Const {
740 pub(crate) id: ConstId,
741}
742
743impl Const {
744 pub fn module(self, db: &dyn HirDatabase) -> Module {
745 Module { id: self.id.lookup(db.upcast()).module(db.upcast()) }
746 }
747
748 pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> {
749 Some(self.module(db).krate())
750 }
751
752 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
753 db.const_data(self.id).name.clone()
754 }
755}
756
757impl HasVisibility for Const {
758 fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
759 let function_data = db.const_data(self.id);
760 let visibility = &function_data.visibility;
761 visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
762 }
763}
764
765#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
766pub struct Static {
767 pub(crate) id: StaticId,
768}
769
770impl Static {
771 pub fn module(self, db: &dyn HirDatabase) -> Module {
772 Module { id: self.id.lookup(db.upcast()).module(db.upcast()) }
773 }
774
775 pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> {
776 Some(self.module(db).krate())
777 }
778
779 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
780 db.static_data(self.id).name.clone()
781 }
782
783 pub fn is_mut(self, db: &dyn HirDatabase) -> bool {
784 db.static_data(self.id).mutable
785 }
786}
787
788#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
789pub struct Trait {
790 pub(crate) id: TraitId,
791}
792
793impl Trait {
794 pub fn module(self, db: &dyn HirDatabase) -> Module {
795 Module { id: self.id.lookup(db.upcast()).container.module(db.upcast()) }
796 }
797
798 pub fn name(self, db: &dyn HirDatabase) -> Name {
799 db.trait_data(self.id).name.clone()
800 }
801
802 pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> {
803 db.trait_data(self.id).items.iter().map(|(_name, it)| (*it).into()).collect()
804 }
805
806 pub fn is_auto(self, db: &dyn HirDatabase) -> bool {
807 db.trait_data(self.id).auto
808 }
809}
810
811#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
812pub struct TypeAlias {
813 pub(crate) id: TypeAliasId,
814}
815
816impl TypeAlias {
817 pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool {
818 let subst = db.generic_defaults(self.id.into());
819 subst.iter().any(|ty| &ty.value == &Ty::Unknown)
820 }
821
822 pub fn module(self, db: &dyn HirDatabase) -> Module {
823 Module { id: self.id.lookup(db.upcast()).module(db.upcast()) }
824 }
825
826 pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> {
827 Some(self.module(db).krate())
828 }
829
830 pub fn type_ref(self, db: &dyn HirDatabase) -> Option<TypeRef> {
831 db.type_alias_data(self.id).type_ref.clone()
832 }
833
834 pub fn ty(self, db: &dyn HirDatabase) -> Type {
835 Type::from_def(db, self.id.lookup(db.upcast()).module(db.upcast()).krate, self.id)
836 }
837
838 pub fn name(self, db: &dyn HirDatabase) -> Name {
839 db.type_alias_data(self.id).name.clone()
840 }
841}
842
843impl HasVisibility for TypeAlias {
844 fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
845 let function_data = db.type_alias_data(self.id);
846 let visibility = &function_data.visibility;
847 visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
848 }
849}
850
851#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
852pub struct MacroDef {
853 pub(crate) id: MacroDefId,
854}
855
856impl MacroDef {
857 /// FIXME: right now, this just returns the root module of the crate that
858 /// defines this macro. The reasons for this is that macros are expanded
859 /// early, in `ra_hir_expand`, where modules simply do not exist yet.
860 pub fn module(self, db: &dyn HirDatabase) -> Option<Module> {
861 let krate = self.id.krate?;
862 let module_id = db.crate_def_map(krate).root;
863 Some(Module::new(Crate { id: krate }, module_id))
864 }
865
866 /// XXX: this parses the file
867 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
868 self.source(db).value.name().map(|it| it.as_name())
869 }
870
871 /// Indicate it is a proc-macro
872 pub fn is_proc_macro(&self) -> bool {
873 matches!(self.id.kind, MacroDefKind::CustomDerive(_))
874 }
875
876 /// Indicate it is a derive macro
877 pub fn is_derive_macro(&self) -> bool {
878 matches!(self.id.kind, MacroDefKind::CustomDerive(_) | MacroDefKind::BuiltInDerive(_))
879 }
880}
881
882/// Invariant: `inner.as_assoc_item(db).is_some()`
883/// We do not actively enforce this invariant.
884#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
885pub enum AssocItem {
886 Function(Function),
887 Const(Const),
888 TypeAlias(TypeAlias),
889}
890pub enum AssocItemContainer {
891 Trait(Trait),
892 ImplDef(ImplDef),
893}
894pub trait AsAssocItem {
895 fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem>;
896}
897
898impl AsAssocItem for Function {
899 fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> {
900 as_assoc_item(db, AssocItem::Function, self.id)
901 }
902}
903impl AsAssocItem for Const {
904 fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> {
905 as_assoc_item(db, AssocItem::Const, self.id)
906 }
907}
908impl AsAssocItem for TypeAlias {
909 fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> {
910 as_assoc_item(db, AssocItem::TypeAlias, self.id)
911 }
912}
913fn as_assoc_item<ID, DEF, CTOR, AST>(db: &dyn HirDatabase, ctor: CTOR, id: ID) -> Option<AssocItem>
914where
915 ID: Lookup<Data = AssocItemLoc<AST>>,
916 DEF: From<ID>,
917 CTOR: FnOnce(DEF) -> AssocItem,
918 AST: ItemTreeNode,
919{
920 match id.lookup(db.upcast()).container {
921 AssocContainerId::TraitId(_) | AssocContainerId::ImplId(_) => Some(ctor(DEF::from(id))),
922 AssocContainerId::ContainerId(_) => None,
923 }
924}
925
926impl AssocItem {
927 pub fn module(self, db: &dyn HirDatabase) -> Module {
928 match self {
929 AssocItem::Function(f) => f.module(db),
930 AssocItem::Const(c) => c.module(db),
931 AssocItem::TypeAlias(t) => t.module(db),
932 }
933 }
934 pub fn container(self, db: &dyn HirDatabase) -> AssocItemContainer {
935 let container = match self {
936 AssocItem::Function(it) => it.id.lookup(db.upcast()).container,
937 AssocItem::Const(it) => it.id.lookup(db.upcast()).container,
938 AssocItem::TypeAlias(it) => it.id.lookup(db.upcast()).container,
939 };
940 match container {
941 AssocContainerId::TraitId(id) => AssocItemContainer::Trait(id.into()),
942 AssocContainerId::ImplId(id) => AssocItemContainer::ImplDef(id.into()),
943 AssocContainerId::ContainerId(_) => panic!("invalid AssocItem"),
944 }
945 }
946}
947
948impl HasVisibility for AssocItem {
949 fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
950 match self {
951 AssocItem::Function(f) => f.visibility(db),
952 AssocItem::Const(c) => c.visibility(db),
953 AssocItem::TypeAlias(t) => t.visibility(db),
954 }
955 }
956}
957
958#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
959pub enum GenericDef {
960 Function(Function),
961 Adt(Adt),
962 Trait(Trait),
963 TypeAlias(TypeAlias),
964 ImplDef(ImplDef),
965 // enum variants cannot have generics themselves, but their parent enums
966 // can, and this makes some code easier to write
967 EnumVariant(EnumVariant),
968 // consts can have type parameters from their parents (i.e. associated consts of traits)
969 Const(Const),
970}
971impl_from!(
972 Function,
973 Adt(Struct, Enum, Union),
974 Trait,
975 TypeAlias,
976 ImplDef,
977 EnumVariant,
978 Const
979 for GenericDef
980);
981
982impl GenericDef {
983 pub fn params(self, db: &dyn HirDatabase) -> Vec<TypeParam> {
984 let generics: Arc<hir_def::generics::GenericParams> = db.generic_params(self.into());
985 generics
986 .types
987 .iter()
988 .map(|(local_id, _)| TypeParam { id: TypeParamId { parent: self.into(), local_id } })
989 .collect()
990 }
991}
992
993#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
994pub struct Local {
995 pub(crate) parent: DefWithBodyId,
996 pub(crate) pat_id: PatId,
997}
998
999impl Local {
1000 pub fn is_param(self, db: &dyn HirDatabase) -> bool {
1001 let src = self.source(db);
1002 match src.value {
1003 Either::Left(bind_pat) => {
1004 bind_pat.syntax().ancestors().any(|it| ast::Param::can_cast(it.kind()))
1005 }
1006 Either::Right(_self_param) => true,
1007 }
1008 }
1009
1010 // FIXME: why is this an option? It shouldn't be?
1011 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
1012 let body = db.body(self.parent.into());
1013 match &body[self.pat_id] {
1014 Pat::Bind { name, .. } => Some(name.clone()),
1015 _ => None,
1016 }
1017 }
1018
1019 pub fn is_self(self, db: &dyn HirDatabase) -> bool {
1020 self.name(db) == Some(name![self])
1021 }
1022
1023 pub fn is_mut(self, db: &dyn HirDatabase) -> bool {
1024 let body = db.body(self.parent.into());
1025 match &body[self.pat_id] {
1026 Pat::Bind { mode, .. } => match mode {
1027 BindingAnnotation::Mutable | BindingAnnotation::RefMut => true,
1028 _ => false,
1029 },
1030 _ => false,
1031 }
1032 }
1033
1034 pub fn parent(self, _db: &dyn HirDatabase) -> DefWithBody {
1035 self.parent.into()
1036 }
1037
1038 pub fn module(self, db: &dyn HirDatabase) -> Module {
1039 self.parent(db).module(db)
1040 }
1041
1042 pub fn ty(self, db: &dyn HirDatabase) -> Type {
1043 let def = DefWithBodyId::from(self.parent);
1044 let infer = db.infer(def);
1045 let ty = infer[self.pat_id].clone();
1046 let krate = def.module(db.upcast()).krate;
1047 Type::new(db, krate, def, ty)
1048 }
1049
1050 pub fn source(self, db: &dyn HirDatabase) -> InFile<Either<ast::BindPat, ast::SelfParam>> {
1051 let (_body, source_map) = db.body_with_source_map(self.parent.into());
1052 let src = source_map.pat_syntax(self.pat_id).unwrap(); // Hmm...
1053 let root = src.file_syntax(db.upcast());
1054 src.map(|ast| {
1055 ast.map_left(|it| it.cast().unwrap().to_node(&root)).map_right(|it| it.to_node(&root))
1056 })
1057 }
1058}
1059
1060#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1061pub struct TypeParam {
1062 pub(crate) id: TypeParamId,
1063}
1064
1065impl TypeParam {
1066 pub fn name(self, db: &dyn HirDatabase) -> Name {
1067 let params = db.generic_params(self.id.parent);
1068 params.types[self.id.local_id].name.clone().unwrap_or_else(Name::missing)
1069 }
1070
1071 pub fn module(self, db: &dyn HirDatabase) -> Module {
1072 self.id.parent.module(db.upcast()).into()
1073 }
1074
1075 pub fn ty(self, db: &dyn HirDatabase) -> Type {
1076 let resolver = self.id.parent.resolver(db.upcast());
1077 let environment = TraitEnvironment::lower(db, &resolver);
1078 let ty = Ty::Placeholder(self.id);
1079 Type {
1080 krate: self.id.parent.module(db.upcast()).krate,
1081 ty: InEnvironment { value: ty, environment },
1082 }
1083 }
1084
1085 pub fn default(self, db: &dyn HirDatabase) -> Option<Type> {
1086 let params = db.generic_defaults(self.id.parent);
1087 let local_idx = hir_ty::param_idx(db, self.id)?;
1088 let resolver = self.id.parent.resolver(db.upcast());
1089 let environment = TraitEnvironment::lower(db, &resolver);
1090 let ty = params.get(local_idx)?.clone();
1091 let subst = Substs::type_params(db, self.id.parent);
1092 let ty = ty.subst(&subst.prefix(local_idx));
1093 Some(Type {
1094 krate: self.id.parent.module(db.upcast()).krate,
1095 ty: InEnvironment { value: ty, environment },
1096 })
1097 }
1098}
1099
1100// FIXME: rename from `ImplDef` to `Impl`
1101#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1102pub struct ImplDef {
1103 pub(crate) id: ImplId,
1104}
1105
1106impl ImplDef {
1107 pub fn all_in_crate(db: &dyn HirDatabase, krate: Crate) -> Vec<ImplDef> {
1108 let inherent = db.inherent_impls_in_crate(krate.id);
1109 let trait_ = db.trait_impls_in_crate(krate.id);
1110
1111 inherent.all_impls().chain(trait_.all_impls()).map(Self::from).collect()
1112 }
1113 pub fn for_trait(db: &dyn HirDatabase, krate: Crate, trait_: Trait) -> Vec<ImplDef> {
1114 let impls = db.trait_impls_in_crate(krate.id);
1115 impls.for_trait(trait_.id).map(Self::from).collect()
1116 }
1117
1118 pub fn target_trait(self, db: &dyn HirDatabase) -> Option<TypeRef> {
1119 db.impl_data(self.id).target_trait.clone()
1120 }
1121
1122 pub fn target_type(self, db: &dyn HirDatabase) -> TypeRef {
1123 db.impl_data(self.id).target_type.clone()
1124 }
1125
1126 pub fn target_ty(self, db: &dyn HirDatabase) -> Type {
1127 let impl_data = db.impl_data(self.id);
1128 let resolver = self.id.resolver(db.upcast());
1129 let ctx = hir_ty::TyLoweringContext::new(db, &resolver);
1130 let environment = TraitEnvironment::lower(db, &resolver);
1131 let ty = Ty::from_hir(&ctx, &impl_data.target_type);
1132 Type {
1133 krate: self.id.lookup(db.upcast()).container.module(db.upcast()).krate,
1134 ty: InEnvironment { value: ty, environment },
1135 }
1136 }
1137
1138 pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> {
1139 db.impl_data(self.id).items.iter().map(|it| (*it).into()).collect()
1140 }
1141
1142 pub fn is_negative(self, db: &dyn HirDatabase) -> bool {
1143 db.impl_data(self.id).is_negative
1144 }
1145
1146 pub fn module(self, db: &dyn HirDatabase) -> Module {
1147 self.id.lookup(db.upcast()).container.module(db.upcast()).into()
1148 }
1149
1150 pub fn krate(self, db: &dyn HirDatabase) -> Crate {
1151 Crate { id: self.module(db).id.krate }
1152 }
1153
1154 pub fn is_builtin_derive(self, db: &dyn HirDatabase) -> Option<InFile<ast::Attr>> {
1155 let src = self.source(db);
1156 let item = src.file_id.is_builtin_derive(db.upcast())?;
1157 let hygenic = hir_expand::hygiene::Hygiene::new(db.upcast(), item.file_id);
1158
1159 let attr = item
1160 .value
1161 .attrs()
1162 .filter_map(|it| {
1163 let path = hir_def::path::ModPath::from_src(it.path()?, &hygenic)?;
1164 if path.as_ident()?.to_string() == "derive" {
1165 Some(it)
1166 } else {
1167 None
1168 }
1169 })
1170 .last()?;
1171
1172 Some(item.with_value(attr))
1173 }
1174}
1175
1176#[derive(Clone, PartialEq, Eq, Debug)]
1177pub struct Type {
1178 krate: CrateId,
1179 ty: InEnvironment<Ty>,
1180}
1181
1182impl Type {
1183 pub(crate) fn new_with_resolver(
1184 db: &dyn HirDatabase,
1185 resolver: &Resolver,
1186 ty: Ty,
1187 ) -> Option<Type> {
1188 let krate = resolver.krate()?;
1189 Some(Type::new_with_resolver_inner(db, krate, resolver, ty))
1190 }
1191 pub(crate) fn new_with_resolver_inner(
1192 db: &dyn HirDatabase,
1193 krate: CrateId,
1194 resolver: &Resolver,
1195 ty: Ty,
1196 ) -> Type {
1197 let environment = TraitEnvironment::lower(db, &resolver);
1198 Type { krate, ty: InEnvironment { value: ty, environment } }
1199 }
1200
1201 fn new(db: &dyn HirDatabase, krate: CrateId, lexical_env: impl HasResolver, ty: Ty) -> Type {
1202 let resolver = lexical_env.resolver(db.upcast());
1203 let environment = TraitEnvironment::lower(db, &resolver);
1204 Type { krate, ty: InEnvironment { value: ty, environment } }
1205 }
1206
1207 fn from_def(
1208 db: &dyn HirDatabase,
1209 krate: CrateId,
1210 def: impl HasResolver + Into<TyDefId> + Into<GenericDefId>,
1211 ) -> Type {
1212 let substs = Substs::build_for_def(db, def).fill_with_unknown().build();
1213 let ty = db.ty(def.into()).subst(&substs);
1214 Type::new(db, krate, def, ty)
1215 }
1216
1217 pub fn is_unit(&self) -> bool {
1218 matches!(
1219 self.ty.value,
1220 Ty::Apply(ApplicationTy { ctor: TypeCtor::Tuple { cardinality: 0 }, .. })
1221 )
1222 }
1223 pub fn is_bool(&self) -> bool {
1224 matches!(self.ty.value, Ty::Apply(ApplicationTy { ctor: TypeCtor::Bool, .. }))
1225 }
1226
1227 pub fn is_mutable_reference(&self) -> bool {
1228 matches!(
1229 self.ty.value,
1230 Ty::Apply(ApplicationTy { ctor: TypeCtor::Ref(Mutability::Mut), .. })
1231 )
1232 }
1233
1234 pub fn is_unknown(&self) -> bool {
1235 matches!(self.ty.value, Ty::Unknown)
1236 }
1237
1238 /// Checks that particular type `ty` implements `std::future::Future`.
1239 /// This function is used in `.await` syntax completion.
1240 pub fn impls_future(&self, db: &dyn HirDatabase) -> bool {
1241 let krate = self.krate;
1242
1243 let std_future_trait =
1244 db.lang_item(krate, "future_trait".into()).and_then(|it| it.as_trait());
1245 let std_future_trait = match std_future_trait {
1246 Some(it) => it,
1247 None => return false,
1248 };
1249
1250 let canonical_ty = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) };
1251 method_resolution::implements_trait(
1252 &canonical_ty,
1253 db,
1254 self.ty.environment.clone(),
1255 krate,
1256 std_future_trait,
1257 )
1258 }
1259
1260 pub fn impls_trait(&self, db: &dyn HirDatabase, trait_: Trait, args: &[Type]) -> bool {
1261 let trait_ref = hir_ty::TraitRef {
1262 trait_: trait_.id,
1263 substs: Substs::build_for_def(db, trait_.id)
1264 .push(self.ty.value.clone())
1265 .fill(args.iter().map(|t| t.ty.value.clone()))
1266 .build(),
1267 };
1268
1269 let goal = Canonical {
1270 value: hir_ty::InEnvironment::new(
1271 self.ty.environment.clone(),
1272 hir_ty::Obligation::Trait(trait_ref),
1273 ),
1274 kinds: Arc::new([]),
1275 };
1276
1277 db.trait_solve(self.krate, goal).is_some()
1278 }
1279
1280 pub fn as_callable(&self, db: &dyn HirDatabase) -> Option<Callable> {
1281 let def = match self.ty.value {
1282 Ty::Apply(ApplicationTy { ctor: TypeCtor::FnDef(def), parameters: _ }) => Some(def),
1283 _ => None,
1284 };
1285
1286 let sig = self.ty.value.callable_sig(db)?;
1287 Some(Callable { ty: self.clone(), sig, def, is_bound_method: false })
1288 }
1289
1290 pub fn is_closure(&self) -> bool {
1291 matches!(&self.ty.value, Ty::Apply(ApplicationTy { ctor: TypeCtor::Closure { .. }, .. }))
1292 }
1293
1294 pub fn is_fn(&self) -> bool {
1295 matches!(&self.ty.value,
1296 Ty::Apply(ApplicationTy { ctor: TypeCtor::FnDef(..), .. }) |
1297 Ty::Apply(ApplicationTy { ctor: TypeCtor::FnPtr { .. }, .. })
1298 )
1299 }
1300
1301 pub fn is_raw_ptr(&self) -> bool {
1302 matches!(&self.ty.value, Ty::Apply(ApplicationTy { ctor: TypeCtor::RawPtr(..), .. }))
1303 }
1304
1305 pub fn contains_unknown(&self) -> bool {
1306 return go(&self.ty.value);
1307
1308 fn go(ty: &Ty) -> bool {
1309 match ty {
1310 Ty::Unknown => true,
1311 Ty::Apply(a_ty) => a_ty.parameters.iter().any(go),
1312 _ => false,
1313 }
1314 }
1315 }
1316
1317 pub fn fields(&self, db: &dyn HirDatabase) -> Vec<(Field, Type)> {
1318 if let Ty::Apply(a_ty) = &self.ty.value {
1319 let variant_id = match a_ty.ctor {
1320 TypeCtor::Adt(AdtId::StructId(s)) => s.into(),
1321 TypeCtor::Adt(AdtId::UnionId(u)) => u.into(),
1322 _ => return Vec::new(),
1323 };
1324
1325 return db
1326 .field_types(variant_id)
1327 .iter()
1328 .map(|(local_id, ty)| {
1329 let def = Field { parent: variant_id.into(), id: local_id };
1330 let ty = ty.clone().subst(&a_ty.parameters);
1331 (def, self.derived(ty))
1332 })
1333 .collect();
1334 };
1335 Vec::new()
1336 }
1337
1338 pub fn tuple_fields(&self, _db: &dyn HirDatabase) -> Vec<Type> {
1339 let mut res = Vec::new();
1340 if let Ty::Apply(a_ty) = &self.ty.value {
1341 if let TypeCtor::Tuple { .. } = a_ty.ctor {
1342 for ty in a_ty.parameters.iter() {
1343 let ty = ty.clone();
1344 res.push(self.derived(ty));
1345 }
1346 }
1347 };
1348 res
1349 }
1350
1351 pub fn autoderef<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Type> + 'a {
1352 // There should be no inference vars in types passed here
1353 // FIXME check that?
1354 let canonical = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) };
1355 let environment = self.ty.environment.clone();
1356 let ty = InEnvironment { value: canonical, environment };
1357 autoderef(db, Some(self.krate), ty)
1358 .map(|canonical| canonical.value)
1359 .map(move |ty| self.derived(ty))
1360 }
1361
1362 // This would be nicer if it just returned an iterator, but that runs into
1363 // lifetime problems, because we need to borrow temp `CrateImplDefs`.
1364 pub fn iterate_assoc_items<T>(
1365 self,
1366 db: &dyn HirDatabase,
1367 krate: Crate,
1368 mut callback: impl FnMut(AssocItem) -> Option<T>,
1369 ) -> Option<T> {
1370 for krate in self.ty.value.def_crates(db, krate.id)? {
1371 let impls = db.inherent_impls_in_crate(krate);
1372
1373 for impl_def in impls.for_self_ty(&self.ty.value) {
1374 for &item in db.impl_data(*impl_def).items.iter() {
1375 if let Some(result) = callback(item.into()) {
1376 return Some(result);
1377 }
1378 }
1379 }
1380 }
1381 None
1382 }
1383
1384 pub fn iterate_method_candidates<T>(
1385 &self,
1386 db: &dyn HirDatabase,
1387 krate: Crate,
1388 traits_in_scope: &FxHashSet<TraitId>,
1389 name: Option<&Name>,
1390 mut callback: impl FnMut(&Ty, Function) -> Option<T>,
1391 ) -> Option<T> {
1392 // There should be no inference vars in types passed here
1393 // FIXME check that?
1394 // FIXME replace Unknown by bound vars here
1395 let canonical = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) };
1396
1397 let env = self.ty.environment.clone();
1398 let krate = krate.id;
1399
1400 method_resolution::iterate_method_candidates(
1401 &canonical,
1402 db,
1403 env,
1404 krate,
1405 traits_in_scope,
1406 name,
1407 method_resolution::LookupMode::MethodCall,
1408 |ty, it| match it {
1409 AssocItemId::FunctionId(f) => callback(ty, f.into()),
1410 _ => None,
1411 },
1412 )
1413 }
1414
1415 pub fn iterate_path_candidates<T>(
1416 &self,
1417 db: &dyn HirDatabase,
1418 krate: Crate,
1419 traits_in_scope: &FxHashSet<TraitId>,
1420 name: Option<&Name>,
1421 mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>,
1422 ) -> Option<T> {
1423 // There should be no inference vars in types passed here
1424 // FIXME check that?
1425 // FIXME replace Unknown by bound vars here
1426 let canonical = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) };
1427
1428 let env = self.ty.environment.clone();
1429 let krate = krate.id;
1430
1431 method_resolution::iterate_method_candidates(
1432 &canonical,
1433 db,
1434 env,
1435 krate,
1436 traits_in_scope,
1437 name,
1438 method_resolution::LookupMode::Path,
1439 |ty, it| callback(ty, it.into()),
1440 )
1441 }
1442
1443 pub fn as_adt(&self) -> Option<Adt> {
1444 let (adt, _subst) = self.ty.value.as_adt()?;
1445 Some(adt.into())
1446 }
1447
1448 pub fn as_dyn_trait(&self) -> Option<Trait> {
1449 self.ty.value.dyn_trait().map(Into::into)
1450 }
1451
1452 pub fn as_impl_traits(&self, db: &dyn HirDatabase) -> Option<Vec<Trait>> {
1453 self.ty.value.impl_trait_bounds(db).map(|it| {
1454 it.into_iter()
1455 .filter_map(|pred| match pred {
1456 hir_ty::GenericPredicate::Implemented(trait_ref) => {
1457 Some(Trait::from(trait_ref.trait_))
1458 }
1459 _ => None,
1460 })
1461 .collect()
1462 })
1463 }
1464
1465 pub fn as_associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<Trait> {
1466 self.ty.value.associated_type_parent_trait(db).map(Into::into)
1467 }
1468
1469 // FIXME: provide required accessors such that it becomes implementable from outside.
1470 pub fn is_equal_for_find_impls(&self, other: &Type) -> bool {
1471 match (&self.ty.value, &other.ty.value) {
1472 (Ty::Apply(a_original_ty), Ty::Apply(ApplicationTy { ctor, parameters })) => match ctor
1473 {
1474 TypeCtor::Ref(..) => match parameters.as_single() {
1475 Ty::Apply(a_ty) => a_original_ty.ctor == a_ty.ctor,
1476 _ => false,
1477 },
1478 _ => a_original_ty.ctor == *ctor,
1479 },
1480 _ => false,
1481 }
1482 }
1483
1484 fn derived(&self, ty: Ty) -> Type {
1485 Type {
1486 krate: self.krate,
1487 ty: InEnvironment { value: ty, environment: self.ty.environment.clone() },
1488 }
1489 }
1490
1491 pub fn walk(&self, db: &dyn HirDatabase, mut cb: impl FnMut(Type)) {
1492 // TypeWalk::walk for a Ty at first visits parameters and only after that the Ty itself.
1493 // We need a different order here.
1494
1495 fn walk_substs(
1496 db: &dyn HirDatabase,
1497 type_: &Type,
1498 substs: &Substs,
1499 cb: &mut impl FnMut(Type),
1500 ) {
1501 for ty in substs.iter() {
1502 walk_type(db, &type_.derived(ty.clone()), cb);
1503 }
1504 }
1505
1506 fn walk_bounds(
1507 db: &dyn HirDatabase,
1508 type_: &Type,
1509 bounds: &[GenericPredicate],
1510 cb: &mut impl FnMut(Type),
1511 ) {
1512 for pred in bounds {
1513 match pred {
1514 GenericPredicate::Implemented(trait_ref) => {
1515 cb(type_.clone());
1516 walk_substs(db, type_, &trait_ref.substs, cb);
1517 }
1518 _ => (),
1519 }
1520 }
1521 }
1522
1523 fn walk_type(db: &dyn HirDatabase, type_: &Type, cb: &mut impl FnMut(Type)) {
1524 let ty = type_.ty.value.strip_references();
1525 match ty {
1526 Ty::Apply(ApplicationTy { ctor, parameters }) => {
1527 match ctor {
1528 TypeCtor::Adt(_) => {
1529 cb(type_.derived(ty.clone()));
1530 }
1531 TypeCtor::AssociatedType(_) => {
1532 if let Some(_) = ty.associated_type_parent_trait(db) {
1533 cb(type_.derived(ty.clone()));
1534 }
1535 }
1536 _ => (),
1537 }
1538
1539 // adt params, tuples, etc...
1540 walk_substs(db, type_, parameters, cb);
1541 }
1542 Ty::Opaque(opaque_ty) => {
1543 if let Some(bounds) = ty.impl_trait_bounds(db) {
1544 walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb);
1545 }
1546
1547 walk_substs(db, type_, &opaque_ty.parameters, cb);
1548 }
1549 Ty::Placeholder(_) => {
1550 if let Some(bounds) = ty.impl_trait_bounds(db) {
1551 walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb);
1552 }
1553 }
1554 Ty::Dyn(bounds) => {
1555 walk_bounds(db, &type_.derived(ty.clone()), bounds.as_ref(), cb);
1556 }
1557
1558 _ => (),
1559 }
1560 }
1561
1562 walk_type(db, self, &mut cb);
1563 }
1564}
1565
1566impl HirDisplay for Type {
1567 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
1568 self.ty.value.hir_fmt(f)
1569 }
1570}
1571
1572// FIXME: closures
1573#[derive(Debug)]
1574pub struct Callable {
1575 ty: Type,
1576 sig: FnSig,
1577 def: Option<CallableDefId>,
1578 pub(crate) is_bound_method: bool,
1579}
1580
1581pub enum CallableKind {
1582 Function(Function),
1583 TupleStruct(Struct),
1584 TupleEnumVariant(EnumVariant),
1585 Closure,
1586}
1587
1588impl Callable {
1589 pub fn kind(&self) -> CallableKind {
1590 match self.def {
1591 Some(CallableDefId::FunctionId(it)) => CallableKind::Function(it.into()),
1592 Some(CallableDefId::StructId(it)) => CallableKind::TupleStruct(it.into()),
1593 Some(CallableDefId::EnumVariantId(it)) => CallableKind::TupleEnumVariant(it.into()),
1594 None => CallableKind::Closure,
1595 }
1596 }
1597 pub fn receiver_param(&self, db: &dyn HirDatabase) -> Option<ast::SelfParam> {
1598 let func = match self.def {
1599 Some(CallableDefId::FunctionId(it)) if self.is_bound_method => it,
1600 _ => return None,
1601 };
1602 let src = func.lookup(db.upcast()).source(db.upcast());
1603 let param_list = src.value.param_list()?;
1604 param_list.self_param()
1605 }
1606 pub fn n_params(&self) -> usize {
1607 self.sig.params().len() - if self.is_bound_method { 1 } else { 0 }
1608 }
1609 pub fn params(
1610 &self,
1611 db: &dyn HirDatabase,
1612 ) -> Vec<(Option<Either<ast::SelfParam, ast::Pat>>, Type)> {
1613 let types = self
1614 .sig
1615 .params()
1616 .iter()
1617 .skip(if self.is_bound_method { 1 } else { 0 })
1618 .map(|ty| self.ty.derived(ty.clone()));
1619 let patterns = match self.def {
1620 Some(CallableDefId::FunctionId(func)) => {
1621 let src = func.lookup(db.upcast()).source(db.upcast());
1622 src.value.param_list().map(|param_list| {
1623 param_list
1624 .self_param()
1625 .map(|it| Some(Either::Left(it)))
1626 .filter(|_| !self.is_bound_method)
1627 .into_iter()
1628 .chain(param_list.params().map(|it| it.pat().map(Either::Right)))
1629 })
1630 }
1631 _ => None,
1632 };
1633 patterns.into_iter().flatten().chain(iter::repeat(None)).zip(types).collect()
1634 }
1635 pub fn return_type(&self) -> Type {
1636 self.ty.derived(self.sig.ret().clone())
1637 }
1638}
1639
1640/// For IDE only
1641#[derive(Debug)]
1642pub enum ScopeDef {
1643 ModuleDef(ModuleDef),
1644 MacroDef(MacroDef),
1645 GenericParam(TypeParam),
1646 ImplSelfType(ImplDef),
1647 AdtSelfType(Adt),
1648 Local(Local),
1649 Unknown,
1650}
1651
1652impl ScopeDef {
1653 pub fn all_items(def: PerNs) -> ArrayVec<[Self; 3]> {
1654 let mut items = ArrayVec::new();
1655
1656 match (def.take_types(), def.take_values()) {
1657 (Some(m1), None) => items.push(ScopeDef::ModuleDef(m1.into())),
1658 (None, Some(m2)) => items.push(ScopeDef::ModuleDef(m2.into())),
1659 (Some(m1), Some(m2)) => {
1660 // Some items, like unit structs and enum variants, are
1661 // returned as both a type and a value. Here we want
1662 // to de-duplicate them.
1663 if m1 != m2 {
1664 items.push(ScopeDef::ModuleDef(m1.into()));
1665 items.push(ScopeDef::ModuleDef(m2.into()));
1666 } else {
1667 items.push(ScopeDef::ModuleDef(m1.into()));
1668 }
1669 }
1670 (None, None) => {}
1671 };
1672
1673 if let Some(macro_def_id) = def.take_macros() {
1674 items.push(ScopeDef::MacroDef(macro_def_id.into()));
1675 }
1676
1677 if items.is_empty() {
1678 items.push(ScopeDef::Unknown);
1679 }
1680
1681 items
1682 }
1683}
1684
1685#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1686pub enum AttrDef {
1687 Module(Module),
1688 Field(Field),
1689 Adt(Adt),
1690 Function(Function),
1691 EnumVariant(EnumVariant),
1692 Static(Static),
1693 Const(Const),
1694 Trait(Trait),
1695 TypeAlias(TypeAlias),
1696 MacroDef(MacroDef),
1697}
1698
1699impl_from!(
1700 Module,
1701 Field,
1702 Adt(Struct, Enum, Union),
1703 EnumVariant,
1704 Static,
1705 Const,
1706 Function,
1707 Trait,
1708 TypeAlias,
1709 MacroDef
1710 for AttrDef
1711);
1712
1713pub trait HasAttrs {
1714 fn attrs(self, db: &dyn HirDatabase) -> Attrs;
1715}
1716
1717impl<T: Into<AttrDef>> HasAttrs for T {
1718 fn attrs(self, db: &dyn HirDatabase) -> Attrs {
1719 let def: AttrDef = self.into();
1720 db.attrs(def.into())
1721 }
1722}
1723
1724pub trait Docs {
1725 fn docs(&self, db: &dyn HirDatabase) -> Option<Documentation>;
1726}
1727impl<T: Into<AttrDef> + Copy> Docs for T {
1728 fn docs(&self, db: &dyn HirDatabase) -> Option<Documentation> {
1729 let def: AttrDef = (*self).into();
1730 db.documentation(def.into())
1731 }
1732}
1733
1734pub trait HasVisibility {
1735 fn visibility(&self, db: &dyn HirDatabase) -> Visibility;
1736 fn is_visible_from(&self, db: &dyn HirDatabase, module: Module) -> bool {
1737 let vis = self.visibility(db);
1738 vis.is_visible_from(db.upcast(), module.id)
1739 }
1740}
1741
1742impl Resolvable for ModuleDef {
1743 fn resolver<D: DefDatabase + HirDatabase>(&self, db: &D) -> Option<Resolver> {
1744 Some(match self {
1745 ModuleDef::Module(m) => ModuleId::from(m.clone()).resolver(db),
1746 ModuleDef::Function(f) => FunctionId::from(f.clone()).resolver(db),
1747 ModuleDef::Adt(adt) => AdtId::from(adt.clone()).resolver(db),
1748 ModuleDef::EnumVariant(ev) => {
1749 GenericDefId::from(GenericDef::from(ev.clone())).resolver(db)
1750 }
1751 ModuleDef::Const(c) => GenericDefId::from(GenericDef::from(c.clone())).resolver(db),
1752 ModuleDef::Static(s) => StaticId::from(s.clone()).resolver(db),
1753 ModuleDef::Trait(t) => TraitId::from(t.clone()).resolver(db),
1754 ModuleDef::TypeAlias(t) => ModuleId::from(t.module(db)).resolver(db),
1755 // FIXME: This should be a resolver relative to `std/core`
1756 ModuleDef::BuiltinType(_t) => None?,
1757 })
1758 }
1759
1760 fn try_into_module_def(self) -> Option<ModuleDef> {
1761 Some(self)
1762 }
1763}
1764
1765impl Resolvable for TypeParam {
1766 fn resolver<D: DefDatabase + HirDatabase>(&self, db: &D) -> Option<Resolver> {
1767 Some(Into::<ModuleId>::into(self.module(db)).resolver(db))
1768 }
1769
1770 fn try_into_module_def(self) -> Option<ModuleDef> {
1771 None
1772 }
1773}
1774
1775impl Resolvable for MacroDef {
1776 fn resolver<D: DefDatabase + HirDatabase>(&self, db: &D) -> Option<Resolver> {
1777 Some(Into::<ModuleId>::into(self.module(db)?).resolver(db))
1778 }
1779
1780 fn try_into_module_def(self) -> Option<ModuleDef> {
1781 None
1782 }
1783}
1784
1785impl Resolvable for Field {
1786 fn resolver<D: DefDatabase + HirDatabase>(&self, db: &D) -> Option<Resolver> {
1787 Some(Into::<VariantId>::into(Into::<VariantDef>::into(self.parent_def(db))).resolver(db))
1788 }
1789
1790 fn try_into_module_def(self) -> Option<ModuleDef> {
1791 None
1792 }
1793}
1794
1795impl Resolvable for ImplDef {
1796 fn resolver<D: DefDatabase + HirDatabase>(&self, db: &D) -> Option<Resolver> {
1797 Some(Into::<ModuleId>::into(self.module(db)).resolver(db))
1798 }
1799
1800 fn try_into_module_def(self) -> Option<ModuleDef> {
1801 None
1802 }
1803}
1804
1805impl Resolvable for Local {
1806 fn resolver<D: DefDatabase + HirDatabase>(&self, db: &D) -> Option<Resolver> {
1807 Some(Into::<ModuleId>::into(self.module(db)).resolver(db))
1808 }
1809
1810 fn try_into_module_def(self) -> Option<ModuleDef> {
1811 None
1812 }
1813}
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
deleted file mode 100644
index a2b9f3e35..000000000
--- a/crates/ra_hir/src/db.rs
+++ /dev/null
@@ -1,28 +0,0 @@
1//! FIXME: write short doc here
2
3pub use hir_def::db::{
4 AttrsQuery, BodyQuery, BodyWithSourceMapQuery, ConstDataQuery, CrateDefMapQueryQuery,
5 CrateLangItemsQuery, DefDatabase, DefDatabaseStorage, DocumentationQuery, EnumDataQuery,
6 ExprScopesQuery, FunctionDataQuery, GenericParamsQuery, ImplDataQuery, ImportMapQuery,
7 InternConstQuery, InternDatabase, InternDatabaseStorage, InternEnumQuery, InternFunctionQuery,
8 InternImplQuery, InternStaticQuery, InternStructQuery, InternTraitQuery, InternTypeAliasQuery,
9 InternUnionQuery, ItemTreeQuery, LangItemQuery, ModuleLangItemsQuery, StaticDataQuery,
10 StructDataQuery, TraitDataQuery, TypeAliasDataQuery, UnionDataQuery,
11};
12pub use hir_expand::db::{
13 AstDatabase, AstDatabaseStorage, AstIdMapQuery, InternEagerExpansionQuery, InternMacroQuery,
14 MacroArgTextQuery, MacroDefQuery, MacroExpandQuery, ParseMacroQuery,
15};
16pub use hir_ty::db::{
17 AssociatedTyDataQuery, AssociatedTyValueQuery, CallableItemSignatureQuery, FieldTypesQuery,
18 GenericDefaultsQuery, GenericPredicatesForParamQuery, GenericPredicatesQuery, HirDatabase,
19 HirDatabaseStorage, ImplDatumQuery, ImplSelfTyQuery, ImplTraitQuery, InferQueryQuery,
20 InherentImplsInCrateQuery, InternTypeParamIdQuery, ReturnTypeImplTraitsQuery, StructDatumQuery,
21 TraitDatumQuery, TraitImplsInCrateQuery, TraitImplsInDepsQuery, TraitSolveQuery, TyQuery,
22 ValueTyQuery,
23};
24
25#[test]
26fn hir_database_is_object_safe() {
27 fn _assert_object_safe(_: &dyn HirDatabase) {}
28}
diff --git a/crates/ra_hir/src/diagnostics.rs b/crates/ra_hir/src/diagnostics.rs
deleted file mode 100644
index 266b513dc..000000000
--- a/crates/ra_hir/src/diagnostics.rs
+++ /dev/null
@@ -1,8 +0,0 @@
1//! FIXME: write short doc here
2pub use hir_def::diagnostics::UnresolvedModule;
3pub use hir_expand::diagnostics::{
4 AstDiagnostic, Diagnostic, DiagnosticSink, DiagnosticSinkBuilder,
5};
6pub use hir_ty::diagnostics::{
7 MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkInTailExpr, NoSuchField,
8};
diff --git a/crates/ra_hir/src/from_id.rs b/crates/ra_hir/src/from_id.rs
deleted file mode 100644
index 679ae8121..000000000
--- a/crates/ra_hir/src/from_id.rs
+++ /dev/null
@@ -1,247 +0,0 @@
1//! Utility module for converting between hir_def ids and code_model wrappers.
2//!
3//! It's unclear if we need this long-term, but it's definitelly useful while we
4//! are splitting the hir.
5
6use hir_def::{
7 expr::PatId, AdtId, AssocItemId, AttrDefId, DefWithBodyId, EnumVariantId, FieldId,
8 GenericDefId, ModuleDefId, VariantId,
9};
10
11use crate::{
12 code_model::ItemInNs, Adt, AssocItem, AttrDef, DefWithBody, EnumVariant, Field, GenericDef,
13 Local, MacroDef, ModuleDef, VariantDef,
14};
15
16macro_rules! from_id {
17 ($(($id:path, $ty:path)),*) => {$(
18 impl From<$id> for $ty {
19 fn from(id: $id) -> $ty {
20 $ty { id }
21 }
22 }
23 impl From<$ty> for $id {
24 fn from(ty: $ty) -> $id {
25 ty.id
26 }
27 }
28 )*}
29}
30
31from_id![
32 (ra_db::CrateId, crate::Crate),
33 (hir_def::ModuleId, crate::Module),
34 (hir_def::StructId, crate::Struct),
35 (hir_def::UnionId, crate::Union),
36 (hir_def::EnumId, crate::Enum),
37 (hir_def::TypeAliasId, crate::TypeAlias),
38 (hir_def::TraitId, crate::Trait),
39 (hir_def::StaticId, crate::Static),
40 (hir_def::ConstId, crate::Const),
41 (hir_def::FunctionId, crate::Function),
42 (hir_def::ImplId, crate::ImplDef),
43 (hir_def::TypeParamId, crate::TypeParam),
44 (hir_expand::MacroDefId, crate::MacroDef)
45];
46
47impl From<AdtId> for Adt {
48 fn from(id: AdtId) -> Self {
49 match id {
50 AdtId::StructId(it) => Adt::Struct(it.into()),
51 AdtId::UnionId(it) => Adt::Union(it.into()),
52 AdtId::EnumId(it) => Adt::Enum(it.into()),
53 }
54 }
55}
56
57impl From<Adt> for AdtId {
58 fn from(id: Adt) -> Self {
59 match id {
60 Adt::Struct(it) => AdtId::StructId(it.id),
61 Adt::Union(it) => AdtId::UnionId(it.id),
62 Adt::Enum(it) => AdtId::EnumId(it.id),
63 }
64 }
65}
66
67impl From<EnumVariantId> for EnumVariant {
68 fn from(id: EnumVariantId) -> Self {
69 EnumVariant { parent: id.parent.into(), id: id.local_id }
70 }
71}
72
73impl From<EnumVariant> for EnumVariantId {
74 fn from(def: EnumVariant) -> Self {
75 EnumVariantId { parent: def.parent.id, local_id: def.id }
76 }
77}
78
79impl From<ModuleDefId> for ModuleDef {
80 fn from(id: ModuleDefId) -> Self {
81 match id {
82 ModuleDefId::ModuleId(it) => ModuleDef::Module(it.into()),
83 ModuleDefId::FunctionId(it) => ModuleDef::Function(it.into()),
84 ModuleDefId::AdtId(it) => ModuleDef::Adt(it.into()),
85 ModuleDefId::EnumVariantId(it) => ModuleDef::EnumVariant(it.into()),
86 ModuleDefId::ConstId(it) => ModuleDef::Const(it.into()),
87 ModuleDefId::StaticId(it) => ModuleDef::Static(it.into()),
88 ModuleDefId::TraitId(it) => ModuleDef::Trait(it.into()),
89 ModuleDefId::TypeAliasId(it) => ModuleDef::TypeAlias(it.into()),
90 ModuleDefId::BuiltinType(it) => ModuleDef::BuiltinType(it),
91 }
92 }
93}
94
95impl From<ModuleDef> for ModuleDefId {
96 fn from(id: ModuleDef) -> Self {
97 match id {
98 ModuleDef::Module(it) => ModuleDefId::ModuleId(it.into()),
99 ModuleDef::Function(it) => ModuleDefId::FunctionId(it.into()),
100 ModuleDef::Adt(it) => ModuleDefId::AdtId(it.into()),
101 ModuleDef::EnumVariant(it) => ModuleDefId::EnumVariantId(it.into()),
102 ModuleDef::Const(it) => ModuleDefId::ConstId(it.into()),
103 ModuleDef::Static(it) => ModuleDefId::StaticId(it.into()),
104 ModuleDef::Trait(it) => ModuleDefId::TraitId(it.into()),
105 ModuleDef::TypeAlias(it) => ModuleDefId::TypeAliasId(it.into()),
106 ModuleDef::BuiltinType(it) => ModuleDefId::BuiltinType(it),
107 }
108 }
109}
110
111impl From<DefWithBody> for DefWithBodyId {
112 fn from(def: DefWithBody) -> Self {
113 match def {
114 DefWithBody::Function(it) => DefWithBodyId::FunctionId(it.id),
115 DefWithBody::Static(it) => DefWithBodyId::StaticId(it.id),
116 DefWithBody::Const(it) => DefWithBodyId::ConstId(it.id),
117 }
118 }
119}
120
121impl From<DefWithBodyId> for DefWithBody {
122 fn from(def: DefWithBodyId) -> Self {
123 match def {
124 DefWithBodyId::FunctionId(it) => DefWithBody::Function(it.into()),
125 DefWithBodyId::StaticId(it) => DefWithBody::Static(it.into()),
126 DefWithBodyId::ConstId(it) => DefWithBody::Const(it.into()),
127 }
128 }
129}
130
131impl From<AssocItemId> for AssocItem {
132 fn from(def: AssocItemId) -> Self {
133 match def {
134 AssocItemId::FunctionId(it) => AssocItem::Function(it.into()),
135 AssocItemId::TypeAliasId(it) => AssocItem::TypeAlias(it.into()),
136 AssocItemId::ConstId(it) => AssocItem::Const(it.into()),
137 }
138 }
139}
140
141impl From<GenericDef> for GenericDefId {
142 fn from(def: GenericDef) -> Self {
143 match def {
144 GenericDef::Function(it) => GenericDefId::FunctionId(it.id),
145 GenericDef::Adt(it) => GenericDefId::AdtId(it.into()),
146 GenericDef::Trait(it) => GenericDefId::TraitId(it.id),
147 GenericDef::TypeAlias(it) => GenericDefId::TypeAliasId(it.id),
148 GenericDef::ImplDef(it) => GenericDefId::ImplId(it.id),
149 GenericDef::EnumVariant(it) => {
150 GenericDefId::EnumVariantId(EnumVariantId { parent: it.parent.id, local_id: it.id })
151 }
152 GenericDef::Const(it) => GenericDefId::ConstId(it.id),
153 }
154 }
155}
156
157impl From<Adt> for GenericDefId {
158 fn from(id: Adt) -> Self {
159 match id {
160 Adt::Struct(it) => it.id.into(),
161 Adt::Union(it) => it.id.into(),
162 Adt::Enum(it) => it.id.into(),
163 }
164 }
165}
166
167impl From<VariantId> for VariantDef {
168 fn from(def: VariantId) -> Self {
169 match def {
170 VariantId::StructId(it) => VariantDef::Struct(it.into()),
171 VariantId::EnumVariantId(it) => VariantDef::EnumVariant(it.into()),
172 VariantId::UnionId(it) => VariantDef::Union(it.into()),
173 }
174 }
175}
176
177impl From<VariantDef> for VariantId {
178 fn from(def: VariantDef) -> Self {
179 match def {
180 VariantDef::Struct(it) => VariantId::StructId(it.id),
181 VariantDef::EnumVariant(it) => VariantId::EnumVariantId(it.into()),
182 VariantDef::Union(it) => VariantId::UnionId(it.id),
183 }
184 }
185}
186
187impl From<Field> for FieldId {
188 fn from(def: Field) -> Self {
189 FieldId { parent: def.parent.into(), local_id: def.id }
190 }
191}
192
193impl From<FieldId> for Field {
194 fn from(def: FieldId) -> Self {
195 Field { parent: def.parent.into(), id: def.local_id }
196 }
197}
198
199impl From<AttrDef> for AttrDefId {
200 fn from(def: AttrDef) -> Self {
201 match def {
202 AttrDef::Module(it) => AttrDefId::ModuleId(it.id),
203 AttrDef::Field(it) => AttrDefId::FieldId(it.into()),
204 AttrDef::Adt(it) => AttrDefId::AdtId(it.into()),
205 AttrDef::Function(it) => AttrDefId::FunctionId(it.id),
206 AttrDef::EnumVariant(it) => AttrDefId::EnumVariantId(it.into()),
207 AttrDef::Static(it) => AttrDefId::StaticId(it.id),
208 AttrDef::Const(it) => AttrDefId::ConstId(it.id),
209 AttrDef::Trait(it) => AttrDefId::TraitId(it.id),
210 AttrDef::TypeAlias(it) => AttrDefId::TypeAliasId(it.id),
211 AttrDef::MacroDef(it) => AttrDefId::MacroDefId(it.id),
212 }
213 }
214}
215
216impl From<AssocItem> for GenericDefId {
217 fn from(item: AssocItem) -> Self {
218 match item {
219 AssocItem::Function(f) => f.id.into(),
220 AssocItem::Const(c) => c.id.into(),
221 AssocItem::TypeAlias(t) => t.id.into(),
222 }
223 }
224}
225
226impl From<(DefWithBodyId, PatId)> for Local {
227 fn from((parent, pat_id): (DefWithBodyId, PatId)) -> Self {
228 Local { parent, pat_id }
229 }
230}
231
232impl From<MacroDef> for ItemInNs {
233 fn from(macro_def: MacroDef) -> Self {
234 ItemInNs::Macros(macro_def.into())
235 }
236}
237
238impl From<ModuleDef> for ItemInNs {
239 fn from(module_def: ModuleDef) -> Self {
240 match module_def {
241 ModuleDef::Static(_) | ModuleDef::Const(_) | ModuleDef::Function(_) => {
242 ItemInNs::Values(module_def.into())
243 }
244 _ => ItemInNs::Types(module_def.into()),
245 }
246 }
247}
diff --git a/crates/ra_hir/src/has_source.rs b/crates/ra_hir/src/has_source.rs
deleted file mode 100644
index 1c691d961..000000000
--- a/crates/ra_hir/src/has_source.rs
+++ /dev/null
@@ -1,135 +0,0 @@
1//! FIXME: write short doc here
2
3use either::Either;
4use hir_def::{
5 nameres::{ModuleOrigin, ModuleSource},
6 src::{HasChildSource, HasSource as _},
7 Lookup, VariantId,
8};
9use ra_syntax::ast;
10
11use crate::{
12 db::HirDatabase, Const, Enum, EnumVariant, Field, FieldSource, Function, ImplDef, MacroDef,
13 Module, Static, Struct, Trait, TypeAlias, TypeParam, Union,
14};
15
16pub use hir_expand::InFile;
17
18pub trait HasSource {
19 type Ast;
20 fn source(self, db: &dyn HirDatabase) -> InFile<Self::Ast>;
21}
22
23/// NB: Module is !HasSource, because it has two source nodes at the same time:
24/// definition and declaration.
25impl Module {
26 /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items.
27 pub fn definition_source(self, db: &dyn HirDatabase) -> InFile<ModuleSource> {
28 let def_map = db.crate_def_map(self.id.krate);
29 def_map[self.id.local_id].definition_source(db.upcast())
30 }
31
32 pub fn is_mod_rs(self, db: &dyn HirDatabase) -> bool {
33 let def_map = db.crate_def_map(self.id.krate);
34 match def_map[self.id.local_id].origin {
35 ModuleOrigin::File { is_mod_rs, .. } => is_mod_rs,
36 _ => false,
37 }
38 }
39
40 /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`.
41 /// `None` for the crate root.
42 pub fn declaration_source(self, db: &dyn HirDatabase) -> Option<InFile<ast::Module>> {
43 let def_map = db.crate_def_map(self.id.krate);
44 def_map[self.id.local_id].declaration_source(db.upcast())
45 }
46}
47
48impl HasSource for Field {
49 type Ast = FieldSource;
50 fn source(self, db: &dyn HirDatabase) -> InFile<FieldSource> {
51 let var = VariantId::from(self.parent);
52 let src = var.child_source(db.upcast());
53 src.map(|it| match it[self.id].clone() {
54 Either::Left(it) => FieldSource::Pos(it),
55 Either::Right(it) => FieldSource::Named(it),
56 })
57 }
58}
59impl HasSource for Struct {
60 type Ast = ast::Struct;
61 fn source(self, db: &dyn HirDatabase) -> InFile<ast::Struct> {
62 self.id.lookup(db.upcast()).source(db.upcast())
63 }
64}
65impl HasSource for Union {
66 type Ast = ast::Union;
67 fn source(self, db: &dyn HirDatabase) -> InFile<ast::Union> {
68 self.id.lookup(db.upcast()).source(db.upcast())
69 }
70}
71impl HasSource for Enum {
72 type Ast = ast::Enum;
73 fn source(self, db: &dyn HirDatabase) -> InFile<ast::Enum> {
74 self.id.lookup(db.upcast()).source(db.upcast())
75 }
76}
77impl HasSource for EnumVariant {
78 type Ast = ast::Variant;
79 fn source(self, db: &dyn HirDatabase) -> InFile<ast::Variant> {
80 self.parent.id.child_source(db.upcast()).map(|map| map[self.id].clone())
81 }
82}
83impl HasSource for Function {
84 type Ast = ast::Fn;
85 fn source(self, db: &dyn HirDatabase) -> InFile<ast::Fn> {
86 self.id.lookup(db.upcast()).source(db.upcast())
87 }
88}
89impl HasSource for Const {
90 type Ast = ast::Const;
91 fn source(self, db: &dyn HirDatabase) -> InFile<ast::Const> {
92 self.id.lookup(db.upcast()).source(db.upcast())
93 }
94}
95impl HasSource for Static {
96 type Ast = ast::Static;
97 fn source(self, db: &dyn HirDatabase) -> InFile<ast::Static> {
98 self.id.lookup(db.upcast()).source(db.upcast())
99 }
100}
101impl HasSource for Trait {
102 type Ast = ast::Trait;
103 fn source(self, db: &dyn HirDatabase) -> InFile<ast::Trait> {
104 self.id.lookup(db.upcast()).source(db.upcast())
105 }
106}
107impl HasSource for TypeAlias {
108 type Ast = ast::TypeAlias;
109 fn source(self, db: &dyn HirDatabase) -> InFile<ast::TypeAlias> {
110 self.id.lookup(db.upcast()).source(db.upcast())
111 }
112}
113impl HasSource for MacroDef {
114 type Ast = ast::MacroCall;
115 fn source(self, db: &dyn HirDatabase) -> InFile<ast::MacroCall> {
116 InFile {
117 file_id: self.id.ast_id.expect("MacroDef without ast_id").file_id,
118 value: self.id.ast_id.expect("MacroDef without ast_id").to_node(db.upcast()),
119 }
120 }
121}
122impl HasSource for ImplDef {
123 type Ast = ast::Impl;
124 fn source(self, db: &dyn HirDatabase) -> InFile<ast::Impl> {
125 self.id.lookup(db.upcast()).source(db.upcast())
126 }
127}
128
129impl HasSource for TypeParam {
130 type Ast = Either<ast::Trait, ast::TypeParam>;
131 fn source(self, db: &dyn HirDatabase) -> InFile<Self::Ast> {
132 let child_source = self.id.parent.child_source(db.upcast());
133 child_source.map(|it| it[self.id.local_id].clone())
134 }
135}
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
deleted file mode 100644
index b33293a18..000000000
--- a/crates/ra_hir/src/lib.rs
+++ /dev/null
@@ -1,63 +0,0 @@
1//! HIR (previously known as descriptors) provides a high-level object oriented
2//! access to Rust code.
3//!
4//! The principal difference between HIR and syntax trees is that HIR is bound
5//! to a particular crate instance. That is, it has cfg flags and features
6//! applied. So, the relation between syntax and HIR is many-to-one.
7//!
8//! HIR is the public API of the all of the compiler logic above syntax trees.
9//! It is written in "OO" style. Each type is self contained (as in, it knows it's
10//! parents and full context). It should be "clean code".
11//!
12//! `ra_hir_*` crates are the implementation of the compiler logic.
13//! They are written in "ECS" style, with relatively little abstractions.
14//! Many types are not self-contained, and explicitly use local indexes, arenas, etc.
15//!
16//! `ra_hir` is what insulates the "we don't know how to actually write an incremental compiler"
17//! from the ide with completions, hovers, etc. It is a (soft, internal) boundary:
18//! https://www.tedinski.com/2018/02/06/system-boundaries.html.
19
20#![recursion_limit = "512"]
21
22mod semantics;
23pub mod db;
24mod source_analyzer;
25
26pub mod diagnostics;
27
28mod from_id;
29mod code_model;
30mod link_rewrite;
31
32mod has_source;
33
34pub use crate::{
35 code_model::{
36 Adt, AsAssocItem, AssocItem, AssocItemContainer, AttrDef, Callable, CallableKind, Const,
37 Crate, CrateDependency, DefWithBody, Docs, Enum, EnumVariant, Field, FieldSource, Function,
38 GenericDef, HasAttrs, HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef, ScopeDef,
39 Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, VariantDef, Visibility,
40 },
41 has_source::HasSource,
42 link_rewrite::resolve_doc_link,
43 semantics::{original_range, PathResolution, Semantics, SemanticsScope},
44};
45
46pub use hir_def::{
47 adt::StructKind,
48 attr::Attrs,
49 body::scope::ExprScopes,
50 builtin_type::BuiltinType,
51 docs::Documentation,
52 item_scope::ItemInNs,
53 nameres::ModuleSource,
54 path::{ModPath, Path, PathKind},
55 type_ref::Mutability,
56};
57pub use hir_expand::{
58 hygiene::Hygiene,
59 name::{AsName, Name},
60 HirFileId, InFile, MacroCallId, MacroCallLoc, MacroDefId, /* FIXME */
61 MacroFile, Origin,
62};
63pub use hir_ty::display::HirDisplay;
diff --git a/crates/ra_hir/src/link_rewrite.rs b/crates/ra_hir/src/link_rewrite.rs
deleted file mode 100644
index a66f1e6fc..000000000
--- a/crates/ra_hir/src/link_rewrite.rs
+++ /dev/null
@@ -1,226 +0,0 @@
1//! Resolves and rewrites links in markdown documentation for hovers/completion windows.
2
3use std::iter::once;
4
5use itertools::Itertools;
6use url::Url;
7
8use crate::{db::HirDatabase, Adt, AsName, Crate, Hygiene, ItemInNs, ModPath, ModuleDef};
9use hir_def::{db::DefDatabase, resolver::Resolver};
10use ra_syntax::ast::Path;
11
12pub fn resolve_doc_link<T: Resolvable + Clone, D: DefDatabase + HirDatabase>(
13 db: &D,
14 definition: &T,
15 link_text: &str,
16 link_target: &str,
17) -> Option<(String, String)> {
18 try_resolve_intra(db, definition, link_text, &link_target).or_else(|| {
19 if let Some(definition) = definition.clone().try_into_module_def() {
20 try_resolve_path(db, &definition, &link_target)
21 .map(|target| (target, link_text.to_string()))
22 } else {
23 None
24 }
25 })
26}
27
28/// Try to resolve path to local documentation via intra-doc-links (i.e. `super::gateway::Shard`).
29///
30/// See [RFC1946](https://github.com/rust-lang/rfcs/blob/master/text/1946-intra-rustdoc-links.md).
31fn try_resolve_intra<T: Resolvable, D: DefDatabase + HirDatabase>(
32 db: &D,
33 definition: &T,
34 link_text: &str,
35 link_target: &str,
36) -> Option<(String, String)> {
37 // Set link_target for implied shortlinks
38 let link_target =
39 if link_target.is_empty() { link_text.trim_matches('`') } else { link_target };
40
41 // Namespace disambiguation
42 let namespace = Namespace::from_intra_spec(link_target);
43
44 // Strip prefixes/suffixes
45 let link_target = strip_prefixes_suffixes(link_target);
46
47 // Parse link as a module path
48 let path = Path::parse(link_target).ok()?;
49 let modpath = ModPath::from_src(path, &Hygiene::new_unhygienic()).unwrap();
50
51 // Resolve it relative to symbol's location (according to the RFC this should consider small scopes)
52 let resolver = definition.resolver(db)?;
53
54 let resolved = resolver.resolve_module_path_in_items(db, &modpath);
55 let (defid, namespace) = match namespace {
56 // FIXME: .or(resolved.macros)
57 None => resolved
58 .types
59 .map(|t| (t.0, Namespace::Types))
60 .or(resolved.values.map(|t| (t.0, Namespace::Values)))?,
61 Some(ns @ Namespace::Types) => (resolved.types?.0, ns),
62 Some(ns @ Namespace::Values) => (resolved.values?.0, ns),
63 // FIXME:
64 Some(Namespace::Macros) => None?,
65 };
66
67 // Get the filepath of the final symbol
68 let def: ModuleDef = defid.into();
69 let module = def.module(db)?;
70 let krate = module.krate();
71 let ns = match namespace {
72 Namespace::Types => ItemInNs::Types(defid),
73 Namespace::Values => ItemInNs::Values(defid),
74 // FIXME:
75 Namespace::Macros => None?,
76 };
77 let import_map = db.import_map(krate.into());
78 let path = import_map.path_of(ns)?;
79
80 Some((
81 get_doc_url(db, &krate)?
82 .join(&format!("{}/", krate.display_name(db)?))
83 .ok()?
84 .join(&path.segments.iter().map(|name| name.to_string()).join("/"))
85 .ok()?
86 .join(&get_symbol_filename(db, &def)?)
87 .ok()?
88 .into_string(),
89 strip_prefixes_suffixes(link_text).to_string(),
90 ))
91}
92
93/// Try to resolve path to local documentation via path-based links (i.e. `../gateway/struct.Shard.html`).
94fn try_resolve_path(db: &dyn HirDatabase, moddef: &ModuleDef, link_target: &str) -> Option<String> {
95 if !link_target.contains("#") && !link_target.contains(".html") {
96 return None;
97 }
98 let ns = ItemInNs::Types(moddef.clone().into());
99
100 let module = moddef.module(db)?;
101 let krate = module.krate();
102 let import_map = db.import_map(krate.into());
103 let base = once(format!("{}", krate.display_name(db)?))
104 .chain(import_map.path_of(ns)?.segments.iter().map(|name| format!("{}", name)))
105 .join("/");
106
107 get_doc_url(db, &krate)
108 .and_then(|url| url.join(&base).ok())
109 .and_then(|url| {
110 get_symbol_filename(db, moddef).as_deref().map(|f| url.join(f).ok()).flatten()
111 })
112 .and_then(|url| url.join(link_target).ok())
113 .map(|url| url.into_string())
114}
115
116// Strip prefixes, suffixes, and inline code marks from the given string.
117fn strip_prefixes_suffixes(mut s: &str) -> &str {
118 s = s.trim_matches('`');
119
120 [
121 (TYPES.0.iter(), TYPES.1.iter()),
122 (VALUES.0.iter(), VALUES.1.iter()),
123 (MACROS.0.iter(), MACROS.1.iter()),
124 ]
125 .iter()
126 .for_each(|(prefixes, suffixes)| {
127 prefixes.clone().for_each(|prefix| s = s.trim_start_matches(*prefix));
128 suffixes.clone().for_each(|suffix| s = s.trim_end_matches(*suffix));
129 });
130 let s = s.trim_start_matches("@").trim();
131 s
132}
133
134fn get_doc_url(db: &dyn HirDatabase, krate: &Crate) -> Option<Url> {
135 krate
136 .get_doc_url(db)
137 .or_else(||
138 // Fallback to docs.rs
139 // FIXME: Specify an exact version here. This may be difficult, as multiple versions of the same crate could exist.
140 Some(format!("https://docs.rs/{}/*/", krate.display_name(db)?)))
141 .and_then(|s| Url::parse(&s).ok())
142}
143
144/// Get the filename and extension generated for a symbol by rustdoc.
145///
146/// Example: `struct.Shard.html`
147fn get_symbol_filename(db: &dyn HirDatabase, definition: &ModuleDef) -> Option<String> {
148 Some(match definition {
149 ModuleDef::Adt(adt) => match adt {
150 Adt::Struct(s) => format!("struct.{}.html", s.name(db)),
151 Adt::Enum(e) => format!("enum.{}.html", e.name(db)),
152 Adt::Union(u) => format!("union.{}.html", u.name(db)),
153 },
154 ModuleDef::Module(_) => "index.html".to_string(),
155 ModuleDef::Trait(t) => format!("trait.{}.html", t.name(db)),
156 ModuleDef::TypeAlias(t) => format!("type.{}.html", t.name(db)),
157 ModuleDef::BuiltinType(t) => format!("primitive.{}.html", t.as_name()),
158 ModuleDef::Function(f) => format!("fn.{}.html", f.name(db)),
159 ModuleDef::EnumVariant(ev) => {
160 format!("enum.{}.html#variant.{}", ev.parent_enum(db).name(db), ev.name(db))
161 }
162 ModuleDef::Const(c) => format!("const.{}.html", c.name(db)?),
163 ModuleDef::Static(s) => format!("static.{}.html", s.name(db)?),
164 })
165}
166
167#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
168enum Namespace {
169 Types,
170 Values,
171 Macros,
172}
173
174static TYPES: ([&str; 7], [&str; 0]) =
175 (["type", "struct", "enum", "mod", "trait", "union", "module"], []);
176static VALUES: ([&str; 8], [&str; 1]) =
177 (["value", "function", "fn", "method", "const", "static", "mod", "module"], ["()"]);
178static MACROS: ([&str; 1], [&str; 1]) = (["macro"], ["!"]);
179
180impl Namespace {
181 /// Extract the specified namespace from an intra-doc-link if one exists.
182 ///
183 /// # Examples
184 ///
185 /// * `struct MyStruct` -> `Namespace::Types`
186 /// * `panic!` -> `Namespace::Macros`
187 /// * `fn@from_intra_spec` -> `Namespace::Values`
188 fn from_intra_spec(s: &str) -> Option<Self> {
189 [
190 (Namespace::Types, (TYPES.0.iter(), TYPES.1.iter())),
191 (Namespace::Values, (VALUES.0.iter(), VALUES.1.iter())),
192 (Namespace::Macros, (MACROS.0.iter(), MACROS.1.iter())),
193 ]
194 .iter()
195 .filter(|(_ns, (prefixes, suffixes))| {
196 prefixes
197 .clone()
198 .map(|prefix| {
199 s.starts_with(*prefix)
200 && s.chars()
201 .nth(prefix.len() + 1)
202 .map(|c| c == '@' || c == ' ')
203 .unwrap_or(false)
204 })
205 .any(|cond| cond)
206 || suffixes
207 .clone()
208 .map(|suffix| {
209 s.starts_with(*suffix)
210 && s.chars()
211 .nth(suffix.len() + 1)
212 .map(|c| c == '@' || c == ' ')
213 .unwrap_or(false)
214 })
215 .any(|cond| cond)
216 })
217 .map(|(ns, (_, _))| *ns)
218 .next()
219 }
220}
221
222/// Sealed trait used solely for the generic bound on [`resolve_doc_link`].
223pub trait Resolvable {
224 fn resolver<D: DefDatabase + HirDatabase>(&self, db: &D) -> Option<Resolver>;
225 fn try_into_module_def(self) -> Option<ModuleDef>;
226}
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs
deleted file mode 100644
index 6f3b3dc9a..000000000
--- a/crates/ra_hir/src/semantics.rs
+++ /dev/null
@@ -1,731 +0,0 @@
1//! See `Semantics`.
2
3mod source_to_def;
4
5use std::{cell::RefCell, fmt, iter::successors};
6
7use hir_def::{
8 resolver::{self, HasResolver, Resolver},
9 AsMacroCall, FunctionId, TraitId, VariantId,
10};
11use hir_expand::{diagnostics::AstDiagnostic, hygiene::Hygiene, ExpansionInfo};
12use hir_ty::associated_type_shorthand_candidates;
13use itertools::Itertools;
14use ra_db::{FileId, FileRange};
15use ra_prof::profile;
16use ra_syntax::{
17 algo::{find_node_at_offset, skip_trivia_token},
18 ast, AstNode, Direction, SyntaxNode, SyntaxToken, TextRange, TextSize,
19};
20use rustc_hash::{FxHashMap, FxHashSet};
21
22use crate::{
23 db::HirDatabase,
24 diagnostics::Diagnostic,
25 semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
26 source_analyzer::{resolve_hir_path, resolve_hir_path_qualifier, SourceAnalyzer},
27 AssocItem, Callable, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module,
28 ModuleDef, Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, VariantDef,
29};
30use resolver::TypeNs;
31
32#[derive(Debug, Clone, PartialEq, Eq)]
33pub enum PathResolution {
34 /// An item
35 Def(ModuleDef),
36 /// A local binding (only value namespace)
37 Local(Local),
38 /// A generic parameter
39 TypeParam(TypeParam),
40 SelfType(ImplDef),
41 Macro(MacroDef),
42 AssocItem(AssocItem),
43}
44
45impl PathResolution {
46 fn in_type_ns(&self) -> Option<TypeNs> {
47 match self {
48 PathResolution::Def(ModuleDef::Adt(adt)) => Some(TypeNs::AdtId((*adt).into())),
49 PathResolution::Def(ModuleDef::BuiltinType(builtin)) => {
50 Some(TypeNs::BuiltinType(*builtin))
51 }
52 PathResolution::Def(ModuleDef::Const(_))
53 | PathResolution::Def(ModuleDef::EnumVariant(_))
54 | PathResolution::Def(ModuleDef::Function(_))
55 | PathResolution::Def(ModuleDef::Module(_))
56 | PathResolution::Def(ModuleDef::Static(_))
57 | PathResolution::Def(ModuleDef::Trait(_)) => None,
58 PathResolution::Def(ModuleDef::TypeAlias(alias)) => {
59 Some(TypeNs::TypeAliasId((*alias).into()))
60 }
61 PathResolution::Local(_) | PathResolution::Macro(_) => None,
62 PathResolution::TypeParam(param) => Some(TypeNs::GenericParam((*param).into())),
63 PathResolution::SelfType(impl_def) => Some(TypeNs::SelfType((*impl_def).into())),
64 PathResolution::AssocItem(AssocItem::Const(_))
65 | PathResolution::AssocItem(AssocItem::Function(_)) => None,
66 PathResolution::AssocItem(AssocItem::TypeAlias(alias)) => {
67 Some(TypeNs::TypeAliasId((*alias).into()))
68 }
69 }
70 }
71
72 /// Returns an iterator over associated types that may be specified after this path (using
73 /// `Ty::Assoc` syntax).
74 pub fn assoc_type_shorthand_candidates<R>(
75 &self,
76 db: &dyn HirDatabase,
77 mut cb: impl FnMut(TypeAlias) -> Option<R>,
78 ) -> Option<R> {
79 associated_type_shorthand_candidates(db, self.in_type_ns()?, |_, _, id| cb(id.into()))
80 }
81}
82
83/// Primary API to get semantic information, like types, from syntax trees.
84pub struct Semantics<'db, DB> {
85 pub db: &'db DB,
86 imp: SemanticsImpl<'db>,
87}
88
89pub struct SemanticsImpl<'db> {
90 pub db: &'db dyn HirDatabase,
91 s2d_cache: RefCell<SourceToDefCache>,
92 expansion_info_cache: RefCell<FxHashMap<HirFileId, Option<ExpansionInfo>>>,
93 cache: RefCell<FxHashMap<SyntaxNode, HirFileId>>,
94}
95
96impl<DB> fmt::Debug for Semantics<'_, DB> {
97 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
98 write!(f, "Semantics {{ ... }}")
99 }
100}
101
102impl<'db, DB: HirDatabase> Semantics<'db, DB> {
103 pub fn new(db: &DB) -> Semantics<DB> {
104 let impl_ = SemanticsImpl::new(db);
105 Semantics { db, imp: impl_ }
106 }
107
108 pub fn parse(&self, file_id: FileId) -> ast::SourceFile {
109 self.imp.parse(file_id)
110 }
111
112 pub fn ast<T: AstDiagnostic + Diagnostic>(&self, d: &T) -> <T as AstDiagnostic>::AST {
113 let file_id = d.source().file_id;
114 let root = self.db.parse_or_expand(file_id).unwrap();
115 self.imp.cache(root, file_id);
116 d.ast(self.db.upcast())
117 }
118
119 pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> {
120 self.imp.expand(macro_call)
121 }
122
123 pub fn expand_hypothetical(
124 &self,
125 actual_macro_call: &ast::MacroCall,
126 hypothetical_args: &ast::TokenTree,
127 token_to_map: SyntaxToken,
128 ) -> Option<(SyntaxNode, SyntaxToken)> {
129 self.imp.expand_hypothetical(actual_macro_call, hypothetical_args, token_to_map)
130 }
131
132 pub fn descend_into_macros(&self, token: SyntaxToken) -> SyntaxToken {
133 self.imp.descend_into_macros(token)
134 }
135
136 pub fn descend_node_at_offset<N: ast::AstNode>(
137 &self,
138 node: &SyntaxNode,
139 offset: TextSize,
140 ) -> Option<N> {
141 self.imp.descend_node_at_offset(node, offset).find_map(N::cast)
142 }
143
144 pub fn original_range(&self, node: &SyntaxNode) -> FileRange {
145 self.imp.original_range(node)
146 }
147
148 pub fn diagnostics_range(&self, diagnostics: &dyn Diagnostic) -> FileRange {
149 self.imp.diagnostics_range(diagnostics)
150 }
151
152 pub fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator<Item = SyntaxNode> + '_ {
153 self.imp.ancestors_with_macros(node)
154 }
155
156 pub fn ancestors_at_offset_with_macros(
157 &self,
158 node: &SyntaxNode,
159 offset: TextSize,
160 ) -> impl Iterator<Item = SyntaxNode> + '_ {
161 self.imp.ancestors_at_offset_with_macros(node, offset)
162 }
163
164 /// Find a AstNode by offset inside SyntaxNode, if it is inside *Macrofile*,
165 /// search up until it is of the target AstNode type
166 pub fn find_node_at_offset_with_macros<N: AstNode>(
167 &self,
168 node: &SyntaxNode,
169 offset: TextSize,
170 ) -> Option<N> {
171 self.imp.ancestors_at_offset_with_macros(node, offset).find_map(N::cast)
172 }
173
174 /// Find a AstNode by offset inside SyntaxNode, if it is inside *MacroCall*,
175 /// descend it and find again
176 pub fn find_node_at_offset_with_descend<N: AstNode>(
177 &self,
178 node: &SyntaxNode,
179 offset: TextSize,
180 ) -> Option<N> {
181 if let Some(it) = find_node_at_offset(&node, offset) {
182 return Some(it);
183 }
184
185 self.imp.descend_node_at_offset(node, offset).find_map(N::cast)
186 }
187
188 pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> {
189 self.imp.type_of_expr(expr)
190 }
191
192 pub fn type_of_pat(&self, pat: &ast::Pat) -> Option<Type> {
193 self.imp.type_of_pat(pat)
194 }
195
196 pub fn type_of_self(&self, param: &ast::SelfParam) -> Option<Type> {
197 self.imp.type_of_self(param)
198 }
199
200 pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> {
201 self.imp.resolve_method_call(call).map(Function::from)
202 }
203
204 pub fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> {
205 self.imp.resolve_method_call_as_callable(call)
206 }
207
208 pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<Field> {
209 self.imp.resolve_field(field)
210 }
211
212 pub fn resolve_record_field(
213 &self,
214 field: &ast::RecordExprField,
215 ) -> Option<(Field, Option<Local>)> {
216 self.imp.resolve_record_field(field)
217 }
218
219 pub fn resolve_record_field_pat(&self, field: &ast::RecordFieldPat) -> Option<Field> {
220 self.imp.resolve_record_field_pat(field)
221 }
222
223 pub fn resolve_macro_call(&self, macro_call: &ast::MacroCall) -> Option<MacroDef> {
224 self.imp.resolve_macro_call(macro_call)
225 }
226
227 pub fn resolve_path(&self, path: &ast::Path) -> Option<PathResolution> {
228 self.imp.resolve_path(path)
229 }
230
231 pub fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantDef> {
232 self.imp.resolve_variant(record_lit).map(VariantDef::from)
233 }
234
235 pub fn lower_path(&self, path: &ast::Path) -> Option<Path> {
236 self.imp.lower_path(path)
237 }
238
239 pub fn resolve_bind_pat_to_const(&self, pat: &ast::BindPat) -> Option<ModuleDef> {
240 self.imp.resolve_bind_pat_to_const(pat)
241 }
242
243 // FIXME: use this instead?
244 // pub fn resolve_name_ref(&self, name_ref: &ast::NameRef) -> Option<???>;
245
246 pub fn record_literal_missing_fields(&self, literal: &ast::RecordExpr) -> Vec<(Field, Type)> {
247 self.imp.record_literal_missing_fields(literal)
248 }
249
250 pub fn record_pattern_missing_fields(&self, pattern: &ast::RecordPat) -> Vec<(Field, Type)> {
251 self.imp.record_pattern_missing_fields(pattern)
252 }
253
254 pub fn to_def<T: ToDef>(&self, src: &T) -> Option<T::Def> {
255 let src = self.imp.find_file(src.syntax().clone()).with_value(src).cloned();
256 T::to_def(&self.imp, src)
257 }
258
259 pub fn to_module_def(&self, file: FileId) -> Option<Module> {
260 self.imp.to_module_def(file)
261 }
262
263 pub fn scope(&self, node: &SyntaxNode) -> SemanticsScope<'db> {
264 self.imp.scope(node)
265 }
266
267 pub fn scope_at_offset(&self, node: &SyntaxNode, offset: TextSize) -> SemanticsScope<'db> {
268 self.imp.scope_at_offset(node, offset)
269 }
270
271 pub fn scope_for_def(&self, def: Trait) -> SemanticsScope<'db> {
272 self.imp.scope_for_def(def)
273 }
274
275 pub fn assert_contains_node(&self, node: &SyntaxNode) {
276 self.imp.assert_contains_node(node)
277 }
278}
279
280impl<'db> SemanticsImpl<'db> {
281 fn new(db: &'db dyn HirDatabase) -> Self {
282 SemanticsImpl {
283 db,
284 s2d_cache: Default::default(),
285 cache: Default::default(),
286 expansion_info_cache: Default::default(),
287 }
288 }
289
290 fn parse(&self, file_id: FileId) -> ast::SourceFile {
291 let tree = self.db.parse(file_id).tree();
292 self.cache(tree.syntax().clone(), file_id.into());
293 tree
294 }
295
296 fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> {
297 let macro_call = self.find_file(macro_call.syntax().clone()).with_value(macro_call);
298 let sa = self.analyze2(macro_call.map(|it| it.syntax()), None);
299 let file_id = sa.expand(self.db, macro_call)?;
300 let node = self.db.parse_or_expand(file_id)?;
301 self.cache(node.clone(), file_id);
302 Some(node)
303 }
304
305 fn expand_hypothetical(
306 &self,
307 actual_macro_call: &ast::MacroCall,
308 hypothetical_args: &ast::TokenTree,
309 token_to_map: SyntaxToken,
310 ) -> Option<(SyntaxNode, SyntaxToken)> {
311 let macro_call =
312 self.find_file(actual_macro_call.syntax().clone()).with_value(actual_macro_call);
313 let sa = self.analyze2(macro_call.map(|it| it.syntax()), None);
314 let krate = sa.resolver.krate()?;
315 let macro_call_id = macro_call.as_call_id(self.db.upcast(), krate, |path| {
316 sa.resolver.resolve_path_as_macro(self.db.upcast(), &path)
317 })?;
318 hir_expand::db::expand_hypothetical(
319 self.db.upcast(),
320 macro_call_id,
321 hypothetical_args,
322 token_to_map,
323 )
324 }
325
326 fn descend_into_macros(&self, token: SyntaxToken) -> SyntaxToken {
327 let _p = profile("descend_into_macros");
328 let parent = token.parent();
329 let parent = self.find_file(parent);
330 let sa = self.analyze2(parent.as_ref(), None);
331
332 let token = successors(Some(parent.with_value(token)), |token| {
333 self.db.check_canceled();
334 let macro_call = token.value.ancestors().find_map(ast::MacroCall::cast)?;
335 let tt = macro_call.token_tree()?;
336 if !tt.syntax().text_range().contains_range(token.value.text_range()) {
337 return None;
338 }
339 let file_id = sa.expand(self.db, token.with_value(&macro_call))?;
340 let token = self
341 .expansion_info_cache
342 .borrow_mut()
343 .entry(file_id)
344 .or_insert_with(|| file_id.expansion_info(self.db.upcast()))
345 .as_ref()?
346 .map_token_down(token.as_ref())?;
347
348 self.cache(find_root(&token.value.parent()), token.file_id);
349
350 Some(token)
351 })
352 .last()
353 .unwrap();
354
355 token.value
356 }
357
358 fn descend_node_at_offset(
359 &self,
360 node: &SyntaxNode,
361 offset: TextSize,
362 ) -> impl Iterator<Item = SyntaxNode> + '_ {
363 // Handle macro token cases
364 node.token_at_offset(offset)
365 .map(|token| self.descend_into_macros(token))
366 .map(|it| self.ancestors_with_macros(it.parent()))
367 .flatten()
368 }
369
370 fn original_range(&self, node: &SyntaxNode) -> FileRange {
371 let node = self.find_file(node.clone());
372 original_range(self.db, node.as_ref())
373 }
374
375 fn diagnostics_range(&self, diagnostics: &dyn Diagnostic) -> FileRange {
376 let src = diagnostics.source();
377 let root = self.db.parse_or_expand(src.file_id).unwrap();
378 let node = src.value.to_node(&root);
379 original_range(self.db, src.with_value(&node))
380 }
381
382 fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator<Item = SyntaxNode> + '_ {
383 let node = self.find_file(node);
384 node.ancestors_with_macros(self.db.upcast()).map(|it| it.value)
385 }
386
387 fn ancestors_at_offset_with_macros(
388 &self,
389 node: &SyntaxNode,
390 offset: TextSize,
391 ) -> impl Iterator<Item = SyntaxNode> + '_ {
392 node.token_at_offset(offset)
393 .map(|token| self.ancestors_with_macros(token.parent()))
394 .kmerge_by(|node1, node2| node1.text_range().len() < node2.text_range().len())
395 }
396
397 fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> {
398 self.analyze(expr.syntax()).type_of_expr(self.db, &expr)
399 }
400
401 fn type_of_pat(&self, pat: &ast::Pat) -> Option<Type> {
402 self.analyze(pat.syntax()).type_of_pat(self.db, &pat)
403 }
404
405 fn type_of_self(&self, param: &ast::SelfParam) -> Option<Type> {
406 self.analyze(param.syntax()).type_of_self(self.db, &param)
407 }
408
409 fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<FunctionId> {
410 self.analyze(call.syntax()).resolve_method_call(self.db, call)
411 }
412
413 fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> {
414 // FIXME: this erases Substs
415 let func = self.resolve_method_call(call)?;
416 let ty = self.db.value_ty(func.into());
417 let resolver = self.analyze(call.syntax()).resolver;
418 let ty = Type::new_with_resolver(self.db, &resolver, ty.value)?;
419 let mut res = ty.as_callable(self.db)?;
420 res.is_bound_method = true;
421 Some(res)
422 }
423
424 fn resolve_field(&self, field: &ast::FieldExpr) -> Option<Field> {
425 self.analyze(field.syntax()).resolve_field(self.db, field)
426 }
427
428 fn resolve_record_field(&self, field: &ast::RecordExprField) -> Option<(Field, Option<Local>)> {
429 self.analyze(field.syntax()).resolve_record_field(self.db, field)
430 }
431
432 fn resolve_record_field_pat(&self, field: &ast::RecordFieldPat) -> Option<Field> {
433 self.analyze(field.syntax()).resolve_record_field_pat(self.db, field)
434 }
435
436 fn resolve_macro_call(&self, macro_call: &ast::MacroCall) -> Option<MacroDef> {
437 let sa = self.analyze(macro_call.syntax());
438 let macro_call = self.find_file(macro_call.syntax().clone()).with_value(macro_call);
439 sa.resolve_macro_call(self.db, macro_call)
440 }
441
442 fn resolve_path(&self, path: &ast::Path) -> Option<PathResolution> {
443 self.analyze(path.syntax()).resolve_path(self.db, path)
444 }
445
446 fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantId> {
447 self.analyze(record_lit.syntax()).resolve_variant(self.db, record_lit)
448 }
449
450 fn lower_path(&self, path: &ast::Path) -> Option<Path> {
451 let src = self.find_file(path.syntax().clone());
452 Path::from_src(path.clone(), &Hygiene::new(self.db.upcast(), src.file_id.into()))
453 }
454
455 fn resolve_bind_pat_to_const(&self, pat: &ast::BindPat) -> Option<ModuleDef> {
456 self.analyze(pat.syntax()).resolve_bind_pat_to_const(self.db, pat)
457 }
458
459 fn record_literal_missing_fields(&self, literal: &ast::RecordExpr) -> Vec<(Field, Type)> {
460 self.analyze(literal.syntax())
461 .record_literal_missing_fields(self.db, literal)
462 .unwrap_or_default()
463 }
464
465 fn record_pattern_missing_fields(&self, pattern: &ast::RecordPat) -> Vec<(Field, Type)> {
466 self.analyze(pattern.syntax())
467 .record_pattern_missing_fields(self.db, pattern)
468 .unwrap_or_default()
469 }
470
471 fn with_ctx<F: FnOnce(&mut SourceToDefCtx) -> T, T>(&self, f: F) -> T {
472 let mut cache = self.s2d_cache.borrow_mut();
473 let mut ctx = SourceToDefCtx { db: self.db, cache: &mut *cache };
474 f(&mut ctx)
475 }
476
477 fn to_module_def(&self, file: FileId) -> Option<Module> {
478 self.with_ctx(|ctx| ctx.file_to_def(file)).map(Module::from)
479 }
480
481 fn scope(&self, node: &SyntaxNode) -> SemanticsScope<'db> {
482 let node = self.find_file(node.clone());
483 let resolver = self.analyze2(node.as_ref(), None).resolver;
484 SemanticsScope { db: self.db, resolver }
485 }
486
487 fn scope_at_offset(&self, node: &SyntaxNode, offset: TextSize) -> SemanticsScope<'db> {
488 let node = self.find_file(node.clone());
489 let resolver = self.analyze2(node.as_ref(), Some(offset)).resolver;
490 SemanticsScope { db: self.db, resolver }
491 }
492
493 fn scope_for_def(&self, def: Trait) -> SemanticsScope<'db> {
494 let resolver = def.id.resolver(self.db.upcast());
495 SemanticsScope { db: self.db, resolver }
496 }
497
498 fn analyze(&self, node: &SyntaxNode) -> SourceAnalyzer {
499 let src = self.find_file(node.clone());
500 self.analyze2(src.as_ref(), None)
501 }
502
503 fn analyze2(&self, src: InFile<&SyntaxNode>, offset: Option<TextSize>) -> SourceAnalyzer {
504 let _p = profile("Semantics::analyze2");
505
506 let container = match self.with_ctx(|ctx| ctx.find_container(src)) {
507 Some(it) => it,
508 None => return SourceAnalyzer::new_for_resolver(Resolver::default(), src),
509 };
510
511 let resolver = match container {
512 ChildContainer::DefWithBodyId(def) => {
513 return SourceAnalyzer::new_for_body(self.db, def, src, offset)
514 }
515 ChildContainer::TraitId(it) => it.resolver(self.db.upcast()),
516 ChildContainer::ImplId(it) => it.resolver(self.db.upcast()),
517 ChildContainer::ModuleId(it) => it.resolver(self.db.upcast()),
518 ChildContainer::EnumId(it) => it.resolver(self.db.upcast()),
519 ChildContainer::VariantId(it) => it.resolver(self.db.upcast()),
520 ChildContainer::TypeAliasId(it) => it.resolver(self.db.upcast()),
521 ChildContainer::GenericDefId(it) => it.resolver(self.db.upcast()),
522 };
523 SourceAnalyzer::new_for_resolver(resolver, src)
524 }
525
526 fn cache(&self, root_node: SyntaxNode, file_id: HirFileId) {
527 assert!(root_node.parent().is_none());
528 let mut cache = self.cache.borrow_mut();
529 let prev = cache.insert(root_node, file_id);
530 assert!(prev == None || prev == Some(file_id))
531 }
532
533 fn assert_contains_node(&self, node: &SyntaxNode) {
534 self.find_file(node.clone());
535 }
536
537 fn lookup(&self, root_node: &SyntaxNode) -> Option<HirFileId> {
538 let cache = self.cache.borrow();
539 cache.get(root_node).copied()
540 }
541
542 fn find_file(&self, node: SyntaxNode) -> InFile<SyntaxNode> {
543 let root_node = find_root(&node);
544 let file_id = self.lookup(&root_node).unwrap_or_else(|| {
545 panic!(
546 "\n\nFailed to lookup {:?} in this Semantics.\n\
547 Make sure to use only query nodes, derived from this instance of Semantics.\n\
548 root node: {:?}\n\
549 known nodes: {}\n\n",
550 node,
551 root_node,
552 self.cache
553 .borrow()
554 .keys()
555 .map(|it| format!("{:?}", it))
556 .collect::<Vec<_>>()
557 .join(", ")
558 )
559 });
560 InFile::new(file_id, node)
561 }
562}
563
564pub trait ToDef: AstNode + Clone {
565 type Def;
566
567 fn to_def(sema: &SemanticsImpl, src: InFile<Self>) -> Option<Self::Def>;
568}
569
570macro_rules! to_def_impls {
571 ($(($def:path, $ast:path, $meth:ident)),* ,) => {$(
572 impl ToDef for $ast {
573 type Def = $def;
574 fn to_def(sema: &SemanticsImpl, src: InFile<Self>) -> Option<Self::Def> {
575 sema.with_ctx(|ctx| ctx.$meth(src)).map(<$def>::from)
576 }
577 }
578 )*}
579}
580
581to_def_impls![
582 (crate::Module, ast::Module, module_to_def),
583 (crate::Struct, ast::Struct, struct_to_def),
584 (crate::Enum, ast::Enum, enum_to_def),
585 (crate::Union, ast::Union, union_to_def),
586 (crate::Trait, ast::Trait, trait_to_def),
587 (crate::ImplDef, ast::Impl, impl_to_def),
588 (crate::TypeAlias, ast::TypeAlias, type_alias_to_def),
589 (crate::Const, ast::Const, const_to_def),
590 (crate::Static, ast::Static, static_to_def),
591 (crate::Function, ast::Fn, fn_to_def),
592 (crate::Field, ast::RecordField, record_field_to_def),
593 (crate::Field, ast::TupleField, tuple_field_to_def),
594 (crate::EnumVariant, ast::Variant, enum_variant_to_def),
595 (crate::TypeParam, ast::TypeParam, type_param_to_def),
596 (crate::MacroDef, ast::MacroCall, macro_call_to_def), // this one is dubious, not all calls are macros
597 (crate::Local, ast::BindPat, bind_pat_to_def),
598];
599
600fn find_root(node: &SyntaxNode) -> SyntaxNode {
601 node.ancestors().last().unwrap()
602}
603
604#[derive(Debug)]
605pub struct SemanticsScope<'a> {
606 pub db: &'a dyn HirDatabase,
607 resolver: Resolver,
608}
609
610impl<'a> SemanticsScope<'a> {
611 pub fn module(&self) -> Option<Module> {
612 Some(Module { id: self.resolver.module()? })
613 }
614
615 /// Note: `FxHashSet<TraitId>` should be treated as an opaque type, passed into `Type
616 // FIXME: rename to visible_traits to not repeat scope?
617 pub fn traits_in_scope(&self) -> FxHashSet<TraitId> {
618 let resolver = &self.resolver;
619 resolver.traits_in_scope(self.db.upcast())
620 }
621
622 pub fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef)) {
623 let resolver = &self.resolver;
624
625 resolver.process_all_names(self.db.upcast(), &mut |name, def| {
626 let def = match def {
627 resolver::ScopeDef::PerNs(it) => {
628 let items = ScopeDef::all_items(it);
629 for item in items {
630 f(name.clone(), item);
631 }
632 return;
633 }
634 resolver::ScopeDef::ImplSelfType(it) => ScopeDef::ImplSelfType(it.into()),
635 resolver::ScopeDef::AdtSelfType(it) => ScopeDef::AdtSelfType(it.into()),
636 resolver::ScopeDef::GenericParam(id) => ScopeDef::GenericParam(TypeParam { id }),
637 resolver::ScopeDef::Local(pat_id) => {
638 let parent = resolver.body_owner().unwrap().into();
639 ScopeDef::Local(Local { parent, pat_id })
640 }
641 };
642 f(name, def)
643 })
644 }
645
646 pub fn resolve_hir_path(&self, path: &Path) -> Option<PathResolution> {
647 resolve_hir_path(self.db, &self.resolver, path)
648 }
649
650 /// Resolves a path where we know it is a qualifier of another path.
651 ///
652 /// For example, if we have:
653 /// ```
654 /// mod my {
655 /// pub mod foo {
656 /// struct Bar;
657 /// }
658 ///
659 /// pub fn foo() {}
660 /// }
661 /// ```
662 /// then we know that `foo` in `my::foo::Bar` refers to the module, not the function.
663 pub fn resolve_hir_path_qualifier(&self, path: &Path) -> Option<PathResolution> {
664 resolve_hir_path_qualifier(self.db, &self.resolver, path)
665 }
666}
667
668// FIXME: Change `HasSource` trait to work with `Semantics` and remove this?
669pub fn original_range(db: &dyn HirDatabase, node: InFile<&SyntaxNode>) -> FileRange {
670 if let Some(range) = original_range_opt(db, node) {
671 let original_file = range.file_id.original_file(db.upcast());
672 if range.file_id == original_file.into() {
673 return FileRange { file_id: original_file, range: range.value };
674 }
675
676 log::error!("Fail to mapping up more for {:?}", range);
677 return FileRange { file_id: range.file_id.original_file(db.upcast()), range: range.value };
678 }
679
680 // Fall back to whole macro call
681 if let Some(expansion) = node.file_id.expansion_info(db.upcast()) {
682 if let Some(call_node) = expansion.call_node() {
683 return FileRange {
684 file_id: call_node.file_id.original_file(db.upcast()),
685 range: call_node.value.text_range(),
686 };
687 }
688 }
689
690 FileRange { file_id: node.file_id.original_file(db.upcast()), range: node.value.text_range() }
691}
692
693fn original_range_opt(
694 db: &dyn HirDatabase,
695 node: InFile<&SyntaxNode>,
696) -> Option<InFile<TextRange>> {
697 let expansion = node.file_id.expansion_info(db.upcast())?;
698
699 // the input node has only one token ?
700 let single = skip_trivia_token(node.value.first_token()?, Direction::Next)?
701 == skip_trivia_token(node.value.last_token()?, Direction::Prev)?;
702
703 Some(node.value.descendants().find_map(|it| {
704 let first = skip_trivia_token(it.first_token()?, Direction::Next)?;
705 let first = ascend_call_token(db, &expansion, node.with_value(first))?;
706
707 let last = skip_trivia_token(it.last_token()?, Direction::Prev)?;
708 let last = ascend_call_token(db, &expansion, node.with_value(last))?;
709
710 if (!single && first == last) || (first.file_id != last.file_id) {
711 return None;
712 }
713
714 Some(first.with_value(first.value.text_range().cover(last.value.text_range())))
715 })?)
716}
717
718fn ascend_call_token(
719 db: &dyn HirDatabase,
720 expansion: &ExpansionInfo,
721 token: InFile<SyntaxToken>,
722) -> Option<InFile<SyntaxToken>> {
723 let (mapped, origin) = expansion.map_token_up(token.as_ref())?;
724 if origin != Origin::Call {
725 return None;
726 }
727 if let Some(info) = mapped.file_id.expansion_info(db.upcast()) {
728 return ascend_call_token(db, &info, mapped);
729 }
730 Some(mapped)
731}
diff --git a/crates/ra_hir/src/semantics/source_to_def.rs b/crates/ra_hir/src/semantics/source_to_def.rs
deleted file mode 100644
index d1994e2e7..000000000
--- a/crates/ra_hir/src/semantics/source_to_def.rs
+++ /dev/null
@@ -1,276 +0,0 @@
1//! Maps *syntax* of various definitions to their semantic ids.
2
3use hir_def::{
4 child_by_source::ChildBySource,
5 dyn_map::DynMap,
6 expr::PatId,
7 keys::{self, Key},
8 ConstId, DefWithBodyId, EnumId, EnumVariantId, FieldId, FunctionId, GenericDefId, ImplId,
9 ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId, VariantId,
10};
11use hir_expand::{name::AsName, AstId, MacroDefKind};
12use ra_db::FileId;
13use ra_prof::profile;
14use ra_syntax::{
15 ast::{self, NameOwner},
16 match_ast, AstNode, SyntaxNode,
17};
18use rustc_hash::FxHashMap;
19use stdx::impl_from;
20
21use crate::{db::HirDatabase, InFile, MacroDefId};
22
23pub(super) type SourceToDefCache = FxHashMap<ChildContainer, DynMap>;
24
25pub(super) struct SourceToDefCtx<'a, 'b> {
26 pub(super) db: &'b dyn HirDatabase,
27 pub(super) cache: &'a mut SourceToDefCache,
28}
29
30impl SourceToDefCtx<'_, '_> {
31 pub(super) fn file_to_def(&mut self, file: FileId) -> Option<ModuleId> {
32 let _p = profile("SourceBinder::to_module_def");
33 let (krate, local_id) = self.db.relevant_crates(file).iter().find_map(|&crate_id| {
34 let crate_def_map = self.db.crate_def_map(crate_id);
35 let local_id = crate_def_map.modules_for_file(file).next()?;
36 Some((crate_id, local_id))
37 })?;
38 Some(ModuleId { krate, local_id })
39 }
40
41 pub(super) fn module_to_def(&mut self, src: InFile<ast::Module>) -> Option<ModuleId> {
42 let _p = profile("module_to_def");
43 let parent_declaration = src
44 .as_ref()
45 .map(|it| it.syntax())
46 .cloned()
47 .ancestors_with_macros(self.db.upcast())
48 .skip(1)
49 .find_map(|it| {
50 let m = ast::Module::cast(it.value.clone())?;
51 Some(it.with_value(m))
52 });
53
54 let parent_module = match parent_declaration {
55 Some(parent_declaration) => self.module_to_def(parent_declaration),
56 None => {
57 let file_id = src.file_id.original_file(self.db.upcast());
58 self.file_to_def(file_id)
59 }
60 }?;
61
62 let child_name = src.value.name()?.as_name();
63 let def_map = self.db.crate_def_map(parent_module.krate);
64 let child_id = *def_map[parent_module.local_id].children.get(&child_name)?;
65 Some(ModuleId { krate: parent_module.krate, local_id: child_id })
66 }
67
68 pub(super) fn trait_to_def(&mut self, src: InFile<ast::Trait>) -> Option<TraitId> {
69 self.to_def(src, keys::TRAIT)
70 }
71 pub(super) fn impl_to_def(&mut self, src: InFile<ast::Impl>) -> Option<ImplId> {
72 self.to_def(src, keys::IMPL)
73 }
74 pub(super) fn fn_to_def(&mut self, src: InFile<ast::Fn>) -> Option<FunctionId> {
75 self.to_def(src, keys::FUNCTION)
76 }
77 pub(super) fn struct_to_def(&mut self, src: InFile<ast::Struct>) -> Option<StructId> {
78 self.to_def(src, keys::STRUCT)
79 }
80 pub(super) fn enum_to_def(&mut self, src: InFile<ast::Enum>) -> Option<EnumId> {
81 self.to_def(src, keys::ENUM)
82 }
83 pub(super) fn union_to_def(&mut self, src: InFile<ast::Union>) -> Option<UnionId> {
84 self.to_def(src, keys::UNION)
85 }
86 pub(super) fn static_to_def(&mut self, src: InFile<ast::Static>) -> Option<StaticId> {
87 self.to_def(src, keys::STATIC)
88 }
89 pub(super) fn const_to_def(&mut self, src: InFile<ast::Const>) -> Option<ConstId> {
90 self.to_def(src, keys::CONST)
91 }
92 pub(super) fn type_alias_to_def(&mut self, src: InFile<ast::TypeAlias>) -> Option<TypeAliasId> {
93 self.to_def(src, keys::TYPE_ALIAS)
94 }
95 pub(super) fn record_field_to_def(&mut self, src: InFile<ast::RecordField>) -> Option<FieldId> {
96 self.to_def(src, keys::RECORD_FIELD)
97 }
98 pub(super) fn tuple_field_to_def(&mut self, src: InFile<ast::TupleField>) -> Option<FieldId> {
99 self.to_def(src, keys::TUPLE_FIELD)
100 }
101 pub(super) fn enum_variant_to_def(
102 &mut self,
103 src: InFile<ast::Variant>,
104 ) -> Option<EnumVariantId> {
105 self.to_def(src, keys::VARIANT)
106 }
107 pub(super) fn bind_pat_to_def(
108 &mut self,
109 src: InFile<ast::BindPat>,
110 ) -> Option<(DefWithBodyId, PatId)> {
111 let container = self.find_pat_container(src.as_ref().map(|it| it.syntax()))?;
112 let (_body, source_map) = self.db.body_with_source_map(container);
113 let src = src.map(ast::Pat::from);
114 let pat_id = source_map.node_pat(src.as_ref())?;
115 Some((container, pat_id))
116 }
117
118 fn to_def<Ast: AstNode + 'static, ID: Copy + 'static>(
119 &mut self,
120 src: InFile<Ast>,
121 key: Key<Ast, ID>,
122 ) -> Option<ID> {
123 let container = self.find_container(src.as_ref().map(|it| it.syntax()))?;
124 let db = self.db;
125 let dyn_map =
126 &*self.cache.entry(container).or_insert_with(|| container.child_by_source(db));
127 dyn_map[key].get(&src).copied()
128 }
129
130 pub(super) fn type_param_to_def(&mut self, src: InFile<ast::TypeParam>) -> Option<TypeParamId> {
131 let container: ChildContainer =
132 self.find_type_param_container(src.as_ref().map(|it| it.syntax()))?.into();
133 let db = self.db;
134 let dyn_map =
135 &*self.cache.entry(container).or_insert_with(|| container.child_by_source(db));
136 dyn_map[keys::TYPE_PARAM].get(&src).copied()
137 }
138
139 // FIXME: use DynMap as well?
140 pub(super) fn macro_call_to_def(&mut self, src: InFile<ast::MacroCall>) -> Option<MacroDefId> {
141 let kind = MacroDefKind::Declarative;
142 let file_id = src.file_id.original_file(self.db.upcast());
143 let krate = self.file_to_def(file_id)?.krate;
144 let file_ast_id = self.db.ast_id_map(src.file_id).ast_id(&src.value);
145 let ast_id = Some(AstId::new(src.file_id, file_ast_id));
146 Some(MacroDefId { krate: Some(krate), ast_id, kind, local_inner: false })
147 }
148
149 pub(super) fn find_container(&mut self, src: InFile<&SyntaxNode>) -> Option<ChildContainer> {
150 for container in src.cloned().ancestors_with_macros(self.db.upcast()).skip(1) {
151 let res: ChildContainer = match_ast! {
152 match (container.value) {
153 ast::Module(it) => {
154 let def = self.module_to_def(container.with_value(it))?;
155 def.into()
156 },
157 ast::Trait(it) => {
158 let def = self.trait_to_def(container.with_value(it))?;
159 def.into()
160 },
161 ast::Impl(it) => {
162 let def = self.impl_to_def(container.with_value(it))?;
163 def.into()
164 },
165 ast::Fn(it) => {
166 let def = self.fn_to_def(container.with_value(it))?;
167 DefWithBodyId::from(def).into()
168 },
169 ast::Struct(it) => {
170 let def = self.struct_to_def(container.with_value(it))?;
171 VariantId::from(def).into()
172 },
173 ast::Enum(it) => {
174 let def = self.enum_to_def(container.with_value(it))?;
175 def.into()
176 },
177 ast::Union(it) => {
178 let def = self.union_to_def(container.with_value(it))?;
179 VariantId::from(def).into()
180 },
181 ast::Static(it) => {
182 let def = self.static_to_def(container.with_value(it))?;
183 DefWithBodyId::from(def).into()
184 },
185 ast::Const(it) => {
186 let def = self.const_to_def(container.with_value(it))?;
187 DefWithBodyId::from(def).into()
188 },
189 ast::TypeAlias(it) => {
190 let def = self.type_alias_to_def(container.with_value(it))?;
191 def.into()
192 },
193 _ => continue,
194 }
195 };
196 return Some(res);
197 }
198
199 let def = self.file_to_def(src.file_id.original_file(self.db.upcast()))?;
200 Some(def.into())
201 }
202
203 fn find_type_param_container(&mut self, src: InFile<&SyntaxNode>) -> Option<GenericDefId> {
204 for container in src.cloned().ancestors_with_macros(self.db.upcast()).skip(1) {
205 let res: GenericDefId = match_ast! {
206 match (container.value) {
207 ast::Fn(it) => self.fn_to_def(container.with_value(it))?.into(),
208 ast::Struct(it) => self.struct_to_def(container.with_value(it))?.into(),
209 ast::Enum(it) => self.enum_to_def(container.with_value(it))?.into(),
210 ast::Trait(it) => self.trait_to_def(container.with_value(it))?.into(),
211 ast::TypeAlias(it) => self.type_alias_to_def(container.with_value(it))?.into(),
212 ast::Impl(it) => self.impl_to_def(container.with_value(it))?.into(),
213 _ => continue,
214 }
215 };
216 return Some(res);
217 }
218 None
219 }
220
221 fn find_pat_container(&mut self, src: InFile<&SyntaxNode>) -> Option<DefWithBodyId> {
222 for container in src.cloned().ancestors_with_macros(self.db.upcast()).skip(1) {
223 let res: DefWithBodyId = match_ast! {
224 match (container.value) {
225 ast::Const(it) => self.const_to_def(container.with_value(it))?.into(),
226 ast::Static(it) => self.static_to_def(container.with_value(it))?.into(),
227 ast::Fn(it) => self.fn_to_def(container.with_value(it))?.into(),
228 _ => continue,
229 }
230 };
231 return Some(res);
232 }
233 None
234 }
235}
236
237#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
238pub(crate) enum ChildContainer {
239 DefWithBodyId(DefWithBodyId),
240 ModuleId(ModuleId),
241 TraitId(TraitId),
242 ImplId(ImplId),
243 EnumId(EnumId),
244 VariantId(VariantId),
245 TypeAliasId(TypeAliasId),
246 /// XXX: this might be the same def as, for example an `EnumId`. However,
247 /// here the children generic parameters, and not, eg enum variants.
248 GenericDefId(GenericDefId),
249}
250impl_from! {
251 DefWithBodyId,
252 ModuleId,
253 TraitId,
254 ImplId,
255 EnumId,
256 VariantId,
257 TypeAliasId,
258 GenericDefId
259 for ChildContainer
260}
261
262impl ChildContainer {
263 fn child_by_source(self, db: &dyn HirDatabase) -> DynMap {
264 let db = db.upcast();
265 match self {
266 ChildContainer::DefWithBodyId(it) => it.child_by_source(db),
267 ChildContainer::ModuleId(it) => it.child_by_source(db),
268 ChildContainer::TraitId(it) => it.child_by_source(db),
269 ChildContainer::ImplId(it) => it.child_by_source(db),
270 ChildContainer::EnumId(it) => it.child_by_source(db),
271 ChildContainer::VariantId(it) => it.child_by_source(db),
272 ChildContainer::TypeAliasId(_) => DynMap::default(),
273 ChildContainer::GenericDefId(it) => it.child_by_source(db),
274 }
275 }
276}
diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs
deleted file mode 100644
index f2e630ef1..000000000
--- a/crates/ra_hir/src/source_analyzer.rs
+++ /dev/null
@@ -1,535 +0,0 @@
1//! Lookup hir elements using positions in the source code. This is a lossy
2//! transformation: in general, a single source might correspond to several
3//! modules, functions, etc, due to macros, cfgs and `#[path=]` attributes on
4//! modules.
5//!
6//! So, this modules should not be used during hir construction, it exists
7//! purely for "IDE needs".
8use std::{iter::once, sync::Arc};
9
10use hir_def::{
11 body::{
12 scope::{ExprScopes, ScopeId},
13 Body, BodySourceMap,
14 },
15 expr::{ExprId, Pat, PatId},
16 resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs},
17 AsMacroCall, DefWithBodyId, FieldId, FunctionId, LocalFieldId, VariantId,
18};
19use hir_expand::{hygiene::Hygiene, name::AsName, HirFileId, InFile};
20use hir_ty::{
21 diagnostics::{record_literal_missing_fields, record_pattern_missing_fields},
22 InferenceResult, Substs, Ty,
23};
24use ra_syntax::{
25 ast::{self, AstNode},
26 SyntaxNode, TextRange, TextSize,
27};
28
29use crate::{
30 db::HirDatabase, semantics::PathResolution, Adt, Const, EnumVariant, Field, Function, Local,
31 MacroDef, ModPath, ModuleDef, Path, PathKind, Static, Struct, Trait, Type, TypeAlias,
32 TypeParam,
33};
34use ra_db::CrateId;
35
36/// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of
37/// original source files. It should not be used inside the HIR itself.
38#[derive(Debug)]
39pub(crate) struct SourceAnalyzer {
40 file_id: HirFileId,
41 pub(crate) resolver: Resolver,
42 body: Option<Arc<Body>>,
43 body_source_map: Option<Arc<BodySourceMap>>,
44 infer: Option<Arc<InferenceResult>>,
45 scopes: Option<Arc<ExprScopes>>,
46}
47
48impl SourceAnalyzer {
49 pub(crate) fn new_for_body(
50 db: &dyn HirDatabase,
51 def: DefWithBodyId,
52 node: InFile<&SyntaxNode>,
53 offset: Option<TextSize>,
54 ) -> SourceAnalyzer {
55 let (body, source_map) = db.body_with_source_map(def);
56 let scopes = db.expr_scopes(def);
57 let scope = match offset {
58 None => scope_for(&scopes, &source_map, node),
59 Some(offset) => scope_for_offset(db, &scopes, &source_map, node.with_value(offset)),
60 };
61 let resolver = resolver_for_scope(db.upcast(), def, scope);
62 SourceAnalyzer {
63 resolver,
64 body: Some(body),
65 body_source_map: Some(source_map),
66 infer: Some(db.infer(def)),
67 scopes: Some(scopes),
68 file_id: node.file_id,
69 }
70 }
71
72 pub(crate) fn new_for_resolver(
73 resolver: Resolver,
74 node: InFile<&SyntaxNode>,
75 ) -> SourceAnalyzer {
76 SourceAnalyzer {
77 resolver,
78 body: None,
79 body_source_map: None,
80 infer: None,
81 scopes: None,
82 file_id: node.file_id,
83 }
84 }
85
86 fn expr_id(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<ExprId> {
87 let src = match expr {
88 ast::Expr::MacroCall(call) => {
89 self.expand_expr(db, InFile::new(self.file_id, call.clone()))?
90 }
91 _ => InFile::new(self.file_id, expr.clone()),
92 };
93 let sm = self.body_source_map.as_ref()?;
94 sm.node_expr(src.as_ref())
95 }
96
97 fn pat_id(&self, pat: &ast::Pat) -> Option<PatId> {
98 // FIXME: macros, see `expr_id`
99 let src = InFile { file_id: self.file_id, value: pat };
100 self.body_source_map.as_ref()?.node_pat(src)
101 }
102
103 fn expand_expr(
104 &self,
105 db: &dyn HirDatabase,
106 expr: InFile<ast::MacroCall>,
107 ) -> Option<InFile<ast::Expr>> {
108 let macro_file = self.body_source_map.as_ref()?.node_macro_file(expr.as_ref())?;
109 let expanded = db.parse_or_expand(macro_file)?;
110
111 let res = match ast::MacroCall::cast(expanded.clone()) {
112 Some(call) => self.expand_expr(db, InFile::new(macro_file, call))?,
113 _ => InFile::new(macro_file, ast::Expr::cast(expanded)?),
114 };
115 Some(res)
116 }
117
118 pub(crate) fn type_of_expr(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<Type> {
119 let expr_id = self.expr_id(db, expr)?;
120 let ty = self.infer.as_ref()?[expr_id].clone();
121 Type::new_with_resolver(db, &self.resolver, ty)
122 }
123
124 pub(crate) fn type_of_pat(&self, db: &dyn HirDatabase, pat: &ast::Pat) -> Option<Type> {
125 let pat_id = self.pat_id(pat)?;
126 let ty = self.infer.as_ref()?[pat_id].clone();
127 Type::new_with_resolver(db, &self.resolver, ty)
128 }
129
130 pub(crate) fn type_of_self(
131 &self,
132 db: &dyn HirDatabase,
133 param: &ast::SelfParam,
134 ) -> Option<Type> {
135 let src = InFile { file_id: self.file_id, value: param };
136 let pat_id = self.body_source_map.as_ref()?.node_self_param(src)?;
137 let ty = self.infer.as_ref()?[pat_id].clone();
138 Type::new_with_resolver(db, &self.resolver, ty)
139 }
140
141 pub(crate) fn resolve_method_call(
142 &self,
143 db: &dyn HirDatabase,
144 call: &ast::MethodCallExpr,
145 ) -> Option<FunctionId> {
146 let expr_id = self.expr_id(db, &call.clone().into())?;
147 self.infer.as_ref()?.method_resolution(expr_id)
148 }
149
150 pub(crate) fn resolve_field(
151 &self,
152 db: &dyn HirDatabase,
153 field: &ast::FieldExpr,
154 ) -> Option<Field> {
155 let expr_id = self.expr_id(db, &field.clone().into())?;
156 self.infer.as_ref()?.field_resolution(expr_id).map(|it| it.into())
157 }
158
159 pub(crate) fn resolve_record_field(
160 &self,
161 db: &dyn HirDatabase,
162 field: &ast::RecordExprField,
163 ) -> Option<(Field, Option<Local>)> {
164 let expr = field.expr()?;
165 let expr_id = self.expr_id(db, &expr)?;
166 let local = if field.name_ref().is_some() {
167 None
168 } else {
169 let local_name = field.field_name()?.as_name();
170 let path = ModPath::from_segments(PathKind::Plain, once(local_name));
171 match self.resolver.resolve_path_in_value_ns_fully(db.upcast(), &path) {
172 Some(ValueNs::LocalBinding(pat_id)) => {
173 Some(Local { pat_id, parent: self.resolver.body_owner()? })
174 }
175 _ => None,
176 }
177 };
178 let struct_field = self.infer.as_ref()?.record_field_resolution(expr_id)?;
179 Some((struct_field.into(), local))
180 }
181
182 pub(crate) fn resolve_record_field_pat(
183 &self,
184 _db: &dyn HirDatabase,
185 field: &ast::RecordFieldPat,
186 ) -> Option<Field> {
187 let pat_id = self.pat_id(&field.pat()?)?;
188 let struct_field = self.infer.as_ref()?.record_field_pat_resolution(pat_id)?;
189 Some(struct_field.into())
190 }
191
192 pub(crate) fn resolve_macro_call(
193 &self,
194 db: &dyn HirDatabase,
195 macro_call: InFile<&ast::MacroCall>,
196 ) -> Option<MacroDef> {
197 let hygiene = Hygiene::new(db.upcast(), macro_call.file_id);
198 let path = macro_call.value.path().and_then(|ast| Path::from_src(ast, &hygiene))?;
199 self.resolver.resolve_path_as_macro(db.upcast(), path.mod_path()).map(|it| it.into())
200 }
201
202 pub(crate) fn resolve_bind_pat_to_const(
203 &self,
204 db: &dyn HirDatabase,
205 pat: &ast::BindPat,
206 ) -> Option<ModuleDef> {
207 let pat_id = self.pat_id(&pat.clone().into())?;
208 let body = self.body.as_ref()?;
209 let path = match &body[pat_id] {
210 Pat::Path(path) => path,
211 _ => return None,
212 };
213 let res = resolve_hir_path(db, &self.resolver, &path)?;
214 match res {
215 PathResolution::Def(def) => Some(def),
216 _ => None,
217 }
218 }
219
220 pub(crate) fn resolve_path(
221 &self,
222 db: &dyn HirDatabase,
223 path: &ast::Path,
224 ) -> Option<PathResolution> {
225 if let Some(path_expr) = path.syntax().parent().and_then(ast::PathExpr::cast) {
226 let expr_id = self.expr_id(db, &path_expr.into())?;
227 if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_expr(expr_id) {
228 return Some(PathResolution::AssocItem(assoc.into()));
229 }
230 if let Some(VariantId::EnumVariantId(variant)) =
231 self.infer.as_ref()?.variant_resolution_for_expr(expr_id)
232 {
233 return Some(PathResolution::Def(ModuleDef::EnumVariant(variant.into())));
234 }
235 }
236
237 if let Some(path_pat) = path.syntax().parent().and_then(ast::PathPat::cast) {
238 let pat_id = self.pat_id(&path_pat.into())?;
239 if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_pat(pat_id) {
240 return Some(PathResolution::AssocItem(assoc.into()));
241 }
242 if let Some(VariantId::EnumVariantId(variant)) =
243 self.infer.as_ref()?.variant_resolution_for_pat(pat_id)
244 {
245 return Some(PathResolution::Def(ModuleDef::EnumVariant(variant.into())));
246 }
247 }
248
249 if let Some(rec_lit) = path.syntax().parent().and_then(ast::RecordExpr::cast) {
250 let expr_id = self.expr_id(db, &rec_lit.into())?;
251 if let Some(VariantId::EnumVariantId(variant)) =
252 self.infer.as_ref()?.variant_resolution_for_expr(expr_id)
253 {
254 return Some(PathResolution::Def(ModuleDef::EnumVariant(variant.into())));
255 }
256 }
257
258 if let Some(rec_pat) = path.syntax().parent().and_then(ast::RecordPat::cast) {
259 let pat_id = self.pat_id(&rec_pat.into())?;
260 if let Some(VariantId::EnumVariantId(variant)) =
261 self.infer.as_ref()?.variant_resolution_for_pat(pat_id)
262 {
263 return Some(PathResolution::Def(ModuleDef::EnumVariant(variant.into())));
264 }
265 }
266
267 // This must be a normal source file rather than macro file.
268 let hir_path =
269 crate::Path::from_src(path.clone(), &Hygiene::new(db.upcast(), self.file_id))?;
270
271 // Case where path is a qualifier of another path, e.g. foo::bar::Baz where we
272 // trying to resolve foo::bar.
273 if let Some(outer_path) = path.syntax().parent().and_then(ast::Path::cast) {
274 if let Some(qualifier) = outer_path.qualifier() {
275 if path == &qualifier {
276 return resolve_hir_path_qualifier(db, &self.resolver, &hir_path);
277 }
278 }
279 }
280
281 resolve_hir_path(db, &self.resolver, &hir_path)
282 }
283
284 pub(crate) fn record_literal_missing_fields(
285 &self,
286 db: &dyn HirDatabase,
287 literal: &ast::RecordExpr,
288 ) -> Option<Vec<(Field, Type)>> {
289 let krate = self.resolver.krate()?;
290 let body = self.body.as_ref()?;
291 let infer = self.infer.as_ref()?;
292
293 let expr_id = self.expr_id(db, &literal.clone().into())?;
294 let substs = match &infer.type_of_expr[expr_id] {
295 Ty::Apply(a_ty) => &a_ty.parameters,
296 _ => return None,
297 };
298
299 let (variant, missing_fields, _exhaustive) =
300 record_literal_missing_fields(db, infer, expr_id, &body[expr_id])?;
301 let res = self.missing_fields(db, krate, substs, variant, missing_fields);
302 Some(res)
303 }
304
305 pub(crate) fn record_pattern_missing_fields(
306 &self,
307 db: &dyn HirDatabase,
308 pattern: &ast::RecordPat,
309 ) -> Option<Vec<(Field, Type)>> {
310 let krate = self.resolver.krate()?;
311 let body = self.body.as_ref()?;
312 let infer = self.infer.as_ref()?;
313
314 let pat_id = self.pat_id(&pattern.clone().into())?;
315 let substs = match &infer.type_of_pat[pat_id] {
316 Ty::Apply(a_ty) => &a_ty.parameters,
317 _ => return None,
318 };
319
320 let (variant, missing_fields, _exhaustive) =
321 record_pattern_missing_fields(db, infer, pat_id, &body[pat_id])?;
322 let res = self.missing_fields(db, krate, substs, variant, missing_fields);
323 Some(res)
324 }
325
326 fn missing_fields(
327 &self,
328 db: &dyn HirDatabase,
329 krate: CrateId,
330 substs: &Substs,
331 variant: VariantId,
332 missing_fields: Vec<LocalFieldId>,
333 ) -> Vec<(Field, Type)> {
334 let field_types = db.field_types(variant);
335
336 missing_fields
337 .into_iter()
338 .map(|local_id| {
339 let field = FieldId { parent: variant, local_id };
340 let ty = field_types[local_id].clone().subst(substs);
341 (field.into(), Type::new_with_resolver_inner(db, krate, &self.resolver, ty))
342 })
343 .collect()
344 }
345
346 pub(crate) fn expand(
347 &self,
348 db: &dyn HirDatabase,
349 macro_call: InFile<&ast::MacroCall>,
350 ) -> Option<HirFileId> {
351 let krate = self.resolver.krate()?;
352 let macro_call_id = macro_call.as_call_id(db.upcast(), krate, |path| {
353 self.resolver.resolve_path_as_macro(db.upcast(), &path)
354 })?;
355 Some(macro_call_id.as_file()).filter(|it| it.expansion_level(db.upcast()) < 64)
356 }
357
358 pub(crate) fn resolve_variant(
359 &self,
360 db: &dyn HirDatabase,
361 record_lit: ast::RecordExpr,
362 ) -> Option<VariantId> {
363 let infer = self.infer.as_ref()?;
364 let expr_id = self.expr_id(db, &record_lit.into())?;
365 infer.variant_resolution_for_expr(expr_id)
366 }
367}
368
369fn scope_for(
370 scopes: &ExprScopes,
371 source_map: &BodySourceMap,
372 node: InFile<&SyntaxNode>,
373) -> Option<ScopeId> {
374 node.value
375 .ancestors()
376 .filter_map(ast::Expr::cast)
377 .filter_map(|it| source_map.node_expr(InFile::new(node.file_id, &it)))
378 .find_map(|it| scopes.scope_for(it))
379}
380
381fn scope_for_offset(
382 db: &dyn HirDatabase,
383 scopes: &ExprScopes,
384 source_map: &BodySourceMap,
385 offset: InFile<TextSize>,
386) -> Option<ScopeId> {
387 scopes
388 .scope_by_expr()
389 .iter()
390 .filter_map(|(id, scope)| {
391 let source = source_map.expr_syntax(*id).ok()?;
392 // FIXME: correctly handle macro expansion
393 if source.file_id != offset.file_id {
394 return None;
395 }
396 let root = source.file_syntax(db.upcast());
397 let node = source.value.to_node(&root);
398 Some((node.syntax().text_range(), scope))
399 })
400 // find containing scope
401 .min_by_key(|(expr_range, _scope)| {
402 (
403 !(expr_range.start() <= offset.value && offset.value <= expr_range.end()),
404 expr_range.len(),
405 )
406 })
407 .map(|(expr_range, scope)| {
408 adjust(db, scopes, source_map, expr_range, offset).unwrap_or(*scope)
409 })
410}
411
412// XXX: during completion, cursor might be outside of any particular
413// expression. Try to figure out the correct scope...
414fn adjust(
415 db: &dyn HirDatabase,
416 scopes: &ExprScopes,
417 source_map: &BodySourceMap,
418 expr_range: TextRange,
419 offset: InFile<TextSize>,
420) -> Option<ScopeId> {
421 let child_scopes = scopes
422 .scope_by_expr()
423 .iter()
424 .filter_map(|(id, scope)| {
425 let source = source_map.expr_syntax(*id).ok()?;
426 // FIXME: correctly handle macro expansion
427 if source.file_id != offset.file_id {
428 return None;
429 }
430 let root = source.file_syntax(db.upcast());
431 let node = source.value.to_node(&root);
432 Some((node.syntax().text_range(), scope))
433 })
434 .filter(|&(range, _)| {
435 range.start() <= offset.value && expr_range.contains_range(range) && range != expr_range
436 });
437
438 child_scopes
439 .max_by(|&(r1, _), &(r2, _)| {
440 if r1.contains_range(r2) {
441 std::cmp::Ordering::Greater
442 } else if r2.contains_range(r1) {
443 std::cmp::Ordering::Less
444 } else {
445 r1.start().cmp(&r2.start())
446 }
447 })
448 .map(|(_ptr, scope)| *scope)
449}
450
451pub(crate) fn resolve_hir_path(
452 db: &dyn HirDatabase,
453 resolver: &Resolver,
454 path: &crate::Path,
455) -> Option<PathResolution> {
456 let types =
457 resolver.resolve_path_in_type_ns_fully(db.upcast(), path.mod_path()).map(|ty| match ty {
458 TypeNs::SelfType(it) => PathResolution::SelfType(it.into()),
459 TypeNs::GenericParam(id) => PathResolution::TypeParam(TypeParam { id }),
460 TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => {
461 PathResolution::Def(Adt::from(it).into())
462 }
463 TypeNs::EnumVariantId(it) => PathResolution::Def(EnumVariant::from(it).into()),
464 TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()),
465 TypeNs::BuiltinType(it) => PathResolution::Def(it.into()),
466 TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()),
467 });
468
469 let body_owner = resolver.body_owner();
470 let values =
471 resolver.resolve_path_in_value_ns_fully(db.upcast(), path.mod_path()).and_then(|val| {
472 let res = match val {
473 ValueNs::LocalBinding(pat_id) => {
474 let var = Local { parent: body_owner?.into(), pat_id };
475 PathResolution::Local(var)
476 }
477 ValueNs::FunctionId(it) => PathResolution::Def(Function::from(it).into()),
478 ValueNs::ConstId(it) => PathResolution::Def(Const::from(it).into()),
479 ValueNs::StaticId(it) => PathResolution::Def(Static::from(it).into()),
480 ValueNs::StructId(it) => PathResolution::Def(Struct::from(it).into()),
481 ValueNs::EnumVariantId(it) => PathResolution::Def(EnumVariant::from(it).into()),
482 ValueNs::ImplSelf(impl_id) => PathResolution::SelfType(impl_id.into()),
483 };
484 Some(res)
485 });
486
487 let items = resolver
488 .resolve_module_path_in_items(db.upcast(), path.mod_path())
489 .take_types()
490 .map(|it| PathResolution::Def(it.into()));
491
492 types.or(values).or(items).or_else(|| {
493 resolver
494 .resolve_path_as_macro(db.upcast(), path.mod_path())
495 .map(|def| PathResolution::Macro(def.into()))
496 })
497}
498
499/// Resolves a path where we know it is a qualifier of another path.
500///
501/// For example, if we have:
502/// ```
503/// mod my {
504/// pub mod foo {
505/// struct Bar;
506/// }
507///
508/// pub fn foo() {}
509/// }
510/// ```
511/// then we know that `foo` in `my::foo::Bar` refers to the module, not the function.
512pub(crate) fn resolve_hir_path_qualifier(
513 db: &dyn HirDatabase,
514 resolver: &Resolver,
515 path: &crate::Path,
516) -> Option<PathResolution> {
517 let items = resolver
518 .resolve_module_path_in_items(db.upcast(), path.mod_path())
519 .take_types()
520 .map(|it| PathResolution::Def(it.into()));
521
522 if items.is_some() {
523 return items;
524 }
525
526 resolver.resolve_path_in_type_ns_fully(db.upcast(), path.mod_path()).map(|ty| match ty {
527 TypeNs::SelfType(it) => PathResolution::SelfType(it.into()),
528 TypeNs::GenericParam(id) => PathResolution::TypeParam(TypeParam { id }),
529 TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => PathResolution::Def(Adt::from(it).into()),
530 TypeNs::EnumVariantId(it) => PathResolution::Def(EnumVariant::from(it).into()),
531 TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()),
532 TypeNs::BuiltinType(it) => PathResolution::Def(it.into()),
533 TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()),
534 })
535}