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 ide_db::RootDatabase;
44 use test_fixture::WithFixture;
45
46 use crate::{DiagnosticCode, DiagnosticsConfig, tests::check_diagnostics_with_config};
47
48 #[track_caller]
49 pub(crate) fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
50 let config = DiagnosticsConfig {
51 disabled: std::iter::once("unlinked-file".to_owned()).collect(),
52 ..DiagnosticsConfig::test_sample()
53 };
54 check_diagnostics_with_config(config, ra_fixture)
55 }
56
57 #[test]
58 fn cfg_diagnostics() {
59 check(
60 r#"
61fn f() {
62 // The three g̶e̶n̶d̶e̶r̶s̶ statements:
63
64 #[cfg(a)] fn f() {} // Item statement
65 //^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
66 #[cfg(a)] {} // Expression statement
67 //^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
68 #[cfg(a)] let x = 0; // let statement
69 //^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
70
71 fn abc() {}
72 abc(#[cfg(a)] 0);
73 //^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
74 let x = Struct {
75 #[cfg(a)] f: 0,
76 //^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
77 };
78 match () {
79 () => (),
80 #[cfg(a)] () => (),
81 //^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
82 }
83
84 #[cfg(a)] 0 // Trailing expression of block
85 //^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
86}
87 "#,
88 );
89 }
90
91 #[test]
92 fn inactive_item() {
93 check(
96 r#"
97 #[cfg(no)] pub fn f() {}
98 //^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no is disabled
99
100 #[cfg(no)] #[cfg(no2)] mod m;
101 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no is disabled
102
103 #[cfg(all(not(a), b))] enum E {}
104 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: b is disabled
105
106 #[cfg(feature = "std")] use std;
107 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: feature = "std" is disabled
108
109 #[cfg(any())] pub fn f() {}
110 //^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives
111"#,
112 );
113 }
114
115 #[test]
116 fn inactive_assoc_item() {
117 check(
118 r#"
119struct Foo;
120impl Foo {
121 #[cfg(any())] pub fn f() {}
122 //^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives
123}
124
125trait Bar {
126 #[cfg(any())] pub fn f() {}
127 //^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives
128}
129"#,
130 );
131 }
132
133 #[test]
135 fn inactive_via_cfg_attr() {
136 check(
137 r#"
138 #[cfg_attr(not(never), cfg(no))] fn f() {}
139 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no is disabled
140
141 #[cfg_attr(not(never), cfg(not(no)))] fn f() {}
142
143 #[cfg_attr(never, cfg(no))] fn g() {}
144
145 #[cfg_attr(not(never), inline, cfg(no))] fn h() {}
146 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no is disabled
147"#,
148 );
149 }
150
151 #[test]
152 fn inactive_fields_and_variants() {
153 check(
154 r#"
155enum Foo {
156 #[cfg(a)] Bar,
157//^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
158 Baz {
159 #[cfg(a)] baz: String,
160 //^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
161 },
162 Qux(#[cfg(a)] String),
163 //^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
164}
165
166struct Baz {
167 #[cfg(a)] baz: String,
168//^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
169}
170
171struct Qux(#[cfg(a)] String);
172 //^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
173
174union FooBar {
175 #[cfg(a)] baz: u32,
176//^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
177}
178"#,
179 );
180 }
181
182 #[test]
183 fn modules() {
184 check(
185 r#"
186//- /main.rs
187 #[cfg(outline)] mod outline;
188//^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: outline is disabled
189
190 mod outline_inner;
191//^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: outline_inner is disabled
192
193 #[cfg(inline)] mod inline {}
194//^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: inline is disabled
195
196//- /outline_inner.rs
197#![cfg(outline_inner)]
198//- /outline.rs
199"#,
200 );
201 }
202
203 #[test]
204 fn cfg_true_false() {
205 check(
206 r#"
207 #[cfg(false)] fn inactive() {}
208//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: false is disabled
209
210 #[cfg(true)] fn active() {}
211
212 #[cfg(any(not(true), false))] fn inactive2() {}
213//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: true is enabled and false is disabled
214
215"#,
216 );
217 }
218
219 #[test]
220 fn inactive_crate() {
221 let db = RootDatabase::with_files(
222 r#"
223#![cfg(false)]
224
225fn foo() {}
226 "#,
227 );
228 let file_id = db.test_crate().root_file_id(&db);
229 let diagnostics = hir::attach_db(&db, || {
230 crate::full_diagnostics(
231 &db,
232 &DiagnosticsConfig::test_sample(),
233 &ide_db::assists::AssistResolveStrategy::All,
234 file_id.file_id(&db),
235 )
236 });
237 let [inactive_code] = &*diagnostics else {
238 panic!("expected one inactive_code diagnostic, found {diagnostics:#?}");
239 };
240 assert_eq!(
241 inactive_code.code,
242 DiagnosticCode::Ra("inactive-code", ide_db::Severity::WeakWarning)
243 );
244 assert_eq!(
245 inactive_code.message,
246 "code is inactive due to #[cfg] directives: false is disabled",
247 );
248 assert!(inactive_code.fixes.is_none());
249 let full_file_range = file_id.parse(&db).syntax_node().text_range();
250 assert_eq!(
251 inactive_code.range,
252 ide_db::FileRange { file_id: file_id.file_id(&db), range: full_file_range },
253 );
254 }
255}