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 ++++++ 2 files changed, 104 insertions(+), 65 deletions(-) (limited to 'crates/ide/src') 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 { -- cgit v1.2.3