aboutsummaryrefslogtreecommitdiff
path: root/crates/ide/src/syntax_highlighting.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide/src/syntax_highlighting.rs')
-rw-r--r--crates/ide/src/syntax_highlighting.rs63
1 files changed, 52 insertions, 11 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()