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