Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #22136 from ada4a/cleanup-attr-completions
Clean-up attribute completions
8 files changed, 124 insertions, 118 deletions
diff --git a/crates/ide-completion/src/completions/attribute.rs b/crates/ide-completion/src/completions/attribute.rs index da1e664f96..0ce0dde2e2 100644 --- a/crates/ide-completion/src/completions/attribute.rs +++ b/crates/ide-completion/src/completions/attribute.rs @@ -4,13 +4,7 @@ use std::sync::LazyLock; -use ide_db::{ - FxHashMap, SymbolKind, - generated::lints::{ - CLIPPY_LINT_GROUPS, CLIPPY_LINTS, DEFAULT_LINTS, FEATURES, Lint, RUSTDOC_LINTS, - }, - syntax_helpers::node_ext::parse_tt_as_comma_sep_paths, -}; +use ide_db::{FxHashMap, SymbolKind, syntax_helpers::node_ext::parse_tt_as_comma_sep_paths}; use itertools::Itertools; use syntax::{ AstNode, Edition, SyntaxKind, T, @@ -26,6 +20,7 @@ use crate::{ mod cfg; mod derive; mod diagnostic; +mod feature; mod lint; mod macro_use; mod repr; @@ -37,7 +32,7 @@ pub(crate) use self::derive::complete_derive_path; pub(crate) fn complete_known_attribute_input( acc: &mut Completions, ctx: &CompletionContext<'_>, - &colon_prefix: &bool, + colon_prefix: bool, fake_attribute_under_caret: &ast::TokenTreeMeta, extern_crate: Option<&ast::ExternCrate>, ) -> Option<()> { @@ -49,35 +44,25 @@ pub(crate) fn complete_known_attribute_input( let tt = attribute.token_tree()?; match segments.as_slice() { - ["repr"] => repr::complete_repr(acc, ctx, tt), - ["feature"] => lint::complete_lint( + ["repr"] => repr::complete_repr(acc, ctx, &parse_comma_sep_expr(tt)?), + ["feature"] => { + feature::complete_feature(acc, ctx, &parse_tt_as_comma_sep_paths(tt, ctx.edition)?) + } + ["allow" | "expect" | "deny" | "forbid" | "warn"] => lint::complete_lint( acc, ctx, colon_prefix, &parse_tt_as_comma_sep_paths(tt, ctx.edition)?, - FEATURES, ), - ["allow"] | ["expect"] | ["deny"] | ["forbid"] | ["warn"] => { - let existing_lints = parse_tt_as_comma_sep_paths(tt, ctx.edition)?; - - let lints: Vec<Lint> = CLIPPY_LINT_GROUPS - .iter() - .map(|g| &g.lint) - .chain(DEFAULT_LINTS) - .chain(CLIPPY_LINTS) - .chain(RUSTDOC_LINTS) - .cloned() - .collect(); - - lint::complete_lint(acc, ctx, colon_prefix, &existing_lints, &lints); - } ["macro_use"] => macro_use::complete_macro_use( acc, ctx, extern_crate, &parse_tt_as_comma_sep_paths(tt, ctx.edition)?, ), - ["diagnostic", "on_unimplemented"] => diagnostic::complete_on_unimplemented(acc, ctx, tt), + ["diagnostic", "on_unimplemented"] => { + diagnostic::complete_on_unimplemented(acc, ctx, &parse_comma_sep_expr(tt)?) + } _ => (), } Some(()) @@ -190,7 +175,7 @@ pub(crate) fn complete_attribute_path( match attributes { Some(applicable) => applicable .iter() - .flat_map(|name| ATTRIBUTES.binary_search_by(|attr| attr.key().cmp(name)).ok()) + .flat_map(|name| ATTRIBUTES.binary_search_by_key(name, |attr| attr.key()).ok()) .flat_map(|idx| ATTRIBUTES.get(idx)) .for_each(add_completion), None if is_inner => ATTRIBUTES.iter().for_each(add_completion), diff --git a/crates/ide-completion/src/completions/attribute/cfg.rs b/crates/ide-completion/src/completions/attribute/cfg.rs index 0d36fb7a40..1bd6e6d9bf 100644 --- a/crates/ide-completion/src/completions/attribute/cfg.rs +++ b/crates/ide-completion/src/completions/attribute/cfg.rs @@ -11,7 +11,7 @@ pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext<'_>) { let mut completion = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), item, ctx.edition); completion.insert_text(format!(r#""{item}""#)); - acc.add(completion.build(ctx.db)); + completion.add_to(acc, ctx.db); }; // FIXME: Move this into context/analysis.rs @@ -49,8 +49,7 @@ pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext<'_>) { ctx.edition, ); item.insert_text(insert_text); - - acc.add(item.build(ctx.db)); + item.add_to(acc, ctx.db); }), }, None => ctx @@ -82,7 +81,7 @@ pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext<'_>) { { item.insert_snippet(cap, snippet); } - acc.add(item.build(ctx.db)); + item.add_to(acc, ctx.db); }), } } diff --git a/crates/ide-completion/src/completions/attribute/diagnostic.rs b/crates/ide-completion/src/completions/attribute/diagnostic.rs index 8adc974239..0899bbff14 100644 --- a/crates/ide-completion/src/completions/attribute/diagnostic.rs +++ b/crates/ide-completion/src/completions/attribute/diagnostic.rs @@ -10,46 +10,44 @@ use super::AttrCompletion; pub(super) fn complete_on_unimplemented( acc: &mut Completions, ctx: &CompletionContext<'_>, - input: ast::TokenTree, + existing_keys: &[ast::Expr], ) { - if let Some(existing_keys) = super::parse_comma_sep_expr(input) { - for attr in ATTRIBUTE_ARGS { - let already_annotated = existing_keys - .iter() - .filter_map(|expr| match expr { - ast::Expr::PathExpr(path) => path.path()?.as_single_name_ref(), - ast::Expr::BinExpr(bin) - if bin.op_kind() == Some(ast::BinaryOp::Assignment { op: None }) => - { - match bin.lhs()? { - ast::Expr::PathExpr(path) => path.path()?.as_single_name_ref(), - _ => None, - } + for attr in ATTRIBUTE_ARGS { + let already_annotated = existing_keys + .iter() + .filter_map(|expr| match expr { + ast::Expr::PathExpr(path) => path.path()?.as_single_name_ref(), + ast::Expr::BinExpr(bin) + if bin.op_kind() == Some(ast::BinaryOp::Assignment { op: None }) => + { + match bin.lhs()? { + ast::Expr::PathExpr(path) => path.path()?.as_single_name_ref(), + _ => None, } - _ => None, - }) - .any(|it| { - let text = it.text(); - attr.key() == text && text != "note" - }); - if already_annotated { - continue; - } + } + _ => None, + }) + .any(|it| { + let text = it.text(); + attr.key() == text && text != "note" + }); + if already_annotated { + continue; + } - let mut item = CompletionItem::new( - SymbolKind::BuiltinAttr, - ctx.source_range(), - attr.label, - ctx.edition, - ); - if let Some(lookup) = attr.lookup { - item.lookup_by(lookup); - } - if let Some((snippet, cap)) = attr.snippet.zip(ctx.config.snippet_cap) { - item.insert_snippet(cap, snippet); - } - item.add_to(acc, ctx.db); + let mut item = CompletionItem::new( + SymbolKind::BuiltinAttr, + ctx.source_range(), + attr.label, + ctx.edition, + ); + if let Some(lookup) = attr.lookup { + item.lookup_by(lookup); + } + if let Some((snippet, cap)) = attr.snippet.zip(ctx.config.snippet_cap) { + item.insert_snippet(cap, snippet); } + item.add_to(acc, ctx.db); } } diff --git a/crates/ide-completion/src/completions/attribute/feature.rs b/crates/ide-completion/src/completions/attribute/feature.rs new file mode 100644 index 0000000000..1e6baca864 --- /dev/null +++ b/crates/ide-completion/src/completions/attribute/feature.rs @@ -0,0 +1,30 @@ +//! Completion for features +use ide_db::{ + SymbolKind, + documentation::Documentation, + generated::lints::{FEATURES, Lint}, +}; +use syntax::ast; + +use crate::{Completions, context::CompletionContext, item::CompletionItem}; + +pub(super) fn complete_feature( + acc: &mut Completions, + ctx: &CompletionContext<'_>, + existing_features: &[ast::Path], +) { + for &Lint { label, description, .. } in FEATURES { + let feature_already_annotated = existing_features + .iter() + .filter_map(|p| p.as_single_name_ref()) + .any(|n| n.text() == label); + if feature_already_annotated { + continue; + } + + let mut item = + CompletionItem::new(SymbolKind::Attribute, ctx.source_range(), label, ctx.edition); + item.documentation(Documentation::new_borrowed(description)); + item.add_to(acc, ctx.db) + } +} diff --git a/crates/ide-completion/src/completions/attribute/lint.rs b/crates/ide-completion/src/completions/attribute/lint.rs index df577b8ed0..f810196bfe 100644 --- a/crates/ide-completion/src/completions/attribute/lint.rs +++ b/crates/ide-completion/src/completions/attribute/lint.rs @@ -1,5 +1,9 @@ //! Completion for lints -use ide_db::{SymbolKind, documentation::Documentation, generated::lints::Lint}; +use ide_db::{ + SymbolKind, + documentation::Documentation, + generated::lints::{CLIPPY_LINT_GROUPS, CLIPPY_LINTS, DEFAULT_LINTS, Lint, RUSTDOC_LINTS}, +}; use syntax::ast; use crate::{Completions, context::CompletionContext, item::CompletionItem}; @@ -9,21 +13,17 @@ pub(super) fn complete_lint( ctx: &CompletionContext<'_>, is_qualified: bool, existing_lints: &[ast::Path], - lints_completions: &[Lint], ) { - for &Lint { label, description, .. } in lints_completions { - let (qual, name) = { - // FIXME: change `Lint`'s label to not store a path in it but split the prefix off instead? - let mut parts = label.split("::"); - let ns_or_label = match parts.next() { - Some(it) => it, - None => continue, - }; - let label = parts.next(); - match label { - Some(label) => (Some(ns_or_label), label), - None => (None, ns_or_label), - } + let lints = (CLIPPY_LINT_GROUPS.iter().map(|g| &g.lint)) + .chain(DEFAULT_LINTS) + .chain(CLIPPY_LINTS) + .chain(RUSTDOC_LINTS); + + for &Lint { label, description, .. } in lints { + // FIXME: change `Lint`'s label to not store a path in it but split the prefix off instead? + let (qual, name) = match label.split_once("::") { + Some((qual, name)) => (Some(qual), name), + None => (None, label), }; if qual.is_none() && is_qualified { // qualified completion requested, but this lint is unqualified @@ -56,7 +56,7 @@ pub(super) fn complete_lint( }; let mut item = CompletionItem::new(SymbolKind::Attribute, ctx.source_range(), label, ctx.edition); - item.documentation(Documentation::new_owned(description.to_owned())); + item.documentation(Documentation::new_borrowed(description)); item.add_to(acc, ctx.db) } } diff --git a/crates/ide-completion/src/completions/attribute/macro_use.rs b/crates/ide-completion/src/completions/attribute/macro_use.rs index 136315c61f..9c0fe0055d 100644 --- a/crates/ide-completion/src/completions/attribute/macro_use.rs +++ b/crates/ide-completion/src/completions/attribute/macro_use.rs @@ -20,11 +20,11 @@ pub(super) fn complete_macro_use( let mac_name = mac.name(ctx.db); let mac_name = mac_name.as_str(); - let existing_import = existing_imports + let already_imported = existing_imports .iter() .filter_map(|p| p.as_single_name_ref()) - .find(|n| n.text() == mac_name); - if existing_import.is_some() { + .any(|n| n.text() == mac_name); + if already_imported { continue; } diff --git a/crates/ide-completion/src/completions/attribute/repr.rs b/crates/ide-completion/src/completions/attribute/repr.rs index cb7ccf7373..b04358963a 100644 --- a/crates/ide-completion/src/completions/attribute/repr.rs +++ b/crates/ide-completion/src/completions/attribute/repr.rs @@ -8,42 +8,36 @@ use crate::{Completions, context::CompletionContext, item::CompletionItem}; pub(super) fn complete_repr( acc: &mut Completions, ctx: &CompletionContext<'_>, - input: ast::TokenTree, + existing_reprs: &[ast::Expr], ) { - if let Some(existing_reprs) = super::parse_comma_sep_expr(input) { - for &ReprCompletion { label, snippet, lookup, collides } in REPR_COMPLETIONS { - let repr_already_annotated = existing_reprs - .iter() - .filter_map(|expr| match expr { + for &ReprCompletion { label, snippet, lookup, collides } in REPR_COMPLETIONS { + let repr_already_annotated = existing_reprs + .iter() + .filter_map(|expr| match expr { + ast::Expr::PathExpr(path) => path.path()?.as_single_name_ref(), + ast::Expr::CallExpr(call) => match call.expr()? { ast::Expr::PathExpr(path) => path.path()?.as_single_name_ref(), - ast::Expr::CallExpr(call) => match call.expr()? { - ast::Expr::PathExpr(path) => path.path()?.as_single_name_ref(), - _ => None, - }, _ => None, - }) - .any(|it| { - let text = it.text(); - lookup.unwrap_or(label) == text || collides.contains(&text.as_str()) - }); - if repr_already_annotated { - continue; - } + }, + _ => None, + }) + .any(|it| { + let text = it.text(); + lookup.unwrap_or(label) == text || collides.contains(&text.as_str()) + }); + if repr_already_annotated { + continue; + } - let mut item = CompletionItem::new( - SymbolKind::BuiltinAttr, - ctx.source_range(), - label, - ctx.edition, - ); - if let Some(lookup) = lookup { - item.lookup_by(lookup); - } - if let Some((snippet, cap)) = snippet.zip(ctx.config.snippet_cap) { - item.insert_snippet(cap, snippet); - } - item.add_to(acc, ctx.db); + let mut item = + CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), label, ctx.edition); + if let Some(lookup) = lookup { + item.lookup_by(lookup); + } + if let Some((snippet, cap)) = snippet.zip(ctx.config.snippet_cap) { + item.insert_snippet(cap, snippet); } + item.add_to(acc, ctx.db); } } diff --git a/crates/ide-completion/src/lib.rs b/crates/ide-completion/src/lib.rs index 3df511a5ad..66ecb790a0 100644 --- a/crates/ide-completion/src/lib.rs +++ b/crates/ide-completion/src/lib.rs @@ -258,7 +258,7 @@ pub fn completions( completions::attribute::complete_known_attribute_input( acc, ctx, - colon_prefix, + *colon_prefix, attr, extern_crate.as_ref(), ); |