Skip to content

Commit 347695a

Browse files
committed
Auto merge of #15528 - Veykril:r-a-cfg, r=Veykril
Enable `rust_analyzer` for cfgs when code is being analyzed by rust-analyzer This allows one to have r-a skip analysis/replace macros that work not well with r-a at all by gating them behind this cfg (an example being the `quote` macro which r-a struggles with in terms of performance).
2 parents b67606c + fddef42 commit 347695a

File tree

10 files changed

+170
-59
lines changed

10 files changed

+170
-59
lines changed

crates/base-db/src/fixture.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,8 @@ impl ChangeFixture {
179179
meta.edition,
180180
Some(crate_name.clone().into()),
181181
version,
182-
meta.cfg,
183-
Default::default(),
182+
meta.cfg.clone(),
183+
Some(meta.cfg),
184184
meta.env,
185185
false,
186186
origin,
@@ -200,7 +200,7 @@ impl ChangeFixture {
200200
} else if meta.path == "/main.rs" || meta.path == "/lib.rs" {
201201
assert!(default_crate_root.is_none());
202202
default_crate_root = Some(file_id);
203-
default_cfg = meta.cfg;
203+
default_cfg.extend(meta.cfg.into_iter());
204204
default_env.extend(meta.env.iter().map(|(x, y)| (x.to_owned(), y.to_owned())));
205205
default_target_data_layout = meta.target_data_layout;
206206
}
@@ -220,8 +220,8 @@ impl ChangeFixture {
220220
Edition::CURRENT,
221221
Some(CrateName::new("test").unwrap().into()),
222222
None,
223-
default_cfg,
224-
Default::default(),
223+
default_cfg.clone(),
224+
Some(default_cfg),
225225
default_env,
226226
false,
227227
CrateOrigin::Local { repo: None, name: None },

crates/cfg/src/lib.rs

+26
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,32 @@ impl CfgOptions {
8686
}
8787
}
8888

89+
impl Extend<CfgAtom> for CfgOptions {
90+
fn extend<T: IntoIterator<Item = CfgAtom>>(&mut self, iter: T) {
91+
iter.into_iter().for_each(|cfg_flag| _ = self.enabled.insert(cfg_flag));
92+
}
93+
}
94+
95+
impl IntoIterator for CfgOptions {
96+
type Item = <FxHashSet<CfgAtom> as IntoIterator>::Item;
97+
98+
type IntoIter = <FxHashSet<CfgAtom> as IntoIterator>::IntoIter;
99+
100+
fn into_iter(self) -> Self::IntoIter {
101+
<FxHashSet<CfgAtom> as IntoIterator>::into_iter(self.enabled)
102+
}
103+
}
104+
105+
impl<'a> IntoIterator for &'a CfgOptions {
106+
type Item = <&'a FxHashSet<CfgAtom> as IntoIterator>::Item;
107+
108+
type IntoIter = <&'a FxHashSet<CfgAtom> as IntoIterator>::IntoIter;
109+
110+
fn into_iter(self) -> Self::IntoIter {
111+
<&FxHashSet<CfgAtom> as IntoIterator>::into_iter(&self.enabled)
112+
}
113+
}
114+
89115
#[derive(Default, Clone, Debug, PartialEq, Eq)]
90116
pub struct CfgDiff {
91117
// Invariants: No duplicates, no atom that's both in `enable` and `disable`.

crates/ide-completion/src/completions/attribute/cfg.rs

+34-23
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
//! Completion for cfg
22
3-
use std::iter;
4-
53
use ide_db::SymbolKind;
64
use itertools::Itertools;
7-
use syntax::SyntaxKind;
5+
use syntax::{algo, ast::Ident, AstToken, Direction, NodeOrToken, SyntaxKind};
86

97
use crate::{completions::Completions, context::CompletionContext, CompletionItem};
108

@@ -15,31 +13,44 @@ pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext<'_>) {
1513
acc.add(completion.build(ctx.db));
1614
};
1715

18-
let previous = iter::successors(ctx.original_token.prev_token(), |t| {
19-
(matches!(t.kind(), SyntaxKind::EQ) || t.kind().is_trivia())
20-
.then(|| t.prev_token())
21-
.flatten()
22-
})
23-
.find(|t| matches!(t.kind(), SyntaxKind::IDENT));
24-
25-
match previous.as_ref().map(|p| p.text()) {
26-
Some("target_arch") => KNOWN_ARCH.iter().copied().for_each(add_completion),
27-
Some("target_env") => KNOWN_ENV.iter().copied().for_each(add_completion),
28-
Some("target_os") => KNOWN_OS.iter().copied().for_each(add_completion),
29-
Some("target_vendor") => KNOWN_VENDOR.iter().copied().for_each(add_completion),
30-
Some("target_endian") => ["little", "big"].into_iter().for_each(add_completion),
31-
Some(name) => ctx.krate.potential_cfg(ctx.db).get_cfg_values(name).cloned().for_each(|s| {
32-
let insert_text = format!(r#""{s}""#);
33-
let mut item = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), s);
34-
item.insert_text(insert_text);
16+
// FIXME: Move this into context/analysis.rs
17+
let previous = ctx
18+
.original_token
19+
.prev_token()
20+
.and_then(|it| {
21+
if matches!(it.kind(), SyntaxKind::EQ) {
22+
Some(it.into())
23+
} else {
24+
algo::non_trivia_sibling(it.into(), Direction::Prev)
25+
}
26+
})
27+
.filter(|t| matches!(t.kind(), SyntaxKind::EQ))
28+
.and_then(|it| algo::non_trivia_sibling(it.prev_sibling_or_token()?, Direction::Prev))
29+
.map(|it| match it {
30+
NodeOrToken::Node(_) => None,
31+
NodeOrToken::Token(t) => Ident::cast(t),
32+
});
33+
match previous {
34+
Some(None) => (),
35+
Some(Some(p)) => match p.text() {
36+
"target_arch" => KNOWN_ARCH.iter().copied().for_each(add_completion),
37+
"target_env" => KNOWN_ENV.iter().copied().for_each(add_completion),
38+
"target_os" => KNOWN_OS.iter().copied().for_each(add_completion),
39+
"target_vendor" => KNOWN_VENDOR.iter().copied().for_each(add_completion),
40+
"target_endian" => ["little", "big"].into_iter().for_each(add_completion),
41+
name => ctx.krate.potential_cfg(ctx.db).get_cfg_values(name).cloned().for_each(|s| {
42+
let insert_text = format!(r#""{s}""#);
43+
let mut item = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), s);
44+
item.insert_text(insert_text);
3545

36-
acc.add(item.build(ctx.db));
37-
}),
46+
acc.add(item.build(ctx.db));
47+
}),
48+
},
3849
None => ctx.krate.potential_cfg(ctx.db).get_cfg_keys().cloned().unique().for_each(|s| {
3950
let item = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), s);
4051
acc.add(item.build(ctx.db));
4152
}),
42-
};
53+
}
4354
}
4455

