diff options
| author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-10-28 16:49:55 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-10-28 16:49:55 +0000 |
| commit | b025bd6e7d52b6041bb1b4e4058e17037e0bb186 (patch) | |
| tree | c8c0918c1669ad68e7697d0c7b318f111842aed1 | |
| parent | 166c0ac0de96d44a7823ffa2ec79119b65608ec4 (diff) | |
| parent | 7fdbdc4ab216a3efa759f78e637626092e8a71be (diff) | |
| download | rust-b025bd6e7d52b6041bb1b4e4058e17037e0bb186.tar.gz rust-b025bd6e7d52b6041bb1b4e4058e17037e0bb186.zip | |
Merge #10656
10656: fix: Enable auto-import and qualify-path in derive attributes r=Veykril a=Veykril cc https://github.com/rust-analyzer/rust-analyzer/issues/10052 Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
| -rw-r--r-- | crates/hir/src/semantics/source_to_def.rs | 8 | ||||
| -rw-r--r-- | crates/hir_def/src/child_by_source.rs | 11 | ||||
| -rw-r--r-- | crates/hir_def/src/keys.rs | 2 | ||||
| -rw-r--r-- | crates/hir_def/src/nameres/collector.rs | 2 | ||||
| -rw-r--r-- | crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html | 1 | ||||
| -rw-r--r-- | crates/ide/src/syntax_highlighting/tests.rs | 1 | ||||
| -rw-r--r-- | crates/ide_assists/src/handlers/auto_import.rs | 52 | ||||
| -rw-r--r-- | crates/ide_assists/src/handlers/qualify_path.rs | 83 |
8 files changed, 123 insertions, 37 deletions
diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs index 20e2481af6c..877d385fbd1 100644 --- a/crates/hir/src/semantics/source_to_def.rs +++ b/crates/hir/src/semantics/source_to_def.rs @@ -299,8 +299,14 @@ impl SourceToDefCtx<'_, '_> { dyn_map[keys::CONST_PARAM].get(&src).copied() } - // FIXME: use DynMap as well? pub(super) fn macro_to_def(&mut self, src: InFile<ast::Macro>) -> Option<MacroDefId> { + let makro = self.dyn_map(src.as_ref()).and_then(|it| it[keys::MACRO].get(&src).copied()); + if let res @ Some(_) = makro { + return res; + } + + // Not all macros are recorded in the dyn map, only the ones behaving like items, so fall back + // for the non-item like definitions. let file_ast_id = self.db.ast_id_map(src.file_id).ast_id(&src.value); let ast_id = AstId::new(src.file_id, file_ast_id.upcast()); let kind = MacroDefKind::Declarative(ast_id); diff --git a/crates/hir_def/src/child_by_source.rs b/crates/hir_def/src/child_by_source.rs index 6d63570428b..1baf74c512b 100644 --- a/crates/hir_def/src/child_by_source.rs +++ b/crates/hir_def/src/child_by_source.rs @@ -101,6 +101,17 @@ impl ChildBySource for ModuleId { impl ChildBySource for ItemScope { fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) { self.declarations().for_each(|item| add_module_def(db, file_id, res, item)); + self.macros().for_each(|(_, makro)| { + let ast_id = makro.ast_id(); + if ast_id.either(|it| it.file_id, |it| it.file_id) == file_id { + let src = match ast_id { + Either::Left(ast_id) => ast_id.with_value(ast_id.to_node(db.upcast())), + // FIXME: Do we need to add proc-macros into a PROCMACRO dynmap here? + Either::Right(_fn) => return, + }; + res[keys::MACRO].insert(src, makro); + } + }); self.unnamed_consts().for_each(|konst| { let src = konst.lookup(db).source(db); res[keys::CONST].insert(src, konst); diff --git a/crates/hir_def/src/keys.rs b/crates/hir_def/src/keys.rs index c554540391f..07c4d083d63 100644 --- a/crates/hir_def/src/keys.rs +++ b/crates/hir_def/src/keys.rs @@ -31,7 +31,7 @@ pub const TYPE_PARAM: Key<ast::TypeParam, TypeParamId> = Key::new(); pub const LIFETIME_PARAM: Key<ast::LifetimeParam, LifetimeParamId> = Key::new(); pub const CONST_PARAM: Key<ast::ConstParam, ConstParamId> = Key::new(); -pub const MACRO: Key<ast::MacroCall, MacroDefId> = Key::new(); +pub const MACRO: Key<ast::Macro, MacroDefId> = Key::new(); pub const ATTR_MACRO: Key<ast::Item, MacroCallId> = Key::new(); pub const DERIVE_MACRO: Key<ast::Attr, Box<[MacroCallId]>> = Key::new(); diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index b048f46f9cb..0349754fbad 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs @@ -1907,7 +1907,7 @@ impl ModCollector<'_, '_> { let mac = &self.item_tree[id]; let ast_id = InFile::new(self.file_id(), mac.ast_id.upcast()); - // Case 1: bulitin macros + // Case 1: builtin macros let attrs = self.item_tree.attrs(self.def_collector.db, krate, ModItem::from(id).into()); if attrs.by_key("rustc_builtin_macro").exists() { let macro_id = find_builtin_macro(&mac.name, krate, ast_id) diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html index d9e1a05a036..9c92bd3e742 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html @@ -128,6 +128,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd <span class="brace">}</span> <span class="comment documentation">/// ```</span> +<span class="comment documentation">/// </span><span class="keyword injected">macro_rules</span><span class="punctuation injected">!</span><span class="none injected"> </span><span class="macro declaration injected">noop</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected"> </span><span class="parenthesis injected">(</span><span class="punctuation injected">$</span><span class="none injected">expr</span><span class="colon injected">:</span><span class="none injected">expr</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="operator injected">=</span><span class="angle injected">></span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected"> </span><span class="punctuation injected">$</span><span class="none injected">expr </span><span class="brace injected">}</span><span class="brace injected">}</span> <span class="comment documentation">/// </span><span class="macro injected">noop!</span><span class="parenthesis injected">(</span><span class="numeric_literal injected">1</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span> <span class="comment documentation">/// ```</span> <span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">noop</span> <span class="brace">{</span> diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs index 42d34040faf..05158c169e0 100644 --- a/crates/ide/src/syntax_highlighting/tests.rs +++ b/crates/ide/src/syntax_highlighting/tests.rs @@ -707,6 +707,7 @@ pub mod module { } /// ``` +/// macro_rules! noop { ($expr:expr) => { $expr }} /// noop!(1); /// ``` macro_rules! noop { diff --git a/crates/ide_assists/src/handlers/auto_import.rs b/crates/ide_assists/src/handlers/auto_import.rs index c877748246e..a5858869c50 100644 --- a/crates/ide_assists/src/handlers/auto_import.rs +++ b/crates/ide_assists/src/handlers/auto_import.rs @@ -3,7 +3,7 @@ use ide_db::helpers::{ insert_use::{insert_use, ImportScope}, mod_path_to_ast, }; -use syntax::{ast, AstNode, AstToken, SyntaxNode}; +use syntax::{ast, AstNode, AstToken, NodeOrToken, SyntaxElement}; use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel}; @@ -90,9 +90,18 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> return None; } - let range = ctx.sema.original_range(&syntax_under_caret).range; + let range = match &syntax_under_caret { + NodeOrToken::Node(node) => ctx.sema.original_range(node).range, + NodeOrToken::Token(token) => token.text_range(), + }; let group_label = group_label(import_assets.import_candidate()); - let scope = ImportScope::find_insert_use_container_with_macros(&syntax_under_caret, &ctx.sema)?; + let scope = ImportScope::find_insert_use_container_with_macros( + &match syntax_under_caret { + NodeOrToken::Node(it) => it, + NodeOrToken::Token(it) => it.parent()?, + }, + &ctx.sema, + )?; // we aren't interested in different namespaces proposed_imports.dedup_by(|a, b| a.import_path == b.import_path); @@ -115,23 +124,24 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> Some(()) } -pub(super) fn find_importable_node(ctx: &AssistContext) -> Option<(ImportAssets, SyntaxNode)> { +pub(super) fn find_importable_node(ctx: &AssistContext) -> Option<(ImportAssets, SyntaxElement)> { if let Some(path_under_caret) = ctx.find_node_at_offset_with_descend::<ast::Path>() { ImportAssets::for_exact_path(&path_under_caret, &ctx.sema) - .zip(Some(path_under_caret.syntax().clone())) + .zip(Some(path_under_caret.syntax().clone().into())) } else if let Some(method_under_caret) = ctx.find_node_at_offset_with_descend::<ast::MethodCallExpr>() { ImportAssets::for_method_call(&method_under_caret, &ctx.sema) - .zip(Some(method_under_caret.syntax().clone())) + .zip(Some(method_under_caret.syntax().clone().into())) } else if let Some(pat) = ctx .find_node_at_offset_with_descend::<ast::IdentPat>() .filter(ast::IdentPat::is_simple_ident) { - ImportAssets::for_ident_pat(&ctx.sema, &pat).zip(Some(pat.syntax().clone())) + ImportAssets::for_ident_pat(&ctx.sema, &pat).zip(Some(pat.syntax().clone().into())) } else { + // FIXME: Descend? let ident = ctx.find_token_at_offset()?; - ImportAssets::for_derive_ident(&ctx.sema, &ident).zip(ident.syntax().parent()) + ImportAssets::for_derive_ident(&ctx.sema, &ident).zip(Some(ident.syntax().clone().into())) } } @@ -1031,4 +1041,30 @@ fn foo() { "#, ); } + + #[test] + fn works_in_derives() { + check_assist( + auto_import, + r#" +//- minicore:derive +mod foo { + #[rustc_builtin_macro] + pub macro Copy {} +} +#[derive(Copy$0)] +struct Foo; +"#, + r#" +use foo::Copy; + +mod foo { + #[rustc_builtin_macro] + pub macro Copy {} +} +#[derive(Copy)] +struct Foo; +"#, + ); + } } diff --git a/crates/ide_assists/src/handlers/qualify_path.rs b/crates/ide_assists/src/handlers/qualify_path.rs index 29f2c785bc2..23b642fcb1b 100644 --- a/crates/ide_assists/src/handlers/qualify_path.rs +++ b/crates/ide_assists/src/handlers/qualify_path.rs @@ -9,7 +9,7 @@ use ide_db::RootDatabase; use syntax::{ ast, ast::{make, HasArgList}, - AstNode, + AstNode, NodeOrToken, }; use crate::{ @@ -42,32 +42,39 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext) -> Option<()> return None; } - let range = ctx.sema.original_range(&syntax_under_caret).range; + let range = match &syntax_under_caret { + NodeOrToken::Node(node) => ctx.sema.original_range(node).range, + NodeOrToken::Token(token) => token.text_range(), + }; let candidate = import_assets.import_candidate(); - let qualify_candidate = match candidate { - ImportCandidate::Path(candidate) if candidate.qualifier.is_some() => { - cov_mark::hit!(qualify_path_qualifier_start); - let path = ast::Path::cast(syntax_under_caret)?; - let (prev_segment, segment) = (path.qualifier()?.segment()?, path.segment()?); - QualifyCandidate::QualifierStart(segment, prev_segment.generic_arg_list()) - } - ImportCandidate::Path(_) => { - cov_mark::hit!(qualify_path_unqualified_name); - let path = ast::Path::cast(syntax_under_caret)?; - let generics = path.segment()?.generic_arg_list(); - QualifyCandidate::UnqualifiedName(generics) - } - ImportCandidate::TraitAssocItem(_) => { - cov_mark::hit!(qualify_path_trait_assoc_item); - let path = ast::Path::cast(syntax_under_caret)?; - let (qualifier, segment) = (path.qualifier()?, path.segment()?); - QualifyCandidate::TraitAssocItem(qualifier, segment) - } - ImportCandidate::TraitMethod(_) => { - cov_mark::hit!(qualify_path_trait_method); - let mcall_expr = ast::MethodCallExpr::cast(syntax_under_caret)?; - QualifyCandidate::TraitMethod(ctx.sema.db, mcall_expr) - } + let qualify_candidate = match syntax_under_caret { + NodeOrToken::Node(syntax_under_caret) => match candidate { + ImportCandidate::Path(candidate) if candidate.qualifier.is_some() => { + cov_mark::hit!(qualify_path_qualifier_start); + let path = ast::Path::cast(syntax_under_caret)?; + let (prev_segment, segment) = (path.qualifier()?.segment()?, path.segment()?); + QualifyCandidate::QualifierStart(segment, prev_segment.generic_arg_list()) + } + ImportCandidate::Path(_) => { + cov_mark::hit!(qualify_path_unqualified_name); + let path = ast::Path::cast(syntax_under_caret)?; + let generics = path.segment()?.generic_arg_list(); + QualifyCandidate::UnqualifiedName(generics) + } + ImportCandidate::TraitAssocItem(_) => { + cov_mark::hit!(qualify_path_trait_assoc_item); + let path = ast::Path::cast(syntax_under_caret)?; + let (qualifier, segment) = (path.qualifier()?, path.segment()?); + QualifyCandidate::TraitAssocItem(qualifier, segment) + } + ImportCandidate::TraitMethod(_) => { + cov_mark::hit!(qualify_path_trait_method); + let mcall_expr = ast::MethodCallExpr::cast(syntax_under_caret)?; + QualifyCandidate::TraitMethod(ctx.sema.db, mcall_expr) + } + }, + // derive attribute path + NodeOrToken::Token(_) => QualifyCandidate::UnqualifiedName(None), }; // we aren't interested in different namespaces @@ -1239,4 +1246,28 @@ fn main() { "#, ); } + + #[test] + fn works_in_derives() { + check_assist( + qualify_path, + r#" +//- minicore:derive +mod foo { + #[rustc_builtin_macro] + pub macro Copy {} +} +#[derive(Copy$0)] +struct Foo; +"#, + r#" +mod foo { + #[rustc_builtin_macro] + pub macro Copy {} +} +#[derive(foo::Copy)] +struct Foo; +"#, + ); + } } |
