From 853f8a21f7e403201617dcf93c5340859b35ac1b Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 29 Aug 2023 10:57:24 +0200 Subject: [PATCH] Fix cfg completions not working --- crates/base-db/src/fixture.rs | 10 ++-- crates/cfg/src/lib.rs | 26 +++++++++ .../src/completions/attribute/cfg.rs | 57 +++++++++++-------- crates/ide-completion/src/tests/attribute.rs | 38 +++++++++++-- 4 files changed, 98 insertions(+), 33 deletions(-) diff --git a/crates/base-db/src/fixture.rs b/crates/base-db/src/fixture.rs index aaac0fc379..3f5ccb621c 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 183b9b7d27..0aeb0b0505 100644 --- a/crates/cfg/src/lib.rs +++ b/crates/cfg/src/lib.rs @@ -86,6 +86,32 @@ impl CfgOptions { } } +impl Extend for CfgOptions { + fn extend>(&mut self, iter: T) { + iter.into_iter().for_each(|cfg_flag| _ = self.enabled.insert(cfg_flag)); + } +} + +impl IntoIterator for CfgOptions { + type Item = as IntoIterator>::Item; + + type IntoIter = as IntoIterator>::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + as IntoIterator>::into_iter(self.enabled) + } +} + +impl<'a> IntoIterator for &'a CfgOptions { + type Item = <&'a FxHashSet as IntoIterator>::Item; + + type IntoIter = <&'a FxHashSet as IntoIterator>::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + <&FxHashSet 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 62bdb6ee68..87a286778e 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)); + // 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); - 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); - - 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 1aaf395872..d8c134c533 100644 --- a/crates/ide-completion/src/tests/attribute.rs +++ b/crates/ide-completion/src/tests/attribute.rs @@ -66,11 +66,6 @@ struct Foo; ) } -#[test] -fn inside_nested_attr() { - check(r#"#[cfg($0)]"#, expect![[]]) -} - #[test] fn with_existing_attr() { check( @@ -635,6 +630,32 @@ struct Foo; 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( @@ -644,6 +665,13 @@ mod cfg { ba little "#]], ); + check( + r#"#[cfg(target_endian = b$0"#, + expect![[r#" + ba big + ba little + "#]], + ); } }