Unnamed repository; edit this file 'description' to name the repository.
Merge #11676
11676: internal: Expand into pseudo-derive attribute expansions in completions r=Veykril a=Veykril With this we now properly handle qualified path completions in derives bors r+ Co-authored-by: Lukas Wirth <[email protected]>
bors[bot] 2022-03-11
parent e963443 · parent 6c8c02f · commit 69e5bd5
-rw-r--r--crates/hir/src/display.rs15
-rw-r--r--crates/hir/src/lib.rs4
-rw-r--r--crates/hir/src/semantics.rs49
-rw-r--r--crates/hir_expand/src/builtin_attr_macro.rs27
-rw-r--r--crates/hir_expand/src/db.rs40
-rw-r--r--crates/ide/src/hover/render.rs16
-rw-r--r--crates/ide/src/hover/tests.rs48
-rw-r--r--crates/ide_assists/src/handlers/remove_dbg.rs2
-rw-r--r--crates/ide_completion/src/completions/attribute.rs9
-rw-r--r--crates/ide_completion/src/completions/attribute/derive.rs196
-rw-r--r--crates/ide_completion/src/completions/flyimport.rs9
-rw-r--r--crates/ide_completion/src/completions/qualified_path.rs14
-rw-r--r--crates/ide_completion/src/completions/unqualified_path.rs13
-rw-r--r--crates/ide_completion/src/context.rs85
-rw-r--r--crates/ide_completion/src/lib.rs1
-rw-r--r--crates/ide_completion/src/render/macro_.rs23
-rw-r--r--crates/ide_completion/src/tests/attribute.rs91
-rw-r--r--crates/ide_completion/src/tests/expression.rs18
-rw-r--r--crates/ide_completion/src/tests/flyimport.rs2
-rw-r--r--crates/ide_completion/src/tests/item.rs24
-rw-r--r--crates/ide_completion/src/tests/item_list.rs36
-rw-r--r--crates/ide_completion/src/tests/pattern.rs24
-rw-r--r--crates/ide_completion/src/tests/predicate.rs36
-rw-r--r--crates/ide_completion/src/tests/type_pos.rs42
-rw-r--r--crates/ide_db/src/syntax_helpers/node_ext.rs2
-rw-r--r--crates/syntax/src/display.rs36
26 files changed, 478 insertions, 384 deletions
diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs
index 8f80f3a5db..6e3285fd4f 100644
--- a/crates/hir/src/display.rs
+++ b/crates/hir/src/display.rs
@@ -18,8 +18,8 @@ use syntax::SmolStr;
use crate::{
Adt, Const, ConstParam, Enum, Field, Function, GenericParam, HasCrate, HasVisibility,
- LifetimeParam, Module, Static, Struct, Trait, TyBuilder, Type, TypeAlias, TypeOrConstParam,
- TypeParam, Union, Variant,
+ LifetimeParam, Macro, Module, Static, Struct, Trait, TyBuilder, Type, TypeAlias,
+ TypeOrConstParam, TypeParam, Union, Variant,
};
impl HirDisplay for Function {
@@ -509,3 +509,14 @@ impl HirDisplay for Module {
}
}
}
+
+impl HirDisplay for Macro {
+ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
+ match self.id {
+ hir_def::MacroId::Macro2Id(_) => write!(f, "macro"),
+ hir_def::MacroId::MacroRulesId(_) => write!(f, "macro_rules!"),
+ hir_def::MacroId::ProcMacroId(_) => write!(f, "proc_macro"),
+ }?;
+ write!(f, " {}", self.name(f.db))
+ }
+}
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 0aabb415d4..a90120a467 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -1811,6 +1811,10 @@ impl Macro {
pub fn is_attr(&self, db: &dyn HirDatabase) -> bool {
matches!(self.kind(db), MacroKind::Attr)
}
+
+ pub fn is_derive(&self, db: &dyn HirDatabase) -> bool {
+ matches!(self.kind(db), MacroKind::Derive)
+ }
}
impl HasVisibility for Macro {
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 6d6a86fc8a..45544559ea 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -151,6 +151,10 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
self.imp.expand_attr_macro(item)
}
+ pub fn expand_derive_as_pseudo_attr_macro(&self, attr: &ast::Attr) -> Option<SyntaxNode> {
+ self.imp.expand_derive_as_pseudo_attr_macro(attr)
+ }
+
pub fn resolve_derive_macro(&self, derive: &ast::Attr) -> Option<Vec<Option<Macro>>> {
self.imp.resolve_derive_macro(derive)
}
@@ -185,6 +189,19 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
self.imp.speculative_expand_attr(actual_macro_call, speculative_args, token_to_map)
}
+ pub fn speculative_expand_derive_as_pseudo_attr_macro(
+ &self,
+ actual_macro_call: &ast::Attr,
+ speculative_args: &ast::Attr,
+ token_to_map: SyntaxToken,
+ ) -> Option<(SyntaxNode, SyntaxToken)> {
+ self.imp.speculative_expand_derive_as_pseudo_attr_macro(
+ actual_macro_call,
+ speculative_args,
+ token_to_map,
+ )
+ }
+
/// Descend the token into macrocalls to its first mapped counterpart.
pub fn descend_into_macros_single(&self, token: SyntaxToken) -> SyntaxToken {
self.imp.descend_into_macros_single(token)
@@ -438,9 +455,16 @@ impl<'db> SemanticsImpl<'db> {
fn expand_attr_macro(&self, item: &ast::Item) -> Option<SyntaxNode> {
let src = self.wrap_node_infile(item.clone());
let macro_call_id = self.with_ctx(|ctx| ctx.item_to_macro_call(src))?;
- let file_id = macro_call_id.as_file();
- let node = self.parse_or_expand(file_id)?;
- Some(node)
+ self.parse_or_expand(macro_call_id.as_file())
+ }
+
+ fn expand_derive_as_pseudo_attr_macro(&self, attr: &ast::Attr) -> Option<SyntaxNode> {
+ let src = self.wrap_node_infile(attr.clone());
+ let adt = attr.syntax().parent().and_then(ast::Adt::cast)?;
+ let call_id = self.with_ctx(|ctx| {
+ ctx.attr_to_derive_macro_call(src.with_value(&adt), src).map(|(_, it, _)| it)
+ })?;
+ self.parse_or_expand(call_id.as_file())
}
fn resolve_derive_macro(&self, attr: &ast::Attr) -> Option<Vec<Option<Macro>>> {
@@ -533,6 +557,25 @@ impl<'db> SemanticsImpl<'db> {
)
}
+ fn speculative_expand_derive_as_pseudo_attr_macro(
+ &self,
+ actual_macro_call: &ast::Attr,
+ speculative_args: &ast::Attr,
+ token_to_map: SyntaxToken,
+ ) -> Option<(SyntaxNode, SyntaxToken)> {
+ let attr = self.wrap_node_infile(actual_macro_call.clone());
+ let adt = actual_macro_call.syntax().parent().and_then(ast::Adt::cast)?;
+ let macro_call_id = self.with_ctx(|ctx| {
+ ctx.attr_to_derive_macro_call(attr.with_value(&adt), attr).map(|(_, it, _)| it)
+ })?;
+ hir_expand::db::expand_speculative(
+ self.db.upcast(),
+ macro_call_id,
+ speculative_args.syntax(),
+ token_to_map,
+ )
+ }
+
// This might not be the correct way to do this, but it works for now
fn descend_node_into_attributes<N: AstNode>(&self, node: N) -> SmallVec<[N; 1]> {
let mut res = smallvec![];
diff --git a/crates/hir_expand/src/builtin_attr_macro.rs b/crates/hir_expand/src/builtin_attr_macro.rs
index 6535f27a63..0c886ac4da 100644
--- a/crates/hir_expand/src/builtin_attr_macro.rs
+++ b/crates/hir_expand/src/builtin_attr_macro.rs
@@ -1,7 +1,5 @@
//! Builtin attributes.
-use itertools::Itertools;
-
use crate::{db::AstDatabase, name, ExpandResult, MacroCallId, MacroCallKind};
macro_rules! register_builtin {
@@ -98,10 +96,16 @@ fn derive_attr_expand(
) -> ExpandResult<tt::Subtree> {
let loc = db.lookup_intern_macro_call(id);
let derives = match &loc.kind {
- MacroCallKind::Attr { attr_args, .. } => &attr_args.0,
- _ => return ExpandResult::ok(tt.clone()),
+ MacroCallKind::Attr { attr_args, is_derive: true, .. } => &attr_args.0,
+ _ => return ExpandResult::ok(Default::default()),
};
+ pseudo_derive_attr_expansion(tt, derives)
+}
+pub fn pseudo_derive_attr_expansion(
+ tt: &tt::Subtree,
+ args: &tt::Subtree,
+) -> ExpandResult<tt::Subtree> {
let mk_leaf = |char| {
tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct {
char,
@@ -111,21 +115,12 @@ fn derive_attr_expand(
};
let mut token_trees = Vec::new();
- for (comma, group) in &derives
- .token_trees
- .iter()
- .filter_map(|tt| match tt {
- tt::TokenTree::Leaf(l) => Some(l),
- tt::TokenTree::Subtree(_) => None,
- })
- .group_by(|l| matches!(l, tt::Leaf::Punct(tt::Punct { char: ',', .. })))
+ for tt in (&args.token_trees)
+ .split(|tt| matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: ',', .. }))))
{
- if comma {
- continue;
- }
token_trees.push(mk_leaf('#'));
token_trees.push(mk_leaf('['));
- token_trees.extend(group.cloned().map(tt::TokenTree::Leaf));
+ token_trees.extend(tt.iter().cloned());
token_trees.push(mk_leaf(']'));
}
token_trees.push(mk_leaf('('));
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs
index d6d33b4cd7..9fe414de26 100644
--- a/crates/hir_expand/src/db.rs
+++ b/crates/hir_expand/src/db.rs
@@ -14,10 +14,10 @@ use syntax::{
};
use crate::{
- ast_id_map::AstIdMap, fixup, hygiene::HygieneFrame, BuiltinAttrExpander, BuiltinDeriveExpander,
- BuiltinFnLikeExpander, ExpandError, ExpandResult, ExpandTo, HirFileId, HirFileIdRepr,
- MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind, MacroFile,
- ProcMacroExpander,
+ ast_id_map::AstIdMap, builtin_attr_macro::pseudo_derive_attr_expansion, fixup,
+ hygiene::HygieneFrame, BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander,
+ ExpandError, ExpandResult, ExpandTo, HirFileId, HirFileIdRepr, MacroCallId, MacroCallKind,
+ MacroCallLoc, MacroDefId, MacroDefKind, MacroFile, ProcMacroExpander,
};
/// Total limit on the number of tokens produced by any macro invocation.
@@ -161,14 +161,16 @@ pub fn expand_speculative(
);
let (attr_arg, token_id) = match loc.kind {
- MacroCallKind::Attr { invoc_attr_index, .. } => {
- // Attributes may have an input token tree, build the subtree and map for this as well
- // then try finding a token id for our token if it is inside this input subtree.
- let item = ast::Item::cast(speculative_args.clone())?;
- let attr = item
- .doc_comments_and_attrs()
- .nth(invoc_attr_index as usize)
- .and_then(Either::left)?;
+ MacroCallKind::Attr { invoc_attr_index, is_derive, .. } => {
+ let attr = if is_derive {
+ // for pseudo-derive expansion we actually pass the attribute itself only
+ ast::Attr::cast(speculative_args.clone())
+ } else {
+ // Attributes may have an input token tree, build the subtree and map for this as well
+ // then try finding a token id for our token if it is inside this input subtree.
+ let item = ast::Item::cast(speculative_args.clone())?;
+ item.doc_comments_and_attrs().nth(invoc_attr_index as usize).and_then(Either::left)
+ }?;
match attr.token_tree() {
Some(token_tree) => {
let (mut tree, map) = syntax_node_to_token_tree(attr.token_tree()?.syntax());
@@ -205,11 +207,15 @@ pub fn expand_speculative(
// Do the actual expansion, we need to directly expand the proc macro due to the attribute args
// Otherwise the expand query will fetch the non speculative attribute args and pass those instead.
- let mut speculative_expansion = if let MacroDefKind::ProcMacro(expander, ..) = loc.def.kind {
- tt.delimiter = None;
- expander.expand(db, loc.krate, &tt, attr_arg.as_ref())
- } else {
- macro_def.expand(db, actual_macro_call, &tt)
+ let mut speculative_expansion = match loc.def.kind {
+ MacroDefKind::ProcMacro(expander, ..) => {
+ tt.delimiter = None;
+ expander.expand(db, loc.krate, &tt, attr_arg.as_ref())
+ }
+ MacroDefKind::BuiltInAttr(BuiltinAttrExpander::Derive, _) => {
+ pseudo_derive_attr_expansion(&tt, attr_arg.as_ref()?)
+ }
+ _ => macro_def.expand(db, actual_macro_call, &tt),
};
let expand_to = macro_expand_to(db, actual_macro_call);
diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs
index c298065f4e..2e141600e8 100644
--- a/crates/ide/src/hover/render.rs
+++ b/crates/ide/src/hover/render.rs
@@ -2,7 +2,7 @@
use std::fmt::Display;
use either::Either;
-use hir::{AsAssocItem, AttributeTemplate, HasAttrs, HasSource, HirDisplay, Semantics, TypeInfo};
+use hir::{AsAssocItem, AttributeTemplate, HasAttrs, HirDisplay, Semantics, TypeInfo};
use ide_db::{
base_db::SourceDatabase,
defs::Definition,
@@ -13,9 +13,7 @@ use ide_db::{
use itertools::Itertools;
use stdx::format_to;
use syntax::{
- algo, ast,
- display::{fn_as_proc_macro_label, macro_label},
- match_ast, AstNode, Direction,
+ algo, ast, match_ast, AstNode, Direction,
SyntaxKind::{LET_EXPR, LET_STMT},
SyntaxToken, T,
};
@@ -342,14 +340,8 @@ pub(super) fn definition(
) -> Option<Markup> {
let mod_path = definition_mod_path(db, &def);
let (label, docs) = match def {
- Definition::Macro(it) => (
- match &it.source(db)?.value {
- Either::Left(mac) => macro_label(mac),
- Either::Right(mac_fn) => fn_as_proc_macro_label(mac_fn),
- },
- it.attrs(db).docs(),
- ),
- Definition::Field(def) => label_and_docs(db, def),
+ Definition::Macro(it) => label_and_docs(db, it),
+ Definition::Field(it) => label_and_docs(db, it),
Definition::Module(it) => label_and_docs(db, it),
Definition::Function(it) => label_and_docs(db, it),
Definition::Adt(it) => label_and_docs(db, it),
diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index 2ec7802394..df27f935c8 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -4102,16 +4102,16 @@ identity!{
}
"#,
expect![[r#"
- *Copy*
+ *Copy*
- ```rust
- test
- ```
+ ```rust
+ test
+ ```
- ```rust
- pub macro Copy
- ```
- "#]],
+ ```rust
+ macro Copy
+ ```
+ "#]],
);
}
@@ -4126,16 +4126,16 @@ pub macro Copy {}
struct Foo;
"#,
expect![[r#"
- *Copy*
+ *Copy*
- ```rust
- test
- ```
+ ```rust
+ test
+ ```
- ```rust
- pub macro Copy
- ```
- "#]],
+ ```rust
+ macro Copy
+ ```
+ "#]],
);
check(
r#"
@@ -4148,16 +4148,16 @@ mod foo {
struct Foo;
"#,
expect![[r#"
- *Copy*
+ *Copy*
- ```rust
- test::foo
- ```
+ ```rust
+ test::foo
+ ```
- ```rust
- pub macro Copy
- ```
- "#]],
+ ```rust
+ macro Copy
+ ```
+ "#]],
);
}
diff --git a/crates/ide_assists/src/handlers/remove_dbg.rs b/crates/ide_assists/src/handlers/remove_dbg.rs
index 07dcfd9671..ebea2d5dea 100644
--- a/crates/ide_assists/src/handlers/remove_dbg.rs
+++ b/crates/ide_assists/src/handlers/remove_dbg.rs
@@ -32,7 +32,7 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
}
let mac_input = tt.syntax().children_with_tokens().skip(1).take_while(|it| *it != r_delim);
- let input_expressions = mac_input.into_iter().group_by(|tok| tok.kind() == T![,]);
+ let input_expressions = mac_input.group_by(|tok| tok.kind() == T![,]);
let input_expressions = input_expressions
.into_iter()
.filter_map(|(is_sep, group)| (!is_sep).then(|| group))
diff --git a/crates/ide_completion/src/completions/attribute.rs b/crates/ide_completion/src/completions/attribute.rs
index 3c5dd8f3fd..6b51e19bbb 100644
--- a/crates/ide_completion/src/completions/attribute.rs
+++ b/crates/ide_completion/src/completions/attribute.rs
@@ -29,6 +29,8 @@ mod derive;
mod lint;
mod repr;
+pub(crate) use self::derive::complete_derive;
+
/// Complete inputs to known builtin attributes as well as derive attributes
pub(crate) fn complete_known_attribute_input(
acc: &mut Completions,
@@ -46,7 +48,6 @@ pub(crate) fn complete_known_attribute_input(
match path.text().as_str() {
"repr" => repr::complete_repr(acc, ctx, tt),
- "derive" => derive::complete_derive(acc, ctx, ctx.attr.as_ref()?),
"feature" => lint::complete_lint(acc, ctx, &parse_tt_as_comma_sep_paths(tt)?, FEATURES),
"allow" | "warn" | "deny" | "forbid" => {
let existing_lints = parse_tt_as_comma_sep_paths(tt)?;
@@ -62,9 +63,7 @@ pub(crate) fn complete_known_attribute_input(
lint::complete_lint(acc, ctx, &existing_lints, &lints);
}
- "cfg" => {
- cfg::complete_cfg(acc, ctx);
- }
+ "cfg" => cfg::complete_cfg(acc, ctx),
_ => (),
}
Some(())
@@ -347,7 +346,7 @@ fn parse_comma_sep_expr(input: ast::TokenTree) -> Option<Vec<ast::Expr>> {
.children_with_tokens()
.skip(1)
.take_while(|it| it.as_token() != Some(&r_paren));
- let input_expressions = tokens.into_iter().group_by(|tok| tok.kind() == T![,]);
+ let input_expressions = tokens.group_by(|tok| tok.kind() == T![,]);
Some(
input_expressions
.into_iter()
diff --git a/crates/ide_completion/src/completions/attribute/derive.rs b/crates/ide_completion/src/completions/attribute/derive.rs
index 64f6e3989d..1edc92d5d6 100644
--- a/crates/ide_completion/src/completions/attribute/derive.rs
+++ b/crates/ide_completion/src/completions/attribute/derive.rs
@@ -1,123 +1,111 @@
//! Completion for derives
-use hir::{HasAttrs, Macro, MacroKind};
-use ide_db::{
- imports::{import_assets::ImportAssets, insert_use::ImportScope},
- SymbolKind,
-};
+use hir::{HasAttrs, ScopeDef};
+use ide_db::SymbolKind;
use itertools::Itertools;
-use rustc_hash::FxHashSet;
-use syntax::{ast, SmolStr, SyntaxKind};
+use syntax::SmolStr;
use crate::{
- completions::flyimport::compute_fuzzy_completion_order_key, context::CompletionContext,
- item::CompletionItem, Completions, ImportEdit,
+ context::{CompletionContext, PathCompletionCtx, PathKind, PathQualifierCtx},
+ item::CompletionItem,
+ Completions,
};
-pub(super) fn complete_derive(acc: &mut Completions, ctx: &CompletionContext, attr: &ast::Attr) {
+pub(crate) fn complete_derive(acc: &mut Completions, ctx: &CompletionContext) {
+ let (qualifier, is_absolute_path) = match ctx.path_context {
+ Some(PathCompletionCtx {
+ kind: Some(PathKind::Derive),
+ ref qualifier,
+ is_absolute_path,
+ ..
+ }) => (qualifier, is_absolute_path),
+ _ => return,
+ };
+
let core = ctx.famous_defs().core();
- let existing_derives: FxHashSet<_> =
- ctx.sema.resolve_derive_macro(attr).into_iter().flatten().flatten().collect();
- for (name, mac) in get_derives_in_scope(ctx) {
- if existing_derives.contains(&mac) {
- continue;
- }
+ match qualifier {
+ Some(PathQualifierCtx { resolution, is_super_chain, .. }) => {
+ if *is_super_chain {
+ acc.add_keyword(ctx, "super::");
+ }
- let name = name.to_smol_str();
- let (label, lookup) = match (core, mac.module(ctx.db).krate()) {
- // show derive dependencies for `core`/`std` derives
- (Some(core), mac_krate) if core == mac_krate => {
- if let Some(derive_completion) = DEFAULT_DERIVE_DEPENDENCIES
- .iter()
- .find(|derive_completion| derive_completion.label == name)
- {
- let mut components = vec![derive_completion.label];
- components.extend(derive_completion.dependencies.iter().filter(
- |&&dependency| {
- !existing_derives
- .iter()
- .map(|it| it.name(ctx.db))
- .any(|it| it.to_smol_str() == dependency)
- },
- ));
- let lookup = components.join(", ");
- let label = Itertools::intersperse(components.into_iter().rev(), ", ");
- (SmolStr::from_iter(label), Some(lookup))
- } else {
- (name, None)
+ let module = match resolution {
+ Some(hir::PathResolution::Def(hir::ModuleDef::Module(it))) => it,
+ _ => return,
+ };
+
+ for (name, def) in module.scope(ctx.db, ctx.module) {
+ let add_def = match def {
+ ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => {
+ !ctx.existing_derives.contains(&mac) && mac.is_derive(ctx.db)
+ }
+ ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) => true,
+ _ => false,
+ };
+ if add_def {
+ acc.add_resolution(ctx, name, def);
}
}
- _ => (name, None),
- };
-
- let mut item = CompletionItem::new(SymbolKind::Derive, ctx.source_range(), label);
- if let Some(docs) = mac.docs(ctx.db) {
- item.documentation(docs);
+ return;
}
- if let Some(lookup) = lookup {
- item.lookup_by(lookup);
- }
- item.add_to(acc);
- }
+ None if is_absolute_path => acc.add_crate_roots(ctx),
+ // only show modules in a fresh UseTree
+ None => {
+ ctx.process_all_names(&mut |name, def| {
+ let mac = match def {
+ ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac))
+ if !ctx.existing_derives.contains(&mac) && mac.is_derive(ctx.db) =>
+ {
+ mac
+ }
+ ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) => {
+ return acc.add_resolution(ctx, name, def);
+ }
+ _ => return,
+ };
- flyimport_derive(acc, ctx);
-}
+ match (core, mac.module(ctx.db).krate()) {
+ // show derive dependencies for `core`/`std` derives
+ (Some(core), mac_krate) if core == mac_krate && qualifier.is_none() => {}
+ _ => return acc.add_resolution(ctx, name, def),
+ };
-fn get_derives_in_scope(ctx: &CompletionContext) -> Vec<(hir::Name, Macro)> {
- let mut result = Vec::default();
- ctx.process_all_names(&mut |name, scope_def| {
- if let hir::ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) = scope_def {
- if mac.kind(ctx.db) == hir::MacroKind::Derive {
- result.push((name, mac));
- }
- }
- });
- result
-}
+ let name_ = name.to_smol_str();
+ let find = DEFAULT_DERIVE_DEPENDENCIES
+ .iter()
+ .find(|derive_completion| derive_completion.label == name_);
-fn flyimport_derive(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
- if ctx.token.kind() != SyntaxKind::IDENT {
- return None;
- };
- let potential_import_name = ctx.token.to_string();
- let module = ctx.module?;
- let parent = ctx.token.parent()?;
- let user_input_lowercased = potential_import_name.to_lowercase();
- let import_assets = ImportAssets::for_fuzzy_path(
- module,
- None,
- potential_import_name,
- &ctx.sema,
- parent.clone(),
- )?;
- let import_scope = ImportScope::find_insert_use_container(&parent, &ctx.sema)?;
- acc.add_all(
- import_assets
- .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind)
- .into_iter()
- .filter_map(|import| match import.original_item {
- hir::ItemInNs::Macros(mac) => Some((import, mac)),
- _ => None,
- })
- .filter(|&(_, mac)| mac.kind(ctx.db) == MacroKind::Derive)
- .filter(|&(_, mac)| !ctx.is_item_hidden(&hir::ItemInNs::Macros(mac)))
- .sorted_by_key(|(import, _)| {
- compute_fuzzy_completion_order_key(&import.import_path, &user_input_lowercased)
- })
- .filter_map(|(import, mac)| {
- let mut item = CompletionItem::new(
- SymbolKind::Derive,
- ctx.source_range(),
- mac.name(ctx.db).to_smol_str(),
- );
- item.add_import(ImportEdit { import, scope: import_scope.clone() });
- if let Some(docs) = mac.docs(ctx.db) {
- item.documentation(docs);
+ match find {
+ Some(derive_completion) => {
+ let mut components = vec![derive_completion.label];
+ components.extend(derive_completion.dependencies.iter().filter(
+ |&&dependency| {
+ !ctx.existing_derives
+ .iter()
+ .map(|it| it.name(ctx.db))
+ .any(|it| it.to_smol_str() == dependency)
+ },
+ ));
+ let lookup = components.join(", ");
+ let label = Itertools::intersperse(components.into_iter().rev(), ", ");
+
+ let mut item = CompletionItem::new(
+ SymbolKind::Derive,
+ ctx.source_range(),
+ SmolStr::from_iter(label),
+ );
+ if let Some(docs) = mac.docs(ctx.db) {
+ item.documentation(docs);
+ }
+ item.lookup_by(lookup);
+ item.add_to(acc);
+ }
+ None => acc.add_resolution(ctx, name, def),
}
- Some(item.build())
- }),
- );
- Some(())
+ });
+ acc.add_nameref_keywords(ctx);
+ }
+ }
}
struct DeriveDependencies {
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs
index b4cfc3273b..aee2bbb53c 100644
--- a/crates/ide_completion/src/completions/flyimport.rs
+++ b/crates/ide_completion/src/completions/flyimport.rs
@@ -142,7 +142,7 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
)?;
let ns_filter = |import: &LocatedImport| {
- let kind = match ctx.path_kind() {
+ let path_kind = match ctx.path_kind() {
Some(kind) => kind,
None => {
return match import.original_item {
@@ -151,7 +151,7 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
}
}
};
- match (kind, import.original_item) {
+ match (path_kind, import.original_item) {
// Aren't handled in flyimport
(PathKind::Vis { .. } | PathKind::Use, _) => false,
// modules are always fair game
@@ -173,6 +173,11 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
(PathKind::Attr { .. }, ItemInNs::Macros(mac)) => mac.is_attr(ctx.db),
(PathKind::Attr { .. }, _) => false,
+
+ (PathKind::Derive, ItemInNs::Macros(mac)) => {
+ mac.is_derive(ctx.db) && !ctx.existing_derives.contains(&mac)
+ }
+ (PathKind::Derive, _) => false,
}
};
diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs
index c4ba77b3f7..acd02616b1 100644
--- a/crates/ide_completion/src/completions/qualified_path.rs
+++ b/crates/ide_completion/src/completions/qualified_path.rs
@@ -63,7 +63,13 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
}
match kind {
- Some(PathKind::Pat | PathKind::Attr { .. } | PathKind::Vis { .. } | PathKind::Use) => {
+ Some(
+ PathKind::Pat
+ | PathKind::Attr { .. }
+ | PathKind::Vis { .. }
+ | PathKind::Use
+ | PathKind::Derive,
+ ) => {
return;
}
_ => {
@@ -415,10 +421,10 @@ macro_rules! foo { () => {} }
fn main() { let _ = crate::$0 }
"#,
- expect![[r##"
+ expect![[r#"
fn main() fn()
- ma foo!(…) #[macro_export] macro_rules! foo
- "##]],
+ ma foo!(…) macro_rules! foo
+ "#]],
);
}
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs
index ddd068488a..235d7870c7 100644
--- a/crates/ide_completion/src/completions/unqualified_path.rs
+++ b/crates/ide_completion/src/completions/unqualified_path.rs
@@ -19,10 +19,11 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
Some(PathCompletionCtx {
kind:
Some(
- PathKind::Vis { .. }
- | PathKind::Attr { .. }
+ PathKind::Attr { .. }
+ | PathKind::Derive
+ | PathKind::Pat
| PathKind::Use { .. }
- | PathKind::Pat,
+ | PathKind::Vis { .. },
),
..
}) => return,
@@ -207,12 +208,12 @@ mod macros {
macro_rules! concat { }
}
"#,
- expect![[r##"
+ expect![[r#"
fn f() fn()
- ma concat!(…) #[macro_export] macro_rules! concat
+ ma concat!(…) macro_rules! concat
md std
bt u32
- "##]],
+ "#]],
);
}
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs
index da80224dd8..51bbd66ff3 100644
--- a/crates/ide_completion/src/context.rs
+++ b/crates/ide_completion/src/context.rs
@@ -12,6 +12,7 @@ use ide_db::{
famous_defs::FamousDefs,
RootDatabase,
};
+use rustc_hash::FxHashSet;
use syntax::{
algo::{find_node_at_offset, non_trivia_sibling},
ast::{self, AttrKind, HasName, NameOrNameRef},
@@ -43,11 +44,12 @@ pub(crate) enum Visible {
No,
}
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub(super) enum PathKind {
Expr,
Type,
Attr { kind: AttrKind, annotated_item_kind: Option<SyntaxKind> },
+ Derive,
Mac,
Pat,
Vis { has_in_token: bool },
@@ -126,7 +128,6 @@ pub(crate) struct CompletionContext<'a> {
/// The parent function of the cursor position if it exists.
pub(super) function_def: Option<ast::Fn>,
- pub(super) attr: Option<ast::Attr>,
/// The parent impl of the cursor position if it exists.
pub(super) impl_def: Option<ast::Impl>,
/// The NameLike under the cursor in the original file if it exists.
@@ -142,6 +143,8 @@ pub(crate) struct CompletionContext<'a> {
pub(super) pattern_ctx: Option<PatternContext>,
pub(super) path_context: Option<PathCompletionCtx>,
+ pub(super) existing_derives: FxHashSet<hir::Macro>,
+
pub(super) locals: Vec<(Name, Local)>,
no_completion_required: bool,
@@ -439,7 +442,6 @@ impl<'a> CompletionContext<'a> {
expected_name: None,
expected_type: None,
function_def: None,
- attr: None,
impl_def: None,
name_syntax: None,
lifetime_ctx: None,
@@ -452,6 +454,7 @@ impl<'a> CompletionContext<'a> {
locals,
incomplete_let: false,
no_completion_required: false,
+ existing_derives: Default::default(),
};
ctx.expand_and_fill(
original_file.syntax().clone(),
@@ -472,6 +475,8 @@ impl<'a> CompletionContext<'a> {
mut fake_ident_token: SyntaxToken,
) {
let _p = profile::span("CompletionContext::expand_and_fill");
+ let mut derive_ctx = None;
+
'expansion: loop {
let parent_item =
|item: &ast::Item| item.syntax().ancestors().skip(1).find_map(ast::Item::cast);
@@ -509,11 +514,45 @@ impl<'a> CompletionContext<'a> {
_ => break 'expansion,
}
}
+ let orig_tt = match find_node_at_offset::<ast::TokenTree>(&original_file, offset) {
+ Some(it) => it,
+ None => break,
+ };
+ let spec_tt = match find_node_at_offset::<ast::TokenTree>(&speculative_file, offset) {
+ Some(it) => it,
+ None => break,
+ };
+
+ // Expand pseudo-derive expansion
+ if let (Some(orig_attr), Some(spec_attr)) = (
+ orig_tt.syntax().parent().and_then(ast::Meta::cast).and_then(|it| it.parent_attr()),
+ spec_tt.syntax().parent().and_then(ast::Meta::cast).and_then(|it| it.parent_attr()),
+ ) {
+ match (
+ self.sema.expand_derive_as_pseudo_attr_macro(&orig_attr),
+ self.sema.speculative_expand_derive_as_pseudo_attr_macro(
+ &orig_attr,
+ &spec_attr,
+ fake_ident_token.clone(),
+ ),
+ ) {
+ // Clearly not a derive macro
+ (None, None) => (),
+ // successful expansions
+ (Some(actual_expansion), Some((fake_expansion, fake_mapped_token))) => {
+ let new_offset = fake_mapped_token.text_range().start();
+ derive_ctx = Some((actual_expansion, fake_expansion, new_offset));
+ break 'expansion;
+ }
+ // exactly one expansion failed, inconsistent state so stop expanding completely
+ _ => break 'expansion,
+ }
+ }
// Expand fn-like macro calls
if let (Some(actual_macro_call), Some(macro_call_with_fake_ident)) = (
- find_node_at_offset::<ast::MacroCall>(&original_file, offset),
- find_node_at_offset::<ast::MacroCall>(&speculative_file, offset),
+ orig_tt.syntax().ancestors().find_map(ast::MacroCall::cast),
+ spec_tt.syntax().ancestors().find_map(ast::MacroCall::cast),
) {
let mac_call_path0 = actual_macro_call.path().as_ref().map(|s| s.syntax().text());
let mac_call_path1 =
@@ -553,7 +592,7 @@ impl<'a> CompletionContext<'a> {
break;
}
- self.fill(&original_file, speculative_file, offset);
+ self.fill(&original_file, speculative_file, offset, derive_ctx);
}
fn expected_type_and_name(&self) -> (Option<Type>, Option<NameOrNameRef>) {
@@ -697,6 +736,7 @@ impl<'a> CompletionContext<'a> {
original_file: &SyntaxNode,
file_with_fake_ident: SyntaxNode,
offset: TextSize,
+ derive_ctx: Option<(SyntaxNode, SyntaxNode, TextSize)>,
) {
let fake_ident_token = file_with_fake_ident.token_at_offset(offset).right_biased().unwrap();
let syntax_element = NodeOrToken::Token(fake_ident_token);
@@ -708,11 +748,6 @@ impl<'a> CompletionContext<'a> {
(fn_is_prev && !inside_impl_trait_block) || for_is_prev2
};
- self.attr = self
- .sema
- .token_ancestors_with_macros(self.token.clone())
- .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE)
- .find_map(ast::Attr::cast);
self.fake_attribute_under_caret = syntax_element.ancestors().find_map(ast::Attr::cast);
self.incomplete_let =
@@ -724,6 +759,33 @@ impl<'a> CompletionContext<'a> {
self.expected_type = expected_type;
self.expected_name = expected_name;
+ // Overwrite the path kind for derives
+ if let Some((original_file, file_with_fake_ident, offset)) = derive_ctx {
+ let attr = self
+ .sema
+ .token_ancestors_with_macros(self.token.clone())
+ .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE)
+ .find_map(ast::Attr::cast);
+ if let Some(attr) = &attr {
+ self.existing_derives =
+ self.sema.resolve_derive_macro(attr).into_iter().flatten().flatten().collect();
+ }
+
+ if let Some(ast::NameLike::NameRef(name_ref)) =
+ find_node_at_offset(&file_with_fake_ident, offset)
+ {
+ self.name_syntax =
+ find_node_at_offset(&original_file, name_ref.syntax().text_range().start());
+ if let Some((path_ctx, _)) =
+ Self::classify_name_ref(&self.sema, &original_file, name_ref)
+ {
+ self.path_context =
+ Some(PathCompletionCtx { kind: Some(PathKind::Derive), ..path_ctx });
+ }
+ }
+ return;
+ }
+
let name_like = match find_node_at_offset(&file_with_fake_ident, offset) {
Some(it) => it,
None => return,
@@ -743,6 +805,7 @@ impl<'a> CompletionContext<'a> {
.token_ancestors_with_macros(self.token.clone())
.take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE)
.find_map(ast::Fn::cast);
+
match name_like {
ast::NameLike::Lifetime(lifetime) => {
self.lifetime_ctx =
diff --git a/crates/ide_completion/src/lib.rs b/crates/ide_completion/src/lib.rs
index 3225a0bc9f..86a6947b1d 100644
--- a/crates/ide_completion/src/lib.rs
+++ b/crates/ide_completion/src/lib.rs
@@ -152,6 +152,7 @@ pub fn completions(
let mut acc = Completions::default();
completions::attribute::complete_attribute(&mut acc, &ctx);
+ completions::attribute::complete_derive(&mut acc, &ctx);
completions::attribute::complete_known_attribute_input(&mut acc, &ctx);
completions::dot::complete_dot(&mut acc, &ctx);
completions::extern_abi::complete_extern_abi(&mut acc, &ctx);
diff --git a/crates/ide_completion/src/render/macro_.rs b/crates/ide_completion/src/render/macro_.rs
index 6fdb622be7..d3b0de429c 100644
--- a/crates/ide_completion/src/render/macro_.rs
+++ b/crates/ide_completion/src/render/macro_.rs
@@ -1,12 +1,8 @@
//! Renderer for macro invocations.
-use either::Either;
-use hir::{Documentation, HasSource, InFile, Semantics};
-use ide_db::{RootDatabase, SymbolKind};
-use syntax::{
- display::{fn_as_proc_macro_label, macro_label},
- SmolStr,
-};
+use hir::{Documentation, HirDisplay};
+use ide_db::SymbolKind;
+use syntax::SmolStr;
use crate::{
context::PathKind,
@@ -52,7 +48,7 @@ fn render(
label(&ctx, needs_bang, bra, ket, &name),
);
item.set_deprecated(ctx.is_deprecated(macro_))
- .set_detail(detail(&completion.sema, macro_))
+ .detail(macro_.display(completion.db).to_string())
.set_documentation(docs)
.set_relevance(ctx.completion_relevance());
@@ -103,17 +99,6 @@ fn banged_name(name: &str) -> SmolStr {
SmolStr::from_iter([name, "!"])
}
-fn detail(sema: &Semantics<RootDatabase>, macro_: hir::Macro) -> Option<String> {
- // FIXME: This is parsing the file!
- let InFile { file_id, value } = macro_.source(sema.db)?;
- let _ = sema.parse_or_expand(file_id);
- let detail = match value {
- Either::Left(node) => macro_label(&node),
- Either::Right(node) => fn_as_proc_macro_label(&node),
- };
- Some(detail)
-}
-
fn guess_macro_braces(macro_name: &str, docs: &str) -> (&'static str, &'static str) {
let mut votes = [0, 0, 0];
for (idx, s) in docs.match_indices(&macro_name) {
diff --git a/crates/ide_completion/src/tests/attribute.rs b/crates/ide_completion/src/tests/attribute.rs
index ae7ba7e055..4ee95e8928 100644
--- a/crates/ide_completion/src/tests/attribute.rs
+++ b/crates/ide_completion/src/tests/attribute.rs
@@ -62,7 +62,7 @@ fn proc_macros_qualified() {
struct Foo;
"#,
expect![[r#"
- at identity pub macro identity
+ at identity proc_macro identity
"#]],
)
}
@@ -302,7 +302,7 @@ struct Foo;
"#,
expect![[r#"
md core
- at derive pub macro derive
+ at derive macro derive
kw self::
kw super::
kw crate::
@@ -688,13 +688,17 @@ mod derive {
#[derive($0)] struct Test;
"#,
expect![[r#"
- de Default
+ md core
+ de Default macro Default
de Clone, Copy
- de PartialEq
+ de PartialEq macro PartialEq
de PartialEq, Eq
de PartialEq, Eq, PartialOrd, Ord
- de Clone
+ de Clone macro Clone
de PartialEq, PartialOrd
+ kw self::
+ kw super::
+ kw crate::
"#]],
);
}
@@ -707,12 +711,16 @@ mod derive {
#[derive(serde::Serialize, PartialEq, $0)] struct Test;
"#,
expect![[r#"
- de Default
+ md core
+ de Default macro Default
de Clone, Copy
de Eq
de Eq, PartialOrd, Ord
- de Clone
+ de Clone macro Clone
de PartialOrd
+ kw self::
+ kw super::
+ kw crate::
"#]],
)
}
@@ -725,33 +733,17 @@ mod derive {
#[derive($0 serde::Serialize, PartialEq)] struct Test;
"#,
expect![[r#"
- de Default
+ md core
+ de Default macro Default
de Clone, Copy
de Eq
de Eq, PartialOrd, Ord
- de Clone
+ de Clone macro Clone
de PartialOrd
+ kw self::
+ kw super::
+ kw crate::
"#]],
- )
- }
-
- #[test]
- fn derive_no_attrs() {
- check_derive(
- r#"
-//- proc_macros: identity
-//- minicore: derive
-#[derive($0)] struct Test;
-"#,
- expect![[r#""#]],
- );
- check_derive(
- r#"
-//- proc_macros: identity
-//- minicore: derive
-#[derive(i$0)] struct Test;
-"#,
- expect![[r#""#]],
);
}
@@ -760,20 +752,32 @@ mod derive {
check_derive(
r#"
//- proc_macros: derive_identity
+//- minicore: derive
#[derive(der$0)] struct Test;
"#,
expect![[r#"
- de DeriveIdentity (use proc_macros::DeriveIdentity)
+ md proc_macros
+ md core
+ kw self::
+ kw super::
+ kw crate::
+ de DeriveIdentity (use proc_macros::DeriveIdentity) proc_macro DeriveIdentity
"#]],
);
check_derive(
r#"
//- proc_macros: derive_identity
+//- minicore: derive
use proc_macros::DeriveIdentity;
#[derive(der$0)] struct Test;
"#,
expect![[r#"
- de DeriveIdentity
+ de DeriveIdentity proc_macro DeriveIdentity
+ md proc_macros
+ md core
+ kw self::
+ kw super::
+ kw crate::
"#]],
);
}
@@ -784,6 +788,7 @@ use proc_macros::DeriveIdentity;
"DeriveIdentity",
r#"
//- proc_macros: derive_identity
+//- minicore: derive
#[derive(der$0)] struct Test;
"#,
r#"
@@ -793,6 +798,30 @@ use proc_macros::DeriveIdentity;
"#,
);
}
+
+ #[test]
+ fn qualified() {
+ check_derive(
+ r#"
+//- proc_macros: derive_identity
+//- minicore: derive, copy, clone
+#[derive(proc_macros::$0)] struct Test;
+"#,
+ expect![[r#"
+ de DeriveIdentity proc_macro DeriveIdentity
+ "#]],
+ );
+ check_derive(
+ r#"
+//- proc_macros: derive_identity
+//- minicore: derive, copy, clone
+#[derive(proc_macros::C$0)] struct Test;
+"#,
+ expect![[r#"
+ de DeriveIdentity proc_macro DeriveIdentity
+ "#]],
+ );
+ }
}
mod lint {
diff --git a/crates/ide_completion/src/tests/expression.rs b/crates/ide_completion/src/tests/expression.rs
index 5e1fae68fd..a841605e49 100644
--- a/crates/ide_completion/src/tests/expression.rs
+++ b/crates/ide_completion/src/tests/expression.rs
@@ -30,7 +30,7 @@ fn baz() {
}
"#,
// This should not contain `FooDesc {…}`.
- expect![[r##"
+ expect![[r#"
kw unsafe
kw match
kw while
@@ -57,13 +57,13 @@ fn baz() {
fn baz() fn()
st Unit
md _69latrick
- ma makro!(…) #[macro_export] macro_rules! makro
+ ma makro!(…) macro_rules! makro
fn function() fn()
sc STATIC
un Union
ev TupleV(…) (u32)
ct CONST
- "##]],
+ "#]],
)
}
@@ -125,7 +125,7 @@ impl Unit {
}
"#,
// `self` is in here twice, once as the module, once as the local
- expect![[r##"
+ expect![[r#"
me self.foo() fn(self)
kw unsafe
kw fn
@@ -166,14 +166,14 @@ impl Unit {
md module
st Unit
md qualified
- ma makro!(…) #[macro_export] macro_rules! makro
+ ma makro!(…) macro_rules! makro
?? Unresolved
fn function() fn()
sc STATIC
un Union
ev TupleV(…) (u32)
ct CONST
- "##]],
+ "#]],
);
check(
r#"
@@ -187,7 +187,7 @@ impl Unit {
}
}
"#,
- expect![[r##"
+ expect![[r#"
tt Trait
en Enum
st Record
@@ -195,14 +195,14 @@ impl Unit {
md module
st Unit
md qualified
- ma makro!(…) #[macro_export] macro_rules! makro
+ ma makro!(…) macro_rules! makro
?? Unresolved
fn function() fn()
sc STATIC
un Union
ev TupleV(…) (u32)
ct CONST
- "##]],
+ "#]],
);
}
diff --git a/crates/ide_completion/src/tests/flyimport.rs b/crates/ide_completion/src/tests/flyimport.rs
index fbef6d9937..c996a5f01f 100644
--- a/crates/ide_completion/src/tests/flyimport.rs
+++ b/crates/ide_completion/src/tests/flyimport.rs
@@ -1108,7 +1108,7 @@ fn flyimport_attribute() {
struct Foo;
"#,
expect![[r#"
- at identity (use proc_macros::identity) pub macro identity
+ at identity (use proc_macros::identity) proc_macro identity
"#]],
);
check_edit(
diff --git a/crates/ide_completion/src/tests/item.rs b/crates/ide_completion/src/tests/item.rs
index d94fab2f5f..1d5ddc092e 100644
--- a/crates/ide_completion/src/tests/item.rs
+++ b/crates/ide_completion/src/tests/item.rs
@@ -17,7 +17,7 @@ fn target_type_or_trait_in_impl_block() {
r#"
impl Tra$0
"#,
- expect![[r##"
+ expect![[r#"
kw self
kw super
kw crate
@@ -27,10 +27,10 @@ impl Tra$0
st Tuple
md module
st Unit
- ma makro!(…) #[macro_export] macro_rules! makro
+ ma makro!(…) macro_rules! makro
un Union
bt u32
- "##]],
+ "#]],
)
}
@@ -40,7 +40,7 @@ fn target_type_in_trait_impl_block() {
r#"
impl Trait for Str$0
"#,
- expect![[r##"
+ expect![[r#"
kw self
kw super
kw crate
@@ -50,10 +50,10 @@ impl Trait for Str$0
st Tuple
md module
st Unit
- ma makro!(…) #[macro_export] macro_rules! makro
+ ma makro!(…) macro_rules! makro
un Union
bt u32
- "##]],
+ "#]],
)
}
@@ -85,7 +85,7 @@ fn after_struct_name() {
// FIXME: This should emit `kw where` only
check(
r"struct Struct $0",
- expect![[r##"
+ expect![[r#"
kw pub(crate)
kw pub(super)
kw pub
@@ -109,8 +109,8 @@ fn after_struct_name() {
kw super
kw crate
md module
- ma makro!(…) #[macro_export] macro_rules! makro
- "##]],
+ ma makro!(…) macro_rules! makro
+ "#]],
);
}
@@ -119,7 +119,7 @@ fn after_fn_name() {
// FIXME: This should emit `kw where` only
check(
r"fn func() $0",
- expect![[r##"
+ expect![[r#"
kw pub(crate)
kw pub(super)
kw pub
@@ -143,8 +143,8 @@ fn after_fn_name() {
kw super
kw crate
md module
- ma makro!(…) #[macro_export] macro_rules! makro
- "##]],
+ ma makro!(…) macro_rules! makro
+ "#]],
);
}
diff --git a/crates/ide_completion/src/tests/item_list.rs b/crates/ide_completion/src/tests/item_list.rs
index 4c76963054..82824fd393 100644
--- a/crates/ide_completion/src/tests/item_list.rs
+++ b/crates/ide_completion/src/tests/item_list.rs
@@ -12,7 +12,7 @@ fn check(ra_fixture: &str, expect: Expect) {
fn in_mod_item_list() {
check(
r#"mod tests { $0 }"#,
- expect![[r##"
+ expect![[r#"
kw pub(crate)
kw pub(super)
kw pub
@@ -35,8 +35,8 @@ fn in_mod_item_list() {
kw self
kw super
kw crate
- ma makro!(…) #[macro_export] macro_rules! makro
- "##]],
+ ma makro!(…) macro_rules! makro
+ "#]],
)
}
@@ -44,7 +44,7 @@ fn in_mod_item_list() {
fn in_source_file_item_list() {
check(
r#"$0"#,
- expect![[r##"
+ expect![[r#"
kw pub(crate)
kw pub(super)
kw pub
@@ -68,8 +68,8 @@ fn in_source_file_item_list() {
kw super
kw crate
md module
- ma makro!(…) #[macro_export] macro_rules! makro
- "##]],
+ ma makro!(…) macro_rules! makro
+ "#]],
)
}
@@ -106,10 +106,10 @@ fn in_qualified_path() {
cov_mark::check!(no_keyword_completion_in_non_trivial_path);
check(
r#"crate::$0"#,
- expect![[r##"
+ expect![[r#"
md module
- ma makro!(…) #[macro_export] macro_rules! makro
- "##]],
+ ma makro!(…) macro_rules! makro
+ "#]],
)
}
@@ -162,7 +162,7 @@ fn after_visibility_unsafe() {
fn in_impl_assoc_item_list() {
check(
r#"impl Struct { $0 }"#,
- expect![[r##"
+ expect![[r#"
kw pub(crate)
kw pub(super)
kw pub
@@ -174,8 +174,8 @@ fn in_impl_assoc_item_list() {
kw super
kw crate
md module
- ma makro!(…) #[macro_export] macro_rules! makro
- "##]],
+ ma makro!(…) macro_rules! makro
+ "#]],
)
}
@@ -199,7 +199,7 @@ fn in_impl_assoc_item_list_after_attr() {
fn in_trait_assoc_item_list() {
check(
r"trait Foo { $0 }",
- expect![[r##"
+ expect![[r#"
kw unsafe
kw fn
kw const
@@ -208,8 +208,8 @@ fn in_trait_assoc_item_list() {
kw super
kw crate
md module
- ma makro!(…) #[macro_export] macro_rules! makro
- "##]],
+ ma makro!(…) macro_rules! makro
+ "#]],
);
}
@@ -233,7 +233,7 @@ impl Test for () {
$0
}
"#,
- expect![[r##"
+ expect![[r#"
kw pub(crate)
kw pub(super)
kw pub
@@ -245,7 +245,7 @@ impl Test for () {
kw super
kw crate
md module
- ma makro!(…) #[macro_export] macro_rules! makro
- "##]],
+ ma makro!(…) macro_rules! makro
+ "#]],
);
}
diff --git a/crates/ide_completion/src/tests/pattern.rs b/crates/ide_completion/src/tests/pattern.rs
index fe53257672..0ca20f93b5 100644
--- a/crates/ide_completion/src/tests/pattern.rs
+++ b/crates/ide_completion/src/tests/pattern.rs
@@ -102,7 +102,7 @@ fn foo() {
if let a$0
}
"#,
- expect![[r##"
+ expect![[r#"
kw ref
kw mut
en Enum
@@ -112,11 +112,11 @@ fn foo() {
st Tuple
md module
st Unit
- ma makro!(…) #[macro_export] macro_rules! makro
+ ma makro!(…) macro_rules! makro
bn TupleV TupleV($1)$0
ev TupleV
ct CONST
- "##]],
+ "#]],
);
}
@@ -132,7 +132,7 @@ fn foo() {
let a$0
}
"#,
- expect![[r##"
+ expect![[r#"
kw ref
kw mut
bn Record Record { field$1 }$0
@@ -142,8 +142,8 @@ fn foo() {
ev Variant
en SingleVariantEnum
st Unit
- ma makro!(…) #[macro_export] macro_rules! makro
- "##]],
+ ma makro!(…) macro_rules! makro
+ "#]],
);
}
@@ -154,7 +154,7 @@ fn in_param() {
fn foo(a$0) {
}
"#,
- expect![[r##"
+ expect![[r#"
kw ref
kw mut
bn Record Record { field$1 }: Record$0
@@ -162,15 +162,15 @@ fn foo(a$0) {
bn Tuple Tuple($1): Tuple$0
st Tuple
st Unit
- ma makro!(…) #[macro_export] macro_rules! makro
- "##]],
+ ma makro!(…) macro_rules! makro
+ "#]],
);
check(
r#"
fn foo(a$0: Tuple) {
}
"#,
- expect![[r##"
+ expect![[r#"
kw ref
kw mut
bn Record Record { field$1 }$0
@@ -178,8 +178,8 @@ fn foo(a$0: Tuple) {
bn Tuple Tuple($1)$0
st Tuple
st Unit
- ma makro!(…) #[macro_export] macro_rules! makro
- "##]],
+ ma makro!(…) macro_rules! makro
+ "#]],
);
}
diff --git a/crates/ide_completion/src/tests/predicate.rs b/crates/ide_completion/src/tests/predicate.rs
index 163080307d..5e975d715f 100644
--- a/crates/ide_completion/src/tests/predicate.rs
+++ b/crates/ide_completion/src/tests/predicate.rs
@@ -15,7 +15,7 @@ fn predicate_start() {
r#"
struct Foo<'lt, T, const C: usize> where $0 {}
"#,
- expect![[r##"
+ expect![[r#"
kw self
kw super
kw crate
@@ -26,10 +26,10 @@ struct Foo<'lt, T, const C: usize> where $0 {}
md module
st Foo<…>
st Unit
- ma makro!(…) #[macro_export] macro_rules! makro
+ ma makro!(…) macro_rules! makro
un Union
bt u32
- "##]],
+ "#]],
);
}
@@ -39,14 +39,14 @@ fn bound_for_type_pred() {
r#"
struct Foo<'lt, T, const C: usize> where T: $0 {}
"#,
- expect![[r##"
+ expect![[r#"
kw self
kw super
kw crate
tt Trait
md module
- ma makro!(…) #[macro_export] macro_rules! makro
- "##]],
+ ma makro!(…) macro_rules! makro
+ "#]],
);
}
@@ -58,14 +58,14 @@ fn bound_for_lifetime_pred() {
r#"
struct Foo<'lt, T, const C: usize> where 'lt: $0 {}
"#,
- expect![[r##"
+ expect![[r#"
kw self
kw super
kw crate
tt Trait
md module
- ma makro!(…) #[macro_export] macro_rules! makro
- "##]],
+ ma makro!(…) macro_rules! makro
+ "#]],
);
}
@@ -75,14 +75,14 @@ fn bound_for_for_pred() {
r#"
struct Foo<'lt, T, const C: usize> where for<'a> T: $0 {}
"#,
- expect![[r##"
+ expect![[r#"
kw self
kw super
kw crate
tt Trait
md module
- ma makro!(…) #[macro_export] macro_rules! makro
- "##]],
+ ma makro!(…) macro_rules! makro
+ "#]],
);
}
@@ -92,7 +92,7 @@ fn param_list_for_for_pred() {
r#"
struct Foo<'lt, T, const C: usize> where for<'a> $0 {}
"#,
- expect![[r##"
+ expect![[r#"
kw self
kw super
kw crate
@@ -103,10 +103,10 @@ struct Foo<'lt, T, const C: usize> where for<'a> $0 {}
md module
st Foo<…>
st Unit
- ma makro!(…) #[macro_export] macro_rules! makro
+ ma makro!(…) macro_rules! makro
un Union
bt u32
- "##]],
+ "#]],
);
}
@@ -118,7 +118,7 @@ impl Record {
fn method(self) where $0 {}
}
"#,
- expect![[r##"
+ expect![[r#"
kw self
kw super
kw crate
@@ -129,9 +129,9 @@ impl Record {
st Tuple
md module
st Unit
- ma makro!(…) #[macro_export] macro_rules! makro
+ ma makro!(…) macro_rules! makro
un Union
bt u32
- "##]],
+ "#]],
);
}
diff --git a/crates/ide_completion/src/tests/type_pos.rs b/crates/ide_completion/src/tests/type_pos.rs
index d6c1a787ff..c8260f6e23 100644
--- a/crates/ide_completion/src/tests/type_pos.rs
+++ b/crates/ide_completion/src/tests/type_pos.rs
@@ -16,7 +16,7 @@ struct Foo<'lt, T, const C: usize> {
f: $0
}
"#,
- expect![[r##"
+ expect![[r#"
kw self
kw super
kw crate
@@ -29,10 +29,10 @@ struct Foo<'lt, T, const C: usize> {
md module
st Foo<…>
st Unit
- ma makro!(…) #[macro_export] macro_rules! makro
+ ma makro!(…) macro_rules! makro
un Union
bt u32
- "##]],
+ "#]],
)
}
@@ -42,7 +42,7 @@ fn tuple_struct_field() {
r#"
struct Foo<'lt, T, const C: usize>(f$0);
"#,
- expect![[r##"
+ expect![[r#"
kw pub(crate)
kw pub(super)
kw pub
@@ -58,10 +58,10 @@ struct Foo<'lt, T, const C: usize>(f$0);
md module
st Foo<…>
st Unit
- ma makro!(…) #[macro_export] macro_rules! makro
+ ma makro!(…) macro_rules! makro
un Union
bt u32
- "##]],
+ "#]],
)
}
@@ -71,7 +71,7 @@ fn fn_return_type() {
r#"
fn x<'lt, T, const C: usize>() -> $0
"#,
- expect![[r##"
+ expect![[r#"
kw self
kw super
kw crate
@@ -82,10 +82,10 @@ fn x<'lt, T, const C: usize>() -> $0
st Tuple
md module
st Unit
- ma makro!(…) #[macro_export] macro_rules! makro
+ ma makro!(…) macro_rules! makro
un Union
bt u32
- "##]],
+ "#]],
);
}
@@ -98,7 +98,7 @@ fn foo<'lt, T, const C: usize>() {
let _: $0;
}
"#,
- expect![[r##"
+ expect![[r#"
kw self
kw super
kw crate
@@ -109,10 +109,10 @@ fn foo<'lt, T, const C: usize>() {
st Tuple
md module
st Unit
- ma makro!(…) #[macro_export] macro_rules! makro
+ ma makro!(…) macro_rules! makro
un Union
bt u32
- "##]],
+ "#]],
);
check(
r#"
@@ -121,16 +121,16 @@ fn foo<'lt, T, const C: usize>() {
let _: self::$0;
}
"#,
- expect![[r##"
+ expect![[r#"
tt Trait
en Enum
st Record
st Tuple
md module
st Unit
- ma makro!(…) #[macro_export] macro_rules! makro
+ ma makro!(…) macro_rules! makro
un Union
- "##]],
+ "#]],
);
}
@@ -144,7 +144,7 @@ trait Trait2 {
fn foo<'lt, T: Trait2<$0>, const CONST_PARAM: usize>(_: T) {}
"#,
- expect![[r##"
+ expect![[r#"
kw self
kw super
kw crate
@@ -157,12 +157,12 @@ fn foo<'lt, T: Trait2<$0>, const CONST_PARAM: usize>(_: T) {}
st Tuple
md module
st Unit
- ma makro!(…) #[macro_export] macro_rules! makro
+ ma makro!(…) macro_rules! makro
tt Trait2
un Union
ct CONST
bt u32
- "##]],
+ "#]],
);
check(
r#"
@@ -172,18 +172,18 @@ trait Trait2 {
fn foo<'lt, T: Trait2<self::$0>, const CONST_PARAM: usize>(_: T) {}
"#,
- expect![[r##"
+ expect![[r#"
tt Trait
en Enum
st Record
st Tuple
md module
st Unit
- ma makro!(…) #[macro_export] macro_rules! makro
+ ma makro!(…) macro_rules! makro
tt Trait2
un Union
ct CONST
- "##]],
+ "#]],
);
}
diff --git a/crates/ide_db/src/syntax_helpers/node_ext.rs b/crates/ide_db/src/syntax_helpers/node_ext.rs
index 115d83c6e2..c0f0529966 100644
--- a/crates/ide_db/src/syntax_helpers/node_ext.rs
+++ b/crates/ide_db/src/syntax_helpers/node_ext.rs
@@ -443,7 +443,7 @@ pub fn parse_tt_as_comma_sep_paths(input: ast::TokenTree) -> Option<Vec<ast::Pat
None => None,
Some(tok) => Some(tok),
});
- let input_expressions = tokens.into_iter().group_by(|tok| tok.kind() == T![,]);
+ let input_expressions = tokens.group_by(|tok| tok.kind() == T![,]);
let paths = input_expressions
.into_iter()
.filter_map(|(is_sep, group)| (!is_sep).then(|| group))
diff --git a/crates/syntax/src/display.rs b/crates/syntax/src/display.rs
index d03e94d058..f7322656a3 100644
--- a/crates/syntax/src/display.rs
+++ b/crates/syntax/src/display.rs
@@ -1,6 +1,6 @@
//! This module contains utilities for rendering syntax nodes into a string representing their signature.
-use crate::ast::{self, HasAttrs, HasGenericParams, HasName};
+use crate::ast::{self, HasGenericParams, HasName};
use ast::HasVisibility;
use stdx::format_to;
@@ -49,37 +49,3 @@ pub fn function_declaration(node: &ast::Fn) -> String {
}
buf
}
-
-pub fn macro_label(node: &ast::Macro) -> String {
- let name = node.name();
- let mut s = String::new();
- match node {
- ast::Macro::MacroRules(node) => {
- let vis = if node.has_atom_attr("macro_export") { "#[macro_export] " } else { "" };
- format_to!(s, "{}macro_rules!", vis);
- }
- ast::Macro::MacroDef(node) => {
- if let Some(vis) = node.visibility() {
- format_to!(s, "{} ", vis);
- }
- format_to!(s, "macro");
- }
- }
- if let Some(name) = name {
- format_to!(s, " {}", name);
- }
- s
-}
-
-pub fn fn_as_proc_macro_label(node: &ast::Fn) -> String {
- let name = node.name();
- let mut s = String::new();
- if let Some(vis) = node.visibility() {
- format_to!(s, "{} ", vis);
- }
- format_to!(s, "macro");
- if let Some(name) = name {
- format_to!(s, " {}", name);
- }
- s
-}