diff options
Diffstat (limited to 'crates/ide_diagnostics/src/handlers/inactive_code.rs')
-rw-r--r-- | crates/ide_diagnostics/src/handlers/inactive_code.rs | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/crates/ide_diagnostics/src/handlers/inactive_code.rs b/crates/ide_diagnostics/src/handlers/inactive_code.rs new file mode 100644 index 000000000..4b722fd64 --- /dev/null +++ b/crates/ide_diagnostics/src/handlers/inactive_code.rs | |||
@@ -0,0 +1,116 @@ | |||
1 | use cfg::DnfExpr; | ||
2 | use stdx::format_to; | ||
3 | |||
4 | use crate::{Diagnostic, DiagnosticsContext, Severity}; | ||
5 | |||
6 | // Diagnostic: inactive-code | ||
7 | // | ||
8 | // This diagnostic is shown for code with inactive `#[cfg]` attributes. | ||
9 | pub(crate) fn inactive_code( | ||
10 | ctx: &DiagnosticsContext<'_>, | ||
11 | d: &hir::InactiveCode, | ||
12 | ) -> Option<Diagnostic> { | ||
13 | // If there's inactive code somewhere in a macro, don't propagate to the call-site. | ||
14 | if d.node.file_id.expansion_info(ctx.sema.db).is_some() { | ||
15 | return None; | ||
16 | } | ||
17 | |||
18 | let inactive = DnfExpr::new(d.cfg.clone()).why_inactive(&d.opts); | ||
19 | let mut message = "code is inactive due to #[cfg] directives".to_string(); | ||
20 | |||
21 | if let Some(inactive) = inactive { | ||
22 | format_to!(message, ": {}", inactive); | ||
23 | } | ||
24 | |||
25 | let res = Diagnostic::new( | ||
26 | "inactive-code", | ||
27 | message, | ||
28 | ctx.sema.diagnostics_display_range(d.node.clone()).range, | ||
29 | ) | ||
30 | .severity(Severity::WeakWarning) | ||
31 | .with_unused(true); | ||
32 | Some(res) | ||
33 | } | ||
34 | |||
35 | #[cfg(test)] | ||
36 | mod tests { | ||
37 | use crate::{tests::check_diagnostics_with_config, DiagnosticsConfig}; | ||
38 | |||
39 | pub(crate) fn check(ra_fixture: &str) { | ||
40 | let config = DiagnosticsConfig::default(); | ||
41 | check_diagnostics_with_config(config, ra_fixture) | ||
42 | } | ||
43 | |||
44 | #[test] | ||
45 | fn cfg_diagnostics() { | ||
46 | check( | ||
47 | r#" | ||
48 | fn f() { | ||
49 | // The three g̶e̶n̶d̶e̶r̶s̶ statements: | ||
50 | |||
51 | #[cfg(a)] fn f() {} // Item statement | ||
52 | //^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled | ||
53 | #[cfg(a)] {} // Expression statement | ||
54 | //^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled | ||
55 | #[cfg(a)] let x = 0; // let statement | ||
56 | //^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled | ||
57 | |||
58 | abc(#[cfg(a)] 0); | ||
59 | //^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled | ||
60 | let x = Struct { | ||
61 | #[cfg(a)] f: 0, | ||
62 | //^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled | ||
63 | }; | ||
64 | match () { | ||
65 | () => (), | ||
66 | #[cfg(a)] () => (), | ||
67 | //^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled | ||
68 | } | ||
69 | |||
70 | #[cfg(a)] 0 // Trailing expression of block | ||
71 | //^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled | ||
72 | } | ||
73 | "#, | ||
74 | ); | ||
75 | } | ||
76 | |||
77 | #[test] | ||
78 | fn inactive_item() { | ||
79 | // Additional tests in `cfg` crate. This only tests disabled cfgs. | ||
80 | |||
81 | check( | ||
82 | r#" | ||
83 | #[cfg(no)] pub fn f() {} | ||
84 | //^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled | ||
85 | |||
86 | #[cfg(no)] #[cfg(no2)] mod m; | ||
87 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no and no2 are disabled | ||
88 | |||
89 | #[cfg(all(not(a), b))] enum E {} | ||
90 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: b is disabled | ||
91 | |||
92 | #[cfg(feature = "std")] use std; | ||
93 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: feature = "std" is disabled | ||
94 | "#, | ||
95 | ); | ||
96 | } | ||
97 | |||
98 | /// Tests that `cfg` attributes behind `cfg_attr` is handled properly. | ||
99 | #[test] | ||
100 | fn inactive_via_cfg_attr() { | ||
101 | cov_mark::check!(cfg_attr_active); | ||
102 | check( | ||
103 | r#" | ||
104 | #[cfg_attr(not(never), cfg(no))] fn f() {} | ||
105 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled | ||
106 | |||
107 | #[cfg_attr(not(never), cfg(not(no)))] fn f() {} | ||
108 | |||
109 | #[cfg_attr(never, cfg(no))] fn g() {} | ||
110 | |||
111 | #[cfg_attr(not(never), inline, cfg(no))] fn h() {} | ||
112 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled | ||
113 | "#, | ||
114 | ); | ||
115 | } | ||
116 | } | ||