1pub mod assoc;
51pub mod attr_resolution;
52mod collector;
53pub mod diagnostics;
54mod mod_resolution;
55mod path_resolution;
56pub mod proc_macro;
57
58#[cfg(test)]
59mod tests;
60
61use std::ops::Deref;
62
63use base_db::Crate;
64use hir_expand::{
65 EditionedFileId, ErasedAstId, HirFileId, InFile, MacroCallId, mod_path::ModPath, name::Name,
66 proc_macro::ProcMacroKind,
67};
68use intern::Symbol;
69use itertools::Itertools;
70use la_arena::Arena;
71use rustc_hash::{FxHashMap, FxHashSet};
72use span::{Edition, FileAstId, FileId, ROOT_ERASED_FILE_AST_ID};
73use stdx::format_to;
74use syntax::{AstNode, SmolStr, SyntaxNode, ToSmolStr, ast};
75use triomphe::Arc;
76use tt::TextRange;
77
78use crate::{
79 AstId, BlockId, BlockLoc, CrateRootModuleId, ExternCrateId, FunctionId, FxIndexMap,
80 LocalModuleId, Lookup, MacroExpander, MacroId, ModuleId, ProcMacroId, UseId,
81 db::DefDatabase,
82 item_scope::{BuiltinShadowMode, ItemScope},
83 item_tree::TreeId,
84 nameres::{diagnostics::DefDiagnostic, path_resolution::ResolveMode},
85 per_ns::PerNs,
86 visibility::{Visibility, VisibilityExplicitness},
87};
88
89pub use self::path_resolution::ResolvePathResultPrefixInfo;
90
91const PREDEFINED_TOOLS: &[SmolStr] = &[
92 SmolStr::new_static("clippy"),
93 SmolStr::new_static("rustfmt"),
94 SmolStr::new_static("diagnostic"),
95 SmolStr::new_static("miri"),
96 SmolStr::new_static("rust_analyzer"),
97];
98
99#[derive(Debug, PartialEq, Eq, Default)]
108pub struct LocalDefMap {
109 extern_prelude: FxIndexMap<Name, (CrateRootModuleId, Option<ExternCrateId>)>,
113}
114
115impl std::hash::Hash for LocalDefMap {
116 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
117 let LocalDefMap { extern_prelude } = self;
118 extern_prelude.len().hash(state);
119 for (name, (crate_root, extern_crate)) in extern_prelude {
120 name.hash(state);
121 crate_root.hash(state);
122 extern_crate.hash(state);
123 }
124 }
125}
126
127impl LocalDefMap {
128 pub(crate) const EMPTY: &Self =
129 &Self { extern_prelude: FxIndexMap::with_hasher(rustc_hash::FxBuildHasher) };
130
131 fn shrink_to_fit(&mut self) {
132 let Self { extern_prelude } = self;
133 extern_prelude.shrink_to_fit();
134 }
135
136 pub(crate) fn extern_prelude(
137 &self,
138 ) -> impl DoubleEndedIterator<Item = (&Name, (CrateRootModuleId, Option<ExternCrateId>))> + '_
139 {
140 self.extern_prelude.iter().map(|(name, &def)| (name, def))
141 }
142}
143
144#[derive(Debug, PartialEq, Eq)]
154pub struct DefMap {
155 krate: Crate,
157 block: Option<BlockInfo>,
160 pub modules: Arena<ModuleData>,
162 prelude: Option<(ModuleId, Option<UseId>)>,
169 macro_use_prelude: FxHashMap<Name, (MacroId, Option<ExternCrateId>)>,
173
174 derive_helpers_in_scope: FxHashMap<AstId<ast::Item>, Vec<(Name, MacroId, MacroCallId)>>,
178 pub macro_def_to_macro_id: FxHashMap<ErasedAstId, MacroId>,
180
181 diagnostics: Vec<DefDiagnostic>,
183
184 data: Arc<DefMapCrateData>,
186}
187
188#[derive(Clone, Debug, PartialEq, Eq)]
190struct DefMapCrateData {
191 exported_derives: FxHashMap<MacroId, Box<[Name]>>,
193 fn_proc_macro_mapping: FxHashMap<FunctionId, ProcMacroId>,
194
195 registered_tools: Vec<Symbol>,
197 unstable_features: FxHashSet<Symbol>,
199 rustc_coherence_is_core: bool,
201 no_core: bool,
202 no_std: bool,
203
204 edition: Edition,
205 recursion_limit: Option<u32>,
206}
207
208impl DefMapCrateData {
209 fn new(edition: Edition) -> Self {
210 Self {
211 exported_derives: FxHashMap::default(),
212 fn_proc_macro_mapping: FxHashMap::default(),
213 registered_tools: PREDEFINED_TOOLS.iter().map(|it| Symbol::intern(it)).collect(),
214 unstable_features: FxHashSet::default(),
215 rustc_coherence_is_core: false,
216 no_core: false,
217 no_std: false,
218 edition,
219 recursion_limit: None,
220 }
221 }
222
223 fn shrink_to_fit(&mut self) {
224 let Self {
225 exported_derives,
226 fn_proc_macro_mapping,
227 registered_tools,
228 unstable_features,
229 rustc_coherence_is_core: _,
230 no_core: _,
231 no_std: _,
232 edition: _,
233 recursion_limit: _,
234 } = self;
235 exported_derives.shrink_to_fit();
236 fn_proc_macro_mapping.shrink_to_fit();
237 registered_tools.shrink_to_fit();
238 unstable_features.shrink_to_fit();
239 }
240}
241
242#[derive(Debug, PartialEq, Eq, Clone, Copy)]
244struct BlockInfo {
245 block: BlockId,
247 parent: BlockRelativeModuleId,
249}
250
251#[derive(Debug, PartialEq, Eq, Clone, Copy)]
252struct BlockRelativeModuleId {
253 block: Option<BlockId>,
254 local_id: LocalModuleId,
255}
256
257impl BlockRelativeModuleId {
258 fn def_map(self, db: &dyn DefDatabase, krate: Crate) -> &DefMap {
259 self.into_module(krate).def_map(db)
260 }
261
262 fn into_module(self, krate: Crate) -> ModuleId {
263 ModuleId { krate, block: self.block, local_id: self.local_id }
264 }
265
266 fn is_block_module(self) -> bool {
267 self.block.is_some() && self.local_id == DefMap::ROOT
268 }
269}
270
271impl std::ops::Index<LocalModuleId> for DefMap {
272 type Output = ModuleData;
273 fn index(&self, id: LocalModuleId) -> &ModuleData {
274 &self.modules[id]
275 }
276}
277
278#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
279pub enum ModuleOrigin {
280 CrateRoot {
281 definition: EditionedFileId,
282 },
283 File {
285 is_mod_rs: bool,
286 declaration: FileAstId<ast::Module>,
287 declaration_tree_id: TreeId,
288 definition: EditionedFileId,
289 },
290 Inline {
291 definition_tree_id: TreeId,
292 definition: FileAstId<ast::Module>,
293 },
294 BlockExpr {
296 id: BlockId,
297 block: AstId<ast::BlockExpr>,
298 },
299}
300
301impl ModuleOrigin {
302 pub fn declaration(&self) -> Option<AstId<ast::Module>> {
303 match self {
304 &ModuleOrigin::File { declaration, declaration_tree_id, .. } => {
305 Some(AstId::new(declaration_tree_id.file_id(), declaration))
306 }
307 &ModuleOrigin::Inline { definition, definition_tree_id } => {
308 Some(AstId::new(definition_tree_id.file_id(), definition))
309 }
310 ModuleOrigin::CrateRoot { .. } | ModuleOrigin::BlockExpr { .. } => None,
311 }
312 }
313
314 pub fn file_id(&self) -> Option<EditionedFileId> {
315 match self {
316 ModuleOrigin::File { definition, .. } | ModuleOrigin::CrateRoot { definition } => {
317 Some(*definition)
318 }
319 _ => None,
320 }
321 }
322
323 pub fn is_inline(&self) -> bool {
324 match self {
325 ModuleOrigin::Inline { .. } | ModuleOrigin::BlockExpr { .. } => true,
326 ModuleOrigin::CrateRoot { .. } | ModuleOrigin::File { .. } => false,
327 }
328 }
329
330 pub fn definition_source(&self, db: &dyn DefDatabase) -> InFile<ModuleSource> {
333 match self {
334 &ModuleOrigin::File { definition: editioned_file_id, .. }
335 | &ModuleOrigin::CrateRoot { definition: editioned_file_id } => {
336 let sf = db.parse(editioned_file_id).tree();
337 InFile::new(editioned_file_id.into(), ModuleSource::SourceFile(sf))
338 }
339 &ModuleOrigin::Inline { definition, definition_tree_id } => InFile::new(
340 definition_tree_id.file_id(),
341 ModuleSource::Module(
342 AstId::new(definition_tree_id.file_id(), definition).to_node(db),
343 ),
344 ),
345 ModuleOrigin::BlockExpr { block, .. } => {
346 InFile::new(block.file_id, ModuleSource::BlockExpr(block.to_node(db)))
347 }
348 }
349 }
350}
351
352#[derive(Debug, PartialEq, Eq)]
353pub struct ModuleData {
354 pub origin: ModuleOrigin,
356 pub visibility: Visibility,
358 pub parent: Option<LocalModuleId>,
362 pub children: FxIndexMap<Name, LocalModuleId>,
363 pub scope: ItemScope,
364}
365
366#[inline]
367pub fn crate_def_map(db: &dyn DefDatabase, crate_id: Crate) -> &DefMap {
368 crate_local_def_map(db, crate_id).def_map(db)
369}
370
371#[salsa_macros::tracked]
372pub(crate) struct DefMapPair<'db> {
373 #[tracked]
374 #[returns(ref)]
375 pub(crate) def_map: DefMap,
376 #[returns(ref)]
377 pub(crate) local: LocalDefMap,
378}
379
380#[salsa_macros::tracked(returns(ref))]
381pub(crate) fn crate_local_def_map(db: &dyn DefDatabase, crate_id: Crate) -> DefMapPair<'_> {
382 let krate = crate_id.data(db);
383 let _p = tracing::info_span!(
384 "crate_def_map_query",
385 name=?crate_id
386 .extra_data(db)
387 .display_name
388 .as_ref()
389 .map(|it| it.crate_name().to_smolstr())
390 .unwrap_or_default()
391 )
392 .entered();
393
394 let module_data = ModuleData::new(
395 ModuleOrigin::CrateRoot { definition: krate.root_file_id(db) },
396 Visibility::Public,
397 );
398
399 let def_map =
400 DefMap::empty(crate_id, Arc::new(DefMapCrateData::new(krate.edition)), module_data, None);
401 let (def_map, local_def_map) = collector::collect_defs(
402 db,
403 def_map,
404 TreeId::new(krate.root_file_id(db).into(), None),
405 None,
406 );
407
408 DefMapPair::new(db, def_map, local_def_map)
409}
410
411#[salsa_macros::tracked(returns(ref))]
412pub fn block_def_map(db: &dyn DefDatabase, block_id: BlockId) -> DefMap {
413 let BlockLoc { ast_id, module } = block_id.lookup(db);
414
415 let visibility = Visibility::Module(
416 ModuleId { krate: module.krate, local_id: DefMap::ROOT, block: module.block },
417 VisibilityExplicitness::Implicit,
418 );
419 let module_data =
420 ModuleData::new(ModuleOrigin::BlockExpr { block: ast_id, id: block_id }, visibility);
421
422 let local_def_map = crate_local_def_map(db, module.krate);
423 let def_map = DefMap::empty(
424 module.krate,
425 local_def_map.def_map(db).data.clone(),
426 module_data,
427 Some(BlockInfo {
428 block: block_id,
429 parent: BlockRelativeModuleId { block: module.block, local_id: module.local_id },
430 }),
431 );
432
433 let (def_map, _) = collector::collect_defs(
434 db,
435 def_map,
436 TreeId::new(ast_id.file_id, Some(block_id)),
437 Some(local_def_map.local(db)),
438 );
439 def_map
440}
441
442impl DefMap {
443 pub const ROOT: LocalModuleId = LocalModuleId::from_raw(la_arena::RawIdx::from_u32(0));
445
446 pub fn edition(&self) -> Edition {
447 self.data.edition
448 }
449
450 fn empty(
451 krate: Crate,
452 crate_data: Arc<DefMapCrateData>,
453 module_data: ModuleData,
454 block: Option<BlockInfo>,
455 ) -> DefMap {
456 let mut modules: Arena<ModuleData> = Arena::default();
457 let root = modules.alloc(module_data);
458 assert_eq!(root, Self::ROOT);
459
460 DefMap {
461 block,
462 modules,
463 krate,
464 prelude: None,
465 macro_use_prelude: FxHashMap::default(),
466 derive_helpers_in_scope: FxHashMap::default(),
467 diagnostics: Vec::new(),
468 data: crate_data,
469 macro_def_to_macro_id: FxHashMap::default(),
470 }
471 }
472 fn shrink_to_fit(&mut self) {
473 let Self {
475 macro_use_prelude,
476 diagnostics,
477 modules,
478 derive_helpers_in_scope,
479 block: _,
480 krate: _,
481 prelude: _,
482 data: _,
483 macro_def_to_macro_id,
484 } = self;
485
486 macro_def_to_macro_id.shrink_to_fit();
487 macro_use_prelude.shrink_to_fit();
488 diagnostics.shrink_to_fit();
489 modules.shrink_to_fit();
490 derive_helpers_in_scope.shrink_to_fit();
491 for (_, module) in modules.iter_mut() {
492 module.children.shrink_to_fit();
493 module.scope.shrink_to_fit();
494 }
495 }
496}
497
498impl DefMap {
499 pub fn modules_for_file<'a>(
500 &'a self,
501 db: &'a dyn DefDatabase,
502 file_id: FileId,
503 ) -> impl Iterator<Item = LocalModuleId> + 'a {
504 self.modules
505 .iter()
506 .filter(move |(_id, data)| {
507 data.origin.file_id().map(|file_id| file_id.file_id(db)) == Some(file_id)
508 })
509 .map(|(id, _data)| id)
510 }
511
512 pub fn modules(&self) -> impl Iterator<Item = (LocalModuleId, &ModuleData)> + '_ {
513 self.modules.iter()
514 }
515
516 pub fn derive_helpers_in_scope(
517 &self,
518 id: AstId<ast::Adt>,
519 ) -> Option<&[(Name, MacroId, MacroCallId)]> {
520 self.derive_helpers_in_scope.get(&id.map(|it| it.upcast())).map(Deref::deref)
521 }
522
523 pub fn registered_tools(&self) -> &[Symbol] {
524 &self.data.registered_tools
525 }
526
527 pub fn is_unstable_feature_enabled(&self, feature: &Symbol) -> bool {
528 self.data.unstable_features.contains(feature)
529 }
530
531 pub fn is_rustc_coherence_is_core(&self) -> bool {
532 self.data.rustc_coherence_is_core
533 }
534
535 pub fn is_no_std(&self) -> bool {
536 self.data.no_std || self.data.no_core
537 }
538
539 pub fn is_no_core(&self) -> bool {
540 self.data.no_core
541 }
542
543 pub fn fn_as_proc_macro(&self, id: FunctionId) -> Option<ProcMacroId> {
544 self.data.fn_proc_macro_mapping.get(&id).copied()
545 }
546
547 pub fn krate(&self) -> Crate {
548 self.krate
549 }
550
551 pub fn module_id(&self, local_id: LocalModuleId) -> ModuleId {
552 let block = self.block.map(|b| b.block);
553 ModuleId { krate: self.krate, local_id, block }
554 }
555
556 pub fn crate_root(&self) -> CrateRootModuleId {
557 CrateRootModuleId { krate: self.krate }
558 }
559
560 pub fn root_module_id(&self) -> ModuleId {
563 self.module_id(Self::ROOT)
564 }
565
566 pub fn parent(&self) -> Option<ModuleId> {
569 let BlockRelativeModuleId { block, local_id } = self.block?.parent;
570 Some(ModuleId { krate: self.krate, block, local_id })
571 }
572
573 pub fn containing_module(&self, local_mod: LocalModuleId) -> Option<ModuleId> {
576 match self[local_mod].parent {
577 Some(parent) => Some(self.module_id(parent)),
578 None => {
579 self.block.map(
580 |BlockInfo { parent: BlockRelativeModuleId { block, local_id }, .. }| {
581 ModuleId { krate: self.krate, block, local_id }
582 },
583 )
584 }
585 }
586 }
587
588 pub fn diagnostics(&self) -> &[DefDiagnostic] {
590 self.diagnostics.as_slice()
591 }
592
593 pub fn recursion_limit(&self) -> u32 {
594 self.data.recursion_limit.unwrap_or(128)
596 }
597
598 pub fn dump(&self, db: &dyn DefDatabase) -> String {
601 let mut buf = String::new();
602 let mut arc;
603 let mut current_map = self;
604 while let Some(block) = current_map.block {
605 go(&mut buf, db, current_map, "block scope", Self::ROOT);
606 buf.push('\n');
607 arc = block.parent.def_map(db, self.krate);
608 current_map = arc;
609 }
610 go(&mut buf, db, current_map, "crate", Self::ROOT);
611 return buf;
612
613 fn go(
614 buf: &mut String,
615 db: &dyn DefDatabase,
616 map: &DefMap,
617 path: &str,
618 module: LocalModuleId,
619 ) {
620 format_to!(buf, "{}\n", path);
621
622 map.modules[module].scope.dump(db, buf);
623
624 for (name, child) in
625 map.modules[module].children.iter().sorted_by(|a, b| Ord::cmp(&a.0, &b.0))
626 {
627 let path = format!("{path}::{}", name.display(db, Edition::LATEST));
628 buf.push('\n');
629 go(buf, db, map, &path, *child);
630 }
631 }
632 }
633
634 pub fn dump_block_scopes(&self, db: &dyn DefDatabase) -> String {
635 let mut buf = String::new();
636 let mut arc;
637 let mut current_map = self;
638 while let Some(block) = current_map.block {
639 format_to!(buf, "{:?} in {:?}\n", block.block, block.parent);
640 arc = block.parent.def_map(db, self.krate);
641 current_map = arc;
642 }
643
644 format_to!(buf, "crate scope\n");
645 buf
646 }
647}
648
649impl DefMap {
650 pub(crate) fn block_id(&self) -> Option<BlockId> {
651 self.block.map(|block| block.block)
652 }
653
654 pub(crate) fn prelude(&self) -> Option<(ModuleId, Option<UseId>)> {
655 self.prelude
656 }
657
658 pub(crate) fn macro_use_prelude(&self) -> &FxHashMap<Name, (MacroId, Option<ExternCrateId>)> {
659 &self.macro_use_prelude
660 }
661
662 pub(crate) fn resolve_path(
663 &self,
664 local_def_map: &LocalDefMap,
665 db: &dyn DefDatabase,
666 original_module: LocalModuleId,
667 path: &ModPath,
668 shadow: BuiltinShadowMode,
669 expected_macro_subns: Option<MacroSubNs>,
670 ) -> (PerNs, Option<usize>) {
671 let res = self.resolve_path_fp_with_macro(
672 local_def_map,
673 db,
674 ResolveMode::Other,
675 original_module,
676 path,
677 shadow,
678 expected_macro_subns,
679 );
680 (res.resolved_def, res.segment_index)
681 }
682
683 pub(crate) fn resolve_path_locally(
686 &self,
687 local_def_map: &LocalDefMap,
688 db: &dyn DefDatabase,
689 original_module: LocalModuleId,
690 path: &ModPath,
691 shadow: BuiltinShadowMode,
692 ) -> (PerNs, Option<usize>, ResolvePathResultPrefixInfo) {
693 let res = self.resolve_path_fp_with_macro_single(
694 local_def_map,
695 db,
696 ResolveMode::Other,
697 original_module,
698 path,
699 shadow,
700 None, );
702 (res.resolved_def, res.segment_index, res.prefix_info)
703 }
704
705 pub(crate) fn with_ancestor_maps<T>(
710 &self,
711 db: &dyn DefDatabase,
712 local_mod: LocalModuleId,
713 f: &mut dyn FnMut(&DefMap, LocalModuleId) -> Option<T>,
714 ) -> Option<T> {
715 if let Some(it) = f(self, local_mod) {
716 return Some(it);
717 }
718 let mut block = self.block;
719 while let Some(block_info) = block {
720 let parent = block_info.parent.def_map(db, self.krate);
721 if let Some(it) = f(parent, block_info.parent.local_id) {
722 return Some(it);
723 }
724 block = parent.block;
725 }
726
727 None
728 }
729}
730
731impl ModuleData {
732 pub(crate) fn new(origin: ModuleOrigin, visibility: Visibility) -> Self {
733 ModuleData {
734 origin,
735 visibility,
736 parent: None,
737 children: Default::default(),
738 scope: ItemScope::default(),
739 }
740 }
741
742 pub fn definition_source(&self, db: &dyn DefDatabase) -> InFile<ModuleSource> {
744 self.origin.definition_source(db)
745 }
746
747 pub fn definition_source_file_id(&self) -> HirFileId {
749 match self.origin {
750 ModuleOrigin::File { definition, .. } | ModuleOrigin::CrateRoot { definition } => {
751 definition.into()
752 }
753 ModuleOrigin::Inline { definition_tree_id, .. } => definition_tree_id.file_id(),
754 ModuleOrigin::BlockExpr { block, .. } => block.file_id,
755 }
756 }
757
758 pub fn definition_source_range(&self, db: &dyn DefDatabase) -> InFile<TextRange> {
759 match &self.origin {
760 &ModuleOrigin::File { definition, .. } | &ModuleOrigin::CrateRoot { definition } => {
761 InFile::new(
762 definition.into(),
763 ErasedAstId::new(definition.into(), ROOT_ERASED_FILE_AST_ID).to_range(db),
764 )
765 }
766 &ModuleOrigin::Inline { definition, definition_tree_id } => InFile::new(
767 definition_tree_id.file_id(),
768 AstId::new(definition_tree_id.file_id(), definition).to_range(db),
769 ),
770 ModuleOrigin::BlockExpr { block, .. } => InFile::new(block.file_id, block.to_range(db)),
771 }
772 }
773
774 pub fn declaration_source(&self, db: &dyn DefDatabase) -> Option<InFile<ast::Module>> {
777 let decl = self.origin.declaration()?;
778 let value = decl.to_node(db);
779 Some(InFile { file_id: decl.file_id, value })
780 }
781
782 pub fn declaration_source_range(&self, db: &dyn DefDatabase) -> Option<InFile<TextRange>> {
785 let decl = self.origin.declaration()?;
786 Some(InFile { file_id: decl.file_id, value: decl.to_range(db) })
787 }
788}
789
790#[derive(Debug, Clone, PartialEq, Eq)]
791pub enum ModuleSource {
792 SourceFile(ast::SourceFile),
793 Module(ast::Module),
794 BlockExpr(ast::BlockExpr),
795}
796
797impl ModuleSource {
798 pub fn node(&self) -> SyntaxNode {
799 match self {
800 ModuleSource::SourceFile(it) => it.syntax().clone(),
801 ModuleSource::Module(it) => it.syntax().clone(),
802 ModuleSource::BlockExpr(it) => it.syntax().clone(),
803 }
804 }
805}
806
807#[derive(Clone, Copy, PartialEq, Eq)]
809pub enum MacroSubNs {
810 Bang,
812 Attr,
814}
815
816impl MacroSubNs {
817 fn from_id(db: &dyn DefDatabase, macro_id: MacroId) -> Self {
818 let expander = match macro_id {
819 MacroId::Macro2Id(it) => it.lookup(db).expander,
820 MacroId::MacroRulesId(it) => it.lookup(db).expander,
821 MacroId::ProcMacroId(it) => {
822 return match it.lookup(db).kind {
823 ProcMacroKind::CustomDerive | ProcMacroKind::Attr => Self::Attr,
824 ProcMacroKind::Bang => Self::Bang,
825 };
826 }
827 };
828
829 match expander {
831 MacroExpander::Declarative
832 | MacroExpander::BuiltIn(_)
833 | MacroExpander::BuiltInEager(_) => Self::Bang,
834 MacroExpander::BuiltInAttr(_) | MacroExpander::BuiltInDerive(_) => Self::Attr,
835 }
836 }
837}
838
839fn sub_namespace_match(candidate: Option<MacroSubNs>, expected: Option<MacroSubNs>) -> bool {
846 match (candidate, expected) {
847 (Some(candidate), Some(expected)) => candidate == expected,
848 _ => true,
849 }
850}