]> git.lizzy.rs Git - rust.git/blobdiff - crates/ide_completion/src/completions/attribute.rs
Improve completion of cfg attributes
[rust.git] / crates / ide_completion / src / completions / attribute.rs
index c48bb9e6619d0001afc6527aa80397299e360ede..cc4f4b2af728e973af0fcae689eddde843574fbb 100644 (file)
@@ -3,31 +3,37 @@
 //! 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};
 use syntax::{algo::non_trivia_sibling, ast, AstNode, Direction, NodeOrToken, SyntaxKind, T};
 
 use crate::{
     context::CompletionContext,
-    generated_lint_completions::{CLIPPY_LINTS, FEATURES},
     item::{CompletionItem, CompletionItemKind, CompletionKind},
     Completions,
 };
 
+mod cfg;
 mod derive;
 mod lint;
-pub(crate) use self::lint::LintCompletion;
+mod repr;
 
 pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
     let attribute = ctx.attribute_under_caret.as_ref()?;
     match (attribute.path().and_then(|p| p.as_single_name_ref()), attribute.token_tree()) {
         (Some(path), Some(token_tree)) => match path.text().as_str() {
             "derive" => derive::complete_derive(acc, ctx, token_tree),
+            "repr" => repr::complete_repr(acc, ctx, token_tree),
             "feature" => lint::complete_lint(acc, ctx, token_tree, FEATURES),
             "allow" | "warn" | "deny" | "forbid" => {
-                lint::complete_lint(acc, ctx, token_tree.clone(), lint::DEFAULT_LINT_COMPLETIONS);
+                lint::complete_lint(acc, ctx, token_tree.clone(), DEFAULT_LINTS);
                 lint::complete_lint(acc, ctx, token_tree, CLIPPY_LINTS);
             }
+            "cfg" => {
+                cfg::complete_cfg(acc, ctx);
+            }
             _ => (),
         },
         (None, Some(_)) => (),
@@ -69,7 +75,7 @@ fn complete_new_attribute(acc: &mut Completions, ctx: &CompletionContext, attrib
         }
 
         if is_inner || !attr_completion.prefer_inner {
-            acc.add(item.build());
+            item.add_to(acc);
         }
     };
 
@@ -82,6 +88,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);
+                }
+                item.add_to(acc);
+            }
+        }
+    });
 }
 
 struct AttrCompletion {
@@ -201,7 +225,7 @@ macro_rules! attrs {
 });
 const EXPR_ATTRIBUTES: &[&str] = attrs!();
 
-/// https://doc.rust-lang.org/reference/attributes.html#built-in-attributes-index
+/// <https://doc.rust-lang.org/reference/attributes.html#built-in-attributes-index>
 // Keep these sorted for the binary search!
 const ATTRIBUTES: &[AttrCompletion] = &[
     attr("allow(…)", Some("allow"), Some("allow(${0:lint})")),
@@ -304,7 +328,7 @@ mod tests {
 
     use expect_test::{expect, Expect};
 
-    use crate::{test_utils::completion_list, CompletionKind};
+    use crate::tests::completion_list;
 
     #[test]
     fn attributes_are_sorted() {
@@ -323,7 +347,7 @@ fn attributes_are_sorted() {
     }
 
     fn check(ra_fixture: &str, expect: Expect) {
-        let actual = completion_list(ra_fixture, CompletionKind::Attribute);
+        let actual = completion_list(ra_fixture);
         expect.assert_eq(&actual);
     }
 
@@ -774,6 +798,7 @@ fn complete_attribute_on_fn() {
 
     #[test]
     fn complete_attribute_on_expr() {
+        cov_mark::check!(no_keyword_completion_in_attr_of_expr);
         check(
             r#"fn main() { #[$0] foo() }"#,
             expect![[r#"
@@ -831,4 +856,15 @@ fn complete_attribute_in_source_file_end() {
             "#]],
         );
     }
+
+    #[test]
+    fn test_cfg() {
+        check(
+            r#"#[cfg(target_endian = $0"#,
+            expect![[r#"
+                at little
+                at big
+"#]],
+        );
+    }
 }