diff --git a/crates/hir-def/src/data.rs b/crates/hir-def/src/data.rs index 43094114193..35c8708955a 100644 --- a/crates/hir-def/src/data.rs +++ b/crates/hir-def/src/data.rs @@ -12,7 +12,7 @@ db::DefDatabase, intern::Interned, item_tree::{self, AssocItem, FnFlags, ItemTree, ItemTreeId, ModItem, Param, TreeId}, - nameres::{attr_resolution::ResolvedAttr, DefMap}, + nameres::{attr_resolution::ResolvedAttr, proc_macro::ProcMacroKind, DefMap}, type_ref::{TraitRef, TypeBound, TypeRef}, visibility::RawVisibility, AssocItemId, AstIdWithPath, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId, @@ -348,7 +348,8 @@ pub(crate) fn macro_rules_data_query( #[derive(Debug, Clone, PartialEq, Eq)] pub struct ProcMacroData { pub name: Name, - // FIXME: Record deriver helper here? + /// Derive helpers, if this is a derive + pub helpers: Option>, } impl ProcMacroData { @@ -360,17 +361,23 @@ pub(crate) fn proc_macro_data_query( let item_tree = loc.id.item_tree(db); let makro = &item_tree[loc.id.value]; - let name = if let Some(def) = item_tree + let (name, helpers) = if let Some(def) = item_tree .attrs(db, loc.container.krate(), ModItem::from(loc.id.value).into()) .parse_proc_macro_decl(&makro.name) { - def.name + ( + def.name, + match def.kind { + ProcMacroKind::CustomDerive { helpers } => Some(helpers), + ProcMacroKind::FnLike | ProcMacroKind::Attr => None, + }, + ) } else { // eeeh... stdx::never!("proc macro declaration is not a proc macro"); - makro.name.clone() + (makro.name.clone(), None) }; - Arc::new(ProcMacroData { name }) + Arc::new(ProcMacroData { name, helpers }) } } diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs index 25fb302e875..45f631936d2 100644 --- a/crates/hir-def/src/nameres.rs +++ b/crates/hir-def/src/nameres.rs @@ -48,11 +48,11 @@ //! the result pub mod attr_resolution; -mod collector; +pub mod proc_macro; pub mod diagnostics; +mod collector; mod mod_resolution; mod path_resolution; -mod proc_macro; #[cfg(test)] mod tests; diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 86b5bd3c2c8..d4925455d7b 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -2255,12 +2255,27 @@ pub fn source(self, db: &dyn HirDatabase) -> InFile Macro { Macro { id: self.derive.into() } } + + pub fn name(&self, db: &dyn HirDatabase) -> Name { + match self.derive { + MacroId::Macro2Id(_) => None, + MacroId::MacroRulesId(_) => None, + MacroId::ProcMacroId(proc_macro) => db + .proc_macro_data(proc_macro) + .helpers + .as_ref() + .and_then(|it| it.get(self.idx)) + .cloned(), + } + .unwrap_or_else(|| Name::missing()) + } } // FIXME: Wrong name? This is could also be a registered attribute diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index d57a73ade3a..1eb51b20c35 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -35,6 +35,7 @@ method_resolution, Adjust, Adjustment, AutoBorrow, InferenceResult, Interner, Substitution, TyExt, TyKind, TyLoweringContext, }; +use itertools::Itertools; use smallvec::SmallVec; use syntax::{ ast::{self, AstNode}, @@ -487,10 +488,16 @@ pub(crate) fn resolve_path( { // FIXME: Multiple derives can have the same helper let name_ref = name_ref.as_name(); - if let Some(&(_, derive, _)) = - helpers.iter().find(|(name, ..)| *name == name_ref) + for (macro_id, mut helpers) in + helpers.iter().group_by(|(_, macro_id, ..)| macro_id).into_iter() { - return Some(PathResolution::DeriveHelper(DeriveHelper { derive })); + if let Some(idx) = helpers.position(|(name, ..)| *name == name_ref) + { + return Some(PathResolution::DeriveHelper(DeriveHelper { + derive: *macro_id, + idx, + })); + } } } } diff --git a/crates/ide-db/src/defs.rs b/crates/ide-db/src/defs.rs index a9a78e67290..aeaca00ec65 100644 --- a/crates/ide-db/src/defs.rs +++ b/crates/ide-db/src/defs.rs @@ -121,7 +121,7 @@ pub fn name(&self, db: &RootDatabase) -> Option { Definition::Label(it) => it.name(db), Definition::BuiltinAttr(_) => return None, // FIXME Definition::ToolModule(_) => return None, // FIXME - Definition::DeriveHelper(_) => return None, // FIXME + Definition::DeriveHelper(it) => it.name(db), }; Some(name) } diff --git a/crates/ide-db/src/search.rs b/crates/ide-db/src/search.rs index eb4fc364381..bd038cdaa06 100644 --- a/crates/ide-db/src/search.rs +++ b/crates/ide-db/src/search.rs @@ -278,16 +278,16 @@ fn search_scope(&self, db: &RootDatabase) -> SearchScope { } } hir::MacroKind::BuiltIn => SearchScope::crate_graph(db), - // FIXME: We don't actually see derives in derive attributes as these do not - // expand to something that references the derive macro in the output. - // We could get around this by doing pseudo expansions for proc_macro_derive like we - // do for the derive attribute hir::MacroKind::Derive | hir::MacroKind::Attr | hir::MacroKind::ProcMacro => { SearchScope::reverse_dependencies(db, module.krate()) } }; } + if let Definition::DeriveHelper(_) = self { + return SearchScope::reverse_dependencies(db, module.krate()); + } + let vis = self.visibility(db); if let Some(Visibility::Public) = vis { return SearchScope::reverse_dependencies(db, module.krate()); diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs index fcdb23fa18a..6c50a4e6adc 100644 --- a/crates/ide/src/hover/render.rs +++ b/crates/ide/src/hover/render.rs @@ -370,8 +370,7 @@ pub(super) fn definition( // FIXME: We should be able to show more info about these Definition::BuiltinAttr(it) => return render_builtin_attr(db, it), Definition::ToolModule(it) => return Some(Markup::fenced_block(&it.name(db))), - // FIXME: it.name(db) - Definition::DeriveHelper(_it) => ("derive-helper".to_owned(), None), + Definition::DeriveHelper(it) => (format!("derive_helper {}", it.name(db)), None), }; let docs = match config.documentation { diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs index eef717c16f2..d013d6f4b19 100644 --- a/crates/ide/src/syntax_highlighting.rs +++ b/crates/ide/src/syntax_highlighting.rs @@ -432,6 +432,13 @@ fn item(&self) -> &ast::Item { // let the editor do its highlighting for these tokens instead continue; } + if highlight.tag == HlTag::UnresolvedReference + && matches!(attr_or_derive_item, Some(AttrOrDerive::Derive(_)) if inside_attribute) + { + // do not emit unresolved references in derive helpers if the token mapping maps to + // something unresolvable. FIXME: There should be a way to prevent that + continue; + } if inside_attribute { highlight |= HlMod::Attribute }