Unnamed repository; edit this file 'description' to name the repository.
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 0000000000..155bbc569d --- /dev/null +++ b/crates/ide-diagnostics/src/handlers/inactive_code.rs @@ -0,0 +1,116 @@ +use cfg::DnfExpr; +use stdx::format_to; + +use crate::{Diagnostic, DiagnosticsContext, Severity}; + +// Diagnostic: inactive-code +// +// This diagnostic is shown for code with inactive `#[cfg]` attributes. +pub(crate) fn inactive_code( + ctx: &DiagnosticsContext<'_>, + d: &hir::InactiveCode, +) -> Option<Diagnostic> { + // If there's inactive code somewhere in a macro, don't propagate to the call-site. + if d.node.file_id.is_macro() { + return None; + } + + let inactive = DnfExpr::new(d.cfg.clone()).why_inactive(&d.opts); + let mut message = "code is inactive due to #[cfg] directives".to_string(); + + if let Some(inactive) = inactive { + format_to!(message, ": {}", inactive); + } + + let res = Diagnostic::new( + "inactive-code", + message, + ctx.sema.diagnostics_display_range(d.node.clone()).range, + ) + .severity(Severity::WeakWarning) + .with_unused(true); + Some(res) +} + +#[cfg(test)] +mod tests { + use crate::{tests::check_diagnostics_with_config, DiagnosticsConfig}; + + pub(crate) fn check(ra_fixture: &str) { + let config = DiagnosticsConfig::default(); + check_diagnostics_with_config(config, ra_fixture) + } + + #[test] + fn cfg_diagnostics() { + check( + r#" +fn f() { + // The three g̶e̶n̶d̶e̶r̶s̶ statements: + + #[cfg(a)] fn f() {} // Item statement + //^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled + #[cfg(a)] {} // Expression statement + //^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled + #[cfg(a)] let x = 0; // let statement + //^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled + + abc(#[cfg(a)] 0); + //^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled + let x = Struct { + #[cfg(a)] f: 0, + //^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled + }; + match () { + () => (), + #[cfg(a)] () => (), + //^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled + } + + #[cfg(a)] 0 // Trailing expression of block + //^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled +} + "#, + ); + } + + #[test] + fn inactive_item() { + // Additional tests in `cfg` crate. This only tests disabled cfgs. + + check( + r#" + #[cfg(no)] pub fn f() {} + //^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no is disabled + + #[cfg(no)] #[cfg(no2)] mod m; + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no and no2 are disabled + + #[cfg(all(not(a), b))] enum E {} + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: b is disabled + + #[cfg(feature = "std")] use std; + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: feature = "std" is disabled +"#, + ); + } + + /// Tests that `cfg` attributes behind `cfg_attr` is handled properly. + #[test] + fn inactive_via_cfg_attr() { + cov_mark::check!(cfg_attr_active); + check( + r#" + #[cfg_attr(not(never), cfg(no))] fn f() {} + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no is disabled + + #[cfg_attr(not(never), cfg(not(no)))] fn f() {} + + #[cfg_attr(never, cfg(no))] fn g() {} + + #[cfg_attr(not(never), inline, cfg(no))] fn h() {} + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no is disabled +"#, + ); + } +} |