4556
const KNOWN_ARCH: [&str; 20] = [

crates/ide-completion/src/tests/attribute.rs

+33-5
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,6 @@ struct Foo;
6666
)
6767
}
6868

69-
#[test]
70-
fn inside_nested_attr() {
71-
check(r#"#[cfg($0)]"#, expect![[]])
72-
}
73-
7469
#[test]
7570
fn with_existing_attr() {
7671
check(
@@ -635,6 +630,32 @@ struct Foo;
635630
mod cfg {
636631
use super::*;
637632

633+
#[test]
634+
fn inside_cfg() {
635+
check(
636+
r#"
637+
//- /main.rs cfg:test,dbg=false,opt_level=2
638+
#[cfg($0)]
639+
"#,
640+
expect![[r#"
641+
ba dbg
642+
ba opt_level
643+
ba test
644+
"#]],
645+
);
646+
check(
647+
r#"
648+
//- /main.rs cfg:test,dbg=false,opt_level=2
649+
#[cfg(b$0)]
650+
"#,
651+
expect![[r#"
652+
ba dbg
653+
ba opt_level
654+
ba test
655+
"#]],
656+
);
657+
}
658+
638659
#[test]
639660
fn cfg_target_endian() {
640661
check(
@@ -644,6 +665,13 @@ mod cfg {
644665
ba little
645666
"#]],
646667
);
668+
check(
669+
r#"#[cfg(target_endian = b$0"#,
670+
expect![[r#"
671+
ba big
672+
ba little
673+
"#]],
674+
);
647675
}
648676
}
649677

crates/ide-db/src/search.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,6 @@ impl Definition {
221221
}
222222

223223
// def is crate root
224-
// FIXME: We don't do searches for crates currently, as a crate does not actually have a single name
225224
if let &Definition::Module(module) = self {
226225
if module.is_crate_root() {
227226
return SearchScope::reverse_dependencies(db, module.krate());
@@ -393,7 +392,10 @@ impl<'a> FindUsages<'a> {
393392
let name = match self.def {
394393
// special case crate modules as these do not have a proper name
395394
Definition::Module(module) if module.is_crate_root() => {
396-
// FIXME: This assumes the crate name is always equal to its display name when it really isn't
395+
// FIXME: This assumes the crate name is always equal to its display name when it
396+
// really isn't
397+
// we should instead look at the dependency edge name and recursively search our way
398+
// up the ancestors
397399
module
398400
.krate()
399401
.display_name(self.sema.db)

crates/project-model/src/workspace.rs

+23-13
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//! metadata` or `rust-project.json`) into representation stored in the salsa
33
//! database -- `CrateGraph`.
44
5-
use std::{collections::VecDeque, fmt, fs, process::Command, str::FromStr, sync};
5+
use std::{collections::VecDeque, fmt, fs, iter, process::Command, str::FromStr, sync};
66

77
use anyhow::{format_err, Context};
88
use base_db::{
@@ -730,6 +730,7 @@ fn project_json_to_crate_graph(
730730
)
731731
});
732732

733+
let r_a_cfg_flag = CfgFlag::Atom("rust_analyzer".to_owned());
733734
let mut cfg_cache: FxHashMap<&str, Vec<CfgFlag>> = FxHashMap::default();
734735
let crates: FxHashMap<CrateId, CrateId> = project
735736
.crates()
@@ -765,7 +766,12 @@ fn project_json_to_crate_graph(
765766
*edition,
766767
display_name.clone(),
767768
version.clone(),
768-
target_cfgs.iter().chain(cfg.iter()).cloned().collect(),
769+
target_cfgs
770+
.iter()
771+
.chain(cfg.iter())
772+
.chain(iter::once(&r_a_cfg_flag))
773+
.cloned()
774+
.collect(),
769775
None,
770776
env,
771777
*is_proc_macro,
@@ -820,7 +826,7 @@ fn cargo_to_crate_graph(
820826
sysroot: Option<&Sysroot>,
821827
rustc_cfg: Vec<CfgFlag>,
822828
override_cfg: &CfgOverrides,
823-
// Don't compute cfg and use this if present
829+
// Don't compute cfg and use this if present, only used for the sysroot experiment hack
824830
forced_cfg: Option<CfgOptions>,
825831
build_scripts: &WorkspaceBuildScripts,
826832
target_layout: TargetLayoutLoadResult,
@@ -842,12 +848,7 @@ fn cargo_to_crate_graph(
842848
None => (SysrootPublicDeps::default(), None),
843849
};
844850

845-
let cfg_options = {
846-
let mut cfg_options = CfgOptions::default();
847-
cfg_options.extend(rustc_cfg);
848-
cfg_options.insert_atom("debug_assertions".into());
849-
cfg_options
850-
};
851+
let cfg_options = create_cfg_options(rustc_cfg);
851852

852853
// Mapping of a package to its library target
853854
let mut pkg_to_lib_crate = FxHashMap::default();
@@ -866,6 +867,9 @@ fn cargo_to_crate_graph(
866867
if cargo[pkg].is_local {
867868
cfg_options.insert_atom("test".into());
868869
}
870+
if cargo[pkg].is_member {
871+
cfg_options.insert_atom("rust_analyzer".into());
872+
}
869873

870874
if !override_cfg.global.is_empty() {
871875
cfg_options.apply_diff(override_cfg.global.clone());
@@ -1029,8 +1033,8 @@ fn detached_files_to_crate_graph(
10291033
None => (SysrootPublicDeps::default(), None),
10301034
};
10311035

1032-
let mut cfg_options = CfgOptions::default();
1033-
cfg_options.extend(rustc_cfg);
1036+
let mut cfg_options = create_cfg_options(rustc_cfg);
1037+
cfg_options.insert_atom("rust_analyzer".into());
10341038

10351039
for detached_file in detached_files {
10361040
let file_id = match load(detached_file) {
@@ -1295,8 +1299,7 @@ fn sysroot_to_crate_graph(
12951299
channel: Option<ReleaseChannel>,
12961300
) -> (SysrootPublicDeps, Option<CrateId>) {
12971301
let _p = profile::span("sysroot_to_crate_graph");
1298-
let mut cfg_options = CfgOptions::default();
1299-
cfg_options.extend(rustc_cfg.clone());
1302+
let cfg_options = create_cfg_options(rustc_cfg.clone());
13001303
let sysroot_crates: FxHashMap<SysrootCrate, CrateId> = match &sysroot.hack_cargo_workspace {
13011304
Some(cargo) => handle_hack_cargo_workspace(
13021305
load,
@@ -1475,3 +1478,10 @@ fn inject_cargo_env(package: &PackageData, env: &mut Env) {
14751478

14761479
env.set("CARGO_PKG_LICENSE_FILE", String::new());
14771480
}
1481+
1482+
fn create_cfg_options(rustc_cfg: Vec<CfgFlag>) -> CfgOptions {
1483+
let mut cfg_options = CfgOptions::default();
1484+
cfg_options.extend(rustc_cfg);
1485+
cfg_options.insert_atom("debug_assertions".into());
1486+
cfg_options
1487+
}

crates/project-model/test_data/output/cargo_hello_world_project_model.txt

+4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
cfg_options: CfgOptions(
1919
[
2020
"debug_assertions",
21+
"rust_analyzer",
2122
"test",
2223
],
2324
),
@@ -81,6 +82,7 @@
8182
cfg_options: CfgOptions(
8283
[
8384
"debug_assertions",
85+
"rust_analyzer",
8486
"test",
8587
],
8688
),
@@ -151,6 +153,7 @@
151153
cfg_options: CfgOptions(
152154
[
153155
"debug_assertions",
156+
"rust_analyzer",
154157
"test",
155158
],
156159
),
@@ -221,6 +224,7 @@
221224
cfg_options: CfgOptions(
222225
[
223226
"debug_assertions",
227+
"rust_analyzer",
224228
"test",
225229
],
226230
),

crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt

+4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
cfg_options: CfgOptions(
1919
[
2020
"debug_assertions",
21+
"rust_analyzer",
2122
"test",
2223
],
2324
),
@@ -81,6 +82,7 @@
8182
cfg_options: CfgOptions(
8283
[
8384
"debug_assertions",
85+
"rust_analyzer",
8486
"test",
8587
],
8688
),
@@ -151,6 +153,7 @@
151153
cfg_options: CfgOptions(
152154
[
153155
"debug_assertions",
156+
"rust_analyzer",
154157
"test",
155158
],
156159
),
@@ -221,6 +224,7 @@
221224
cfg_options: CfgOptions(
222225
[
223226
"debug_assertions",
227+
"rust_analyzer",
224228
"test",
225229
],
226230
),

0 commit comments

Comments
 (0)