Complete repr attribute parameters

This commit is contained in:
Lukas Wirth 2021-06-17 21:15:35 +02:00
parent 84507a0b9c
commit c1bf1f88ad
3 changed files with 202 additions and 2 deletions

View file

@ -17,12 +17,14 @@ use crate::{
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);

View file

@ -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
"#]],
);
}
}

View 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);