diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-06-13 16:46:09 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2021-06-13 16:46:09 +0100 |
commit | 7bff76d8ae1e8c3fbada1ade9ccf5111a1c0547e (patch) | |
tree | 1e85ed9c3fdf144469d9766c43c5362f5a31530b /crates/ide/src/diagnostics | |
parent | 3d8df2aef87bca7ec3f0994d799462f08d1ad449 (diff) | |
parent | 4af7a35197a1cb159458694e69e17bd83dc9edff (diff) |
Merge #9249
9249: internal: remove def-level diagnostics tests r=matklad a=matklad
bors r+
🤖
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ide/src/diagnostics')
-rw-r--r-- | crates/ide/src/diagnostics/inactive_code.rs | 117 | ||||
-rw-r--r-- | crates/ide/src/diagnostics/macro_error.rs | 163 | ||||
-rw-r--r-- | crates/ide/src/diagnostics/unresolved_macro_call.rs | 12 | ||||
-rw-r--r-- | crates/ide/src/diagnostics/unresolved_proc_macro.rs | 30 |
4 files changed, 322 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..afe333204 --- /dev/null +++ b/crates/ide/src/diagnostics/inactive_code.rs | |||
@@ -0,0 +1,117 @@ | |||
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_inactive_code; | ||
41 | |||
42 | #[test] | ||
43 | fn cfg_diagnostics() { | ||
44 | check_diagnostics_with_inactive_code( | ||
45 | r#" | ||
46 | fn f() { | ||
47 | // The three g̶e̶n̶d̶e̶r̶s̶ statements: | ||
48 | |||
49 | #[cfg(a)] fn f() {} // Item statement | ||
50 | //^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled | ||
51 | #[cfg(a)] {} // Expression statement | ||
52 | //^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled | ||
53 | #[cfg(a)] let x = 0; // let statement | ||
54 | //^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled | ||
55 | |||
56 | abc(#[cfg(a)] 0); | ||
57 | //^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled | ||
58 | let x = Struct { | ||
59 | #[cfg(a)] f: 0, | ||
60 | //^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled | ||
61 | }; | ||
62 | match () { | ||
63 | () => (), | ||
64 | #[cfg(a)] () => (), | ||
65 | //^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled | ||
66 | } | ||
67 | |||
68 | #[cfg(a)] 0 // Trailing expression of block | ||
69 | //^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled | ||
70 | } | ||
71 | "#, | ||
72 | true, | ||
73 | ); | ||
74 | } | ||
75 | |||
76 | #[test] | ||
77 | fn inactive_item() { | ||
78 | // Additional tests in `cfg` crate. This only tests disabled cfgs. | ||
79 | |||
80 | check_diagnostics_with_inactive_code( | ||
81 | r#" | ||
82 | #[cfg(no)] pub fn f() {} | ||
83 | //^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled | ||
84 | |||
85 | #[cfg(no)] #[cfg(no2)] mod m; | ||
86 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no and no2 are disabled | ||
87 | |||
88 | #[cfg(all(not(a), b))] enum E {} | ||
89 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: b is disabled | ||
90 | |||
91 | #[cfg(feature = "std")] use std; | ||
92 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: feature = "std" is disabled | ||
93 | "#, | ||
94 | true, | ||
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_diagnostics_with_inactive_code( | ||
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 | true, | ||
115 | ); | ||
116 | } | ||
117 | } | ||
diff --git a/crates/ide/src/diagnostics/macro_error.rs b/crates/ide/src/diagnostics/macro_error.rs new file mode 100644 index 000000000..8cc8cfb48 --- /dev/null +++ b/crates/ide/src/diagnostics/macro_error.rs | |||
@@ -0,0 +1,163 @@ | |||
1 | use crate::diagnostics::{Diagnostic, DiagnosticsContext}; | ||
2 | |||
3 | // Diagnostic: macro-error | ||
4 | // | ||
5 | // This diagnostic is shown for macro expansion errors. | ||
6 | pub(super) fn macro_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroError) -> Diagnostic { | ||
7 | Diagnostic::new( | ||
8 | "macro-error", | ||
9 | d.message.clone(), | ||
10 | ctx.sema.diagnostics_display_range(d.node.clone()).range, | ||
11 | ) | ||
12 | .experimental() | ||
13 | } | ||
14 | |||
15 | #[cfg(test)] | ||
16 | mod tests { | ||
17 | use crate::diagnostics::tests::{check_diagnostics, check_no_diagnostics}; | ||
18 | |||
19 | #[test] | ||
20 | fn builtin_macro_fails_expansion() { | ||
21 | check_diagnostics( | ||
22 | r#" | ||
23 | #[rustc_builtin_macro] | ||
24 | macro_rules! include { () => {} } | ||
25 | |||
26 | include!("doesntexist"); | ||
27 | //^^^^^^^^^^^^^^^^^^^^^^^^ failed to load file `doesntexist` | ||
28 | "#, | ||
29 | ); | ||
30 | } | ||
31 | |||
32 | #[test] | ||
33 | fn include_macro_should_allow_empty_content() { | ||
34 | check_diagnostics( | ||
35 | r#" | ||
36 | //- /lib.rs | ||
37 | #[rustc_builtin_macro] | ||
38 | macro_rules! include { () => {} } | ||
39 | |||
40 | include!("foo/bar.rs"); | ||
41 | //- /foo/bar.rs | ||
42 | // empty | ||
43 | "#, | ||
44 | ); | ||
45 | } | ||
46 | |||
47 | #[test] | ||
48 | fn good_out_dir_diagnostic() { | ||
49 | check_diagnostics( | ||
50 | r#" | ||
51 | #[rustc_builtin_macro] | ||
52 | macro_rules! include { () => {} } | ||
53 | #[rustc_builtin_macro] | ||
54 | macro_rules! env { () => {} } | ||
55 | #[rustc_builtin_macro] | ||
56 | macro_rules! concat { () => {} } | ||
57 | |||
58 | include!(concat!(env!("OUT_DIR"), "/out.rs")); | ||
59 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix | ||
60 | "#, | ||
61 | ); | ||
62 | } | ||
63 | |||
64 | #[test] | ||
65 | fn register_attr_and_tool() { | ||
66 | cov_mark::check!(register_attr); | ||
67 | cov_mark::check!(register_tool); | ||
68 | check_no_diagnostics( | ||
69 | r#" | ||
70 | #![register_tool(tool)] | ||
71 | #![register_attr(attr)] | ||
72 | |||
73 | #[tool::path] | ||
74 | #[attr] | ||
75 | struct S; | ||
76 | "#, | ||
77 | ); | ||
78 | // NB: we don't currently emit diagnostics here | ||
79 | } | ||
80 | |||
81 | #[test] | ||
82 | fn macro_diag_builtin() { | ||
83 | check_diagnostics( | ||
84 | r#" | ||
85 | #[rustc_builtin_macro] | ||
86 | macro_rules! env {} | ||
87 | |||
88 | #[rustc_builtin_macro] | ||
89 | macro_rules! include {} | ||
90 | |||
91 | #[rustc_builtin_macro] | ||
92 | macro_rules! compile_error {} | ||
93 | |||
94 | #[rustc_builtin_macro] | ||
95 | macro_rules! format_args { () => {} } | ||
96 | |||
97 | fn main() { | ||
98 | // Test a handful of built-in (eager) macros: | ||
99 | |||
100 | include!(invalid); | ||
101 | //^^^^^^^^^^^^^^^^^ could not convert tokens | ||
102 | include!("does not exist"); | ||
103 | //^^^^^^^^^^^^^^^^^^^^^^^^^^ failed to load file `does not exist` | ||
104 | |||
105 | env!(invalid); | ||
106 | //^^^^^^^^^^^^^ could not convert tokens | ||
107 | |||
108 | env!("OUT_DIR"); | ||
109 | //^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix | ||
110 | |||
111 | compile_error!("compile_error works"); | ||
112 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ compile_error works | ||
113 | |||
114 | // Lazy: | ||
115 | |||
116 | format_args!(); | ||
117 | //^^^^^^^^^^^^^^ no rule matches input tokens | ||
118 | } | ||
119 | "#, | ||
120 | ); | ||
121 | } | ||
122 | |||
123 | #[test] | ||
124 | fn macro_rules_diag() { | ||
125 | check_diagnostics( | ||
126 | r#" | ||
127 | macro_rules! m { | ||
128 | () => {}; | ||
129 | } | ||
130 | fn f() { | ||
131 | m!(); | ||
132 | |||
133 | m!(hi); | ||
134 | //^^^^^^ leftover tokens | ||
135 | } | ||
136 | "#, | ||
137 | ); | ||
138 | } | ||
139 | #[test] | ||
140 | fn dollar_crate_in_builtin_macro() { | ||
141 | check_diagnostics( | ||
142 | r#" | ||
143 | #[macro_export] | ||
144 | #[rustc_builtin_macro] | ||
145 | macro_rules! format_args {} | ||
146 | |||
147 | #[macro_export] | ||
148 | macro_rules! arg { () => {} } | ||
149 | |||
150 | #[macro_export] | ||
151 | macro_rules! outer { | ||
152 | () => { | ||
153 | $crate::format_args!( "", $crate::arg!(1) ) | ||
154 | }; | ||
155 | } | ||
156 | |||
157 | fn f() { | ||
158 | outer!(); | ||
159 | } //^^^^^^^^ leftover tokens | ||
160 | "#, | ||
161 | ) | ||
162 | } | ||
163 | } | ||
diff --git a/crates/ide/src/diagnostics/unresolved_macro_call.rs b/crates/ide/src/diagnostics/unresolved_macro_call.rs index a3af332a4..15b6a2730 100644 --- a/crates/ide/src/diagnostics/unresolved_macro_call.rs +++ b/crates/ide/src/diagnostics/unresolved_macro_call.rs | |||
@@ -35,6 +35,18 @@ mod tests { | |||
35 | use crate::diagnostics::tests::check_diagnostics; | 35 | use crate::diagnostics::tests::check_diagnostics; |
36 | 36 | ||
37 | #[test] | 37 | #[test] |
38 | fn unresolved_macro_diag() { | ||
39 | check_diagnostics( | ||
40 | r#" | ||
41 | fn f() { | ||
42 | m!(); | ||
43 | } //^ unresolved macro `m!` | ||
44 | |||
45 | "#, | ||
46 | ); | ||
47 | } | ||
48 | |||
49 | #[test] | ||
38 | fn test_unresolved_macro_range() { | 50 | fn test_unresolved_macro_range() { |
39 | check_diagnostics( | 51 | check_diagnostics( |
40 | r#" | 52 | r#" |
diff --git a/crates/ide/src/diagnostics/unresolved_proc_macro.rs b/crates/ide/src/diagnostics/unresolved_proc_macro.rs new file mode 100644 index 000000000..3dc6ab451 --- /dev/null +++ b/crates/ide/src/diagnostics/unresolved_proc_macro.rs | |||
@@ -0,0 +1,30 @@ | |||
1 | use crate::{ | ||
2 | diagnostics::{Diagnostic, DiagnosticsContext}, | ||
3 | Severity, | ||
4 | }; | ||
5 | |||
6 | // Diagnostic: unresolved-proc-macro | ||
7 | // | ||
8 | // This diagnostic is shown when a procedural macro can not be found. This usually means that | ||
9 | // procedural macro support is simply disabled (and hence is only a weak hint instead of an error), | ||
10 | // but can also indicate project setup problems. | ||
11 | // | ||
12 | // If you are seeing a lot of "proc macro not expanded" warnings, you can add this option to the | ||
13 | // `rust-analyzer.diagnostics.disabled` list to prevent them from showing. Alternatively you can | ||
14 | // enable support for procedural macros (see `rust-analyzer.procMacro.enable`). | ||
15 | pub(super) fn unresolved_proc_macro( | ||
16 | ctx: &DiagnosticsContext<'_>, | ||
17 | d: &hir::UnresolvedProcMacro, | ||
18 | ) -> Diagnostic { | ||
19 | // Use more accurate position if available. | ||
20 | let display_range = d | ||
21 | .precise_location | ||
22 | .unwrap_or_else(|| ctx.sema.diagnostics_display_range(d.node.clone()).range); | ||
23 | // FIXME: it would be nice to tell the user whether proc macros are currently disabled | ||
24 | let message = match &d.macro_name { | ||
25 | Some(name) => format!("proc macro `{}` not expanded", name), | ||
26 | None => "proc macro not expanded".to_string(), | ||
27 | }; | ||
28 | |||
29 | Diagnostic::new("unresolved-proc-macro", message, display_range).severity(Severity::WeakWarning) | ||
30 | } | ||