diff options
5 files changed, 155 insertions, 30 deletions
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs index 25d6f7abd..d9fc25d88 100644 --- a/crates/ide/src/syntax_highlighting.rs +++ b/crates/ide/src/syntax_highlighting.rs | |||
@@ -4,7 +4,7 @@ mod injection; | |||
4 | #[cfg(test)] | 4 | #[cfg(test)] |
5 | mod tests; | 5 | mod tests; |
6 | 6 | ||
7 | use hir::{Name, Semantics, VariantDef}; | 7 | use hir::{Local, Name, Semantics, VariantDef}; |
8 | use ide_db::{ | 8 | use ide_db::{ |
9 | defs::{classify_name, classify_name_ref, Definition, NameClass, NameRefClass}, | 9 | defs::{classify_name, classify_name_ref, Definition, NameClass, NameRefClass}, |
10 | RootDatabase, | 10 | RootDatabase, |
@@ -13,8 +13,8 @@ use rustc_hash::FxHashMap; | |||
13 | use syntax::{ | 13 | use syntax::{ |
14 | ast::{self, HasFormatSpecifier}, | 14 | ast::{self, HasFormatSpecifier}, |
15 | AstNode, AstToken, Direction, NodeOrToken, SyntaxElement, | 15 | AstNode, AstToken, Direction, NodeOrToken, SyntaxElement, |
16 | SyntaxKind::*, | 16 | SyntaxKind::{self, *}, |
17 | TextRange, WalkEvent, T, | 17 | SyntaxNode, SyntaxToken, TextRange, WalkEvent, T, |
18 | }; | 18 | }; |
19 | 19 | ||
20 | use crate::FileId; | 20 | use crate::FileId; |
@@ -454,6 +454,32 @@ fn macro_call_range(macro_call: &ast::MacroCall) -> Option<TextRange> { | |||
454 | Some(TextRange::new(range_start, range_end)) | 454 | Some(TextRange::new(range_start, range_end)) |
455 | } | 455 | } |
456 | 456 | ||
457 | /// Returns true if the parent nodes of `node` all match the `SyntaxKind`s in `kinds` exactly. | ||
458 | fn parents_match(mut node: NodeOrToken<SyntaxNode, SyntaxToken>, mut kinds: &[SyntaxKind]) -> bool { | ||
459 | while let (Some(parent), [kind, rest @ ..]) = (&node.parent(), kinds) { | ||
460 | if parent.kind() != *kind { | ||
461 | return false; | ||
462 | } | ||
463 | |||
464 | // FIXME: Would be nice to get parent out of the match, but binding by-move and by-value | ||
465 | // in the same pattern is unstable: rust-lang/rust#68354. | ||
466 | node = node.parent().unwrap().into(); | ||
467 | kinds = rest; | ||
468 | } | ||
469 | |||
470 | // Only true if we matched all expected kinds | ||
471 | kinds.len() == 0 | ||
472 | } | ||
473 | |||
474 | fn is_consumed_lvalue( | ||
475 | node: NodeOrToken<SyntaxNode, SyntaxToken>, | ||
476 | local: &Local, | ||
477 | db: &RootDatabase, | ||
478 | ) -> bool { | ||
479 | // When lvalues are passed as arguments and they're not Copy, then mark them as Consuming. | ||
480 | parents_match(node, &[PATH_SEGMENT, PATH, PATH_EXPR, ARG_LIST]) && !local.ty(db).is_copy(db) | ||
481 | } | ||
482 | |||
457 | fn highlight_element( | 483 | fn highlight_element( |
458 | sema: &Semantics<RootDatabase>, | 484 | sema: &Semantics<RootDatabase>, |
459 | bindings_shadow_count: &mut FxHashMap<Name, u32>, | 485 | bindings_shadow_count: &mut FxHashMap<Name, u32>, |
@@ -522,6 +548,12 @@ fn highlight_element( | |||
522 | 548 | ||
523 | let mut h = highlight_def(db, def); | 549 | let mut h = highlight_def(db, def); |
524 | 550 | ||
551 | if let Definition::Local(local) = &def { | ||
552 | if is_consumed_lvalue(name_ref.syntax().clone().into(), local, db) { | ||
553 | h |= HighlightModifier::Consuming; | ||
554 | } | ||
555 | } | ||
556 | |||
525 | if let Some(parent) = name_ref.syntax().parent() { | 557 | if let Some(parent) = name_ref.syntax().parent() { |
526 | if matches!(parent.kind(), FIELD_EXPR | RECORD_PAT_FIELD) { | 558 | if matches!(parent.kind(), FIELD_EXPR | RECORD_PAT_FIELD) { |
527 | if let Definition::Field(field) = def { | 559 | if let Definition::Field(field) = def { |
@@ -645,21 +677,30 @@ fn highlight_element( | |||
645 | .and_then(ast::SelfParam::cast) | 677 | .and_then(ast::SelfParam::cast) |
646 | .and_then(|p| p.mut_token()) | 678 | .and_then(|p| p.mut_token()) |
647 | .is_some(); | 679 | .is_some(); |
648 | // closure to enforce lazyness | 680 | let self_path = &element |
649 | let self_path = || { | 681 | .parent() |
650 | sema.resolve_path(&element.parent()?.parent().and_then(ast::Path::cast)?) | 682 | .as_ref() |
651 | }; | 683 | .and_then(SyntaxNode::parent) |
684 | .and_then(ast::Path::cast) | ||
685 | .and_then(|p| sema.resolve_path(&p)); | ||
686 | let mut h = HighlightTag::SelfKeyword.into(); | ||
652 | if self_param_is_mut | 687 | if self_param_is_mut |
653 | || matches!(self_path(), | 688 | || matches!(self_path, |
654 | Some(hir::PathResolution::Local(local)) | 689 | Some(hir::PathResolution::Local(local)) |
655 | if local.is_self(db) | 690 | if local.is_self(db) |
656 | && (local.is_mut(db) || local.ty(db).is_mutable_reference()) | 691 | && (local.is_mut(db) || local.ty(db).is_mutable_reference()) |
657 | ) | 692 | ) |
658 | { | 693 | { |
659 | HighlightTag::SelfKeyword | HighlightModifier::Mutable | 694 | h |= HighlightModifier::Mutable |
660 | } else { | ||
661 | HighlightTag::SelfKeyword.into() | ||
662 | } | 695 | } |
696 | |||
697 | if let Some(hir::PathResolution::Local(local)) = self_path { | ||
698 | if is_consumed_lvalue(element, &local, db) { | ||
699 | h |= HighlightModifier::Consuming; | ||
700 | } | ||
701 | } | ||
702 | |||
703 | h | ||
663 | } | 704 | } |
664 | T![ref] => element | 705 | T![ref] => element |
665 | .parent() | 706 | .parent() |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html index d0df2e0ec..cde42024c 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html | |||
@@ -61,8 +61,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
61 | <span class="punctuation">}</span> | 61 | <span class="punctuation">}</span> |
62 | 62 | ||
63 | <span class="keyword">impl</span> <span class="struct">Foo</span> <span class="punctuation">{</span> | 63 | <span class="keyword">impl</span> <span class="struct">Foo</span> <span class="punctuation">{</span> |
64 | <span class="keyword">fn</span> <span class="function declaration">baz</span><span class="punctuation">(</span><span class="keyword">mut</span> <span class="self_keyword mutable">self</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="builtin_type">i32</span> <span class="punctuation">{</span> | 64 | <span class="keyword">fn</span> <span class="function declaration">baz</span><span class="punctuation">(</span><span class="keyword">mut</span> <span class="self_keyword mutable">self</span><span class="punctuation">,</span> <span class="value_param declaration">f</span><span class="punctuation">:</span> <span class="struct">Foo</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="builtin_type">i32</span> <span class="punctuation">{</span> |
65 | <span class="self_keyword">self</span><span class="punctuation">.</span><span class="field">x</span> | 65 | <span class="value_param">f</span><span class="punctuation">.</span><span class="function consuming">baz</span><span class="punctuation">(</span><span class="self_keyword consuming">self</span><span class="punctuation">)</span> |
66 | <span class="punctuation">}</span> | 66 | <span class="punctuation">}</span> |
67 | 67 | ||
68 | <span class="keyword">fn</span> <span class="function declaration">qux</span><span class="punctuation">(</span><span class="operator">&</span><span class="keyword">mut</span> <span class="self_keyword mutable">self</span><span class="punctuation">)</span> <span class="punctuation">{</span> | 68 | <span class="keyword">fn</span> <span class="function declaration">qux</span><span class="punctuation">(</span><span class="operator">&</span><span class="keyword">mut</span> <span class="self_keyword mutable">self</span><span class="punctuation">)</span> <span class="punctuation">{</span> |
@@ -80,8 +80,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
80 | <span class="punctuation">}</span> | 80 | <span class="punctuation">}</span> |
81 | 81 | ||
82 | <span class="keyword">impl</span> <span class="struct">FooCopy</span> <span class="punctuation">{</span> | 82 | <span class="keyword">impl</span> <span class="struct">FooCopy</span> <span class="punctuation">{</span> |
83 | <span class="keyword">fn</span> <span class="function declaration">baz</span><span class="punctuation">(</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="builtin_type">u32</span> <span class="punctuation">{</span> | 83 | <span class="keyword">fn</span> <span class="function declaration">baz</span><span class="punctuation">(</span><span class="self_keyword">self</span><span class="punctuation">,</span> <span class="value_param declaration">f</span><span class="punctuation">:</span> <span class="struct">FooCopy</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="builtin_type">u32</span> <span class="punctuation">{</span> |
84 | <span class="self_keyword">self</span><span class="punctuation">.</span><span class="field">x</span> | 84 | <span class="value_param">f</span><span class="punctuation">.</span><span class="function">baz</span><span class="punctuation">(</span><span class="self_keyword">self</span><span class="punctuation">)</span> |
85 | <span class="punctuation">}</span> | 85 | <span class="punctuation">}</span> |
86 | 86 | ||
87 | <span class="keyword">fn</span> <span class="function declaration">qux</span><span class="punctuation">(</span><span class="operator">&</span><span class="keyword">mut</span> <span class="self_keyword mutable">self</span><span class="punctuation">)</span> <span class="punctuation">{</span> | 87 | <span class="keyword">fn</span> <span class="function declaration">qux</span><span class="punctuation">(</span><span class="operator">&</span><span class="keyword">mut</span> <span class="self_keyword mutable">self</span><span class="punctuation">)</span> <span class="punctuation">{</span> |
@@ -144,14 +144,15 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
144 | <span class="variable">y</span><span class="punctuation">;</span> | 144 | <span class="variable">y</span><span class="punctuation">;</span> |
145 | 145 | ||
146 | <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">foo</span> <span class="operator">=</span> <span class="struct">Foo</span> <span class="punctuation">{</span> <span class="field">x</span><span class="punctuation">,</span> <span class="field">y</span><span class="punctuation">:</span> <span class="variable mutable">x</span> <span class="punctuation">}</span><span class="punctuation">;</span> | 146 | <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">foo</span> <span class="operator">=</span> <span class="struct">Foo</span> <span class="punctuation">{</span> <span class="field">x</span><span class="punctuation">,</span> <span class="field">y</span><span class="punctuation">:</span> <span class="variable mutable">x</span> <span class="punctuation">}</span><span class="punctuation">;</span> |
147 | <span class="keyword">let</span> <span class="variable declaration">foo2</span> <span class="operator">=</span> <span class="variable mutable">foo</span><span class="punctuation">.</span><span class="unresolved_reference">clone</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> | ||
147 | <span class="variable mutable">foo</span><span class="punctuation">.</span><span class="function">quop</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> | 148 | <span class="variable mutable">foo</span><span class="punctuation">.</span><span class="function">quop</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> |
148 | <span class="variable mutable">foo</span><span class="punctuation">.</span><span class="function mutable">qux</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> | 149 | <span class="variable mutable">foo</span><span class="punctuation">.</span><span class="function mutable">qux</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> |
149 | <span class="variable mutable">foo</span><span class="punctuation">.</span><span class="function consuming">baz</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> | 150 | <span class="variable mutable">foo</span><span class="punctuation">.</span><span class="function consuming">baz</span><span class="punctuation">(</span><span class="variable consuming">foo2</span><span class="punctuation">)</span><span class="punctuation">;</span> |
150 | 151 | ||
151 | <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">copy</span> <span class="operator">=</span> <span class="struct">FooCopy</span> <span class="punctuation">{</span> <span class="field">x</span> <span class="punctuation">}</span><span class="punctuation">;</span> | 152 | <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">copy</span> <span class="operator">=</span> <span class="struct">FooCopy</span> <span class="punctuation">{</span> <span class="field">x</span> <span class="punctuation">}</span><span class="punctuation">;</span> |
152 | <span class="variable mutable">copy</span><span class="punctuation">.</span><span class="function">quop</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> | 153 | <span class="variable mutable">copy</span><span class="punctuation">.</span><span class="function">quop</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> |
153 | <span class="variable mutable">copy</span><span class="punctuation">.</span><span class="function mutable">qux</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> | 154 | <span class="variable mutable">copy</span><span class="punctuation">.</span><span class="function mutable">qux</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> |
154 | <span class="variable mutable">copy</span><span class="punctuation">.</span><span class="function">baz</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> | 155 | <span class="variable mutable">copy</span><span class="punctuation">.</span><span class="function">baz</span><span class="punctuation">(</span><span class="variable mutable">copy</span><span class="punctuation">)</span><span class="punctuation">;</span> |
155 | <span class="punctuation">}</span> | 156 | <span class="punctuation">}</span> |
156 | 157 | ||
157 | <span class="keyword">enum</span> <span class="enum declaration">Option</span><span class="punctuation"><</span><span class="type_param declaration">T</span><span class="punctuation">></span> <span class="punctuation">{</span> | 158 | <span class="keyword">enum</span> <span class="enum declaration">Option</span><span class="punctuation"><</span><span class="type_param declaration">T</span><span class="punctuation">></span> <span class="punctuation">{</span> |
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs index 6f72a29bd..57d4e1252 100644 --- a/crates/ide/src/syntax_highlighting/tests.rs +++ b/crates/ide/src/syntax_highlighting/tests.rs | |||
@@ -35,8 +35,8 @@ impl Bar for Foo { | |||
35 | } | 35 | } |
36 | 36 | ||
37 | impl Foo { | 37 | impl Foo { |
38 | fn baz(mut self) -> i32 { | 38 | fn baz(mut self, f: Foo) -> i32 { |
39 | self.x | 39 | f.baz(self) |
40 | } | 40 | } |
41 | 41 | ||
42 | fn qux(&mut self) { | 42 | fn qux(&mut self) { |
@@ -54,8 +54,8 @@ struct FooCopy { | |||
54 | } | 54 | } |
55 | 55 | ||
56 | impl FooCopy { | 56 | impl FooCopy { |
57 | fn baz(self) -> u32 { | 57 | fn baz(self, f: FooCopy) -> u32 { |
58 | self.x | 58 | f.baz(self) |
59 | } | 59 | } |
60 | 60 | ||
61 | fn qux(&mut self) { | 61 | fn qux(&mut self) { |
@@ -118,14 +118,15 @@ fn main() { | |||
118 | y; | 118 | y; |
119 | 119 | ||
120 | let mut foo = Foo { x, y: x }; | 120 | let mut foo = Foo { x, y: x }; |
121 | let foo2 = foo.clone(); | ||
121 | foo.quop(); | 122 | foo.quop(); |
122 | foo.qux(); | 123 | foo.qux(); |
123 | foo.baz(); | 124 | foo.baz(foo2); |
124 | 125 | ||
125 | let mut copy = FooCopy { x }; | 126 | let mut copy = FooCopy { x }; |
126 | copy.quop(); | 127 | copy.quop(); |
127 | copy.qux(); | 128 | copy.qux(); |
128 | copy.baz(); | 129 | copy.baz(copy); |
129 | } | 130 | } |
130 | 131 | ||
131 | enum Option<T> { | 132 | enum Option<T> { |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt b/crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt index 89dae7d5a..00e8da8a7 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt | |||
@@ -44,4 +44,49 @@ | |||
44 | }, | 44 | }, |
45 | fixes: [], | 45 | fixes: [], |
46 | }, | 46 | }, |
47 | MappedRustDiagnostic { | ||
48 | url: "file:///test/crates/hir_def/src/path.rs", | ||
49 | diagnostic: Diagnostic { | ||
50 | range: Range { | ||
51 | start: Position { | ||
52 | line: 264, | ||
53 | character: 8, | ||
54 | }, | ||
55 | end: Position { | ||
56 | line: 264, | ||
57 | character: 76, | ||
58 | }, | ||
59 | }, | ||
60 | severity: Some( | ||
61 | Error, | ||
62 | ), | ||
63 | code: None, | ||
64 | source: Some( | ||
65 | "rustc", | ||
66 | ), | ||
67 | message: "Please register your known path in the path module", | ||
68 | related_information: Some( | ||
69 | [ | ||
70 | DiagnosticRelatedInformation { | ||
71 | location: Location { | ||
72 | uri: "file:///test/crates/hir_def/src/data.rs", | ||
73 | range: Range { | ||
74 | start: Position { | ||
75 | line: 79, | ||
76 | character: 15, | ||
77 | }, | ||
78 | end: Position { | ||
79 | line: 79, | ||
80 | character: 41, | ||
81 | }, | ||
82 | }, | ||
83 | }, | ||
84 | message: "Exact error occured here", | ||
85 | }, | ||
86 | ], | ||
87 | ), | ||
88 | tags: None, | ||
89 | }, | ||
90 | fixes: [], | ||
91 | }, | ||
47 | ] | 92 | ] |
diff --git a/crates/rust-analyzer/src/diagnostics/to_proto.rs b/crates/rust-analyzer/src/diagnostics/to_proto.rs index f69a949f2..33606edda 100644 --- a/crates/rust-analyzer/src/diagnostics/to_proto.rs +++ b/crates/rust-analyzer/src/diagnostics/to_proto.rs | |||
@@ -225,12 +225,43 @@ pub(crate) fn map_rust_diagnostic_to_lsp( | |||
225 | 225 | ||
226 | // If error occurs from macro expansion, add related info pointing to | 226 | // If error occurs from macro expansion, add related info pointing to |
227 | // where the error originated | 227 | // where the error originated |
228 | if !is_from_macro(&primary_span.file_name) && primary_span.expansion.is_some() { | 228 | // Also, we would generate an additional diagnostic, so that exact place of macro |
229 | related_information.push(lsp_types::DiagnosticRelatedInformation { | 229 | // will be highlighted in the error origin place. |
230 | location: location_naive(workspace_root, &primary_span), | 230 | let additional_diagnostic = |
231 | message: "Error originated from macro here".to_string(), | 231 | if !is_from_macro(&primary_span.file_name) && primary_span.expansion.is_some() { |
232 | }); | 232 | let in_macro_location = location_naive(workspace_root, &primary_span); |
233 | } | 233 | |
234 | // Add related information for the main disagnostic. | ||
235 | related_information.push(lsp_types::DiagnosticRelatedInformation { | ||
236 | location: in_macro_location.clone(), | ||
237 | message: "Error originated from macro here".to_string(), | ||
238 | }); | ||
239 | |||
240 | // For the additional in-macro diagnostic we add the inverse message pointing to the error location in code. | ||
241 | let information_for_additional_diagnostic = | ||
242 | vec![lsp_types::DiagnosticRelatedInformation { | ||
243 | location: location.clone(), | ||
244 | message: "Exact error occured here".to_string(), | ||
245 | }]; | ||
246 | |||
247 | let diagnostic = lsp_types::Diagnostic { | ||
248 | range: in_macro_location.range, | ||
249 | severity, | ||
250 | code: code.clone().map(lsp_types::NumberOrString::String), | ||
251 | source: Some(source.clone()), | ||
252 | message: message.clone(), | ||
253 | related_information: Some(information_for_additional_diagnostic), | ||
254 | tags: if tags.is_empty() { None } else { Some(tags.clone()) }, | ||
255 | }; | ||
256 | |||
257 | Some(MappedRustDiagnostic { | ||
258 | url: in_macro_location.uri, | ||
259 | diagnostic, | ||
260 | fixes: fixes.clone(), | ||
261 | }) | ||
262 | } else { | ||
263 | None | ||
264 | }; | ||
234 | 265 | ||
235 | let diagnostic = lsp_types::Diagnostic { | 266 | let diagnostic = lsp_types::Diagnostic { |
236 | range: location.range, | 267 | range: location.range, |
@@ -246,8 +277,14 @@ pub(crate) fn map_rust_diagnostic_to_lsp( | |||
246 | tags: if tags.is_empty() { None } else { Some(tags.clone()) }, | 277 | tags: if tags.is_empty() { None } else { Some(tags.clone()) }, |
247 | }; | 278 | }; |
248 | 279 | ||
249 | MappedRustDiagnostic { url: location.uri, diagnostic, fixes: fixes.clone() } | 280 | let main_diagnostic = |
281 | MappedRustDiagnostic { url: location.uri, diagnostic, fixes: fixes.clone() }; | ||
282 | match additional_diagnostic { | ||
283 | None => vec![main_diagnostic], | ||
284 | Some(additional_diagnostic) => vec![main_diagnostic, additional_diagnostic], | ||
285 | } | ||
250 | }) | 286 | }) |
287 | .flatten() | ||
251 | .collect() | 288 | .collect() |
252 | } | 289 | } |
253 | 290 | ||