diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-09-09 09:04:00 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2019-09-09 09:04:00 +0100 |
commit | 1db08a54c20c244718e2378272c72ae5c6651f06 (patch) | |
tree | 90fe99eb39d045d9bac34cc200a74d0410d51763 /crates/ra_hir/src/nameres.rs | |
parent | 72259b67bf2393bec1faf6a9f95a575d6fe9cfea (diff) | |
parent | 9ed21d65fb6727f6de4961dfa440981864451af6 (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.rs | 25 |
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)] |
139 | pub struct ModuleScope { | 139 | pub 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 | ||
144 | static BUILTIN_SCOPE: Lazy<FxHashMap<Name, Resolution>> = Lazy::new(|| { | 158 | static 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 | ||
176 | type ItemOrMacro = Either<PerNs<ModuleDef>, MacroDef>; | 194 | type 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> { |