aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_diagnostics
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-06-14 20:37:28 +0100
committerGitHub <[email protected]>2021-06-14 20:37:28 +0100
commitce8fdf3ab05b59b517dee985e4b3828c6e373a91 (patch)
tree8a498dc4c333f2f0e513a5b63a45c226d6e12279 /crates/ide_diagnostics
parent27a70492f7eb8181c90ed5aa62e8e8b7ce035c91 (diff)
parent4cfc767d7fadeab025227d67f104065c9e8a55d3 (diff)
Merge #9276
9276: internal: refactor diagnostics more r=matklad a=matklad bors r+ 🤖 Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ide_diagnostics')
-rw-r--r--crates/ide_diagnostics/src/handlers/break_outside_of_loop.rs2
-rw-r--r--crates/ide_diagnostics/src/handlers/field_shorthand.rs (renamed from crates/ide_diagnostics/src/field_shorthand.rs)2
-rw-r--r--crates/ide_diagnostics/src/handlers/inactive_code.rs26
-rw-r--r--crates/ide_diagnostics/src/handlers/incorrect_case.rs42
-rw-r--r--crates/ide_diagnostics/src/handlers/macro_error.rs20
-rw-r--r--crates/ide_diagnostics/src/handlers/mismatched_arg_count.rs22
-rw-r--r--crates/ide_diagnostics/src/handlers/missing_fields.rs33
-rw-r--r--crates/ide_diagnostics/src/handlers/missing_match_arms.rs96
-rw-r--r--crates/ide_diagnostics/src/handlers/missing_unsafe.rs10
-rw-r--r--crates/ide_diagnostics/src/handlers/no_such_field.rs4
-rw-r--r--crates/ide_diagnostics/src/handlers/remove_this_semicolon.rs2
-rw-r--r--crates/ide_diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs14
-rw-r--r--crates/ide_diagnostics/src/handlers/unlinked_file.rs23
-rw-r--r--crates/ide_diagnostics/src/handlers/unresolved_extern_crate.rs4
-rw-r--r--crates/ide_diagnostics/src/handlers/unresolved_import.rs18
-rw-r--r--crates/ide_diagnostics/src/handlers/unresolved_macro_call.rs8
-rw-r--r--crates/ide_diagnostics/src/handlers/unresolved_module.rs2
-rw-r--r--crates/ide_diagnostics/src/handlers/useless_braces.rs148
-rw-r--r--crates/ide_diagnostics/src/lib.rs224
19 files changed, 359 insertions, 341 deletions
diff --git a/crates/ide_diagnostics/src/handlers/break_outside_of_loop.rs b/crates/ide_diagnostics/src/handlers/break_outside_of_loop.rs
index 5ad0fbd1b..d12594a4c 100644
--- a/crates/ide_diagnostics/src/handlers/break_outside_of_loop.rs
+++ b/crates/ide_diagnostics/src/handlers/break_outside_of_loop.rs
@@ -23,7 +23,7 @@ mod tests {
23 check_diagnostics( 23 check_diagnostics(
24 r#" 24 r#"
25fn foo() { break; } 25fn foo() { break; }
26 //^^^^^ break outside of loop 26 //^^^^^ error: break outside of loop
27"#, 27"#,
28 ); 28 );
29 } 29 }
diff --git a/crates/ide_diagnostics/src/field_shorthand.rs b/crates/ide_diagnostics/src/handlers/field_shorthand.rs
index 0b6af9965..33152e284 100644
--- a/crates/ide_diagnostics/src/field_shorthand.rs
+++ b/crates/ide_diagnostics/src/handlers/field_shorthand.rs
@@ -7,7 +7,7 @@ use text_edit::TextEdit;
7 7
8use crate::{fix, Diagnostic, Severity}; 8use crate::{fix, Diagnostic, Severity};
9 9
10pub(super) fn check(acc: &mut Vec<Diagnostic>, file_id: FileId, node: &SyntaxNode) { 10pub(crate) fn field_shorthand(acc: &mut Vec<Diagnostic>, file_id: FileId, node: &SyntaxNode) {
11 match_ast! { 11 match_ast! {
12 match node { 12 match node {
13 ast::RecordExpr(it) => check_expr_field_shorthand(acc, file_id, it), 13 ast::RecordExpr(it) => check_expr_field_shorthand(acc, file_id, it),
diff --git a/crates/ide_diagnostics/src/handlers/inactive_code.rs b/crates/ide_diagnostics/src/handlers/inactive_code.rs
index 4b722fd64..dfd0e3351 100644
--- a/crates/ide_diagnostics/src/handlers/inactive_code.rs
+++ b/crates/ide_diagnostics/src/handlers/inactive_code.rs
@@ -49,26 +49,26 @@ fn f() {
49 // The three g̶e̶n̶d̶e̶r̶s̶ statements: 49 // The three g̶e̶n̶d̶e̶r̶s̶ statements:
50 50
51 #[cfg(a)] fn f() {} // Item statement 51 #[cfg(a)] fn f() {} // Item statement
52 //^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled 52 //^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
53 #[cfg(a)] {} // Expression statement 53 #[cfg(a)] {} // Expression statement
54 //^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled 54 //^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
55 #[cfg(a)] let x = 0; // let statement 55 #[cfg(a)] let x = 0; // let statement
56 //^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled 56 //^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
57 57
58 abc(#[cfg(a)] 0); 58 abc(#[cfg(a)] 0);
59 //^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled 59 //^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
60 let x = Struct { 60 let x = Struct {
61 #[cfg(a)] f: 0, 61 #[cfg(a)] f: 0,
62 //^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled 62 //^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
63 }; 63 };
64 match () { 64 match () {
65 () => (), 65 () => (),
66 #[cfg(a)] () => (), 66 #[cfg(a)] () => (),
67 //^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled 67 //^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
68 } 68 }
69 69
70 #[cfg(a)] 0 // Trailing expression of block 70 #[cfg(a)] 0 // Trailing expression of block
71 //^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled 71 //^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
72} 72}
73 "#, 73 "#,
74 ); 74 );
@@ -81,16 +81,16 @@ fn f() {
81 check( 81 check(
82 r#" 82 r#"
83 #[cfg(no)] pub fn f() {} 83 #[cfg(no)] pub fn f() {}
84 //^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled 84 //^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no is disabled
85 85
86 #[cfg(no)] #[cfg(no2)] mod m; 86 #[cfg(no)] #[cfg(no2)] mod m;
87 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no and no2 are disabled 87 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no and no2 are disabled
88 88
89 #[cfg(all(not(a), b))] enum E {} 89 #[cfg(all(not(a), b))] enum E {}
90 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: b is disabled 90 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: b is disabled
91 91
92 #[cfg(feature = "std")] use std; 92 #[cfg(feature = "std")] use std;
93 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: feature = "std" is disabled 93 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: feature = "std" is disabled
94"#, 94"#,
95 ); 95 );
96 } 96 }
@@ -102,14 +102,14 @@ fn f() {
102 check( 102 check(
103 r#" 103 r#"
104 #[cfg_attr(not(never), cfg(no))] fn f() {} 104 #[cfg_attr(not(never), cfg(no))] fn f() {}
105 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled 105 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no is disabled
106 106
107 #[cfg_attr(not(never), cfg(not(no)))] fn f() {} 107 #[cfg_attr(not(never), cfg(not(no)))] fn f() {}
108 108
109 #[cfg_attr(never, cfg(no))] fn g() {} 109 #[cfg_attr(never, cfg(no))] fn g() {}
110 110
111 #[cfg_attr(not(never), inline, cfg(no))] fn h() {} 111 #[cfg_attr(not(never), inline, cfg(no))] fn h() {}
112 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled 112 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no is disabled
113"#, 113"#,
114 ); 114 );
115 } 115 }
diff --git a/crates/ide_diagnostics/src/handlers/incorrect_case.rs b/crates/ide_diagnostics/src/handlers/incorrect_case.rs
index 3a33029cf..72f251961 100644
--- a/crates/ide_diagnostics/src/handlers/incorrect_case.rs
+++ b/crates/ide_diagnostics/src/handlers/incorrect_case.rs
@@ -149,7 +149,7 @@ impl TestStruct {
149 check_diagnostics( 149 check_diagnostics(
150 r#" 150 r#"
151fn FOO() {} 151fn FOO() {}
152// ^^^ Function `FOO` should have snake_case name, e.g. `foo` 152// ^^^ 💡 weak: Function `FOO` should have snake_case name, e.g. `foo`
153"#, 153"#,
154 ); 154 );
155 check_fix(r#"fn FOO$0() {}"#, r#"fn foo() {}"#); 155 check_fix(r#"fn FOO$0() {}"#, r#"fn foo() {}"#);
@@ -160,7 +160,7 @@ fn FOO() {}
160 check_diagnostics( 160 check_diagnostics(
161 r#" 161 r#"
162fn NonSnakeCaseName() {} 162fn NonSnakeCaseName() {}
163// ^^^^^^^^^^^^^^^^ Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name` 163// ^^^^^^^^^^^^^^^^ 💡 weak: Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name`
164"#, 164"#,
165 ); 165 );
166 } 166 }
@@ -170,10 +170,10 @@ fn NonSnakeCaseName() {}
170 check_diagnostics( 170 check_diagnostics(
171 r#" 171 r#"
172fn foo(SomeParam: u8) {} 172fn foo(SomeParam: u8) {}
173 // ^^^^^^^^^ Parameter `SomeParam` should have snake_case name, e.g. `some_param` 173 // ^^^^^^^^^ 💡 weak: Parameter `SomeParam` should have snake_case name, e.g. `some_param`
174 174
175fn foo2(ok_param: &str, CAPS_PARAM: u8) {} 175fn foo2(ok_param: &str, CAPS_PARAM: u8) {}
176 // ^^^^^^^^^^ Parameter `CAPS_PARAM` should have snake_case name, e.g. `caps_param` 176 // ^^^^^^^^^^ 💡 weak: Parameter `CAPS_PARAM` should have snake_case name, e.g. `caps_param`
177"#, 177"#,
178 ); 178 );
179 } 179 }
@@ -184,9 +184,9 @@ fn foo2(ok_param: &str, CAPS_PARAM: u8) {}
184 r#" 184 r#"
185fn foo() { 185fn foo() {
186 let SOME_VALUE = 10; 186 let SOME_VALUE = 10;
187 // ^^^^^^^^^^ Variable `SOME_VALUE` should have snake_case name, e.g. `some_value` 187 // ^^^^^^^^^^ 💡 weak: Variable `SOME_VALUE` should have snake_case name, e.g. `some_value`
188 let AnotherValue = 20; 188 let AnotherValue = 20;
189 // ^^^^^^^^^^^^ Variable `AnotherValue` should have snake_case name, e.g. `another_value` 189 // ^^^^^^^^^^^^ 💡 weak: Variable `AnotherValue` should have snake_case name, e.g. `another_value`
190} 190}
191"#, 191"#,
192 ); 192 );
@@ -197,10 +197,10 @@ fn foo() {
197 check_diagnostics( 197 check_diagnostics(
198 r#" 198 r#"
199struct non_camel_case_name {} 199struct non_camel_case_name {}
200 // ^^^^^^^^^^^^^^^^^^^ Structure `non_camel_case_name` should have CamelCase name, e.g. `NonCamelCaseName` 200 // ^^^^^^^^^^^^^^^^^^^ 💡 weak: Structure `non_camel_case_name` should have CamelCase name, e.g. `NonCamelCaseName`
201 201
202struct SCREAMING_CASE {} 202struct SCREAMING_CASE {}
203 // ^^^^^^^^^^^^^^ Structure `SCREAMING_CASE` should have CamelCase name, e.g. `ScreamingCase` 203 // ^^^^^^^^^^^^^^ 💡 weak: Structure `SCREAMING_CASE` should have CamelCase name, e.g. `ScreamingCase`
204"#, 204"#,
205 ); 205 );
206 } 206 }
@@ -219,7 +219,7 @@ struct AABB {}
219 check_diagnostics( 219 check_diagnostics(
220 r#" 220 r#"
221struct SomeStruct { SomeField: u8 } 221struct SomeStruct { SomeField: u8 }
222 // ^^^^^^^^^ Field `SomeField` should have snake_case name, e.g. `some_field` 222 // ^^^^^^^^^ 💡 weak: Field `SomeField` should have snake_case name, e.g. `some_field`
223"#, 223"#,
224 ); 224 );
225 } 225 }
@@ -229,10 +229,10 @@ struct SomeStruct { SomeField: u8 }
229 check_diagnostics( 229 check_diagnostics(
230 r#" 230 r#"
231enum some_enum { Val(u8) } 231enum some_enum { Val(u8) }
232 // ^^^^^^^^^ Enum `some_enum` should have CamelCase name, e.g. `SomeEnum` 232 // ^^^^^^^^^ 💡 weak: Enum `some_enum` should have CamelCase name, e.g. `SomeEnum`
233 233
234enum SOME_ENUM {} 234enum SOME_ENUM {}
235 // ^^^^^^^^^ Enum `SOME_ENUM` should have CamelCase name, e.g. `SomeEnum` 235 // ^^^^^^^^^ 💡 weak: Enum `SOME_ENUM` should have CamelCase name, e.g. `SomeEnum`
236"#, 236"#,
237 ); 237 );
238 } 238 }
@@ -251,7 +251,7 @@ enum AABB {}
251 check_diagnostics( 251 check_diagnostics(
252 r#" 252 r#"
253enum SomeEnum { SOME_VARIANT(u8) } 253enum SomeEnum { SOME_VARIANT(u8) }
254 // ^^^^^^^^^^^^ Variant `SOME_VARIANT` should have CamelCase name, e.g. `SomeVariant` 254 // ^^^^^^^^^^^^ 💡 weak: Variant `SOME_VARIANT` should have CamelCase name, e.g. `SomeVariant`
255"#, 255"#,
256 ); 256 );
257 } 257 }
@@ -261,7 +261,7 @@ enum SomeEnum { SOME_VARIANT(u8) }
261 check_diagnostics( 261 check_diagnostics(
262 r#" 262 r#"
263const some_weird_const: u8 = 10; 263const some_weird_const: u8 = 10;
264 // ^^^^^^^^^^^^^^^^ Constant `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST` 264 // ^^^^^^^^^^^^^^^^ 💡 weak: Constant `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST`
265"#, 265"#,
266 ); 266 );
267 } 267 }
@@ -271,7 +271,7 @@ const some_weird_const: u8 = 10;
271 check_diagnostics( 271 check_diagnostics(
272 r#" 272 r#"
273static some_weird_const: u8 = 10; 273static some_weird_const: u8 = 10;
274 // ^^^^^^^^^^^^^^^^ Static variable `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST` 274 // ^^^^^^^^^^^^^^^^ 💡 weak: Static variable `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST`
275"#, 275"#,
276 ); 276 );
277 } 277 }
@@ -281,13 +281,13 @@ static some_weird_const: u8 = 10;
281 check_diagnostics( 281 check_diagnostics(
282 r#" 282 r#"
283struct someStruct; 283struct someStruct;
284 // ^^^^^^^^^^ Structure `someStruct` should have CamelCase name, e.g. `SomeStruct` 284 // ^^^^^^^^^^ 💡 weak: Structure `someStruct` should have CamelCase name, e.g. `SomeStruct`
285 285
286impl someStruct { 286impl someStruct {
287 fn SomeFunc(&self) { 287 fn SomeFunc(&self) {
288 // ^^^^^^^^ Function `SomeFunc` should have snake_case name, e.g. `some_func` 288 // ^^^^^^^^ 💡 weak: Function `SomeFunc` should have snake_case name, e.g. `some_func`
289 let WHY_VAR_IS_CAPS = 10; 289 let WHY_VAR_IS_CAPS = 10;
290 // ^^^^^^^^^^^^^^^ Variable `WHY_VAR_IS_CAPS` should have snake_case name, e.g. `why_var_is_caps` 290 // ^^^^^^^^^^^^^^^ 💡 weak: Variable `WHY_VAR_IS_CAPS` should have snake_case name, e.g. `why_var_is_caps`
291 } 291 }
292} 292}
293"#, 293"#,
@@ -319,7 +319,7 @@ enum Option { Some, None }
319fn main() { 319fn main() {
320 match Option::None { 320 match Option::None {
321 SOME_VAR @ None => (), 321 SOME_VAR @ None => (),
322 // ^^^^^^^^ Variable `SOME_VAR` should have snake_case name, e.g. `some_var` 322 // ^^^^^^^^ 💡 weak: Variable `SOME_VAR` should have snake_case name, e.g. `some_var`
323 Some => (), 323 Some => (),
324 } 324 }
325} 325}
@@ -421,11 +421,11 @@ extern {
421 check_diagnostics( 421 check_diagnostics(
422 r#" 422 r#"
423trait BAD_TRAIT { 423trait BAD_TRAIT {
424 // ^^^^^^^^^ Trait `BAD_TRAIT` should have CamelCase name, e.g. `BadTrait` 424 // ^^^^^^^^^ 💡 weak: Trait `BAD_TRAIT` should have CamelCase name, e.g. `BadTrait`
425 fn BAD_FUNCTION(); 425 fn BAD_FUNCTION();
426 // ^^^^^^^^^^^^ Function `BAD_FUNCTION` should have snake_case name, e.g. `bad_function` 426 // ^^^^^^^^^^^^ 💡 weak: Function `BAD_FUNCTION` should have snake_case name, e.g. `bad_function`
427 fn BadFunction(); 427 fn BadFunction();
428 // ^^^^^^^^^^^^ Function `BadFunction` should have snake_case name, e.g. `bad_function` 428 // ^^^^^^^^^^^^ 💡 weak: Function `BadFunction` should have snake_case name, e.g. `bad_function`
429} 429}
430 "#, 430 "#,
431 ); 431 );
diff --git a/crates/ide_diagnostics/src/handlers/macro_error.rs b/crates/ide_diagnostics/src/handlers/macro_error.rs
index d4d928ad1..356f089b2 100644
--- a/crates/ide_diagnostics/src/handlers/macro_error.rs
+++ b/crates/ide_diagnostics/src/handlers/macro_error.rs
@@ -27,7 +27,7 @@ mod tests {
27macro_rules! include { () => {} } 27macro_rules! include { () => {} }
28 28
29 include!("doesntexist"); 29 include!("doesntexist");
30//^^^^^^^^^^^^^^^^^^^^^^^^ failed to load file `doesntexist` 30//^^^^^^^^^^^^^^^^^^^^^^^^ error: failed to load file `doesntexist`
31 "#, 31 "#,
32 ); 32 );
33 } 33 }
@@ -66,7 +66,7 @@ macro_rules! env { () => {} }
66macro_rules! concat { () => {} } 66macro_rules! concat { () => {} }
67 67
68 include!(concat!(env!("OUT_DIR"), "/out.rs")); 68 include!(concat!(env!("OUT_DIR"), "/out.rs"));
69//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix 69//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `OUT_DIR` not set, enable "run build scripts" to fix
70"#, 70"#,
71 ); 71 );
72 } 72 }
@@ -108,23 +108,23 @@ fn main() {
108 // Test a handful of built-in (eager) macros: 108 // Test a handful of built-in (eager) macros:
109 109
110 include!(invalid); 110 include!(invalid);
111 //^^^^^^^^^^^^^^^^^ could not convert tokens 111 //^^^^^^^^^^^^^^^^^ error: could not convert tokens
112 include!("does not exist"); 112 include!("does not exist");
113 //^^^^^^^^^^^^^^^^^^^^^^^^^^ failed to load file `does not exist` 113 //^^^^^^^^^^^^^^^^^^^^^^^^^^ error: failed to load file `does not exist`
114 114
115 env!(invalid); 115 env!(invalid);
116 //^^^^^^^^^^^^^ could not convert tokens 116 //^^^^^^^^^^^^^ error: could not convert tokens
117 117
118 env!("OUT_DIR"); 118 env!("OUT_DIR");
119 //^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix 119 //^^^^^^^^^^^^^^^ error: `OUT_DIR` not set, enable "run build scripts" to fix
120 120
121 compile_error!("compile_error works"); 121 compile_error!("compile_error works");
122 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ compile_error works 122 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: compile_error works
123 123
124 // Lazy: 124 // Lazy:
125 125
126 format_args!(); 126 format_args!();
127 //^^^^^^^^^^^^^^ no rule matches input tokens 127 //^^^^^^^^^^^^^^ error: no rule matches input tokens
128} 128}
129"#, 129"#,
130 ); 130 );
@@ -141,7 +141,7 @@ fn f() {
141 m!(); 141 m!();
142 142
143 m!(hi); 143 m!(hi);
144 //^^^^^^ leftover tokens 144 //^^^^^^ error: leftover tokens
145} 145}
146 "#, 146 "#,
147 ); 147 );
@@ -166,7 +166,7 @@ macro_rules! outer {
166 166
167fn f() { 167fn f() {
168 outer!(); 168 outer!();
169} //^^^^^^^^ leftover tokens 169} //^^^^^^^^ error: leftover tokens
170"#, 170"#,
171 ) 171 )
172 } 172 }
diff --git a/crates/ide_diagnostics/src/handlers/mismatched_arg_count.rs b/crates/ide_diagnostics/src/handlers/mismatched_arg_count.rs
index ce313b2cc..a9b6d3870 100644
--- a/crates/ide_diagnostics/src/handlers/mismatched_arg_count.rs
+++ b/crates/ide_diagnostics/src/handlers/mismatched_arg_count.rs
@@ -26,7 +26,7 @@ mod tests {
26 r#" 26 r#"
27fn zero() {} 27fn zero() {}
28fn f() { zero(1); } 28fn f() { zero(1); }
29 //^^^^^^^ expected 0 arguments, found 1 29 //^^^^^^^ error: expected 0 arguments, found 1
30"#, 30"#,
31 ); 31 );
32 32
@@ -44,7 +44,7 @@ fn f() { zero(); }
44 r#" 44 r#"
45fn one(arg: u8) {} 45fn one(arg: u8) {}
46fn f() { one(); } 46fn f() { one(); }
47 //^^^^^ expected 1 argument, found 0 47 //^^^^^ error: expected 1 argument, found 0
48"#, 48"#,
49 ); 49 );
50 50
@@ -65,7 +65,7 @@ impl S { fn method(&self) {} }
65 65
66fn f() { 66fn f() {
67 S::method(); 67 S::method();
68} //^^^^^^^^^^^ expected 1 argument, found 0 68} //^^^^^^^^^^^ error: expected 1 argument, found 0
69"#, 69"#,
70 ); 70 );
71 71
@@ -91,7 +91,7 @@ impl S { fn method(&self, arg: u8) {} }
91 91
92 fn f() { 92 fn f() {
93 S.method(); 93 S.method();
94 } //^^^^^^^^^^ expected 1 argument, found 0 94 } //^^^^^^^^^^ error: expected 1 argument, found 0
95 "#, 95 "#,
96 ); 96 );
97 97
@@ -131,7 +131,7 @@ fn f() {
131struct Tup(u8, u16); 131struct Tup(u8, u16);
132fn f() { 132fn f() {
133 Tup(0); 133 Tup(0);
134} //^^^^^^ expected 2 arguments, found 1 134} //^^^^^^ error: expected 2 arguments, found 1
135"#, 135"#,
136 ) 136 )
137 } 137 }
@@ -143,7 +143,7 @@ fn f() {
143enum En { Variant(u8, u16), } 143enum En { Variant(u8, u16), }
144fn f() { 144fn f() {
145 En::Variant(0); 145 En::Variant(0);
146} //^^^^^^^^^^^^^^ expected 2 arguments, found 1 146} //^^^^^^^^^^^^^^ error: expected 2 arguments, found 1
147"#, 147"#,
148 ) 148 )
149 } 149 }
@@ -162,9 +162,9 @@ impl Foo {
162 fn new() { 162 fn new() {
163 Foo::Bar(0); 163 Foo::Bar(0);
164 Foo::Bar(0, 1); 164 Foo::Bar(0, 1);
165 //^^^^^^^^^^^^^^ expected 1 argument, found 2 165 //^^^^^^^^^^^^^^ error: expected 1 argument, found 2
166 Foo::Bar(); 166 Foo::Bar();
167 //^^^^^^^^^^ expected 1 argument, found 0 167 //^^^^^^^^^^ error: expected 1 argument, found 0
168 } 168 }
169} 169}
170 "#, 170 "#,
@@ -185,7 +185,7 @@ fn f() {
185 unsafe { 185 unsafe {
186 fixed(0); 186 fixed(0);
187 fixed(0, 1); 187 fixed(0, 1);
188 //^^^^^^^^^^^ expected 1 argument, found 2 188 //^^^^^^^^^^^ error: expected 1 argument, found 2
189 varargs(0); 189 varargs(0);
190 varargs(0, 1); 190 varargs(0, 1);
191 varargs2(); 191 varargs2();
@@ -204,10 +204,10 @@ fn f() {
204fn main() { 204fn main() {
205 let f = |()| (); 205 let f = |()| ();
206 f(); 206 f();
207 //^^^ expected 1 argument, found 0 207 //^^^ error: expected 1 argument, found 0
208 f(()); 208 f(());
209 f((), ()); 209 f((), ());
210 //^^^^^^^^^ expected 1 argument, found 2 210 //^^^^^^^^^ error: expected 1 argument, found 2
211} 211}
212"#, 212"#,
213 ) 213 )
diff --git a/crates/ide_diagnostics/src/handlers/missing_fields.rs b/crates/ide_diagnostics/src/handlers/missing_fields.rs
index bc82c0e4a..bc56e0342 100644
--- a/crates/ide_diagnostics/src/handlers/missing_fields.rs
+++ b/crates/ide_diagnostics/src/handlers/missing_fields.rs
@@ -19,7 +19,7 @@ use crate::{fix, Diagnostic, DiagnosticsContext};
19// let a = A { a: 10 }; 19// let a = A { a: 10 };
20// ``` 20// ```
21pub(crate) fn missing_fields(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Diagnostic { 21pub(crate) fn missing_fields(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Diagnostic {
22 let mut message = String::from("Missing structure fields:\n"); 22 let mut message = String::from("missing structure fields:\n");
23 for field in &d.missed_fields { 23 for field in &d.missed_fields {
24 format_to!(message, "- {}\n", field); 24 format_to!(message, "- {}\n", field);
25 } 25 }
@@ -85,7 +85,7 @@ mod tests {
85struct S { foo: i32, bar: () } 85struct S { foo: i32, bar: () }
86fn baz(s: S) { 86fn baz(s: S) {
87 let S { foo: _ } = s; 87 let S { foo: _ } = s;
88 //^ Missing structure fields: 88 //^ error: missing structure fields:
89 //| - bar 89 //| - bar
90} 90}
91"#, 91"#,
@@ -323,4 +323,33 @@ fn f() {
323"#, 323"#,
324 ); 324 );
325 } 325 }
326
327 #[test]
328 fn import_extern_crate_clash_with_inner_item() {
329 // This is more of a resolver test, but doesn't really work with the hir_def testsuite.
330
331 check_diagnostics(
332 r#"
333//- /lib.rs crate:lib deps:jwt
334mod permissions;
335
336use permissions::jwt;
337
338fn f() {
339 fn inner() {}
340 jwt::Claims {}; // should resolve to the local one with 0 fields, and not get a diagnostic
341}
342
343//- /permissions.rs
344pub mod jwt {
345 pub struct Claims {}
346}
347
348//- /jwt/lib.rs crate:jwt
349pub struct Claims {
350 field: u8,
351}
352 "#,
353 );
354 }
326} 355}
diff --git a/crates/ide_diagnostics/src/handlers/missing_match_arms.rs b/crates/ide_diagnostics/src/handlers/missing_match_arms.rs
index 9ea533d74..947b0f2e2 100644
--- a/crates/ide_diagnostics/src/handlers/missing_match_arms.rs
+++ b/crates/ide_diagnostics/src/handlers/missing_match_arms.rs
@@ -31,9 +31,9 @@ mod tests {
31 r#" 31 r#"
32fn main() { 32fn main() {
33 match () { } 33 match () { }
34 //^^ missing match arm 34 //^^ error: missing match arm
35 match (()) { } 35 match (()) { }
36 //^^^^ missing match arm 36 //^^^^ error: missing match arm
37 37
38 match () { _ => (), } 38 match () { _ => (), }
39 match () { () => (), } 39 match () { () => (), }
@@ -49,7 +49,7 @@ fn main() {
49 r#" 49 r#"
50fn main() { 50fn main() {
51 match ((), ()) { } 51 match ((), ()) { }
52 //^^^^^^^^ missing match arm 52 //^^^^^^^^ error: missing match arm
53 53
54 match ((), ()) { ((), ()) => (), } 54 match ((), ()) { ((), ()) => (), }
55} 55}
@@ -63,21 +63,21 @@ fn main() {
63 r#" 63 r#"
64fn test_main() { 64fn test_main() {
65 match false { } 65 match false { }
66 //^^^^^ missing match arm 66 //^^^^^ error: missing match arm
67 match false { true => (), } 67 match false { true => (), }
68 //^^^^^ missing match arm 68 //^^^^^ error: missing match arm
69 match (false, true) {} 69 match (false, true) {}
70 //^^^^^^^^^^^^^ missing match arm 70 //^^^^^^^^^^^^^ error: missing match arm
71 match (false, true) { (true, true) => (), } 71 match (false, true) { (true, true) => (), }
72 //^^^^^^^^^^^^^ missing match arm 72 //^^^^^^^^^^^^^ error: missing match arm
73 match (false, true) { 73 match (false, true) {
74 //^^^^^^^^^^^^^ missing match arm 74 //^^^^^^^^^^^^^ error: missing match arm
75 (false, true) => (), 75 (false, true) => (),
76 (false, false) => (), 76 (false, false) => (),
77 (true, false) => (), 77 (true, false) => (),
78 } 78 }
79 match (false, true) { (true, _x) => (), } 79 match (false, true) { (true, _x) => (), }
80 //^^^^^^^^^^^^^ missing match arm 80 //^^^^^^^^^^^^^ error: missing match arm
81 81
82 match false { true => (), false => (), } 82 match false { true => (), false => (), }
83 match (false, true) { 83 match (false, true) {
@@ -116,11 +116,11 @@ fn test_main() {
116 r#" 116 r#"
117fn main() { 117fn main() {
118 match (false, ((), false)) {} 118 match (false, ((), false)) {}
119 //^^^^^^^^^^^^^^^^^^^^ missing match arm 119 //^^^^^^^^^^^^^^^^^^^^ error: missing match arm
120 match (false, ((), false)) { (true, ((), true)) => (), } 120 match (false, ((), false)) { (true, ((), true)) => (), }
121 //^^^^^^^^^^^^^^^^^^^^ missing match arm 121 //^^^^^^^^^^^^^^^^^^^^ error: missing match arm
122 match (false, ((), false)) { (true, _) => (), } 122 match (false, ((), false)) { (true, _) => (), }
123 //^^^^^^^^^^^^^^^^^^^^ missing match arm 123 //^^^^^^^^^^^^^^^^^^^^ error: missing match arm
124 124
125 match (false, ((), false)) { 125 match (false, ((), false)) {
126 (true, ((), true)) => (), 126 (true, ((), true)) => (),
@@ -146,12 +146,12 @@ enum Either { A, B, }
146 146
147fn main() { 147fn main() {
148 match Either::A { } 148 match Either::A { }
149 //^^^^^^^^^ missing match arm 149 //^^^^^^^^^ error: missing match arm
150 match Either::B { Either::A => (), } 150 match Either::B { Either::A => (), }
151 //^^^^^^^^^ missing match arm 151 //^^^^^^^^^ error: missing match arm
152 152
153 match &Either::B { 153 match &Either::B {
154 //^^^^^^^^^^ missing match arm 154 //^^^^^^^^^^ error: missing match arm
155 Either::A => (), 155 Either::A => (),
156 } 156 }
157 157
@@ -174,9 +174,9 @@ enum Either { A(bool), B }
174 174
175fn main() { 175fn main() {
176 match Either::B { } 176 match Either::B { }
177 //^^^^^^^^^ missing match arm 177 //^^^^^^^^^ error: missing match arm
178 match Either::B { 178 match Either::B {
179 //^^^^^^^^^ missing match arm 179 //^^^^^^^^^ error: missing match arm
180 Either::A(true) => (), Either::B => () 180 Either::A(true) => (), Either::B => ()
181 } 181 }
182 182
@@ -207,7 +207,7 @@ enum Either { A(bool), B(bool, bool) }
207 207
208fn main() { 208fn main() {
209 match Either::A(false) { 209 match Either::A(false) {
210 //^^^^^^^^^^^^^^^^ missing match arm 210 //^^^^^^^^^^^^^^^^ error: missing match arm
211 Either::A(_) => (), 211 Either::A(_) => (),
212 Either::B(false, _) => (), 212 Either::B(false, _) => (),
213 } 213 }
@@ -352,7 +352,7 @@ fn main() {
352 Either::A => (), 352 Either::A => (),
353 } 353 }
354 match loop { break Foo::A } { 354 match loop { break Foo::A } {
355 //^^^^^^^^^^^^^^^^^^^^^ missing match arm 355 //^^^^^^^^^^^^^^^^^^^^^ error: missing match arm
356 Either::A => (), 356 Either::A => (),
357 } 357 }
358 match loop { break Foo::A } { 358 match loop { break Foo::A } {
@@ -390,19 +390,19 @@ enum Either { A { foo: bool }, B }
390fn main() { 390fn main() {
391 let a = Either::A { foo: true }; 391 let a = Either::A { foo: true };
392 match a { } 392 match a { }
393 //^ missing match arm 393 //^ error: missing match arm
394 match a { Either::A { foo: true } => () } 394 match a { Either::A { foo: true } => () }
395 //^ missing match arm 395 //^ error: missing match arm
396 match a { 396 match a {
397 Either::A { } => (), 397 Either::A { } => (),
398 //^^^^^^^^^ Missing structure fields: 398 //^^^^^^^^^ error: missing structure fields:
399 // | - foo 399 // | - foo
400 Either::B => (), 400 Either::B => (),
401 } 401 }
402 match a { 402 match a {
403 //^ missing match arm 403 //^ error: missing match arm
404 Either::A { } => (), 404 Either::A { } => (),
405 } //^^^^^^^^^ Missing structure fields: 405 } //^^^^^^^^^ error: missing structure fields:
406 // | - foo 406 // | - foo
407 407
408 match a { 408 match a {
@@ -431,7 +431,7 @@ enum Either {
431fn main() { 431fn main() {
432 let a = Either::A { foo: true, bar: () }; 432 let a = Either::A { foo: true, bar: () };
433 match a { 433 match a {
434 //^ missing match arm 434 //^ error: missing match arm
435 Either::A { bar: (), foo: false } => (), 435 Either::A { bar: (), foo: false } => (),
436 Either::A { foo: true, bar: () } => (), 436 Either::A { foo: true, bar: () } => (),
437 } 437 }
@@ -458,12 +458,12 @@ enum Either {
458fn main() { 458fn main() {
459 let a = Either::B; 459 let a = Either::B;
460 match a { 460 match a {
461 //^ missing match arm 461 //^ error: missing match arm
462 Either::A { foo: true, .. } => (), 462 Either::A { foo: true, .. } => (),
463 Either::B => (), 463 Either::B => (),
464 } 464 }
465 match a { 465 match a {
466 //^ missing match arm 466 //^ error: missing match arm
467 Either::A { .. } => (), 467 Either::A { .. } => (),
468 } 468 }
469 469
@@ -493,14 +493,14 @@ enum Either {
493 493
494fn main() { 494fn main() {
495 match Either::B { 495 match Either::B {
496 //^^^^^^^^^ missing match arm 496 //^^^^^^^^^ error: missing match arm
497 Either::A(true, .., true) => (), 497 Either::A(true, .., true) => (),
498 Either::A(true, .., false) => (), 498 Either::A(true, .., false) => (),
499 Either::A(false, .., false) => (), 499 Either::A(false, .., false) => (),
500 Either::B => (), 500 Either::B => (),
501 } 501 }
502 match Either::B { 502 match Either::B {
503 //^^^^^^^^^ missing match arm 503 //^^^^^^^^^ error: missing match arm
504 Either::A(true, .., true) => (), 504 Either::A(true, .., true) => (),
505 Either::A(true, .., false) => (), 505 Either::A(true, .., false) => (),
506 Either::A(.., true) => (), 506 Either::A(.., true) => (),
@@ -537,7 +537,7 @@ fn enum_(never: Never) {
537} 537}
538fn enum_ref(never: &Never) { 538fn enum_ref(never: &Never) {
539 match never {} 539 match never {}
540 //^^^^^ missing match arm 540 //^^^^^ error: missing match arm
541} 541}
542fn bang(never: !) { 542fn bang(never: !) {
543 match never {} 543 match never {}
@@ -561,7 +561,7 @@ fn main() {
561 Some(never) => match never {}, 561 Some(never) => match never {},
562 } 562 }
563 match Option::<Never>::None { 563 match Option::<Never>::None {
564 //^^^^^^^^^^^^^^^^^^^^^ missing match arm 564 //^^^^^^^^^^^^^^^^^^^^^ error: missing match arm
565 Option::Some(_never) => {}, 565 Option::Some(_never) => {},
566 } 566 }
567} 567}
@@ -575,7 +575,7 @@ fn main() {
575 r#" 575 r#"
576fn main() { 576fn main() {
577 match (false, true, false) { 577 match (false, true, false) {
578 //^^^^^^^^^^^^^^^^^^^^ missing match arm 578 //^^^^^^^^^^^^^^^^^^^^ error: missing match arm
579 (false, ..) => (), 579 (false, ..) => (),
580 } 580 }
581}"#, 581}"#,
@@ -588,7 +588,7 @@ fn main() {
588 r#" 588 r#"
589fn main() { 589fn main() {
590 match (false, true, false) { 590 match (false, true, false) {
591 //^^^^^^^^^^^^^^^^^^^^ missing match arm 591 //^^^^^^^^^^^^^^^^^^^^ error: missing match arm
592 (.., false) => (), 592 (.., false) => (),
593 } 593 }
594}"#, 594}"#,
@@ -601,7 +601,7 @@ fn main() {
601 r#" 601 r#"
602fn main() { 602fn main() {
603 match (false, true, false) { 603 match (false, true, false) {
604 //^^^^^^^^^^^^^^^^^^^^ missing match arm 604 //^^^^^^^^^^^^^^^^^^^^ error: missing match arm
605 (true, .., false) => (), 605 (true, .., false) => (),
606 } 606 }
607}"#, 607}"#,
@@ -614,11 +614,11 @@ fn main() {
614 r#"struct Foo { a: bool } 614 r#"struct Foo { a: bool }
615fn main(f: Foo) { 615fn main(f: Foo) {
616 match f {} 616 match f {}
617 //^ missing match arm 617 //^ error: missing match arm
618 match f { Foo { a: true } => () } 618 match f { Foo { a: true } => () }
619 //^ missing match arm 619 //^ error: missing match arm
620 match &f { Foo { a: true } => () } 620 match &f { Foo { a: true } => () }
621 //^^ missing match arm 621 //^^ error: missing match arm
622 match f { Foo { a: _ } => () } 622 match f { Foo { a: _ } => () }
623 match f { 623 match f {
624 Foo { a: true } => (), 624 Foo { a: true } => (),
@@ -639,9 +639,9 @@ fn main(f: Foo) {
639 r#"struct Foo(bool); 639 r#"struct Foo(bool);
640fn main(f: Foo) { 640fn main(f: Foo) {
641 match f {} 641 match f {}
642 //^ missing match arm 642 //^ error: missing match arm
643 match f { Foo(true) => () } 643 match f { Foo(true) => () }
644 //^ missing match arm 644 //^ error: missing match arm
645 match f { 645 match f {
646 Foo(true) => (), 646 Foo(true) => (),
647 Foo(false) => (), 647 Foo(false) => (),
@@ -657,7 +657,7 @@ fn main(f: Foo) {
657 r#"struct Foo; 657 r#"struct Foo;
658fn main(f: Foo) { 658fn main(f: Foo) {
659 match f {} 659 match f {}
660 //^ missing match arm 660 //^ error: missing match arm
661 match f { Foo => () } 661 match f { Foo => () }
662} 662}
663"#, 663"#,
@@ -670,9 +670,9 @@ fn main(f: Foo) {
670 r#"struct Foo { foo: bool, bar: bool } 670 r#"struct Foo { foo: bool, bar: bool }
671fn main(f: Foo) { 671fn main(f: Foo) {
672 match f { Foo { foo: true, .. } => () } 672 match f { Foo { foo: true, .. } => () }
673 //^ missing match arm 673 //^ error: missing match arm
674 match f { 674 match f {
675 //^ missing match arm 675 //^ error: missing match arm
676 Foo { foo: true, .. } => (), 676 Foo { foo: true, .. } => (),
677 Foo { bar: false, .. } => () 677 Foo { bar: false, .. } => ()
678 } 678 }
@@ -693,7 +693,7 @@ fn main(f: Foo) {
693fn main() { 693fn main() {
694 enum Either { A(bool), B } 694 enum Either { A(bool), B }
695 match Either::B { 695 match Either::B {
696 //^^^^^^^^^ missing match arm 696 //^^^^^^^^^ error: missing match arm
697 Either::A(true | false) => (), 697 Either::A(true | false) => (),
698 } 698 }
699} 699}
@@ -715,7 +715,7 @@ fn main(v: S) {
715 match v { S{..} => {} } 715 match v { S{..} => {} }
716 match v { _ => {} } 716 match v { _ => {} }
717 match v { } 717 match v { }
718 //^ missing match arm 718 //^ error: missing match arm
719} 719}
720"#, 720"#,
721 ); 721 );
@@ -731,7 +731,7 @@ fn main() {
731 false => {} 731 false => {}
732 } 732 }
733 match true { _x @ true => {} } 733 match true { _x @ true => {} }
734 //^^^^ missing match arm 734 //^^^^ error: missing match arm
735} 735}
736"#, 736"#,
737 ); 737 );
@@ -786,12 +786,12 @@ use lib::E;
786fn main() { 786fn main() {
787 match E::A { _ => {} } 787 match E::A { _ => {} }
788 match E::A { 788 match E::A {
789 //^^^^ missing match arm 789 //^^^^ error: missing match arm
790 E::A => {} 790 E::A => {}
791 E::B => {} 791 E::B => {}
792 } 792 }
793 match E::A { 793 match E::A {
794 //^^^^ missing match arm 794 //^^^^ error: missing match arm
795 E::A | E::B => {} 795 E::A | E::B => {}
796 } 796 }
797} 797}
@@ -810,7 +810,7 @@ fn main() {
810 false => {} 810 false => {}
811 } 811 }
812 match true { 812 match true {
813 //^^^^ missing match arm 813 //^^^^ error: missing match arm
814 true if false => {} 814 true if false => {}
815 false => {} 815 false => {}
816 } 816 }
diff --git a/crates/ide_diagnostics/src/handlers/missing_unsafe.rs b/crates/ide_diagnostics/src/handlers/missing_unsafe.rs
index 62d8687ba..7acd9228a 100644
--- a/crates/ide_diagnostics/src/handlers/missing_unsafe.rs
+++ b/crates/ide_diagnostics/src/handlers/missing_unsafe.rs
@@ -23,7 +23,7 @@ fn main() {
23 let x = &5 as *const usize; 23 let x = &5 as *const usize;
24 unsafe { let y = *x; } 24 unsafe { let y = *x; }
25 let z = *x; 25 let z = *x;
26} //^^ this operation is unsafe and requires an unsafe function or block 26} //^^ error: this operation is unsafe and requires an unsafe function or block
27"#, 27"#,
28 ) 28 )
29 } 29 }
@@ -48,9 +48,9 @@ unsafe fn unsafe_fn() {
48 48
49fn main() { 49fn main() {
50 unsafe_fn(); 50 unsafe_fn();
51 //^^^^^^^^^^^ this operation is unsafe and requires an unsafe function or block 51 //^^^^^^^^^^^ error: this operation is unsafe and requires an unsafe function or block
52 HasUnsafe.unsafe_fn(); 52 HasUnsafe.unsafe_fn();
53 //^^^^^^^^^^^^^^^^^^^^^ this operation is unsafe and requires an unsafe function or block 53 //^^^^^^^^^^^^^^^^^^^^^ error: this operation is unsafe and requires an unsafe function or block
54 unsafe { 54 unsafe {
55 unsafe_fn(); 55 unsafe_fn();
56 HasUnsafe.unsafe_fn(); 56 HasUnsafe.unsafe_fn();
@@ -72,7 +72,7 @@ static mut STATIC_MUT: Ty = Ty { a: 0 };
72 72
73fn main() { 73fn main() {
74 let x = STATIC_MUT.a; 74 let x = STATIC_MUT.a;
75 //^^^^^^^^^^ this operation is unsafe and requires an unsafe function or block 75 //^^^^^^^^^^ error: this operation is unsafe and requires an unsafe function or block
76 unsafe { 76 unsafe {
77 let x = STATIC_MUT.a; 77 let x = STATIC_MUT.a;
78 } 78 }
@@ -93,7 +93,7 @@ extern "rust-intrinsic" {
93fn main() { 93fn main() {
94 let _ = bitreverse(12); 94 let _ = bitreverse(12);
95 let _ = floorf32(12.0); 95 let _ = floorf32(12.0);
96 //^^^^^^^^^^^^^^ this operation is unsafe and requires an unsafe function or block 96 //^^^^^^^^^^^^^^ error: this operation is unsafe and requires an unsafe function or block
97} 97}
98"#, 98"#,
99 ); 99 );
diff --git a/crates/ide_diagnostics/src/handlers/no_such_field.rs b/crates/ide_diagnostics/src/handlers/no_such_field.rs
index e4cc8a840..92e8867f4 100644
--- a/crates/ide_diagnostics/src/handlers/no_such_field.rs
+++ b/crates/ide_diagnostics/src/handlers/no_such_field.rs
@@ -119,11 +119,11 @@ struct S { foo: i32, bar: () }
119impl S { 119impl S {
120 fn new() -> S { 120 fn new() -> S {
121 S { 121 S {
122 //^ Missing structure fields: 122 //^ 💡 error: missing structure fields:
123 //| - bar 123 //| - bar
124 foo: 92, 124 foo: 92,
125 baz: 62, 125 baz: 62,
126 //^^^^^^^ no such field 126 //^^^^^^^ 💡 error: no such field
127 } 127 }
128 } 128 }
129} 129}
diff --git a/crates/ide_diagnostics/src/handlers/remove_this_semicolon.rs b/crates/ide_diagnostics/src/handlers/remove_this_semicolon.rs
index b52e4dc84..4e639f214 100644
--- a/crates/ide_diagnostics/src/handlers/remove_this_semicolon.rs
+++ b/crates/ide_diagnostics/src/handlers/remove_this_semicolon.rs
@@ -49,7 +49,7 @@ mod tests {
49 check_diagnostics( 49 check_diagnostics(
50 r#" 50 r#"
51fn test() -> i32 { 123; } 51fn test() -> i32 { 123; }
52 //^^^ remove this semicolon 52 //^^^ 💡 error: remove this semicolon
53"#, 53"#,
54 ); 54 );
55 } 55 }
diff --git a/crates/ide_diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs b/crates/ide_diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs
index 10d5da15d..cd87a10bb 100644
--- a/crates/ide_diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs
+++ b/crates/ide_diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs
@@ -91,8 +91,8 @@ pub mod iter {
91 check_diagnostics( 91 check_diagnostics(
92 r#" 92 r#"
93 fn foo() { 93 fn foo() {
94 let m = [1, 2, 3].iter().filter_map(|x| if *x == 2 { Some (4) } else { None }).next(); 94 let m = [1, 2, 3].iter().filter_map(|x| Some(92)).next();
95 } //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ replace filter_map(..).next() with find_map(..) 95 } //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 weak: replace filter_map(..).next() with find_map(..)
96"#, 96"#,
97 ); 97 );
98 } 98 }
@@ -104,7 +104,7 @@ pub mod iter {
104fn foo() { 104fn foo() {
105 let m = [1, 2, 3] 105 let m = [1, 2, 3]
106 .iter() 106 .iter()
107 .filter_map(|x| if *x == 2 { Some (4) } else { None }) 107 .filter_map(|x| Some(92))
108 .len(); 108 .len();
109} 109}
110"#, 110"#,
@@ -118,7 +118,7 @@ fn foo() {
118fn foo() { 118fn foo() {
119 let m = [1, 2, 3] 119 let m = [1, 2, 3]
120 .iter() 120 .iter()
121 .filter_map(|x| if *x == 2 { Some (4) } else { None }) 121 .filter_map(|x| Some(92))
122 .map(|x| x + 2) 122 .map(|x| x + 2)
123 .len(); 123 .len();
124} 124}
@@ -133,7 +133,7 @@ fn foo() {
133fn foo() { 133fn foo() {
134 let m = [1, 2, 3] 134 let m = [1, 2, 3]
135 .iter() 135 .iter()
136 .filter_map(|x| if *x == 2 { Some (4) } else { None }); 136 .filter_map(|x| Some(92));
137 let n = m.next(); 137 let n = m.next();
138} 138}
139"#, 139"#,
@@ -148,7 +148,7 @@ fn foo() {
148use core::iter::Iterator; 148use core::iter::Iterator;
149use core::option::Option::{self, Some, None}; 149use core::option::Option::{self, Some, None};
150fn foo() { 150fn foo() {
151 let m = [1, 2, 3].iter().$0filter_map(|x| if *x == 2 { Some (4) } else { None }).next(); 151 let m = [1, 2, 3].iter().$0filter_map(|x| Some(92)).next();
152} 152}
153//- /core/lib.rs crate:core 153//- /core/lib.rs crate:core
154pub mod option { 154pub mod option {
@@ -171,7 +171,7 @@ pub mod iter {
171use core::iter::Iterator; 171use core::iter::Iterator;
172use core::option::Option::{self, Some, None}; 172use core::option::Option::{self, Some, None};
173fn foo() { 173fn foo() {
174 let m = [1, 2, 3].iter().find_map(|x| if *x == 2 { Some (4) } else { None }); 174 let m = [1, 2, 3].iter().find_map(|x| Some(92));
175} 175}
176"#, 176"#,
177 ) 177 )
diff --git a/crates/ide_diagnostics/src/handlers/unlinked_file.rs b/crates/ide_diagnostics/src/handlers/unlinked_file.rs
index 8921ddde2..8e601fa48 100644
--- a/crates/ide_diagnostics/src/handlers/unlinked_file.rs
+++ b/crates/ide_diagnostics/src/handlers/unlinked_file.rs
@@ -14,32 +14,29 @@ use text_edit::TextEdit;
14 14
15use crate::{fix, Assist, Diagnostic, DiagnosticsContext}; 15use crate::{fix, Assist, Diagnostic, DiagnosticsContext};
16 16
17#[derive(Debug)]
18pub(crate) struct UnlinkedFile {
19 pub(crate) file: FileId,
20}
21
22// Diagnostic: unlinked-file 17// Diagnostic: unlinked-file
23// 18//
24// This diagnostic is shown for files that are not included in any crate, or files that are part of 19// This diagnostic is shown for files that are not included in any crate, or files that are part of
25// crates rust-analyzer failed to discover. The file will not have IDE features available. 20// crates rust-analyzer failed to discover. The file will not have IDE features available.
26pub(crate) fn unlinked_file(ctx: &DiagnosticsContext, d: &UnlinkedFile) -> Diagnostic { 21pub(crate) fn unlinked_file(ctx: &DiagnosticsContext, acc: &mut Vec<Diagnostic>, file_id: FileId) {
27 // Limit diagnostic to the first few characters in the file. This matches how VS Code 22 // Limit diagnostic to the first few characters in the file. This matches how VS Code
28 // renders it with the full span, but on other editors, and is less invasive. 23 // renders it with the full span, but on other editors, and is less invasive.
29 let range = ctx.sema.db.parse(d.file).syntax_node().text_range(); 24 let range = ctx.sema.db.parse(file_id).syntax_node().text_range();
30 // FIXME: This is wrong if one of the first three characters is not ascii: `//Ы`. 25 // FIXME: This is wrong if one of the first three characters is not ascii: `//Ы`.
31 let range = range.intersect(TextRange::up_to(TextSize::of("..."))).unwrap_or(range); 26 let range = range.intersect(TextRange::up_to(TextSize::of("..."))).unwrap_or(range);
32 27
33 Diagnostic::new("unlinked-file", "file not included in module tree", range) 28 acc.push(
34 .with_fixes(fixes(ctx, d)) 29 Diagnostic::new("unlinked-file", "file not included in module tree", range)
30 .with_fixes(fixes(ctx, file_id)),
31 );
35} 32}
36 33
37fn fixes(ctx: &DiagnosticsContext, d: &UnlinkedFile) -> Option<Vec<Assist>> { 34fn fixes(ctx: &DiagnosticsContext, file_id: FileId) -> Option<Vec<Assist>> {
38 // If there's an existing module that could add `mod` or `pub mod` items to include the unlinked file, 35 // If there's an existing module that could add `mod` or `pub mod` items to include the unlinked file,
39 // suggest that as a fix. 36 // suggest that as a fix.
40 37
41 let source_root = ctx.sema.db.source_root(ctx.sema.db.file_source_root(d.file)); 38 let source_root = ctx.sema.db.source_root(ctx.sema.db.file_source_root(file_id));
42 let our_path = source_root.path_for_file(&d.file)?; 39 let our_path = source_root.path_for_file(&file_id)?;
43 let module_name = our_path.name_and_extension()?.0; 40 let module_name = our_path.name_and_extension()?.0;
44 41
45 // Candidates to look for: 42 // Candidates to look for:
@@ -68,7 +65,7 @@ fn fixes(ctx: &DiagnosticsContext, d: &UnlinkedFile) -> Option<Vec<Assist>> {
68 } 65 }
69 66
70 if module.origin.file_id() == Some(*parent_id) { 67 if module.origin.file_id() == Some(*parent_id) {
71 return make_fixes(ctx.sema.db, *parent_id, module_name, d.file); 68 return make_fixes(ctx.sema.db, *parent_id, module_name, file_id);
72 } 69 }
73 } 70 }
74 } 71 }
diff --git a/crates/ide_diagnostics/src/handlers/unresolved_extern_crate.rs b/crates/ide_diagnostics/src/handlers/unresolved_extern_crate.rs
index f5313cc0c..74e4a69c6 100644
--- a/crates/ide_diagnostics/src/handlers/unresolved_extern_crate.rs
+++ b/crates/ide_diagnostics/src/handlers/unresolved_extern_crate.rs
@@ -25,7 +25,7 @@ mod tests {
25//- /main.rs crate:main deps:core 25//- /main.rs crate:main deps:core
26extern crate core; 26extern crate core;
27 extern crate doesnotexist; 27 extern crate doesnotexist;
28//^^^^^^^^^^^^^^^^^^^^^^^^^^ unresolved extern crate 28//^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unresolved extern crate
29//- /lib.rs crate:core 29//- /lib.rs crate:core
30"#, 30"#,
31 ); 31 );
@@ -38,7 +38,7 @@ extern crate core;
38 r#" 38 r#"
39//- /lib.rs 39//- /lib.rs
40 extern crate doesnotexist; 40 extern crate doesnotexist;
41//^^^^^^^^^^^^^^^^^^^^^^^^^^ unresolved extern crate 41//^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unresolved extern crate
42// Should not error. 42// Should not error.
43extern crate self as foo; 43extern crate self as foo;
44struct Foo; 44struct Foo;
diff --git a/crates/ide_diagnostics/src/handlers/unresolved_import.rs b/crates/ide_diagnostics/src/handlers/unresolved_import.rs
index f30051c12..e52a88459 100644
--- a/crates/ide_diagnostics/src/handlers/unresolved_import.rs
+++ b/crates/ide_diagnostics/src/handlers/unresolved_import.rs
@@ -30,7 +30,7 @@ mod tests {
30 r#" 30 r#"
31use does_exist; 31use does_exist;
32use does_not_exist; 32use does_not_exist;
33 //^^^^^^^^^^^^^^ unresolved import 33 //^^^^^^^^^^^^^^ error: unresolved import
34 34
35mod does_exist {} 35mod does_exist {}
36"#, 36"#,
@@ -43,18 +43,18 @@ mod does_exist {}
43 check_diagnostics( 43 check_diagnostics(
44 r#" 44 r#"
45use does_exist::{Exists, DoesntExist}; 45use does_exist::{Exists, DoesntExist};
46 //^^^^^^^^^^^ unresolved import 46 //^^^^^^^^^^^ error: unresolved import
47 47
48use {does_not_exist::*, does_exist}; 48use {does_not_exist::*, does_exist};
49 //^^^^^^^^^^^^^^^^^ unresolved import 49 //^^^^^^^^^^^^^^^^^ error: unresolved import
50 50
51use does_not_exist::{ 51use does_not_exist::{
52 a, 52 a,
53 //^ unresolved import 53 //^ error: unresolved import
54 b, 54 b,
55 //^ unresolved import 55 //^ error: unresolved import
56 c, 56 c,
57 //^ unresolved import 57 //^ error: unresolved import
58}; 58};
59 59
60mod does_exist { 60mod does_exist {
@@ -71,18 +71,18 @@ mod does_exist {
71//- /main.rs crate:main 71//- /main.rs crate:main
72mod a { 72mod a {
73 extern crate doesnotexist; 73 extern crate doesnotexist;
74 //^^^^^^^^^^^^^^^^^^^^^^^^^^ unresolved extern crate 74 //^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unresolved extern crate
75 75
76 // Should not error, since we already errored for the missing crate. 76 // Should not error, since we already errored for the missing crate.
77 use doesnotexist::{self, bla, *}; 77 use doesnotexist::{self, bla, *};
78 78
79 use crate::doesnotexist; 79 use crate::doesnotexist;
80 //^^^^^^^^^^^^^^^^^^^ unresolved import 80 //^^^^^^^^^^^^^^^^^^^ error: unresolved import
81} 81}
82 82
83mod m { 83mod m {
84 use super::doesnotexist; 84 use super::doesnotexist;
85 //^^^^^^^^^^^^^^^^^^^ unresolved import 85 //^^^^^^^^^^^^^^^^^^^ error: unresolved import
86} 86}
87"#, 87"#,
88 ); 88 );
diff --git a/crates/ide_diagnostics/src/handlers/unresolved_macro_call.rs b/crates/ide_diagnostics/src/handlers/unresolved_macro_call.rs
index 4c3c1c19a..f0f7725db 100644
--- a/crates/ide_diagnostics/src/handlers/unresolved_macro_call.rs
+++ b/crates/ide_diagnostics/src/handlers/unresolved_macro_call.rs
@@ -40,7 +40,7 @@ mod tests {
40 r#" 40 r#"
41fn f() { 41fn f() {
42 m!(); 42 m!();
43} //^ unresolved macro `m!` 43} //^ error: unresolved macro `m!`
44 44
45"#, 45"#,
46 ); 46 );
@@ -51,7 +51,7 @@ fn f() {
51 check_diagnostics( 51 check_diagnostics(
52 r#" 52 r#"
53foo::bar!(92); 53foo::bar!(92);
54 //^^^ unresolved macro `foo::bar!` 54 //^^^ error: unresolved macro `foo::bar!`
55"#, 55"#,
56 ); 56 );
57 } 57 }
@@ -63,7 +63,7 @@ foo::bar!(92);
63macro_rules! m { () => {} } 63macro_rules! m { () => {} }
64 64
65m!(); m2!(); 65m!(); m2!();
66 //^^ unresolved macro `self::m2!` 66 //^^ error: unresolved macro `self::m2!`
67"#, 67"#,
68 ); 68 );
69 } 69 }
@@ -77,7 +77,7 @@ mod mac {
77macro_rules! m { () => {} } } 77macro_rules! m { () => {} } }
78 78
79self::m!(); self::m2!(); 79self::m!(); self::m2!();
80 //^^ unresolved macro `self::m2!` 80 //^^ error: unresolved macro `self::m2!`
81"#, 81"#,
82 ); 82 );
83 } 83 }
diff --git a/crates/ide_diagnostics/src/handlers/unresolved_module.rs b/crates/ide_diagnostics/src/handlers/unresolved_module.rs
index 17166a0c6..61fc43604 100644
--- a/crates/ide_diagnostics/src/handlers/unresolved_module.rs
+++ b/crates/ide_diagnostics/src/handlers/unresolved_module.rs
@@ -50,7 +50,7 @@ mod tests {
50//- /lib.rs 50//- /lib.rs
51mod foo; 51mod foo;
52 mod bar; 52 mod bar;
53//^^^^^^^^ unresolved module 53//^^^^^^^^ 💡 error: unresolved module
54mod baz {} 54mod baz {}
55//- /foo.rs 55//- /foo.rs
56"#, 56"#,
diff --git a/crates/ide_diagnostics/src/handlers/useless_braces.rs b/crates/ide_diagnostics/src/handlers/useless_braces.rs
new file mode 100644
index 000000000..8b9330e04
--- /dev/null
+++ b/crates/ide_diagnostics/src/handlers/useless_braces.rs
@@ -0,0 +1,148 @@
1use ide_db::{base_db::FileId, source_change::SourceChange};
2use itertools::Itertools;
3use syntax::{ast, AstNode, SyntaxNode, TextRange};
4use text_edit::TextEdit;
5
6use crate::{fix, Diagnostic, Severity};
7
8// Diagnostic: unnecessary-braces
9//
10// Diagnostic for unnecessary braces in `use` items.
11pub(crate) fn useless_braces(
12 acc: &mut Vec<Diagnostic>,
13 file_id: FileId,
14 node: &SyntaxNode,
15) -> Option<()> {
16 let use_tree_list = ast::UseTreeList::cast(node.clone())?;
17 if let Some((single_use_tree,)) = use_tree_list.use_trees().collect_tuple() {
18 // If there is a comment inside the bracketed `use`,
19 // assume it is a commented out module path and don't show diagnostic.
20 if use_tree_list.has_inner_comment() {
21 return Some(());
22 }
23
24 let use_range = use_tree_list.syntax().text_range();
25 let edit = remove_braces(&single_use_tree).unwrap_or_else(|| {
26 let to_replace = single_use_tree.syntax().text().to_string();
27 let mut edit_builder = TextEdit::builder();
28 edit_builder.delete(use_range);
29 edit_builder.insert(use_range.start(), to_replace);
30 edit_builder.finish()
31 });
32
33 acc.push(
34 Diagnostic::new(
35 "unnecessary-braces",
36 "Unnecessary braces in use statement".to_string(),
37 use_range,
38 )
39 .severity(Severity::WeakWarning)
40 .with_fixes(Some(vec![fix(
41 "remove_braces",
42 "Remove unnecessary braces",
43 SourceChange::from_text_edit(file_id, edit),
44 use_range,
45 )])),
46 );
47 }
48
49 Some(())
50}
51
52fn remove_braces(single_use_tree: &ast::UseTree) -> Option<TextEdit> {
53 let use_tree_list_node = single_use_tree.syntax().parent()?;
54 if single_use_tree.path()?.segment()?.self_token().is_some() {
55 let start = use_tree_list_node.prev_sibling_or_token()?.text_range().start();
56 let end = use_tree_list_node.text_range().end();
57 return Some(TextEdit::delete(TextRange::new(start, end)));
58 }
59 None
60}
61
62#[cfg(test)]
63mod tests {
64 use crate::tests::{check_diagnostics, check_fix};
65
66 #[test]
67 fn test_check_unnecessary_braces_in_use_statement() {
68 check_diagnostics(
69 r#"
70use a;
71use a::{c, d::e};
72
73mod a {
74 mod c {}
75 mod d {
76 mod e {}
77 }
78}
79"#,
80 );
81 check_diagnostics(
82 r#"
83use a;
84use a::{
85 c,
86 // d::e
87};
88
89mod a {
90 mod c {}
91 mod d {
92 mod e {}
93 }
94}
95"#,
96 );
97 check_fix(
98 r#"
99mod b {}
100use {$0b};
101"#,
102 r#"
103mod b {}
104use b;
105"#,
106 );
107 check_fix(
108 r#"
109mod b {}
110use {b$0};
111"#,
112 r#"
113mod b {}
114use b;
115"#,
116 );
117 check_fix(
118 r#"
119mod a { mod c {} }
120use a::{c$0};
121"#,
122 r#"
123mod a { mod c {} }
124use a::c;
125"#,
126 );
127 check_fix(
128 r#"
129mod a {}
130use a::{self$0};
131"#,
132 r#"
133mod a {}
134use a;
135"#,
136 );
137 check_fix(
138 r#"
139mod a { mod c {} mod d { mod e {} } }
140use a::{c, d::{e$0}};
141"#,
142 r#"
143mod a { mod c {} mod d { mod e {} } }
144use a::{c, d::e};
145"#,
146 );
147 }
148}
diff --git a/crates/ide_diagnostics/src/lib.rs b/crates/ide_diagnostics/src/lib.rs
index 88037be5a..6ad1b4373 100644
--- a/crates/ide_diagnostics/src/lib.rs
+++ b/crates/ide_diagnostics/src/lib.rs
@@ -37,15 +37,17 @@ mod handlers {
37 pub(crate) mod remove_this_semicolon; 37 pub(crate) mod remove_this_semicolon;
38 pub(crate) mod replace_filter_map_next_with_find_map; 38 pub(crate) mod replace_filter_map_next_with_find_map;
39 pub(crate) mod unimplemented_builtin_macro; 39 pub(crate) mod unimplemented_builtin_macro;
40 pub(crate) mod unlinked_file;
41 pub(crate) mod unresolved_extern_crate; 40 pub(crate) mod unresolved_extern_crate;
42 pub(crate) mod unresolved_import; 41 pub(crate) mod unresolved_import;
43 pub(crate) mod unresolved_macro_call; 42 pub(crate) mod unresolved_macro_call;
44 pub(crate) mod unresolved_module; 43 pub(crate) mod unresolved_module;
45 pub(crate) mod unresolved_proc_macro; 44 pub(crate) mod unresolved_proc_macro;
46}
47 45
48mod field_shorthand; 46 // The handlers bellow are unusual, the implement the diagnostics as well.
47 pub(crate) mod field_shorthand;
48 pub(crate) mod useless_braces;
49 pub(crate) mod unlinked_file;
50}
49 51
50use hir::{diagnostics::AnyDiagnostic, Semantics}; 52use hir::{diagnostics::AnyDiagnostic, Semantics};
51use ide_db::{ 53use ide_db::{
@@ -55,15 +57,8 @@ use ide_db::{
55 source_change::SourceChange, 57 source_change::SourceChange,
56 RootDatabase, 58 RootDatabase,
57}; 59};
58use itertools::Itertools;
59use rustc_hash::FxHashSet; 60use rustc_hash::FxHashSet;
60use syntax::{ 61use syntax::{ast::AstNode, TextRange};
61 ast::{self, AstNode},
62 SyntaxNode, TextRange,
63};
64use text_edit::TextEdit;
65
66use crate::handlers::unlinked_file::UnlinkedFile;
67 62
68#[derive(Copy, Clone, Debug, PartialEq)] 63#[derive(Copy, Clone, Debug, PartialEq)]
69pub struct DiagnosticCode(pub &'static str); 64pub struct DiagnosticCode(pub &'static str);
@@ -123,6 +118,8 @@ impl Diagnostic {
123#[derive(Debug, Copy, Clone)] 118#[derive(Debug, Copy, Clone)]
124pub enum Severity { 119pub enum Severity {
125 Error, 120 Error,
121 // We don't actually emit this one yet, but we should at some point.
122 // Warning,
126 WeakWarning, 123 WeakWarning,
127} 124}
128 125
@@ -157,21 +154,20 @@ pub fn diagnostics(
157 ); 154 );
158 155
159 for node in parse.tree().syntax().descendants() { 156 for node in parse.tree().syntax().descendants() {
160 check_unnecessary_braces_in_use_statement(&mut res, file_id, &node); 157 handlers::useless_braces::useless_braces(&mut res, file_id, &node);
161 field_shorthand::check(&mut res, file_id, &node); 158 handlers::field_shorthand::field_shorthand(&mut res, file_id, &node);
162 } 159 }
163 160
164 let mut diags = Vec::new();
165 let module = sema.to_module_def(file_id); 161 let module = sema.to_module_def(file_id);
166 if let Some(m) = module {
167 m.diagnostics(db, &mut diags)
168 }
169 162
170 let ctx = DiagnosticsContext { config, sema, resolve }; 163 let ctx = DiagnosticsContext { config, sema, resolve };
171 if module.is_none() { 164 if module.is_none() {
172 let d = UnlinkedFile { file: file_id }; 165 handlers::unlinked_file::unlinked_file(&ctx, &mut res, file_id);
173 let d = handlers::unlinked_file::unlinked_file(&ctx, &d); 166 }
174 res.push(d) 167
168 let mut diags = Vec::new();
169 if let Some(m) = module {
170 m.diagnostics(db, &mut diags)
175 } 171 }
176 172
177 for diag in diags { 173 for diag in diags {
@@ -211,61 +207,6 @@ pub fn diagnostics(
211 res 207 res
212} 208}
213 209
214fn check_unnecessary_braces_in_use_statement(
215 acc: &mut Vec<Diagnostic>,
216 file_id: FileId,
217 node: &SyntaxNode,
218) -> Option<()> {
219 let use_tree_list = ast::UseTreeList::cast(node.clone())?;
220 if let Some((single_use_tree,)) = use_tree_list.use_trees().collect_tuple() {
221 // If there is a comment inside the bracketed `use`,
222 // assume it is a commented out module path and don't show diagnostic.
223 if use_tree_list.has_inner_comment() {
224 return Some(());
225 }
226
227 let use_range = use_tree_list.syntax().text_range();
228 let edit =
229 text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(&single_use_tree)
230 .unwrap_or_else(|| {
231 let to_replace = single_use_tree.syntax().text().to_string();
232 let mut edit_builder = TextEdit::builder();
233 edit_builder.delete(use_range);
234 edit_builder.insert(use_range.start(), to_replace);
235 edit_builder.finish()
236 });
237
238 acc.push(
239 Diagnostic::new(
240 "unnecessary-braces",
241 "Unnecessary braces in use statement".to_string(),
242 use_range,
243 )
244 .severity(Severity::WeakWarning)
245 .with_fixes(Some(vec![fix(
246 "remove_braces",
247 "Remove unnecessary braces",
248 SourceChange::from_text_edit(file_id, edit),
249 use_range,
250 )])),
251 );
252 }
253
254 Some(())
255}
256
257fn text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(
258 single_use_tree: &ast::UseTree,
259) -> Option<TextEdit> {
260 let use_tree_list_node = single_use_tree.syntax().parent()?;
261 if single_use_tree.path()?.segment()?.self_token().is_some() {
262 let start = use_tree_list_node.prev_sibling_or_token()?.text_range().start();
263 let end = use_tree_list_node.text_range().end();
264 return Some(TextEdit::delete(TextRange::new(start, end)));
265 }
266 None
267}
268
269fn fix(id: &'static str, label: &str, source_change: SourceChange, target: TextRange) -> Assist { 210fn fix(id: &'static str, label: &str, source_change: SourceChange, target: TextRange) -> Assist {
270 let mut res = unresolved_fix(id, label, target); 211 let mut res = unresolved_fix(id, label, target);
271 res.source_change = Some(source_change); 212 res.source_change = Some(source_change);
@@ -294,7 +235,7 @@ mod tests {
294 use stdx::trim_indent; 235 use stdx::trim_indent;
295 use test_utils::{assert_eq_text, extract_annotations}; 236 use test_utils::{assert_eq_text, extract_annotations};
296 237
297 use crate::DiagnosticsConfig; 238 use crate::{DiagnosticsConfig, Severity};
298 239
299 /// Takes a multi-file input fixture with annotated cursor positions, 240 /// Takes a multi-file input fixture with annotated cursor positions,
300 /// and checks that: 241 /// and checks that:
@@ -390,97 +331,29 @@ mod tests {
390 super::diagnostics(&db, &config, &AssistResolveStrategy::All, file_id); 331 super::diagnostics(&db, &config, &AssistResolveStrategy::All, file_id);
391 332
392 let expected = extract_annotations(&*db.file_text(file_id)); 333 let expected = extract_annotations(&*db.file_text(file_id));
393 let mut actual = 334 let mut actual = diagnostics
394 diagnostics.into_iter().map(|d| (d.range, d.message)).collect::<Vec<_>>(); 335 .into_iter()
336 .map(|d| {
337 let mut annotation = String::new();
338 if let Some(fixes) = &d.fixes {
339 assert!(!fixes.is_empty());
340 annotation.push_str("💡 ")
341 }
342 annotation.push_str(match d.severity {
343 Severity::Error => "error",
344 Severity::WeakWarning => "weak",
345 });
346 annotation.push_str(": ");
347 annotation.push_str(&d.message);
348 (d.range, annotation)
349 })
350 .collect::<Vec<_>>();
395 actual.sort_by_key(|(range, _)| range.start()); 351 actual.sort_by_key(|(range, _)| range.start());
396 assert_eq!(expected, actual); 352 assert_eq!(expected, actual);
397 } 353 }
398 } 354 }
399 355
400 #[test] 356 #[test]
401 fn test_check_unnecessary_braces_in_use_statement() {
402 check_diagnostics(
403 r#"
404use a;
405use a::{c, d::e};
406
407mod a {
408 mod c {}
409 mod d {
410 mod e {}
411 }
412}
413"#,
414 );
415 check_diagnostics(
416 r#"
417use a;
418use a::{
419 c,
420 // d::e
421};
422
423mod a {
424 mod c {}
425 mod d {
426 mod e {}
427 }
428}
429"#,
430 );
431 check_fix(
432 r"
433 mod b {}
434 use {$0b};
435 ",
436 r"
437 mod b {}
438 use b;
439 ",
440 );
441 check_fix(
442 r"
443 mod b {}
444 use {b$0};
445 ",
446 r"
447 mod b {}
448 use b;
449 ",
450 );
451 check_fix(
452 r"
453 mod a { mod c {} }
454 use a::{c$0};
455 ",
456 r"
457 mod a { mod c {} }
458 use a::c;
459 ",
460 );
461 check_fix(
462 r"
463 mod a {}
464 use a::{self$0};
465 ",
466 r"
467 mod a {}
468 use a;
469 ",
470 );
471 check_fix(
472 r"
473 mod a { mod c {} mod d { mod e {} } }
474 use a::{c, d::{e$0}};
475 ",
476 r"
477 mod a { mod c {} mod d { mod e {} } }
478 use a::{c, d::e};
479 ",
480 );
481 }
482
483 #[test]
484 fn test_disabled_diagnostics() { 357 fn test_disabled_diagnostics() {
485 let mut config = DiagnosticsConfig::default(); 358 let mut config = DiagnosticsConfig::default();
486 config.disabled.insert("unresolved-module".into()); 359 config.disabled.insert("unresolved-module".into());
@@ -498,33 +371,4 @@ mod a {
498 ); 371 );
499 assert!(!diagnostics.is_empty()); 372 assert!(!diagnostics.is_empty());
500 } 373 }
501
502 #[test]
503 fn import_extern_crate_clash_with_inner_item() {
504 // This is more of a resolver test, but doesn't really work with the hir_def testsuite.
505
506 check_diagnostics(
507 r#"
508//- /lib.rs crate:lib deps:jwt
509mod permissions;
510
511use permissions::jwt;
512
513fn f() {
514 fn inner() {}
515 jwt::Claims {}; // should resolve to the local one with 0 fields, and not get a diagnostic
516}
517
518//- /permissions.rs
519pub mod jwt {
520 pub struct Claims {}
521}
522
523//- /jwt/lib.rs crate:jwt
524pub struct Claims {
525 field: u8,
526}
527 "#,
528 );
529 }
530} 374}