From aa9d0934887fced0437c1e09ea5255185cac5631 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 19 Oct 2021 13:40:27 +0200 Subject: [PATCH] Resolve derive attributes even when shadowed --- crates/hir/src/semantics.rs | 12 +++++++++++- crates/hir/src/source_analyzer.rs | 9 +++++++++ crates/ide_db/src/helpers.rs | 9 +++------ 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index b6e5ee75313..ca23d85cb24 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -24,7 +24,7 @@ use syntax::{ use crate::{ db::HirDatabase, semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, - source_analyzer::{resolve_hir_path, SourceAnalyzer}, + source_analyzer::{resolve_hir_path, resolve_hir_path_as_macro, SourceAnalyzer}, Access, AssocItem, Callable, ConstParam, Crate, Field, Function, HasSource, HirFileId, Impl, InFile, Label, LifetimeParam, Local, MacroDef, Module, ModuleDef, Name, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, VariantDef, @@ -1134,4 +1134,14 @@ impl<'a> SemanticsScope<'a> { let path = Path::from_src(path.clone(), &ctx)?; resolve_hir_path(self.db, &self.resolver, &path) } + + /// Resolve a path as-if it was written at the given scope. This is + /// necessary a heuristic, as it doesn't take hygiene into account. + // FIXME: This special casing solely exists for attributes for now + // ideally we should have a path resolution infra that properly knows about overlapping namespaces + pub fn speculative_resolve_as_mac(&self, path: &ast::Path) -> Option { + let ctx = body::LowerCtx::new(self.db.upcast(), self.file_id); + let path = Path::from_src(path.clone(), &ctx)?; + resolve_hir_path_as_macro(self.db, &self.resolver, &path) + } } diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 960b290e266..08d0a02d796 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -502,6 +502,15 @@ pub(crate) fn resolve_hir_path( resolve_hir_path_(db, resolver, path, false) } +#[inline] +pub(crate) fn resolve_hir_path_as_macro( + db: &dyn HirDatabase, + resolver: &Resolver, + path: &Path, +) -> Option { + resolver.resolve_path_as_macro(db.upcast(), path.mod_path()).map(Into::into) +} + fn resolve_hir_path_( db: &dyn HirDatabase, resolver: &Resolver, diff --git a/crates/ide_db/src/helpers.rs b/crates/ide_db/src/helpers.rs index a8087d47fe2..173e55b33f6 100644 --- a/crates/ide_db/src/helpers.rs +++ b/crates/ide_db/src/helpers.rs @@ -53,12 +53,9 @@ pub fn try_resolve_derive_input_at( .take_while(|tok| tok.kind() != T!['('] && tok.kind() != T![,]) .collect(); let path = ast::Path::parse(&tokens.into_iter().rev().join("")).ok()?; - match sema.scope(tt.syntax()).speculative_resolve(&path) { - Some(hir::PathResolution::Macro(makro)) if makro.kind() == hir::MacroKind::Derive => { - Some(makro) - } - _ => None, - } + sema.scope(tt.syntax()) + .speculative_resolve_as_mac(&path) + .filter(|mac| mac.kind() == hir::MacroKind::Derive) } /// Picks the token with the highest rank returned by the passed in function.