diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs index 8f80f3a5db6c..6e3285fd4ff0 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 0aabb415d46a..a90120a46763 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 6d6a86fc8ab5..45544559eaba 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 { + self.imp.expand_derive_as_pseudo_attr_macro(attr) + } + pub fn resolve_derive_macro(&self, derive: &ast::Attr) -> Option>> { 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 { 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 { + 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>> { @@ -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(&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 6535f27a6368..0c886ac4da9d 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 { 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 { 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 d6d33b4cd724..9fe414de264e 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 c298065f4e08..2e141600e80b 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 { 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 2ec7802394f3..df27f935c84c 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 07dcfd967177..ebea2d5dea8d 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 3c5dd8f3fd34..6b51e19bbbe3 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> { .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 64f6e3989d25..1edc92d5d628 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) { - 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; - } - - 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) - } - } - _ => (name, None), - }; - - let mut item = CompletionItem::new(SymbolKind::Derive, ctx.source_range(), label); - if let Some(docs) = mac.docs(ctx.db) { - item.documentation(docs); - } - if let Some(lookup) = lookup { - item.lookup_by(lookup); - } - item.add_to(acc); - } - - flyimport_derive(acc, ctx); -} - -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 -} - -fn flyimport_derive(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { - if ctx.token.kind() != SyntaxKind::IDENT { - return None; +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 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); + + let core = ctx.famous_defs().core(); + + match qualifier { + Some(PathQualifierCtx { resolution, is_super_chain, .. }) => { + if *is_super_chain { + acc.add_keyword(ctx, "super::"); + } + + 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); } - Some(item.build()) - }), - ); - Some(()) + } + return; + } + 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, + }; + + 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), + }; + + let name_ = name.to_smol_str(); + let find = DEFAULT_DERIVE_DEPENDENCIES + .iter() + .find(|derive_completion| derive_completion.label == name_); + + 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), + } + }); + 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 b4cfc3273bda..aee2bbb53c3e 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 c4ba77b3f7da..acd02616b157 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 ddd068488aa5..235d7870c7ca 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 da80224dd8c7..51bbd66ff372 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 }, + 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, - pub(super) attr: Option, /// The parent impl of the cursor position if it exists. pub(super) impl_def: Option, /// 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, pub(super) path_context: Option, + pub(super) existing_derives: FxHashSet, + 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::(&original_file, offset) { + Some(it) => it, + None => break, + }; + let spec_tt = match find_node_at_offset::(&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::(&original_file, offset), - find_node_at_offset::(&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, Option) { @@ -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 3225a0bc9f4f..86a6947b1dda 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 6fdb622be7ec..d3b0de429ca6 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, macro_: hir::Macro) -> Option { - // 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(¯o_name) { diff --git a/crates/ide_completion/src/tests/attribute.rs b/crates/ide_completion/src/tests/attribute.rs index ae7ba7e055ce..4ee95e892817 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 5e1fae68fd2a..a841605e496c 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 fbef6d9937e6..c996a5f01f87 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 d94fab2f5f2e..1d5ddc092e50 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 4c7696305490..82824fd3932b 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 fe532576729d..0ca20f93b5e2 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 163080307d71..5e975d715f66 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 d6c1a787ff9b..c8260f6e23c0 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, 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 115d83c6e250..c0f052996631 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 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 d03e94d05832..f7322656a3e0 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 -}