From 26419c03795574b35a8751fd466e500a0ca59233 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 8 Nov 2021 14:31:46 +0100 Subject: [PATCH] Fix proc-macro attributes being shadowed by their functions in IDE layer --- crates/hir/src/semantics.rs | 10 +++++++ crates/hir/src/source_analyzer.rs | 12 +++++++++ .../test_data/highlighting.html | 2 +- crates/ide_db/src/defs.rs | 26 +++++++++---------- 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 { + self.imp.resolve_path_as_macro(path) + } + pub fn resolve_extern_crate(&self, extern_crate: &ast::ExternCrate) -> Option { 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 { + self.analyze(path.syntax()).resolve_path_as_macro(self.db, path) + } + fn resolve_extern_crate(&self, extern_crate: &ast::ExternCrate) -> Option { 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 { + // 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
use inner::{self as inner_mod};
 mod inner {}
 
-#[proc_macros::identity]
+#[proc_macros::identity]
 pub mod ops {
     #[lang = "fn_once"]
     pub trait FnOnce<Args> {}
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),
             };