aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/nameres.rs
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2019-09-09 09:04:00 +0100
committerGitHub <[email protected]>2019-09-09 09:04:00 +0100
commit1db08a54c20c244718e2378272c72ae5c6651f06 (patch)
tree90fe99eb39d045d9bac34cc200a74d0410d51763 /crates/ra_hir/src/nameres.rs
parent72259b67bf2393bec1faf6a9f95a575d6fe9cfea (diff)
parent9ed21d65fb6727f6de4961dfa440981864451af6 (diff)
Merge #1784
1784: Support textual scoped macros r=matklad a=uHOOCCOOHu Refactor the old simulation with `global_macro_scope`. Now it is quite accurate to resolve textual scoped macros. - Expand textual scoped macros in item and non-item place. - Support `#[macro_use]` on `mod`. - Textual scoped macros are collected into `nameres::ModuleScope`, so I think it makes #1727 easier to fix. - It is implemented in a simple way to `clone()` current scoped macro ids into sub-modules. Though only indices are cloned, it will still increase some resolving time. Well, I've not bench-marked yet. In my test with vscode extension, it can now successfully expand `dbg!` from `std` without `std::` prefix. "Goto definition" also works. Screenshot here: <img width="281" alt="Screenshot_20190907_043442" src="https://user-images.githubusercontent.com/14816024/64458794-ddb47900-d128-11e9-95e3-1c8569978825.png"> Co-authored-by: uHOOCCOOHu <[email protected]>
Diffstat (limited to 'crates/ra_hir/src/nameres.rs')
-rw-r--r--crates/ra_hir/src/nameres.rs25
1 files changed, 24 insertions, 1 deletions
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index 7de422128..74546e5e2 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -138,7 +138,21 @@ pub(crate) struct ModuleData {
138#[derive(Debug, Default, PartialEq, Eq, Clone)] 138#[derive(Debug, Default, PartialEq, Eq, Clone)]
139pub struct ModuleScope { 139pub struct ModuleScope {
140 items: FxHashMap<Name, Resolution>, 140 items: FxHashMap<Name, Resolution>,
141 /// Macros in current module scoped
142 ///
143 /// This scope works exactly the same way that item scoping does.
144 /// Macro invocation with quantified path will search in it.
145 /// See details below.
141 macros: FxHashMap<Name, MacroDef>, 146 macros: FxHashMap<Name, MacroDef>,
147 /// Macros visable in current module in legacy textual scope
148 ///
149 /// For macros invoked by an unquatified identifier like `bar!()`, `legacy_macros` will be searched in first.
150 /// If it yields no result, then it turns to module scoped `macros`.
151 /// It macros with name quatified with a path like `crate::foo::bar!()`, `legacy_macros` will be skipped,
152 /// and only normal scoped `macros` will be searched in.
153 ///
154 /// Note that this automatically inherit macros defined textually before the definition of module itself.
155 legacy_macros: FxHashMap<Name, MacroDef>,
142} 156}
143 157
144static BUILTIN_SCOPE: Lazy<FxHashMap<Name, Resolution>> = Lazy::new(|| { 158static BUILTIN_SCOPE: Lazy<FxHashMap<Name, Resolution>> = Lazy::new(|| {
@@ -164,6 +178,7 @@ impl ModuleScope {
164 _ => None, 178 _ => None,
165 }) 179 })
166 } 180 }
181 /// It resolves in module scope. Textual scoped macros are ignored here.
167 fn get_item_or_macro(&self, name: &Name) -> Option<ItemOrMacro> { 182 fn get_item_or_macro(&self, name: &Name) -> Option<ItemOrMacro> {
168 match (self.get(name), self.macros.get(name)) { 183 match (self.get(name), self.macros.get(name)) {
169 (Some(item), _) if !item.def.is_none() => Some(Either::A(item.def)), 184 (Some(item), _) if !item.def.is_none() => Some(Either::A(item.def)),
@@ -171,6 +186,9 @@ impl ModuleScope {
171 _ => None, 186 _ => None,
172 } 187 }
173 } 188 }
189 fn get_legacy_macro(&self, name: &Name) -> Option<MacroDef> {
190 self.legacy_macros.get(name).copied()
191 }
174} 192}
175 193
176type ItemOrMacro = Either<PerNs<ModuleDef>, MacroDef>; 194type ItemOrMacro = Either<PerNs<ModuleDef>, MacroDef>;
@@ -484,16 +502,21 @@ impl CrateDefMap {
484 name: &Name, 502 name: &Name,
485 ) -> ItemOrMacro { 503 ) -> ItemOrMacro {
486 // Resolve in: 504 // Resolve in:
505 // - legacy scope
487 // - current module / scope 506 // - current module / scope
488 // - extern prelude 507 // - extern prelude
489 // - std prelude 508 // - std prelude
509 let from_legacy_macro = self[module]
510 .scope
511 .get_legacy_macro(name)
512 .map_or_else(|| Either::A(PerNs::none()), Either::B);
490 let from_scope = 513 let from_scope =
491 self[module].scope.get_item_or_macro(name).unwrap_or_else(|| Either::A(PerNs::none())); 514 self[module].scope.get_item_or_macro(name).unwrap_or_else(|| Either::A(PerNs::none()));
492 let from_extern_prelude = 515 let from_extern_prelude =
493 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); 516 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
494 let from_prelude = self.resolve_in_prelude(db, name); 517 let from_prelude = self.resolve_in_prelude(db, name);
495 518
496 or(from_scope, or(Either::A(from_extern_prelude), from_prelude)) 519 or(from_legacy_macro, or(from_scope, or(Either::A(from_extern_prelude), from_prelude)))
497 } 520 }
498 521
499 fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> { 522 fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> {