about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crates/hir_def/src/attr.rs4
-rw-r--r--crates/ide_completion/src/completions/attribute/derive.rs80
-rw-r--r--crates/ide_completion/src/completions/attribute/lint.rs12
3 files changed, 56 insertions, 40 deletions
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index 385ba8c80b5..b7e72b79002 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<String>) -> 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 0bc3eab988b..d526824fbdb 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<String> {
-    let mut result = FxHashSet::default();
+fn get_derive_names_in_scope(
+    ctx: &CompletionContext,
+) -> FxHashMap<String, Option<hir::Documentation>> {
+    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 b486c909385..ca99e975926 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;"#,
+        )
+    }
 }