about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-06-05 17:23:40 +0000
committerGitHub <noreply@github.com>2021-06-05 17:23:40 +0000
commitad9234fef2a90105448214255669fb46a382c3a5 (patch)
treee09f9b33d359c9871f03a413b44630509fb97406
parent5092d8c1ae50010d35f6860b6420a69ddcd9ca45 (diff)
parent544eca10d6313eee45eee1bae7fcf7e3dd3f2d3a (diff)
downloadrust-ad9234fef2a90105448214255669fb46a382c3a5.tar.gz
rust-ad9234fef2a90105448214255669fb46a382c3a5.zip
Merge #9140
9140: feat: Render documentation for derive completion r=Veykril a=Veykril

![eEzGiq2wNa](https://user-images.githubusercontent.com/3757771/120847308-9c5a3300-c573-11eb-958d-e0f22f4757ed.gif)

Nothing fancy as all the std derives aren't really documented though maybe some 3rd party crates document them equally to their trait counterparts.

Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
-rw-r--r--crates/hir_def/src/attr.rs4
-rw-r--r--crates/ide_completion/src/completions/attribute.rs19
-rw-r--r--crates/ide_completion/src/completions/attribute/derive.rs80
-rw-r--r--crates/ide_completion/src/completions/attribute/lint.rs12
4 files changed, 75 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.rs b/crates/ide_completion/src/completions/attribute.rs
index f80d7eec345..d3392100d90 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 {
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;"#,
+        )
+    }
 }