aboutsummaryrefslogtreecommitdiff
path: root/crates/ide/src
diff options
context:
space:
mode:
authorPaul Daniel Faria <[email protected]>2020-07-31 03:31:53 +0100
committerPaul Daniel Faria <[email protected]>2020-08-16 15:26:16 +0100
commit3456e2eec7c1e18734f8fa41924a83b4c676dc00 (patch)
tree22c470056daeb136c64966cc4f4c976a8f45bf00 /crates/ide/src
parenta044ff0138d6bff9406b94de89fde43e7672ee1b (diff)
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.
Diffstat (limited to 'crates/ide/src')
-rw-r--r--crates/ide/src/syntax_highlighting.rs139
-rw-r--r--crates/ide/src/syntax_highlighting/tests.rs30
2 files changed, 104 insertions, 65 deletions
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;
4#[cfg(test)] 4#[cfg(test)]
5mod tests; 5mod tests;
6 6
7use hir::{Mutability, Name, Semantics, VariantDef}; 7use hir::{Mutability, Name, SelfKind, 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,
@@ -519,27 +519,29 @@ fn highlight_element(
519 } 519 }
520 NAME_REF => { 520 NAME_REF => {
521 let name_ref = element.into_node().and_then(ast::NameRef::cast).unwrap(); 521 let name_ref = element.into_node().and_then(ast::NameRef::cast).unwrap();
522 let possibly_unsafe = is_possibly_unsafe(&name_ref); 522 highlight_func_by_name_ref(sema, &name_ref).unwrap_or_else(|| {
523 match classify_name_ref(sema, &name_ref) { 523 let possibly_unsafe = is_possibly_unsafe(&name_ref);
524 Some(name_kind) => match name_kind { 524 match classify_name_ref(sema, &name_ref) {
525 NameRefClass::ExternCrate(_) => HighlightTag::Module.into(), 525 Some(name_kind) => match name_kind {
526 NameRefClass::Definition(def) => { 526 NameRefClass::ExternCrate(_) => HighlightTag::Module.into(),
527 if let Definition::Local(local) = &def { 527 NameRefClass::Definition(def) => {
528 if let Some(name) = local.name(db) { 528 if let Definition::Local(local) = &def {
529 let shadow_count = 529 if let Some(name) = local.name(db) {
530 bindings_shadow_count.entry(name.clone()).or_default(); 530 let shadow_count =
531 binding_hash = Some(calc_binding_hash(&name, *shadow_count)) 531 bindings_shadow_count.entry(name.clone()).or_default();
532 } 532 binding_hash = Some(calc_binding_hash(&name, *shadow_count))
533 }; 533 }
534 highlight_name(sema, db, def, Some(name_ref), possibly_unsafe) 534 };
535 highlight_name(sema, db, def, Some(name_ref), possibly_unsafe)
536 }
537 NameRefClass::FieldShorthand { .. } => HighlightTag::Field.into(),
538 },
539 None if syntactic_name_ref_highlighting => {
540 highlight_name_ref_by_syntax(name_ref, sema)
535 } 541 }
536 NameRefClass::FieldShorthand { .. } => HighlightTag::Field.into(), 542 None => HighlightTag::UnresolvedReference.into(),
537 },
538 None if syntactic_name_ref_highlighting => {
539 highlight_name_ref_by_syntax(name_ref, sema)
540 } 543 }
541 None => HighlightTag::UnresolvedReference.into(), 544 })
542 }
543 } 545 }
544 546
545 // Simple token-based highlighting 547 // Simple token-based highlighting
@@ -700,6 +702,35 @@ fn is_child_of_impl(element: &SyntaxElement) -> bool {
700 } 702 }
701} 703}
702 704
705fn highlight_func_by_name_ref(
706 sema: &Semantics<RootDatabase>,
707 name_ref: &ast::NameRef,
708) -> Option<Highlight> {
709 let parent = name_ref.syntax().parent()?;
710 let method_call = ast::MethodCallExpr::cast(parent)?;
711 highlight_method_call(sema, &method_call)
712}
713
714fn highlight_method_call(
715 sema: &Semantics<RootDatabase>,
716 method_call: &ast::MethodCallExpr,
717) -> Option<Highlight> {
718 let func = sema.resolve_method_call(&method_call)?;
719 let mut h = HighlightTag::Function.into();
720 if func.is_unsafe(sema.db) || sema.is_unsafe_method_call(&method_call) {
721 h |= HighlightModifier::Unsafe;
722 }
723
724 sema.method_reciever_kind(&method_call)
725 .map(|self_kind| match self_kind {
726 SelfKind::Shared => h,
727 SelfKind::Mutable => h | HighlightModifier::Mutable,
728 SelfKind::Consuming => h | HighlightModifier::Consuming,
729 SelfKind::Copied => h,
730 })
731 .or_else(|| Some(h))
732}
733
703fn highlight_name( 734fn highlight_name(
704 sema: &Semantics<RootDatabase>, 735 sema: &Semantics<RootDatabase>,
705 db: &RootDatabase, 736 db: &RootDatabase,
@@ -722,30 +753,26 @@ fn highlight_name(
722 Definition::ModuleDef(def) => match def { 753 Definition::ModuleDef(def) => match def {
723 hir::ModuleDef::Module(_) => HighlightTag::Module, 754 hir::ModuleDef::Module(_) => HighlightTag::Module,
724 hir::ModuleDef::Function(func) => { 755 hir::ModuleDef::Function(func) => {
725 let mut h = HighlightTag::Function.into(); 756 return name_ref
726 if func.is_unsafe(db) { 757 .and_then(|name_ref| highlight_func_by_name_ref(sema, &name_ref))
727 h |= HighlightModifier::Unsafe; 758 .unwrap_or_else(|| {
728 } else { 759 let mut h = HighlightTag::Function.into();
729 let is_unsafe = name_ref 760 if func.is_unsafe(db) {
730 .and_then(|name_ref| name_ref.syntax().parent()) 761 h |= HighlightModifier::Unsafe;
731 .and_then(ast::MethodCallExpr::cast) 762 }
732 .map(|method_call_expr| sema.is_unsafe_method_call(&method_call_expr)) 763
733 .unwrap_or(false); 764 return if func.has_self_param(db) {
734 if is_unsafe { 765 match func.mutability_of_self_param(db) {
735 h |= HighlightModifier::Unsafe; 766 Some(mutability) => match mutability {
736 } 767 Mutability::Mut => h | HighlightModifier::Mutable,
737 } 768 Mutability::Shared => h,
738 return if func.has_self_param(db) { 769 },
739 match func.mutability_of_self_param(db) { 770 None => h,
740 Some(mutability) => match mutability { 771 }
741 Mutability::Mut => h | HighlightModifier::Mutable, 772 } else {
742 Mutability::Shared => h, 773 h
743 }, 774 };
744 None => h | HighlightModifier::Consuming, 775 });
745 }
746 } else {
747 h
748 };
749 } 776 }
750 hir::ModuleDef::Adt(hir::Adt::Struct(_)) => HighlightTag::Struct, 777 hir::ModuleDef::Adt(hir::Adt::Struct(_)) => HighlightTag::Struct,
751 hir::ModuleDef::Adt(hir::Adt::Enum(_)) => HighlightTag::Enum, 778 hir::ModuleDef::Adt(hir::Adt::Enum(_)) => HighlightTag::Enum,
@@ -817,27 +844,9 @@ fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics<RootDatabas
817 844
818 match parent.kind() { 845 match parent.kind() {
819 METHOD_CALL_EXPR => { 846 METHOD_CALL_EXPR => {
820 let mut h = Highlight::new(HighlightTag::Function); 847 return ast::MethodCallExpr::cast(parent)
821 ast::MethodCallExpr::cast(parent) 848 .and_then(|method_call| highlight_method_call(sema, &method_call))
822 .and_then(|method_call_expr| { 849 .unwrap_or_else(|| HighlightTag::Function.into());
823 if sema.is_unsafe_method_call(&method_call_expr) {
824 h |= HighlightModifier::Unsafe;
825 }
826
827 let func = sema.resolve_method_call(&method_call_expr)?;
828 if !func.has_self_param(sema.db) {
829 return Some(h);
830 }
831
832 Some(match func.mutability_of_self_param(sema.db) {
833 Some(mutability) => match mutability {
834 Mutability::Mut => h | HighlightModifier::Mutable,
835 Mutability::Shared => h,
836 },
837 None => h | HighlightModifier::Consuming,
838 })
839 })
840 .unwrap_or_else(|| h)
841 } 850 }
842 FIELD_EXPR => { 851 FIELD_EXPR => {
843 let h = HighlightTag::Field; 852 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() {
12use inner::{self as inner_mod}; 12use inner::{self as inner_mod};
13mod inner {} 13mod inner {}
14 14
15// Needed for function consuming vs normal
16pub mod marker {
17 #[lang = "copy"]
18 pub trait Copy {}
19}
20
15#[derive(Clone, Debug)] 21#[derive(Clone, Debug)]
16struct Foo { 22struct Foo {
17 pub x: i32, 23 pub x: i32,
@@ -42,6 +48,25 @@ impl Foo {
42 } 48 }
43} 49}
44 50
51#[derive(Copy, Clone)]
52struct FooCopy {
53 x: u32,
54}
55
56impl FooCopy {
57 fn baz(self) -> u32 {
58 self.x
59 }
60
61 fn qux(&mut self) {
62 self.x = 0;
63 }
64
65 fn quop(&self) -> u32 {
66 self.x
67 }
68}
69
45static mut STATIC_MUT: i32 = 0; 70static mut STATIC_MUT: i32 = 0;
46 71
47fn foo<'a, T>() -> T { 72fn foo<'a, T>() -> T {
@@ -96,6 +121,11 @@ fn main() {
96 foo.quop(); 121 foo.quop();
97 foo.qux(); 122 foo.qux();
98 foo.baz(); 123 foo.baz();
124
125 let mut copy = FooCopy { x };
126 copy.quop();
127 copy.qux();
128 copy.baz();
99} 129}
100 130
101enum Option<T> { 131enum Option<T> {