diff options
Diffstat (limited to 'crates/ide_diagnostics')
-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/missing_fields.rs | 29 | ||||
-rw-r--r-- | crates/ide_diagnostics/src/handlers/unlinked_file.rs | 23 | ||||
-rw-r--r-- | crates/ide_diagnostics/src/handlers/useless_braces.rs | 148 | ||||
-rw-r--r-- | crates/ide_diagnostics/src/lib.rs | 203 |
5 files changed, 204 insertions, 201 deletions
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 | ||
8 | use crate::{fix, Diagnostic, Severity}; | 8 | use crate::{fix, Diagnostic, Severity}; |
9 | 9 | ||
10 | pub(super) fn check(acc: &mut Vec<Diagnostic>, file_id: FileId, node: &SyntaxNode) { | 10 | pub(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/missing_fields.rs b/crates/ide_diagnostics/src/handlers/missing_fields.rs index bc82c0e4a..0dd36fb23 100644 --- a/crates/ide_diagnostics/src/handlers/missing_fields.rs +++ b/crates/ide_diagnostics/src/handlers/missing_fields.rs | |||
@@ -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 | ||
334 | mod permissions; | ||
335 | |||
336 | use permissions::jwt; | ||
337 | |||
338 | fn 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 | ||
344 | pub mod jwt { | ||
345 | pub struct Claims {} | ||
346 | } | ||
347 | |||
348 | //- /jwt/lib.rs crate:jwt | ||
349 | pub struct Claims { | ||
350 | field: u8, | ||
351 | } | ||
352 | "#, | ||
353 | ); | ||
354 | } | ||
326 | } | 355 | } |
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 | ||
15 | use crate::{fix, Assist, Diagnostic, DiagnosticsContext}; | 15 | use crate::{fix, Assist, Diagnostic, DiagnosticsContext}; |
16 | 16 | ||
17 | #[derive(Debug)] | ||
18 | pub(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. |
26 | pub(crate) fn unlinked_file(ctx: &DiagnosticsContext, d: &UnlinkedFile) -> Diagnostic { | 21 | pub(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 | ||
37 | fn fixes(ctx: &DiagnosticsContext, d: &UnlinkedFile) -> Option<Vec<Assist>> { | 34 | fn 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/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 @@ | |||
1 | use ide_db::{base_db::FileId, source_change::SourceChange}; | ||
2 | use itertools::Itertools; | ||
3 | use syntax::{ast, AstNode, SyntaxNode, TextRange}; | ||
4 | use text_edit::TextEdit; | ||
5 | |||
6 | use crate::{fix, Diagnostic, Severity}; | ||
7 | |||
8 | // Diagnostic: unnecessary-braces | ||
9 | // | ||
10 | // Diagnostic for unnecessary braces in `use` items. | ||
11 | pub(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 | |||
52 | fn 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)] | ||
63 | mod 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#" | ||
70 | use a; | ||
71 | use a::{c, d::e}; | ||
72 | |||
73 | mod a { | ||
74 | mod c {} | ||
75 | mod d { | ||
76 | mod e {} | ||
77 | } | ||
78 | } | ||
79 | "#, | ||
80 | ); | ||
81 | check_diagnostics( | ||
82 | r#" | ||
83 | use a; | ||
84 | use a::{ | ||
85 | c, | ||
86 | // d::e | ||
87 | }; | ||
88 | |||
89 | mod a { | ||
90 | mod c {} | ||
91 | mod d { | ||
92 | mod e {} | ||
93 | } | ||
94 | } | ||
95 | "#, | ||
96 | ); | ||
97 | check_fix( | ||
98 | r#" | ||
99 | mod b {} | ||
100 | use {$0b}; | ||
101 | "#, | ||
102 | r#" | ||
103 | mod b {} | ||
104 | use b; | ||
105 | "#, | ||
106 | ); | ||
107 | check_fix( | ||
108 | r#" | ||
109 | mod b {} | ||
110 | use {b$0}; | ||
111 | "#, | ||
112 | r#" | ||
113 | mod b {} | ||
114 | use b; | ||
115 | "#, | ||
116 | ); | ||
117 | check_fix( | ||
118 | r#" | ||
119 | mod a { mod c {} } | ||
120 | use a::{c$0}; | ||
121 | "#, | ||
122 | r#" | ||
123 | mod a { mod c {} } | ||
124 | use a::c; | ||
125 | "#, | ||
126 | ); | ||
127 | check_fix( | ||
128 | r#" | ||
129 | mod a {} | ||
130 | use a::{self$0}; | ||
131 | "#, | ||
132 | r#" | ||
133 | mod a {} | ||
134 | use a; | ||
135 | "#, | ||
136 | ); | ||
137 | check_fix( | ||
138 | r#" | ||
139 | mod a { mod c {} mod d { mod e {} } } | ||
140 | use a::{c, d::{e$0}}; | ||
141 | "#, | ||
142 | r#" | ||
143 | mod a { mod c {} mod d { mod e {} } } | ||
144 | use 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..52474eeab 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 | ||
48 | mod 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 | ||
50 | use hir::{diagnostics::AnyDiagnostic, Semantics}; | 52 | use hir::{diagnostics::AnyDiagnostic, Semantics}; |
51 | use ide_db::{ | 53 | use ide_db::{ |
@@ -55,15 +57,8 @@ use ide_db::{ | |||
55 | source_change::SourceChange, | 57 | source_change::SourceChange, |
56 | RootDatabase, | 58 | RootDatabase, |
57 | }; | 59 | }; |
58 | use itertools::Itertools; | ||
59 | use rustc_hash::FxHashSet; | 60 | use rustc_hash::FxHashSet; |
60 | use syntax::{ | 61 | use syntax::{ast::AstNode, TextRange}; |
61 | ast::{self, AstNode}, | ||
62 | SyntaxNode, TextRange, | ||
63 | }; | ||
64 | use text_edit::TextEdit; | ||
65 | |||
66 | use crate::handlers::unlinked_file::UnlinkedFile; | ||
67 | 62 | ||
68 | #[derive(Copy, Clone, Debug, PartialEq)] | 63 | #[derive(Copy, Clone, Debug, PartialEq)] |
69 | pub struct DiagnosticCode(pub &'static str); | 64 | pub struct DiagnosticCode(pub &'static str); |
@@ -123,6 +118,8 @@ impl Diagnostic { | |||
123 | #[derive(Debug, Copy, Clone)] | 118 | #[derive(Debug, Copy, Clone)] |
124 | pub enum Severity { | 119 | pub 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 | ||
214 | fn 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 | |||
257 | fn 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 | |||
269 | fn fix(id: &'static str, label: &str, source_change: SourceChange, target: TextRange) -> Assist { | 210 | fn 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); |
@@ -398,89 +339,6 @@ mod tests { | |||
398 | } | 339 | } |
399 | 340 | ||
400 | #[test] | 341 | #[test] |
401 | fn test_check_unnecessary_braces_in_use_statement() { | ||
402 | check_diagnostics( | ||
403 | r#" | ||
404 | use a; | ||
405 | use a::{c, d::e}; | ||
406 | |||
407 | mod a { | ||
408 | mod c {} | ||
409 | mod d { | ||
410 | mod e {} | ||
411 | } | ||
412 | } | ||
413 | "#, | ||
414 | ); | ||
415 | check_diagnostics( | ||
416 | r#" | ||
417 | use a; | ||
418 | use a::{ | ||
419 | c, | ||
420 | // d::e | ||
421 | }; | ||
422 | |||
423 | mod 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() { | 342 | fn test_disabled_diagnostics() { |
485 | let mut config = DiagnosticsConfig::default(); | 343 | let mut config = DiagnosticsConfig::default(); |
486 | config.disabled.insert("unresolved-module".into()); | 344 | config.disabled.insert("unresolved-module".into()); |
@@ -498,33 +356,4 @@ mod a { | |||
498 | ); | 356 | ); |
499 | assert!(!diagnostics.is_empty()); | 357 | assert!(!diagnostics.is_empty()); |
500 | } | 358 | } |
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 | ||
509 | mod permissions; | ||
510 | |||
511 | use permissions::jwt; | ||
512 | |||
513 | fn 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 | ||
519 | pub mod jwt { | ||
520 | pub struct Claims {} | ||
521 | } | ||
522 | |||
523 | //- /jwt/lib.rs crate:jwt | ||
524 | pub struct Claims { | ||
525 | field: u8, | ||
526 | } | ||
527 | "#, | ||
528 | ); | ||
529 | } | ||
530 | } | 359 | } |