about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLukas Wirth <lukastw97@gmail.com>2023-08-29 10:57:24 +0200
committerLukas Wirth <lukastw97@gmail.com>2023-09-08 10:49:15 +0200
commit853f8a21f7e403201617dcf93c5340859b35ac1b (patch)
treeefc7f1c49aa3fd283c6197d6d929711a0e1bc753
parentca6ddd8ea3f93bc6c32ec732426691e917175a2f (diff)
downloadrust-853f8a21f7e403201617dcf93c5340859b35ac1b.tar.gz
rust-853f8a21f7e403201617dcf93c5340859b35ac1b.zip
Fix cfg completions not working
-rw-r--r--crates/base-db/src/fixture.rs10
-rw-r--r--crates/cfg/src/lib.rs26
-rw-r--r--crates/ide-completion/src/completions/attribute/cfg.rs57
-rw-r--r--crates/ide-completion/src/tests/attribute.rs38
4 files changed, 98 insertions, 33 deletions
diff --git a/crates/base-db/src/fixture.rs b/crates/base-db/src/fixture.rs
index aaac0fc3790..3f5ccb621c7 100644
--- a/crates/base-db/src/fixture.rs
+++ b/crates/base-db/src/fixture.rs
@@ -179,8 +179,8 @@ impl ChangeFixture {
                     meta.edition,
                     Some(crate_name.clone().into()),
                     version,
-                    meta.cfg,
-                    Default::default(),
+                    meta.cfg.clone(),
+                    Some(meta.cfg),
                     meta.env,
                     false,
                     origin,
@@ -200,7 +200,7 @@ impl ChangeFixture {
             } else if meta.path == "/main.rs" || meta.path == "/lib.rs" {
                 assert!(default_crate_root.is_none());
                 default_crate_root = Some(file_id);
-                default_cfg = meta.cfg;
+                default_cfg.extend(meta.cfg.into_iter());
                 default_env.extend(meta.env.iter().map(|(x, y)| (x.to_owned(), y.to_owned())));
                 default_target_data_layout = meta.target_data_layout;
             }
@@ -220,8 +220,8 @@ impl ChangeFixture {
                 Edition::CURRENT,
                 Some(CrateName::new("test").unwrap().into()),
                 None,
-                default_cfg,
-                Default::default(),
+                default_cfg.clone(),
+                Some(default_cfg),
                 default_env,
                 false,
                 CrateOrigin::Local { repo: None, name: None },
diff --git a/crates/cfg/src/lib.rs b/crates/cfg/src/lib.rs
index 183b9b7d278..0aeb0b05052 100644
--- a/crates/cfg/src/lib.rs
+++ b/crates/cfg/src/lib.rs
@@ -86,6 +86,32 @@ impl CfgOptions {
     }
 }
 
+impl Extend<CfgAtom> for CfgOptions {
+    fn extend<T: IntoIterator<Item = CfgAtom>>(&mut self, iter: T) {
+        iter.into_iter().for_each(|cfg_flag| _ = self.enabled.insert(cfg_flag));
+    }
+}
+
+impl IntoIterator for CfgOptions {
+    type Item = <FxHashSet<CfgAtom> as IntoIterator>::Item;
+
+    type IntoIter = <FxHashSet<CfgAtom> as IntoIterator>::IntoIter;
+
+    fn into_iter(self) -> Self::IntoIter {
+        <FxHashSet<CfgAtom> as IntoIterator>::into_iter(self.enabled)
+    }
+}
+
+impl<'a> IntoIterator for &'a CfgOptions {
+    type Item = <&'a FxHashSet<CfgAtom> as IntoIterator>::Item;
+
+    type IntoIter = <&'a FxHashSet<CfgAtom> as IntoIterator>::IntoIter;
+
+    fn into_iter(self) -> Self::IntoIter {
+        <&FxHashSet<CfgAtom> as IntoIterator>::into_iter(&self.enabled)
+    }
+}
+
 #[derive(Default, Clone, Debug, PartialEq, Eq)]
 pub struct CfgDiff {
     // Invariants: No duplicates, no atom that's both in `enable` and `disable`.
diff --git a/crates/ide-completion/src/completions/attribute/cfg.rs b/crates/ide-completion/src/completions/attribute/cfg.rs
index 62bdb6ee688..87a286778e6 100644
--- a/crates/ide-completion/src/completions/attribute/cfg.rs
+++ b/crates/ide-completion/src/completions/attribute/cfg.rs
@@ -1,10 +1,8 @@
 //! Completion for cfg
 
-use std::iter;
-
 use ide_db::SymbolKind;
 use itertools::Itertools;
-use syntax::SyntaxKind;
+use syntax::{algo, ast::Ident, AstToken, Direction, NodeOrToken, SyntaxKind};
 
 use crate::{completions::Completions, context::CompletionContext, CompletionItem};
 
@@ -15,31 +13,44 @@ pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext<'_>) {
         acc.add(completion.build(ctx.db));
     };
 
-    let previous = iter::successors(ctx.original_token.prev_token(), |t| {
-        (matches!(t.kind(), SyntaxKind::EQ) || t.kind().is_trivia())
-            .then(|| t.prev_token())
-            .flatten()
-    })
-    .find(|t| matches!(t.kind(), SyntaxKind::IDENT));
-
-    match previous.as_ref().map(|p| p.text()) {
-        Some("target_arch") => KNOWN_ARCH.iter().copied().for_each(add_completion),
-        Some("target_env") => KNOWN_ENV.iter().copied().for_each(add_completion),
-        Some("target_os") => KNOWN_OS.iter().copied().for_each(add_completion),
-        Some("target_vendor") => KNOWN_VENDOR.iter().copied().for_each(add_completion),
-        Some("target_endian") => ["little", "big"].into_iter().for_each(add_completion),
-        Some(name) => ctx.krate.potential_cfg(ctx.db).get_cfg_values(name).cloned().for_each(|s| {
-            let insert_text = format!(r#""{s}""#);
-            let mut item = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), s);
-            item.insert_text(insert_text);
+    // FIXME: Move this into context/analysis.rs
+    let previous = ctx
+        .original_token
+        .prev_token()
+        .and_then(|it| {
+            if matches!(it.kind(), SyntaxKind::EQ) {
+                Some(it.into())
+            } else {
+                algo::non_trivia_sibling(it.into(), Direction::Prev)
+            }
+        })
+        .filter(|t| matches!(t.kind(), SyntaxKind::EQ))
+        .and_then(|it| algo::non_trivia_sibling(it.prev_sibling_or_token()?, Direction::Prev))
+        .map(|it| match it {
+            NodeOrToken::Node(_) => None,
+            NodeOrToken::Token(t) => Ident::cast(t),
+        });
+    match previous {
+        Some(None) => (),
+        Some(Some(p)) => match p.text() {
+            "target_arch" => KNOWN_ARCH.iter().copied().for_each(add_completion),
+            "target_env" => KNOWN_ENV.iter().copied().for_each(add_completion),
+            "target_os" => KNOWN_OS.iter().copied().for_each(add_completion),
+            "target_vendor" => KNOWN_VENDOR.iter().copied().for_each(add_completion),
+            "target_endian" => ["little", "big"].into_iter().for_each(add_completion),
+            name => ctx.krate.potential_cfg(ctx.db).get_cfg_values(name).cloned().for_each(|s| {
+                let insert_text = format!(r#""{s}""#);
+                let mut item = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), s);
+                item.insert_text(insert_text);
 
-            acc.add(item.build(ctx.db));
-        }),
+                acc.add(item.build(ctx.db));
+            }),
+        },
         None => ctx.krate.potential_cfg(ctx.db).get_cfg_keys().cloned().unique().for_each(|s| {
             let item = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), s);
             acc.add(item.build(ctx.db));
         }),
