ide_diagnostics/handlers/
inactive_code.rs1use cfg::DnfExpr;
2use stdx::format_to;
3
4use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext, Severity};
5
6pub(crate) fn inactive_code(
10 ctx: &DiagnosticsContext<'_>,
11 d: &hir::InactiveCode,
12) -> Option<Diagnostic> {
13 if d.node.file_id.is_macro() {
15 return None;
16 }
17
18 let inactive = DnfExpr::new(&d.cfg).why_inactive(&d.opts);
19 let mut message = "code is inactive due to #[cfg] directives".to_owned();
20
21 if let Some(inactive) = inactive {
22 let inactive_reasons = inactive.to_string();
23
24 if inactive_reasons.is_empty() {
25 format_to!(message);
26 } else {
27 format_to!(message, ": {}", inactive);
28 }
29 }
30 let res = Diagnostic::new(
32 DiagnosticCode::Ra("inactive-code", Severity::WeakWarning),
33 message,
34 ctx.sema.diagnostics_display_range(d.node),
35 )
36 .stable()
37 .with_unused(true);
38 Some(res)
39}
40
41#[cfg(test)]
42mod tests {
43 use crate::{DiagnosticsConfig, tests::check_diagnostics_with_config};
44
45 #[track_caller]
46 pub(crate) fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
47 let config = DiagnosticsConfig {
48 disabled: std::iter::once("unlinked-file".to_owned()).collect(),
49 ..DiagnosticsConfig::test_sample()
50 };
51 check_diagnostics_with_config(config, ra_fixture)
52 }
53
54 #[test]
55 fn cfg_diagnostics() {
56 check(
57 r#"
58fn f() {
59 // The three g̶e̶n̶d̶e̶r̶s̶ statements:
60
61 #[cfg(a)] fn f() {} // Item statement
62 //^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
63 #[cfg(a)] {} // Expression statement
64 //^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
65 #[cfg(a)] let x = 0; // let statement
66 //^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
67
68 fn abc() {}
69 abc(#[cfg(a)] 0);
70 //^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
71 let x = Struct {
72 #[cfg(a)] f: 0,
73 //^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
74 };
75 match () {
76 () => (),
77 #[cfg(a)] () => (),
78 //^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
79 }
80
81 #[cfg(a)] 0 // Trailing expression of block
82 //^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
83}
84 "#,
85 );
86 }
87
88 #[test]
89 fn inactive_item() {
90 check(
93 r#"
94 #[cfg(no)] pub fn f() {}
95 //^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no is disabled
96
97 #[cfg(no)] #[cfg(no2)] mod m;
98 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no is disabled
99
100 #[cfg(all(not(a), b))] enum E {}
101 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: b is disabled
102
103 #[cfg(feature = "std")] use std;
104 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: feature = "std" is disabled
105
106 #[cfg(any())] pub fn f() {}
107 //^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives
108"#,
109 );
110 }
111
112 #[test]
113 fn inactive_assoc_item() {
114 check(
115 r#"
116struct Foo;
117impl Foo {
118 #[cfg(any())] pub fn f() {}
119 //^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives
120}
121
122trait Bar {
123 #[cfg(any())] pub fn f() {}
124 //^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives
125}
126"#,
127 );
128 }
129
130 #[test]
132 fn inactive_via_cfg_attr() {
133 check(
134 r#"
135 #[cfg_attr(not(never), cfg(no))] fn f() {}
136 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no is disabled
137
138 #[cfg_attr(not(never), cfg(not(no)))] fn f() {}
139
140 #[cfg_attr(never, cfg(no))] fn g() {}
141
142 #[cfg_attr(not(never), inline, cfg(no))] fn h() {}
143 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no is disabled
144"#,
145 );
146 }
147
148 #[test]
149 fn inactive_fields_and_variants() {
150 check(
151 r#"
152enum Foo {
153 #[cfg(a)] Bar,
154//^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
155 Baz {
156 #[cfg(a)] baz: String,
157 //^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
158 },
159 Qux(#[cfg(a)] String),
160 //^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
161}
162
163struct Baz {
164 #[cfg(a)] baz: String,
165//^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
166}
167
168struct Qux(#[cfg(a)] String);
169 //^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
170
171union FooBar {
172 #[cfg(a)] baz: u32,
173//^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
174}
175"#,
176 );
177 }
178
179 #[test]
180 fn modules() {
181 check(
182 r#"
183//- /main.rs
184 #[cfg(outline)] mod outline;
185//^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: outline is disabled
186
187 mod outline_inner;
188//^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: outline_inner is disabled
189
190 #[cfg(inline)] mod inline {}
191//^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: inline is disabled
192
193//- /outline_inner.rs
194#![cfg(outline_inner)]
195//- /outline.rs
196"#,
197 );
198 }
199
200 #[test]
201 fn cfg_true_false() {
202 check(
203 r#"
204 #[cfg(false)] fn inactive() {}
205//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: false is disabled
206
207 #[cfg(true)] fn active() {}
208
209 #[cfg(any(not(true)), false)] fn inactive2() {}
210//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: true is enabled
211
212"#,
213 );
214 }
215}