]> git.lizzy.rs Git - rust.git/commitdiff
Complete `repr` attribute parameters
authorLukas Wirth <lukastw97@gmail.com>
Thu, 17 Jun 2021 19:15:35 +0000 (21:15 +0200)
committerLukas Wirth <lukastw97@gmail.com>
Thu, 17 Jun 2021 19:15:49 +0000 (21:15 +0200)
crates/ide_completion/src/completions/attribute.rs
crates/ide_completion/src/completions/attribute/repr.rs [new file with mode: 0644]
crates/parser/src/grammar/params.rs

index f3b11e72dd1bd894accc385858a11c66819ddf95..9780d01aefef37333d6eca4dcfe851874b7622b8 100644 (file)
 
 mod derive;
 mod lint;
+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(), DEFAULT_LINTS);
diff --git a/crates/ide_completion/src/completions/attribute/repr.rs b/crates/ide_completion/src/completions/attribute/repr.rs
new file mode 100644 (file)
index 0000000..92a262a
--- /dev/null
@@ -0,0 +1,199 @@
+//! Completion for representations.
+
+use syntax::ast;
+
+use crate::{
+    context::CompletionContext,
+    item::{CompletionItem, CompletionItemKind, CompletionKind},
+    Completions,
+};
+
+pub(super) fn complete_repr(
+    acc: &mut Completions,
+    ctx: &CompletionContext,
+    derive_input: ast::TokenTree,
+) {
+    if let Some(existing_reprs) = super::parse_comma_sep_input(derive_input) {
+        for repr_completion in REPR_COMPLETIONS {
+            if existing_reprs
+                .iter()
+                .any(|it| repr_completion.label == it || repr_completion.collides.contains(&&**it))
+            {
+                continue;
+            }
+            let mut item = CompletionItem::new(
+                CompletionKind::Attribute,
+                ctx.source_range(),
+                repr_completion.label,
+            );
+            item.kind(CompletionItemKind::Attribute);
+            if let Some(lookup) = repr_completion.lookup {
+                item.lookup_by(lookup);
+            }
+            if let Some((snippet, cap)) = repr_completion.snippet.zip(ctx.config.snippet_cap) {
+                item.insert_snippet(cap, snippet);
+            }
+            item.add_to(acc);
+        }
+    }
+}
+
+struct ReprCompletion {
+    label: &'static str,
+    snippet: Option<&'static str>,
+    lookup: Option<&'static str>,
+    collides: &'static [&'static str],
+}
+
+const fn attr(label: &'static str, collides: &'static [&'static str]) -> ReprCompletion {
+    ReprCompletion { label, snippet: None, lookup: None, collides }
+}
+
+#[rustfmt::skip]
+const REPR_COMPLETIONS: &[ReprCompletion] = &[
+    ReprCompletion { label: "align($0)", snippet: Some("align($0)"), lookup: Some("align"), collides: &["transparent", "packed"] },
+    attr("packed", &["transparent", "align"]),
+    attr("transparent", &["C", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]),
+    attr("C", &["transparent"]),
+    attr("u8",     &["transparent", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]),
+    attr("u16",    &["transparent", "u8", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]),
+    attr("u32",    &["transparent", "u8", "u16", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]),
+    attr("u64",    &["transparent", "u8", "u16", "u32", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]),
+    attr("u128",   &["transparent", "u8", "u16", "u32", "u64", "usize", "i8", "i16", "i32", "i64", "i128", "isize"]),
+    attr("usize",  &["transparent", "u8", "u16", "u32", "u64", "u128", "i8", "i16", "i32", "i64", "i128", "isize"]),
+    attr("i8",     &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i16", "i32", "i64", "i128", "isize"]),
+    attr("i16",    &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i32", "i64", "i128", "isize"]),
+    attr("i32",    &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i64", "i128", "isize"]),
+    attr("i64",    &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i128", "isize"]),
+    attr("i28",    &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "isize"]),
+    attr("isize",  &["transparent", "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128"]),
+];
+
+#[cfg(test)]
+mod tests {
+    use expect_test::{expect, Expect};
+
+    use crate::tests::completion_list;
+
+    fn check(ra_fixture: &str, expect: Expect) {
+        let actual = completion_list(ra_fixture);
+        expect.assert_eq(&actual);
+    }
+
+    #[test]
+    fn no_completion_for_incorrect_repr() {
+        check(r#"#[repr{$0)] struct Test;"#, expect![[]])
+    }
+
+    #[test]
+    fn empty() {
+        check(
+            r#"#[repr($0)] struct Test;"#,
+            expect![[r#"
+                at align($0)
+                at packed
+                at transparent
+                at C
+                at u8
+                at u16
+                at u32
+                at u64
+                at u128
+                at usize
+                at i8
+                at i16
+                at i32
+                at i64
+                at i28
+                at isize
+            "#]],
+        );
+    }
+
+    #[test]
+    fn transparent() {
+        check(r#"#[repr(transparent, $0)] struct Test;"#, expect![[r#""#]]);
+    }
+
+    #[test]
+    fn align() {
+        check(
+            r#"#[repr(align(1), $0)] struct Test;"#,
+            expect![[r#"
+                at align($0)
+                at transparent
+                at C
+                at u8
+                at u16
+                at u32
+                at u64
+                at u128
+                at usize
+                at i8
+                at i16
+                at i32
+                at i64
+                at i28
+                at isize
+            "#]],
+        );
+    }
+
+    #[test]
+    fn packed() {
+        check(
+            r#"#[repr(packed, $0)] struct Test;"#,
+            expect![[r#"
+                at transparent
+                at C
+                at u8
+                at u16
+                at u32
+                at u64
+                at u128
+                at usize
+                at i8
+                at i16
+                at i32
+                at i64
+                at i28
+                at isize
+            "#]],
+        );
+    }
+
+    #[test]
+    fn c() {
+        check(
+            r#"#[repr(C, $0)] struct Test;"#,
+            expect![[r#"
+                at align($0)
+                at packed
+                at u8
+                at u16
+                at u32
+                at u64
+                at u128
+                at usize
+                at i8
+                at i16
+                at i32
+                at i64
+                at i28
+                at isize
+            "#]],
+        );
+    }
+
+    #[test]
+    fn prim() {
+        check(
+            r#"#[repr(usize, $0)] struct Test;"#,
+            expect![[r#"
+                at align($0)
+                at packed
+                at C
+            "#]],
+        );
+    }
+}
index 01ee26a5304e972a552ab32392765ede1a032bc1..5a78675fb4fbaeadb34bf382b41e5dfdedeade66 100644 (file)
@@ -184,8 +184,7 @@ fn opt_self_param(p: &mut Parser, m: Marker) -> Result<(), Marker> {
         if !matches!(
             (p.current(), la1, la2, la3),
             (T![&], T![self], _, _)
-                | (T![&], T![mut], T![self], _)
-                | (T![&], LIFETIME_IDENT, T![self], _)
+                | (T![&], T![mut] | LIFETIME_IDENT, T![self], _)
                 | (T![&], LIFETIME_IDENT, T![mut], T![self])
         ) {
             return Err(m);