-    };
+    }
 }
 
 const KNOWN_ARCH: [&str; 20] = [
diff --git a/crates/ide-completion/src/tests/attribute.rs b/crates/ide-completion/src/tests/attribute.rs
index 1aaf3958726..d8c134c533b 100644
--- a/crates/ide-completion/src/tests/attribute.rs
+++ b/crates/ide-completion/src/tests/attribute.rs
@@ -67,11 +67,6 @@ struct Foo;
 }
 
 #[test]
-fn inside_nested_attr() {
-    check(r#"#[cfg($0)]"#, expect![[]])
-}
-
-#[test]
 fn with_existing_attr() {
     check(
         r#"#[no_mangle] #[$0] mcall!();"#,
@@ -636,6 +631,32 @@ mod cfg {
     use super::*;
 
     #[test]
+    fn inside_cfg() {
+        check(
+            r#"
+//- /main.rs cfg:test,dbg=false,opt_level=2
+#[cfg($0)]
+"#,
+            expect![[r#"
+                ba dbg
+                ba opt_level
+                ba test
+            "#]],
+        );
+        check(
+            r#"
+//- /main.rs cfg:test,dbg=false,opt_level=2
+#[cfg(b$0)]
+"#,
+            expect![[r#"
+                ba dbg
+                ba opt_level
+                ba test
+            "#]],
+        );
+    }
+
+    #[test]
     fn cfg_target_endian() {
         check(
             r#"#[cfg(target_endian = $0"#,
@@ -644,6 +665,13 @@ mod cfg {
                 ba little
             "#]],
         );
+        check(
+            r#"#[cfg(target_endian = b$0"#,
+            expect![[r#"
+                ba big
+                ba little
+            "#]],
+        );
     }
 }