aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ide/src/syntax_highlighting.rs63
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlighting.html13
-rw-r--r--crates/ide/src/syntax_highlighting/tests.rs13
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt45
-rw-r--r--crates/rust-analyzer/src/diagnostics/to_proto.rs51
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)]
5mod tests; 5mod tests;
6 6
7use hir::{Name, Semantics, VariantDef}; 7use hir::{Local, Name, Semantics, VariantDef};
8use ide_db::{ 8use 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;
13use syntax::{ 13use 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
20use crate::FileId; 20use 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.
458fn 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
474fn 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
457fn highlight_element( 483fn 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">-&gt;</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">-&gt;</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">-&gt;</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">-&gt;</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">&lt;</span><span class="type_param declaration">T</span><span class="punctuation">&gt;</span> <span class="punctuation">{</span> 158<span class="keyword">enum</span> <span class="enum declaration">Option</span><span class="punctuation">&lt;</span><span class="type_param declaration">T</span><span class="punctuation">&gt;</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
37impl Foo { 37impl 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
56impl FooCopy { 56impl 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
131enum Option<T> { 132enum 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