diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs index 25d6f7abd82..4fa9e638a08 100644 --- a/crates/ide/src/syntax_highlighting.rs +++ b/crates/ide/src/syntax_highlighting.rs @@ -13,8 +13,8 @@ use syntax::{ ast::{self, HasFormatSpecifier}, AstNode, AstToken, Direction, NodeOrToken, SyntaxElement, - SyntaxKind::*, - TextRange, WalkEvent, T, + SyntaxKind::{self, *}, + SyntaxNode, TextRange, WalkEvent, T, }; use crate::FileId; @@ -454,6 +454,23 @@ fn macro_call_range(macro_call: &ast::MacroCall) -> Option { Some(TextRange::new(range_start, range_end)) } +/// Returns true if the parent nodes of `node` all match the `SyntaxKind`s in `kinds` exactly. +fn parents_match(mut node: SyntaxNode, mut kinds: &[SyntaxKind]) -> bool { + while let (Some(parent), [kind, rest @ ..]) = (&node.parent(), kinds) { + if parent.kind() != *kind { + return false; + } + + // FIXME: Would be nice to get parent out of the match, but binding by-move and by-value + // in the same pattern is unstable: rust-lang/rust#68354. + node = node.parent().unwrap(); + kinds = rest; + } + + // Only true if we matched all expected kinds + kinds.len() == 0 +} + fn highlight_element( sema: &Semantics, bindings_shadow_count: &mut FxHashMap, @@ -522,6 +539,26 @@ fn highlight_element( let mut h = highlight_def(db, def); + // When lvalues are passed as arguments and they're not Copy, then mark + // them as Consuming. + if parents_match( + name_ref.syntax().clone(), + &[PATH_SEGMENT, PATH, PATH_EXPR, ARG_LIST], + ) { + let lvalue_ty = if let Definition::Local(local) = &def { + Some(local.ty(db)) + } else if let Definition::SelfType(impl_def) = &def { + Some(impl_def.target_ty(db)) + } else { + None + }; + if let Some(lvalue_ty) = lvalue_ty { + if !lvalue_ty.is_copy(db) { + h |= HighlightModifier::Consuming; + } + } + } + if let Some(parent) = name_ref.syntax().parent() { if matches!(parent.kind(), FIELD_EXPR | RECORD_PAT_FIELD) { if let Definition::Field(field) = def { diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html index d0df2e0ec04..cade46348d0 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 } impl Foo { - fn baz(mut self) -> i32 { - self.x + fn baz(mut self, f: Foo) -> i32 { + f.baz(self) } fn qux(&mut self) { @@ -80,8 +80,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd } impl FooCopy { - fn baz(self) -> u32 { - self.x + fn baz(self, f: FooCopy) -> u32 { + f.baz(self) } fn qux(&mut self) { @@ -144,14 +144,15 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd y; let mut foo = Foo { x, y: x }; + let foo2 = foo.clone(); foo.quop(); foo.qux(); - foo.baz(); + foo.baz(foo2); let mut copy = FooCopy { x }; copy.quop(); copy.qux(); - copy.baz(); + copy.baz(copy); } enum Option<T> { diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs index 6f72a29bdc4..57d4e1252d2 100644 --- a/crates/ide/src/syntax_highlighting/tests.rs +++ b/crates/ide/src/syntax_highlighting/tests.rs @@ -35,8 +35,8 @@ fn bar(&self) -> i32 { } impl Foo { - fn baz(mut self) -> i32 { - self.x + fn baz(mut self, f: Foo) -> i32 { + f.baz(self) } fn qux(&mut self) { @@ -54,8 +54,8 @@ struct FooCopy { } impl FooCopy { - fn baz(self) -> u32 { - self.x + fn baz(self, f: FooCopy) -> u32 { + f.baz(self) } fn qux(&mut self) { @@ -118,14 +118,15 @@ fn main() { y; let mut foo = Foo { x, y: x }; + let foo2 = foo.clone(); foo.quop(); foo.qux(); - foo.baz(); + foo.baz(foo2); let mut copy = FooCopy { x }; copy.quop(); copy.qux(); - copy.baz(); + copy.baz(copy); } enum Option {