From 7009d5ee2bff53b9beb555b1572c97ab3882cd98 Mon Sep 17 00:00:00 2001 From: Paul Daniel Faria Date: Thu, 30 Jul 2020 10:20:06 -0400 Subject: Add new HighlightModifier variant, Consuming --- crates/ide/src/syntax_highlighting/tags.rs | 3 +++ 1 file changed, 3 insertions(+) (limited to 'crates/ide') diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs index 49ec94bdc..c1b817f06 100644 --- a/crates/ide/src/syntax_highlighting/tags.rs +++ b/crates/ide/src/syntax_highlighting/tags.rs @@ -62,6 +62,7 @@ pub enum HighlightModifier { Documentation, Injected, Mutable, + Consuming, Unsafe, } @@ -119,6 +120,7 @@ impl HighlightModifier { HighlightModifier::Documentation, HighlightModifier::Injected, HighlightModifier::Mutable, + HighlightModifier::Consuming, HighlightModifier::Unsafe, ]; @@ -130,6 +132,7 @@ impl HighlightModifier { HighlightModifier::Documentation => "documentation", HighlightModifier::Injected => "injected", HighlightModifier::Mutable => "mutable", + HighlightModifier::Consuming => "consuming", HighlightModifier::Unsafe => "unsafe", } } -- cgit v1.2.3 From a044ff0138d6bff9406b94de89fde43e7672ee1b Mon Sep 17 00:00:00 2001 From: Paul Daniel Faria Date: Thu, 30 Jul 2020 11:07:13 -0400 Subject: Mark mutating functions with `mutable` modifier, and owning functions with `consuming`. --- crates/ide/src/syntax_highlighting.rs | 42 ++++++++++++++++++++++------- crates/ide/src/syntax_highlighting/tests.rs | 9 +++++++ crates/ide/test_data/highlighting.html | 15 ++++++++--- 3 files changed, 53 insertions(+), 13 deletions(-) (limited to 'crates/ide') diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs index 5d7c7e8d0..15a78a614 100644 --- a/crates/ide/src/syntax_highlighting.rs +++ b/crates/ide/src/syntax_highlighting.rs @@ -4,7 +4,7 @@ mod injection; #[cfg(test)] mod tests; -use hir::{Name, Semantics, VariantDef}; +use hir::{Mutability, Name, Semantics, VariantDef}; use ide_db::{ defs::{classify_name, classify_name_ref, Definition, NameClass, NameRefClass}, RootDatabase, @@ -729,13 +729,23 @@ fn highlight_name( let is_unsafe = name_ref .and_then(|name_ref| name_ref.syntax().parent()) .and_then(ast::MethodCallExpr::cast) - .map(|method_call_expr| sema.is_unsafe_method_call(method_call_expr)) + .map(|method_call_expr| sema.is_unsafe_method_call(&method_call_expr)) .unwrap_or(false); if is_unsafe { h |= HighlightModifier::Unsafe; } } - return h; + return if func.has_self_param(db) { + match func.mutability_of_self_param(db) { + Some(mutability) => match mutability { + Mutability::Mut => h | HighlightModifier::Mutable, + Mutability::Shared => h, + }, + None => h | HighlightModifier::Consuming, + } + } else { + h + }; } hir::ModuleDef::Adt(hir::Adt::Struct(_)) => HighlightTag::Struct, hir::ModuleDef::Adt(hir::Adt::Enum(_)) => HighlightTag::Enum, @@ -808,14 +818,26 @@ fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics { let mut h = Highlight::new(HighlightTag::Function); - let is_unsafe = ast::MethodCallExpr::cast(parent) - .map(|method_call_expr| sema.is_unsafe_method_call(method_call_expr)) - .unwrap_or(false); - if is_unsafe { - h |= HighlightModifier::Unsafe; - } + ast::MethodCallExpr::cast(parent) + .and_then(|method_call_expr| { + if sema.is_unsafe_method_call(&method_call_expr) { + h |= HighlightModifier::Unsafe; + } + + let func = sema.resolve_method_call(&method_call_expr)?; + if !func.has_self_param(sema.db) { + return Some(h); + } - h + Some(match func.mutability_of_self_param(sema.db) { + Some(mutability) => match mutability { + Mutability::Mut => h | HighlightModifier::Mutable, + Mutability::Shared => h, + }, + None => h | HighlightModifier::Consuming, + }) + }) + .unwrap_or_else(|| h) } FIELD_EXPR => { let h = HighlightTag::Field; diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs index 94f37d773..6cb955d29 100644 --- a/crates/ide/src/syntax_highlighting/tests.rs +++ b/crates/ide/src/syntax_highlighting/tests.rs @@ -36,6 +36,10 @@ impl Foo { fn qux(&mut self) { self.x = 0; } + + fn quop(&self) -> i32 { + self.x + } } static mut STATIC_MUT: i32 = 0; @@ -87,6 +91,11 @@ fn main() { let Foo { x: z, y } = Foo { x: z, y }; y; + + let mut foo = Foo { x, y: x }; + foo.quop(); + foo.qux(); + foo.baz(); } enum Option { diff --git a/crates/ide/test_data/highlighting.html b/crates/ide/test_data/highlighting.html index 8e0160eee..2aad06a92 100644 --- a/crates/ide/test_data/highlighting.html +++ b/crates/ide/test_data/highlighting.html @@ -55,13 +55,17 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd } impl Foo { - fn baz(mut self) -> i32 { + fn baz(mut self) -> i32 { self.x } - fn qux(&mut self) { + fn qux(&mut self) { self.x = 0; } + + fn quop(&self) -> i32 { + self.x + } } static mut STATIC_MUT: i32 = 0; @@ -113,6 +117,11 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd let Foo { x: z, y } = Foo { x: z, y }; y; + + let mut foo = Foo { x, y: x }; + foo.quop(); + foo.qux(); + foo.baz(); } enum Option<T> { @@ -122,7 +131,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd use Option::*; impl<T> Option<T> { - fn and<U>(self, other: Option<U>) -> Option<(T, U)> { + fn and<U>(self, other: Option<U>) -> Option<(T, U)> { match other { None => unimplemented!(), Nope => Nope, -- cgit v1.2.3 From 3456e2eec7c1e18734f8fa41924a83b4c676dc00 Mon Sep 17 00:00:00 2001 From: Paul Daniel Faria Date: Thu, 30 Jul 2020 22:31:53 -0400 Subject: Add new method to Semantics, method_receiver_kind, which returns the kind of self The options are Shared, Mutable, Consuming, and Copied. Use this to add proper highlighting to methods based on usage. --- crates/ide/src/syntax_highlighting.rs | 139 +++++++++++++++------------- crates/ide/src/syntax_highlighting/tests.rs | 30 ++++++ crates/ide/test_data/highlighting.html | 34 ++++++- 3 files changed, 136 insertions(+), 67 deletions(-) (limited to 'crates/ide') diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs index 15a78a614..9827c68af 100644 --- a/crates/ide/src/syntax_highlighting.rs +++ b/crates/ide/src/syntax_highlighting.rs @@ -4,7 +4,7 @@ mod injection; #[cfg(test)] mod tests; -use hir::{Mutability, Name, Semantics, VariantDef}; +use hir::{Mutability, Name, SelfKind, Semantics, VariantDef}; use ide_db::{ defs::{classify_name, classify_name_ref, Definition, NameClass, NameRefClass}, RootDatabase, @@ -519,27 +519,29 @@ fn highlight_element( } NAME_REF => { let name_ref = element.into_node().and_then(ast::NameRef::cast).unwrap(); - let possibly_unsafe = is_possibly_unsafe(&name_ref); - match classify_name_ref(sema, &name_ref) { - Some(name_kind) => match name_kind { - NameRefClass::ExternCrate(_) => HighlightTag::Module.into(), - NameRefClass::Definition(def) => { - if let Definition::Local(local) = &def { - if let Some(name) = local.name(db) { - let shadow_count = - bindings_shadow_count.entry(name.clone()).or_default(); - binding_hash = Some(calc_binding_hash(&name, *shadow_count)) - } - }; - highlight_name(sema, db, def, Some(name_ref), possibly_unsafe) + highlight_func_by_name_ref(sema, &name_ref).unwrap_or_else(|| { + let possibly_unsafe = is_possibly_unsafe(&name_ref); + match classify_name_ref(sema, &name_ref) { + Some(name_kind) => match name_kind { + NameRefClass::ExternCrate(_) => HighlightTag::Module.into(), + NameRefClass::Definition(def) => { + if let Definition::Local(local) = &def { + if let Some(name) = local.name(db) { + let shadow_count = + bindings_shadow_count.entry(name.clone()).or_default(); + binding_hash = Some(calc_binding_hash(&name, *shadow_count)) + } + }; + highlight_name(sema, db, def, Some(name_ref), possibly_unsafe) + } + NameRefClass::FieldShorthand { .. } => HighlightTag::Field.into(), + }, + None if syntactic_name_ref_highlighting => { + highlight_name_ref_by_syntax(name_ref, sema) } - NameRefClass::FieldShorthand { .. } => HighlightTag::Field.into(), - }, - None if syntactic_name_ref_highlighting => { - highlight_name_ref_by_syntax(name_ref, sema) + None => HighlightTag::UnresolvedReference.into(), } - None => HighlightTag::UnresolvedReference.into(), - } + }) } // Simple token-based highlighting @@ -700,6 +702,35 @@ fn is_child_of_impl(element: &SyntaxElement) -> bool { } } +fn highlight_func_by_name_ref( + sema: &Semantics, + name_ref: &ast::NameRef, +) -> Option { + let parent = name_ref.syntax().parent()?; + let method_call = ast::MethodCallExpr::cast(parent)?; + highlight_method_call(sema, &method_call) +} + +fn highlight_method_call( + sema: &Semantics, + method_call: &ast::MethodCallExpr, +) -> Option { + let func = sema.resolve_method_call(&method_call)?; + let mut h = HighlightTag::Function.into(); + if func.is_unsafe(sema.db) || sema.is_unsafe_method_call(&method_call) { + h |= HighlightModifier::Unsafe; + } + + sema.method_reciever_kind(&method_call) + .map(|self_kind| match self_kind { + SelfKind::Shared => h, + SelfKind::Mutable => h | HighlightModifier::Mutable, + SelfKind::Consuming => h | HighlightModifier::Consuming, + SelfKind::Copied => h, + }) + .or_else(|| Some(h)) +} + fn highlight_name( sema: &Semantics, db: &RootDatabase, @@ -722,30 +753,26 @@ fn highlight_name( Definition::ModuleDef(def) => match def { hir::ModuleDef::Module(_) => HighlightTag::Module, hir::ModuleDef::Function(func) => { - let mut h = HighlightTag::Function.into(); - if func.is_unsafe(db) { - h |= HighlightModifier::Unsafe; - } else { - let is_unsafe = name_ref - .and_then(|name_ref| name_ref.syntax().parent()) - .and_then(ast::MethodCallExpr::cast) - .map(|method_call_expr| sema.is_unsafe_method_call(&method_call_expr)) - .unwrap_or(false); - if is_unsafe { - h |= HighlightModifier::Unsafe; - } - } - return if func.has_self_param(db) { - match func.mutability_of_self_param(db) { - Some(mutability) => match mutability { - Mutability::Mut => h | HighlightModifier::Mutable, - Mutability::Shared => h, - }, - None => h | HighlightModifier::Consuming, - } - } else { - h - }; + return name_ref + .and_then(|name_ref| highlight_func_by_name_ref(sema, &name_ref)) + .unwrap_or_else(|| { + let mut h = HighlightTag::Function.into(); + if func.is_unsafe(db) { + h |= HighlightModifier::Unsafe; + } + + return if func.has_self_param(db) { + match func.mutability_of_self_param(db) { + Some(mutability) => match mutability { + Mutability::Mut => h | HighlightModifier::Mutable, + Mutability::Shared => h, + }, + None => h, + } + } else { + h + }; + }); } hir::ModuleDef::Adt(hir::Adt::Struct(_)) => HighlightTag::Struct, hir::ModuleDef::Adt(hir::Adt::Enum(_)) => HighlightTag::Enum, @@ -817,27 +844,9 @@ fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics { - let mut h = Highlight::new(HighlightTag::Function); - ast::MethodCallExpr::cast(parent) - .and_then(|method_call_expr| { - if sema.is_unsafe_method_call(&method_call_expr) { - h |= HighlightModifier::Unsafe; - } - - let func = sema.resolve_method_call(&method_call_expr)?; - if !func.has_self_param(sema.db) { - return Some(h); - } - - Some(match func.mutability_of_self_param(sema.db) { - Some(mutability) => match mutability { - Mutability::Mut => h | HighlightModifier::Mutable, - Mutability::Shared => h, - }, - None => h | HighlightModifier::Consuming, - }) - }) - .unwrap_or_else(|| h) + return ast::MethodCallExpr::cast(parent) + .and_then(|method_call| highlight_method_call(sema, &method_call)) + .unwrap_or_else(|| HighlightTag::Function.into()); } FIELD_EXPR => { let h = HighlightTag::Field; diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs index 6cb955d29..ccb76f552 100644 --- a/crates/ide/src/syntax_highlighting/tests.rs +++ b/crates/ide/src/syntax_highlighting/tests.rs @@ -12,6 +12,12 @@ fn test_highlighting() { use inner::{self as inner_mod}; mod inner {} +// Needed for function consuming vs normal +pub mod marker { + #[lang = "copy"] + pub trait Copy {} +} + #[derive(Clone, Debug)] struct Foo { pub x: i32, @@ -42,6 +48,25 @@ impl Foo { } } +#[derive(Copy, Clone)] +struct FooCopy { + x: u32, +} + +impl FooCopy { + fn baz(self) -> u32 { + self.x + } + + fn qux(&mut self) { + self.x = 0; + } + + fn quop(&self) -> u32 { + self.x + } +} + static mut STATIC_MUT: i32 = 0; fn foo<'a, T>() -> T { @@ -96,6 +121,11 @@ fn main() { foo.quop(); foo.qux(); foo.baz(); + + let mut copy = FooCopy { x }; + copy.quop(); + copy.qux(); + copy.baz(); } enum Option { diff --git a/crates/ide/test_data/highlighting.html b/crates/ide/test_data/highlighting.html index 2aad06a92..a6b79589b 100644 --- a/crates/ide/test_data/highlighting.html +++ b/crates/ide/test_data/highlighting.html @@ -38,6 +38,12 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
use inner::{self as inner_mod};
 mod inner {}
 
