Unnamed repository; edit this file 'description' to name the repository.
Merge #10722
10722: fix: Fix proc-macro attributes being shadowed by their functions in IDE layer r=Veykril a=Veykril We sometimes still didn't resolve proc-macro attrs in attribute paths in the ide crates due to their function definitions resolving first. bors r+ Co-authored-by: Lukas Wirth <[email protected]>
bors[bot] 2021-11-08
parent f48b262 · parent 26419c0 · commit 653b78e
-rw-r--r--crates/hir/src/semantics.rs10
-rw-r--r--crates/hir/src/source_analyzer.rs12
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlighting.html2
-rw-r--r--crates/ide_db/src/defs.rs26
4 files changed, 36 insertions, 14 deletions
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 0f63de9e72..b09c0e753b 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -329,6 +329,10 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
self.imp.resolve_path(path)
}
+ pub fn resolve_path_as_macro(&self, path: &ast::Path) -> Option<MacroDef> {
+ self.imp.resolve_path_as_macro(path)
+ }
+
pub fn resolve_extern_crate(&self, extern_crate: &ast::ExternCrate) -> Option<Crate> {
self.imp.resolve_extern_crate(extern_crate)
}
@@ -845,6 +849,12 @@ impl<'db> SemanticsImpl<'db> {
self.analyze(path.syntax()).resolve_path(self.db, path)
}
+ // FIXME: This shouldn't exist, but is currently required to always resolve attribute paths in
+ // the IDE layer due to namespace collisions
+ fn resolve_path_as_macro(&self, path: &ast::Path) -> Option<MacroDef> {
+ self.analyze(path.syntax()).resolve_path_as_macro(self.db, path)
+ }
+
fn resolve_extern_crate(&self, extern_crate: &ast::ExternCrate) -> Option<Crate> {
let krate = self.scope(extern_crate.syntax()).krate()?;
krate.dependencies(self.db).into_iter().find_map(|dep| {
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index 08d0a02d79..b12461818e 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -246,6 +246,18 @@ impl SourceAnalyzer {
}
}
+ pub(crate) fn resolve_path_as_macro(
+ &self,
+ db: &dyn HirDatabase,
+ path: &ast::Path,
+ ) -> Option<MacroDef> {
+ // This must be a normal source file rather than macro file.
+ let hygiene = Hygiene::new(db.upcast(), self.file_id);
+ let ctx = body::LowerCtx::with_hygiene(db.upcast(), &hygiene);
+ let hir_path = Path::from_src(path.clone(), &ctx)?;
+ resolve_hir_path_as_macro(db, &self.resolver, &hir_path)
+ }
+
pub(crate) fn resolve_path(
&self,
db: &dyn HirDatabase,
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
index 1a10a78d24..ab810aceca 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
@@ -43,7 +43,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
<pre><code><span class="keyword">use</span> <span class="module">inner</span><span class="operator">::</span><span class="brace">{</span><span class="self_keyword">self</span> <span class="keyword">as</span> <span class="module declaration">inner_mod</span><span class="brace">}</span><span class="semicolon">;</span>
<span class="keyword">mod</span> <span class="module declaration">inner</span> <span class="brace">{</span><span class="brace">}</span>
-<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="module attribute">proc_macros</span><span class="operator attribute">::</span><span class="builtin_attr attribute">identity</span><span class="attribute attribute">]</span>
+<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="module attribute">proc_macros</span><span class="operator attribute">::</span><span class="macro attribute">identity</span><span class="attribute attribute">]</span>
<span class="keyword">pub</span> <span class="keyword">mod</span> <span class="module declaration public">ops</span> <span class="brace">{</span>
<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="builtin_attr attribute">lang</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"fn_once"</span><span class="attribute attribute">]</span>
<span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration public">FnOnce</span><span class="angle">&lt;</span><span class="type_param declaration">Args</span><span class="angle">&gt;</span> <span class="brace">{</span><span class="brace">}</span>
diff --git a/crates/ide_db/src/defs.rs b/crates/ide_db/src/defs.rs
index d95bca515f..e4874c7c48 100644
--- a/crates/ide_db/src/defs.rs
+++ b/crates/ide_db/src/defs.rs
@@ -433,20 +433,20 @@ impl NameRefClass {
.find_map(ast::Attr::cast)
.map(|attr| attr.path().as_ref() == Some(&top_path));
return match is_attribute_path {
- Some(true) => sema.resolve_path(&path).and_then(|resolved| {
- match resolved {
- // Don't wanna collide with builtin attributes here like `test` hence guard
- // so only resolve to modules that aren't the last segment
- PathResolution::Def(module @ ModuleDef::Module(_)) if path != top_path => {
- cov_mark::hit!(name_ref_classify_attr_path_qualifier);
- Some(NameRefClass::Definition(Definition::ModuleDef(module)))
- }
- PathResolution::Macro(mac) if mac.kind() == hir::MacroKind::Attr => {
- Some(NameRefClass::Definition(Definition::Macro(mac)))
- }
- _ => None,
+ Some(true) if path == top_path => sema
+ .resolve_path_as_macro(&path)
+ .filter(|mac| mac.kind() == hir::MacroKind::Attr)
+ .map(Definition::Macro)
+ .map(NameRefClass::Definition),
+ // in case of the path being a qualifier, don't resolve to anything but a module
+ Some(true) => match sema.resolve_path(&path)? {
+ PathResolution::Def(module @ ModuleDef::Module(_)) => {
+ cov_mark::hit!(name_ref_classify_attr_path_qualifier);
+ Some(NameRefClass::Definition(Definition::ModuleDef(module)))
}
- }),
+ _ => None,
+ },
+ // inside attribute, but our path isn't part of the attribute's path(might be in its expression only)
Some(false) => None,
None => sema.resolve_path(&path).map(Into::into).map(NameRefClass::Definition),
};