about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-10-19 11:51:07 +0000
committerGitHub <noreply@github.com>2021-10-19 11:51:07 +0000
commit0e4c3b2c2be83251ab0f1ffba74780e05e77c2ff (patch)
treeff5430d6bfdd2c13d5456b872d2cbc905ade2513
parentd85946b73566312f96b2c465d26ed6a613b39109 (diff)
parent3dfe5045c54a927459932c8347d653abf1eca2e2 (diff)
downloadrust-0e4c3b2c2be83251ab0f1ffba74780e05e77c2ff.tar.gz
rust-0e4c3b2c2be83251ab0f1ffba74780e05e77c2ff.zip
Merge #10586
10586: internal: Derive completions work on hir, not names r=Veykril a=Veykril

bors r+

Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
-rw-r--r--crates/ide_completion/src/completions/attribute/derive.rs80
-rw-r--r--crates/ide_completion/src/tests/attribute.rs96
-rw-r--r--crates/test_utils/src/minicore.rs4
3 files changed, 93 insertions, 87 deletions
diff --git a/crates/ide_completion/src/completions/attribute/derive.rs b/crates/ide_completion/src/completions/attribute/derive.rs
index 36758baafc0..2824b2a2c2a 100644
--- a/crates/ide_completion/src/completions/attribute/derive.rs
+++ b/crates/ide_completion/src/completions/attribute/derive.rs
@@ -1,8 +1,9 @@
 //! Completion for derives
-use hir::HasAttrs;
+use hir::{HasAttrs, MacroDef, MacroKind};
+use ide_db::helpers::FamousDefs;
 use itertools::Itertools;
-use rustc_hash::FxHashMap;
-use syntax::{ast, SmolStr};
+use rustc_hash::FxHashSet;
+use syntax::ast;
 
 use crate::{
     context::CompletionContext,
@@ -15,36 +16,51 @@ pub(super) fn complete_derive(
     ctx: &CompletionContext,
     derive_input: ast::TokenTree,
 ) {
-    if let Some(existing_derives) = super::parse_comma_sep_paths(derive_input) {
-        for (derive, docs) in get_derive_names_in_scope(ctx) {
+    if let Some(existing_derives) = super::parse_comma_sep_paths(derive_input.clone()) {
+        let core = FamousDefs(&ctx.sema, ctx.krate).core();
+        let existing_derives: FxHashSet<_> = existing_derives
+            .into_iter()
+            .filter_map(|path| ctx.scope.speculative_resolve_as_mac(&path))
+            .filter(|mac| mac.kind() == MacroKind::Derive)
+            .collect();
+
+        for (name, mac) in get_derives_in_scope(ctx) {
+            if existing_derives.contains(&mac) {
+                continue;
+            }
+
+            let name = name.to_smol_str();
             let label;
-            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
+            let (label, lookup) = match core.zip(mac.module(ctx.db).map(|it| it.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()
-                        .filter_map(|it| it.as_single_name_ref())
-                        .any(|it| it.text() == dependency)
-                }));
-                let lookup = components.join(", ");
-                label = components.iter().rev().join(", ");
-                (&*label, Some(lookup))
-            } else if existing_derives
-                .iter()
-                .filter_map(|it| it.as_single_name_ref())
-                .any(|it| it.text().as_str() == derive)
-            {
-                continue;
-            } else {
-                (&*derive, None)
+                        .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()
+                                    .filter_map(|it| it.name(ctx.db))
+                                    .any(|it| it.to_smol_str() == dependency)
+                            },
+                        ));
+                        let lookup = components.join(", ");
+                        label = components.iter().rev().join(", ");
+                        (label.as_str(), Some(lookup))
+                    } else {
+                        (&*name, None)
+                    }
+                }
+                _ => (&*name, None),
             };
+
             let mut item =
                 CompletionItem::new(CompletionKind::Attribute, ctx.source_range(), label);
             item.kind(CompletionItemKind::Attribute);
-            if let Some(docs) = docs {
+            if let Some(docs) = mac.docs(ctx.db) {
                 item.documentation(docs);
             }
             if let Some(lookup) = lookup {
@@ -55,14 +71,12 @@ pub(super) fn complete_derive(
     }
 }
 
-fn get_derive_names_in_scope(
-    ctx: &CompletionContext,
-) -> FxHashMap<SmolStr, Option<hir::Documentation>> {
-    let mut result = FxHashMap::default();
+fn get_derives_in_scope(ctx: &CompletionContext) -> Vec<(hir::Name, MacroDef)> {
+    let mut result = Vec::default();
     ctx.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_smol_str(), mac.docs(ctx.db));
+                result.push((name, mac));
             }
         }
     });