+// Needed for function consuming vs normal
+pub mod marker {
+    #[lang = "copy"]
+    pub trait Copy {}
+}
+
 #[derive(Clone, Debug)]
 struct Foo {
     pub x: i32,
@@ -55,7 +61,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 }
 
 impl Foo {
-    fn baz(mut self) -> i32 {
+    fn baz(mut self) -> i32 {
         self.x
     }
 
@@ -68,6 +74,25 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     }
 }
 
+#[derive(Copy, Clone)]
+struct FooCopy {
+    x: u32,
+}
+
+impl FooCopy {
+    fn baz(self) -> u32 {
+        self.x
+    }
+
+    fn qux(&mut self) {
+        self.x = 0;
+    }
+
+    fn quop(&self) -> u32 {
+        self.x
+    }
+}
+
 static mut STATIC_MUT: i32 = 0;
 
 fn foo<'a, T>() -> T {
@@ -122,6 +147,11 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     foo.quop();
     foo.qux();
     foo.baz();
+
+    let mut copy = FooCopy { x };
+    copy.quop();
+    copy.qux();
+    copy.baz();
 }
 
 enum Option<T> {
@@ -131,7 +161,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 use Option::*;
 
 impl<T> Option<T> {
-    fn and<U>(self, other: Option<U>) -> Option<(T, U)> {
+    fn and<U>(self, other: Option<U>) -> Option<(T, U)> {
         match other {
             None => unimplemented!(),
             Nope => Nope,
-- 
cgit v1.2.3