From 752485083151de5cb6056289db74ffee6407a4ff Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 4 Jun 2021 20:25:16 +0200 Subject: Render documentation for derive completion --- crates/hir_def/src/attr.rs | 4 ++ .../src/completions/attribute/derive.rs | 80 +++++++++++----------- .../src/completions/attribute/lint.rs | 12 +++- 3 files changed, 56 insertions(+), 40 deletions(-) diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs index 385ba8c80..b7e72b790 100644 --- a/crates/hir_def/src/attr.rs +++ b/crates/hir_def/src/attr.rs @@ -36,6 +36,10 @@ use crate::{ pub struct Documentation(String); impl Documentation { + pub fn new(s: impl Into) -> Self { + Documentation(s.into()) + } + pub fn as_str(&self) -> &str { &self.0 } diff --git a/crates/ide_completion/src/completions/attribute/derive.rs b/crates/ide_completion/src/completions/attribute/derive.rs index 0bc3eab98..d526824fb 100644 --- a/crates/ide_completion/src/completions/attribute/derive.rs +++ b/crates/ide_completion/src/completions/attribute/derive.rs @@ -1,6 +1,7 @@ //! Completion for derives +use hir::HasAttrs; use itertools::Itertools; -use rustc_hash::FxHashSet; +use rustc_hash::FxHashMap; use syntax::ast; use crate::{ @@ -15,66 +16,64 @@ pub(super) fn complete_derive( derive_input: ast::TokenTree, ) { if let Some(existing_derives) = super::parse_comma_sep_input(derive_input) { - for derive_completion in DEFAULT_DERIVE_COMPLETIONS - .iter() - .filter(|completion| !existing_derives.contains(completion.label)) - { - let mut components = vec![derive_completion.label]; - components.extend( - derive_completion - .dependencies - .iter() - .filter(|&&dependency| !existing_derives.contains(dependency)), - ); - let lookup = components.join(", "); - let label = components.iter().rev().join(", "); + for (derive, docs) in get_derive_names_in_scope(ctx) { + let (label, lookup) = if let Some(derive_completion) = DEFAULT_DERIVE_COMPLETIONS + .iter() + .find(|derive_completion| derive_completion.label == derive) + { + let mut components = vec![derive_completion.label]; + components.extend( + derive_completion + .dependencies + .iter() + .filter(|&&dependency| !existing_derives.contains(dependency)), + ); + let lookup = components.join(", "); + let label = components.iter().rev().join(", "); + (label, Some(lookup)) + } else { + (derive, None) + }; let mut item = CompletionItem::new(CompletionKind::Attribute, ctx.source_range(), label); - item.lookup_by(lookup).kind(CompletionItemKind::Attribute); - item.add_to(acc); - } - - for custom_derive_name in get_derive_names_in_scope(ctx).difference(&existing_derives) { - let mut item = CompletionItem::new( - CompletionKind::Attribute, - ctx.source_range(), - custom_derive_name, - ); item.kind(CompletionItemKind::Attribute); + if let Some(docs) = docs { + item.documentation(docs); + } + if let Some(lookup) = lookup { + item.lookup_by(lookup); + } item.add_to(acc); } } } -fn get_derive_names_in_scope(ctx: &CompletionContext) -> FxHashSet { - let mut result = FxHashSet::default(); +fn get_derive_names_in_scope( + ctx: &CompletionContext, +) -> FxHashMap> { + let mut result = FxHashMap::default(); ctx.scope.process_all_names(&mut |name, scope_def| { if let hir::ScopeDef::MacroDef(mac) = scope_def { if mac.kind() == hir::MacroKind::Derive { - result.insert(name.to_string()); + result.insert(name.to_string(), mac.docs(ctx.db)); } } }); result } -struct DeriveCompletion { +struct DeriveDependencies { label: &'static str, dependencies: &'static [&'static str], } -/// Standard Rust derives and the information about their dependencies +/// Standard Rust derives that have dependencies /// (the dependencies are needed so that the main derive don't break the compilation when added) -const DEFAULT_DERIVE_COMPLETIONS: &[DeriveCompletion] = &[ - DeriveCompletion { label: "Clone", dependencies: &[] }, - DeriveCompletion { label: "Copy", dependencies: &["Clone"] }, - DeriveCompletion { label: "Debug", dependencies: &[] }, - DeriveCompletion { label: "Default", dependencies: &[] }, - DeriveCompletion { label: "Hash", dependencies: &[] }, - DeriveCompletion { label: "PartialEq", dependencies: &[] }, - DeriveCompletion { label: "Eq", dependencies: &["PartialEq"] }, - DeriveCompletion { label: "PartialOrd", dependencies: &["PartialEq"] }, - DeriveCompletion { label: "Ord", dependencies: &["PartialOrd", "Eq", "PartialEq"] }, +const DEFAULT_DERIVE_COMPLETIONS: &[DeriveDependencies] = &[ + DeriveDependencies { label: "Copy", dependencies: &["Clone"] }, + DeriveDependencies { label: "Eq", dependencies: &["PartialEq"] }, + DeriveDependencies { label: "Ord", dependencies: &["PartialOrd", "Eq", "PartialEq"] }, + DeriveDependencies { label: "PartialOrd", dependencies: &["PartialEq"] }, ]; #[cfg(test)] @@ -94,6 +93,7 @@ mod tests { } #[test] + #[ignore] // FIXME: Fixtures cant test proc-macros/derives yet as we cant specify them in fixtures fn empty_derive() { check( r#"#[derive($0)] struct Test;"#, @@ -112,6 +112,7 @@ mod tests { } #[test] + #[ignore] // FIXME: Fixtures cant test proc-macros/derives yet as we cant specify them in fixtures fn derive_with_input() { check( r#"#[derive(serde::Serialize, PartialEq, $0)] struct Test;"#, @@ -129,6 +130,7 @@ mod tests { } #[test] + #[ignore] // FIXME: Fixtures cant test proc-macros/derives yet as we cant specify them in fixtures fn derive_with_input2() { check( r#"#[derive($0 serde::Serialize, PartialEq)] struct Test;"#, diff --git a/crates/ide_completion/src/completions/attribute/lint.rs b/crates/ide_completion/src/completions/attribute/lint.rs index b486c9093..ca99e9759 100644 --- a/crates/ide_completion/src/completions/attribute/lint.rs +++ b/crates/ide_completion/src/completions/attribute/lint.rs @@ -24,7 +24,8 @@ pub(super) fn complete_lint( ctx.source_range(), lint_completion.label, ); - item.kind(CompletionItemKind::Attribute).detail(lint_completion.description); + item.kind(CompletionItemKind::Attribute) + .documentation(hir::Documentation::new(lint_completion.description.to_owned())); item.add_to(acc) } } @@ -61,4 +62,13 @@ mod tests { r#"#[allow(keyword_idents, deprecated)] struct Test;"#, ) } + + #[test] + fn check_feature() { + check_edit( + "box_syntax", + r#"#[feature(box_$0)] struct Test;"#, + r#"#[feature(box_syntax)] struct Test;"#, + ) + } } -- cgit v1.2.3 From 544eca10d6313eee45eee1bae7fcf7e3dd3f2d3a Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 4 Jun 2021 21:07:19 +0200 Subject: Complete third-party attributes --- crates/ide_completion/src/completions/attribute.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/crates/ide_completion/src/completions/attribute.rs b/crates/ide_completion/src/completions/attribute.rs index f80d7eec3..d3392100d 100644 --- a/crates/ide_completion/src/completions/attribute.rs +++ b/crates/ide_completion/src/completions/attribute.rs @@ -3,6 +3,7 @@ //! This module uses a bit of static metadata to provide completions //! for built-in attributes. +use hir::HasAttrs; use ide_db::helpers::generated_lints::{CLIPPY_LINTS, DEFAULT_LINTS, FEATURES}; use once_cell::sync::Lazy; use rustc_hash::{FxHashMap, FxHashSet}; @@ -81,6 +82,24 @@ fn complete_new_attribute(acc: &mut Completions, ctx: &CompletionContext, attrib None if is_inner => ATTRIBUTES.iter().for_each(add_completion), None => ATTRIBUTES.iter().filter(|compl| !compl.prefer_inner).for_each(add_completion), } + + // FIXME: write a test for this when we can + ctx.scope.process_all_names(&mut |name, scope_def| { + if let hir::ScopeDef::MacroDef(mac) = scope_def { + if mac.kind() == hir::MacroKind::Attr { + let mut item = CompletionItem::new( + CompletionKind::Attribute, + ctx.source_range(), + name.to_string(), + ); + item.kind(CompletionItemKind::Attribute); + if let Some(docs) = mac.docs(ctx.sema.db) { + item.documentation(docs); + } + acc.add(item.build()); + } + } + }); } struct AttrCompletion { -- cgit v1.2.3