@@ -76,7 +90,7 @@ struct DeriveDependencies {
 
 /// 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: &[DeriveDependencies] = &[
+const DEFAULT_DERIVE_DEPENDENCIES: &[DeriveDependencies] = &[
     DeriveDependencies { label: "Copy", dependencies: &["Clone"] },
     DeriveDependencies { label: "Eq", dependencies: &["PartialEq"] },
     DeriveDependencies { label: "Ord", dependencies: &["PartialOrd", "Eq", "PartialEq"] },
diff --git a/crates/ide_completion/src/tests/attribute.rs b/crates/ide_completion/src/tests/attribute.rs
index 9d22bb196bd..6a37b53cf58 100644
--- a/crates/ide_completion/src/tests/attribute.rs
+++ b/crates/ide_completion/src/tests/attribute.rs
@@ -571,85 +571,73 @@ mod derive {
     use super::*;
 
     fn check_derive(ra_fixture: &str, expect: Expect) {
-        let builtin_derives = r#"
-    #[rustc_builtin_macro]
-    pub macro Clone {}
-    #[rustc_builtin_macro]
-    pub macro Copy {}
-    #[rustc_builtin_macro]
-    pub macro Default {}
-    #[rustc_builtin_macro]
-    pub macro Debug {}
-    #[rustc_builtin_macro]
-    pub macro Hash {}
-    #[rustc_builtin_macro]
-    pub macro PartialEq {}
-    #[rustc_builtin_macro]
-    pub macro Eq {}
-    #[rustc_builtin_macro]
-    pub macro PartialOrd {}
-    #[rustc_builtin_macro]
-    pub macro Ord {}
-
-    "#;
-        let actual = completion_list(&format!("{} {}", builtin_derives, ra_fixture));
+        let actual = completion_list(ra_fixture);
         expect.assert_eq(&actual);
     }
 
     #[test]
     fn no_completion_for_incorrect_derive() {
-        check_derive(r#"#[derive{$0)] struct Test;"#, expect![[]])
+        check_derive(
+            r#"
+//- minicore: derive, copy, clone, ord, eq, default, fmt
+#[derive{$0)] struct Test;
+"#,
+            expect![[]],
+        )
     }
 
     #[test]
     fn empty_derive() {
         check_derive(
-            r#"#[derive($0)] struct Test;"#,
+            r#"
+//- minicore: derive, copy, clone, ord, eq, default, fmt
+#[derive($0)] struct Test;
+"#,
             expect![[r#"
-        at PartialEq
-        at Default
-        at PartialEq, Eq
-        at PartialEq, Eq, PartialOrd, Ord
-        at Clone, Copy
-        at Debug
-        at Clone
-        at Hash
-        at PartialEq, PartialOrd
-    "#]],
+                at Default
+                at Clone, Copy
+                at PartialEq
+                at PartialEq, Eq
+                at PartialEq, Eq, PartialOrd, Ord
+                at Clone
+                at PartialEq, PartialOrd
+            "#]],
         );
     }
 
     #[test]
     fn derive_with_input_before() {
         check_derive(
-            r#"#[derive(serde::Serialize, PartialEq, $0)] struct Test;"#,
+            r#"
+//- minicore: derive, copy, clone, ord, eq, default, fmt
+#[derive(serde::Serialize, PartialEq, $0)] struct Test;
+"#,
             expect![[r#"
-            at Default
-            at Eq
-            at Eq, PartialOrd, Ord
-            at Clone, Copy
-            at Debug
-            at Clone
-            at Hash
-            at PartialOrd
-        "#]],
+                at Default
+                at Clone, Copy
+                at Eq
+                at Eq, PartialOrd, Ord
+                at Clone
+                at PartialOrd
+            "#]],
         )
     }
 
     #[test]
     fn derive_with_input_after() {
         check_derive(
-            r#"#[derive($0 serde::Serialize, PartialEq)] struct Test;"#,
+            r#"
+//- minicore: derive, copy, clone, ord, eq, default, fmt
+#[derive($0 serde::Serialize, PartialEq)] struct Test;
+"#,
             expect![[r#"
-            at Default
-            at Eq
-            at Eq, PartialOrd, Ord
-            at Clone, Copy
-            at Debug
-            at Clone
-            at Hash
-            at PartialOrd
-        "#]],
+                at Default
+                at Clone, Copy
+                at Eq
+                at Eq, PartialOrd, Ord
+                at Clone
+                at PartialOrd
+            "#]],
         )
     }
 }
diff --git a/crates/test_utils/src/minicore.rs b/crates/test_utils/src/minicore.rs
index 045b4898e50..ef38a194bc3 100644
--- a/crates/test_utils/src/minicore.rs
+++ b/crates/test_utils/src/minicore.rs
@@ -87,6 +87,10 @@ pub mod default {
     pub trait Default: Sized {
         fn default() -> Self;
     }
+    // region:derive
+    #[rustc_builtin_macro]
+    pub macro Default($item:item) {}
+    // endregion:derive
 }
 // endregion:default