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