aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src/syntax_highlighting.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide/src/syntax_highlighting.rs')
-rw-r--r--crates/ra_ide/src/syntax_highlighting.rs150
1 files changed, 124 insertions, 26 deletions
diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs
index 32f34ef10..c10e15db8 100644
--- a/crates/ra_ide/src/syntax_highlighting.rs
+++ b/crates/ra_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}; 7use hir::{Name, Semantics, VariantDef};
8use ra_ide_db::{ 8use ra_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,
@@ -455,6 +455,18 @@ fn macro_call_range(macro_call: &ast::MacroCall) -> Option<TextRange> {
455 Some(TextRange::new(range_start, range_end)) 455 Some(TextRange::new(range_start, range_end))
456} 456}
457 457
458fn is_possibly_unsafe(name_ref: &ast::NameRef) -> bool {
459 name_ref
460 .syntax()
461 .parent()
462 .and_then(|parent| {
463 ast::FieldExpr::cast(parent.clone())
464 .map(|_| true)
465 .or_else(|| ast::RecordPatField::cast(parent).map(|_| true))
466 })
467 .unwrap_or(false)
468}
469
458fn highlight_element( 470fn highlight_element(
459 sema: &Semantics<RootDatabase>, 471 sema: &Semantics<RootDatabase>,
460 bindings_shadow_count: &mut FxHashMap<Name, u32>, 472 bindings_shadow_count: &mut FxHashMap<Name, u32>,
@@ -483,11 +495,21 @@ fn highlight_element(
483 }; 495 };
484 496
485 match name_kind { 497 match name_kind {
498 Some(NameClass::ExternCrate(_)) => HighlightTag::Module.into(),
486 Some(NameClass::Definition(def)) => { 499 Some(NameClass::Definition(def)) => {
487 highlight_name(db, def) | HighlightModifier::Definition 500 highlight_name(sema, db, def, None, false) | HighlightModifier::Definition
501 }
502 Some(NameClass::ConstReference(def)) => highlight_name(sema, db, def, None, false),
503 Some(NameClass::FieldShorthand { field, .. }) => {
504 let mut h = HighlightTag::Field.into();
505 if let Definition::Field(field) = field {
506 if let VariantDef::Union(_) = field.parent_def(db) {
507 h |= HighlightModifier::Unsafe;
508 }
509 }
510
511 h
488 } 512 }
489 Some(NameClass::ConstReference(def)) => highlight_name(db, def),
490 Some(NameClass::FieldShorthand { .. }) => HighlightTag::Field.into(),
491 None => highlight_name_by_syntax(name) | HighlightModifier::Definition, 513 None => highlight_name_by_syntax(name) | HighlightModifier::Definition,
492 } 514 }
493 } 515 }
@@ -498,8 +520,10 @@ fn highlight_element(
498 } 520 }
499 NAME_REF => { 521 NAME_REF => {
500 let name_ref = element.into_node().and_then(ast::NameRef::cast).unwrap(); 522 let name_ref = element.into_node().and_then(ast::NameRef::cast).unwrap();
523 let possibly_unsafe = is_possibly_unsafe(&name_ref);
501 match classify_name_ref(sema, &name_ref) { 524 match classify_name_ref(sema, &name_ref) {
502 Some(name_kind) => match name_kind { 525 Some(name_kind) => match name_kind {
526 NameRefClass::ExternCrate(_) => HighlightTag::Module.into(),
503 NameRefClass::Definition(def) => { 527 NameRefClass::Definition(def) => {
504 if let Definition::Local(local) = &def { 528 if let Definition::Local(local) = &def {
505 if let Some(name) = local.name(db) { 529 if let Some(name) = local.name(db) {
@@ -508,11 +532,13 @@ fn highlight_element(
508 binding_hash = Some(calc_binding_hash(&name, *shadow_count)) 532 binding_hash = Some(calc_binding_hash(&name, *shadow_count))
509 } 533 }
510 }; 534 };
511 highlight_name(db, def) 535 highlight_name(sema, db, def, Some(name_ref), possibly_unsafe)
512 } 536 }
513 NameRefClass::FieldShorthand { .. } => HighlightTag::Field.into(), 537 NameRefClass::FieldShorthand { .. } => HighlightTag::Field.into(),
514 }, 538 },
515 None if syntactic_name_ref_highlighting => highlight_name_ref_by_syntax(name_ref), 539 None if syntactic_name_ref_highlighting => {
540 highlight_name_ref_by_syntax(name_ref, sema)
541 }
516 None => HighlightTag::UnresolvedReference.into(), 542 None => HighlightTag::UnresolvedReference.into(),
517 } 543 }
518 } 544 }
@@ -540,13 +566,24 @@ fn highlight_element(
540 } 566 }
541 } 567 }
542 p if p.is_punct() => match p { 568 p if p.is_punct() => match p {
543 T![::] | T![->] | T![=>] | T![&] | T![..] | T![=] | T![@] => { 569 T![&] => {
544 HighlightTag::Operator.into() 570 let h = HighlightTag::Operator.into();
571 let is_unsafe = element
572 .parent()
573 .and_then(ast::RefExpr::cast)
574 .map(|ref_expr| sema.is_unsafe_ref_expr(&ref_expr))
575 .unwrap_or(false);
576 if is_unsafe {
577 h | HighlightModifier::Unsafe
578 } else {
579 h
580 }
545 } 581 }
582 T![::] | T![->] | T![=>] | T![..] | T![=] | T![@] => HighlightTag::Operator.into(),
546 T![!] if element.parent().and_then(ast::MacroCall::cast).is_some() => { 583 T![!] if element.parent().and_then(ast::MacroCall::cast).is_some() => {
547 HighlightTag::Macro.into() 584 HighlightTag::Macro.into()
548 } 585 }
549 T![*] if element.parent().and_then(ast::PointerType::cast).is_some() => { 586 T![*] if element.parent().and_then(ast::PtrType::cast).is_some() => {
550 HighlightTag::Keyword.into() 587 HighlightTag::Keyword.into()
551 } 588 }
552 T![*] if element.parent().and_then(ast::PrefixExpr::cast).is_some() => { 589 T![*] if element.parent().and_then(ast::PrefixExpr::cast).is_some() => {
@@ -623,6 +660,18 @@ fn highlight_element(
623 HighlightTag::SelfKeyword.into() 660 HighlightTag::SelfKeyword.into()
624 } 661 }
625 } 662 }
663 T![ref] => element
664 .parent()
665 .and_then(ast::IdentPat::cast)
666 .and_then(|ident_pat| {
667 if sema.is_unsafe_ident_pat(&ident_pat) {
668 Some(HighlightModifier::Unsafe)
669 } else {
670 None
671 }
672 })
673 .map(|modifier| h | modifier)
674 .unwrap_or(h),
626 _ => h, 675 _ => h,
627 } 676 }
628 } 677 }
@@ -652,16 +701,40 @@ fn is_child_of_impl(element: &SyntaxElement) -> bool {
652 } 701 }
653} 702}
654 703
655fn highlight_name(db: &RootDatabase, def: Definition) -> Highlight { 704fn highlight_name(
705 sema: &Semantics<RootDatabase>,
706 db: &RootDatabase,
707 def: Definition,
708 name_ref: Option<ast::NameRef>,
709 possibly_unsafe: bool,
710) -> Highlight {
656 match def { 711 match def {
657 Definition::Macro(_) => HighlightTag::Macro, 712 Definition::Macro(_) => HighlightTag::Macro,
658 Definition::Field(_) => HighlightTag::Field, 713 Definition::Field(field) => {
714 let mut h = HighlightTag::Field.into();
715 if possibly_unsafe {
716 if let VariantDef::Union(_) = field.parent_def(db) {
717 h |= HighlightModifier::Unsafe;
718 }
719 }
720
721 return h;
722 }
659 Definition::ModuleDef(def) => match def { 723 Definition::ModuleDef(def) => match def {
660 hir::ModuleDef::Module(_) => HighlightTag::Module, 724 hir::ModuleDef::Module(_) => HighlightTag::Module,
661 hir::ModuleDef::Function(func) => { 725 hir::ModuleDef::Function(func) => {
662 let mut h = HighlightTag::Function.into(); 726 let mut h = HighlightTag::Function.into();
663 if func.is_unsafe(db) { 727 if func.is_unsafe(db) {
664 h |= HighlightModifier::Unsafe; 728 h |= HighlightModifier::Unsafe;
729 } else {
730 let is_unsafe = name_ref
731 .and_then(|name_ref| name_ref.syntax().parent())
732 .and_then(ast::MethodCallExpr::cast)
733 .map(|method_call_expr| sema.is_unsafe_method_call(method_call_expr))
734 .unwrap_or(false);
735 if is_unsafe {
736 h |= HighlightModifier::Unsafe;
737 }
665 } 738 }
666 return h; 739 return h;
667 } 740 }
@@ -677,6 +750,7 @@ fn highlight_name(db: &RootDatabase, def: Definition) -> Highlight {
677 let mut h = Highlight::new(HighlightTag::Static); 750 let mut h = Highlight::new(HighlightTag::Static);
678 if s.is_mut(db) { 751 if s.is_mut(db) {
679 h |= HighlightModifier::Mutable; 752 h |= HighlightModifier::Mutable;
753 h |= HighlightModifier::Unsafe;
680 } 754 }
681 return h; 755 return h;
682 } 756 }
@@ -724,7 +798,7 @@ fn highlight_name_by_syntax(name: ast::Name) -> Highlight {
724 tag.into() 798 tag.into()
725} 799}
726 800
727fn highlight_name_ref_by_syntax(name: ast::NameRef) -> Highlight { 801fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics<RootDatabase>) -> Highlight {
728 let default = HighlightTag::UnresolvedReference; 802 let default = HighlightTag::UnresolvedReference;
729 803
730 let parent = match name.syntax().parent() { 804 let parent = match name.syntax().parent() {
@@ -732,9 +806,36 @@ fn highlight_name_ref_by_syntax(name: ast::NameRef) -> Highlight {
732 _ => return default.into(), 806 _ => return default.into(),
733 }; 807 };
734 808
735 let tag = match parent.kind() { 809 match parent.kind() {
736 METHOD_CALL_EXPR => HighlightTag::Function, 810 METHOD_CALL_EXPR => {
737 FIELD_EXPR => HighlightTag::Field, 811 let mut h = Highlight::new(HighlightTag::Function);
812 let is_unsafe = ast::MethodCallExpr::cast(parent)
813 .map(|method_call_expr| sema.is_unsafe_method_call(method_call_expr))
814 .unwrap_or(false);
815 if is_unsafe {
816 h |= HighlightModifier::Unsafe;
817 }
818
819 h
820 }
821 FIELD_EXPR => {
822 let h = HighlightTag::Field;
823 let is_union = ast::FieldExpr::cast(parent)
824 .and_then(|field_expr| {
825 let field = sema.resolve_field(&field_expr)?;
826 Some(if let VariantDef::Union(_) = field.parent_def(sema.db) {
827 true
828 } else {
829 false
830 })
831 })
832 .unwrap_or(false);
833 if is_union {
834 h | HighlightModifier::Unsafe
835 } else {
836 h.into()
837 }
838 }
738 PATH_SEGMENT => { 839 PATH_SEGMENT => {
739 let path = match parent.parent().and_then(ast::Path::cast) { 840 let path = match parent.parent().and_then(ast::Path::cast) {
740 Some(it) => it, 841 Some(it) => it,
@@ -758,18 +859,15 @@ fn highlight_name_ref_by_syntax(name: ast::NameRef) -> Highlight {
758 }; 859 };
759 860
760 match parent.kind() { 861 match parent.kind() {
761 CALL_EXPR => HighlightTag::Function, 862 CALL_EXPR => HighlightTag::Function.into(),
762 _ => { 863 _ => if name.text().chars().next().unwrap_or_default().is_uppercase() {
763 if name.text().chars().next().unwrap_or_default().is_uppercase() { 864 HighlightTag::Struct.into()
764 HighlightTag::Struct 865 } else {
765 } else { 866 HighlightTag::Constant
766 HighlightTag::Constant
767 }
768 } 867 }
868 .into(),
769 } 869 }
770 } 870 }
771 _ => default, 871 _ => default.into(),
772 }; 872 }
773
774 tag.into()
775} 873}