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.rs97
1 files changed, 72 insertions, 25 deletions
diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs
index d456d5d36..f71b804fe 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>,
@@ -464,7 +476,7 @@ fn highlight_element(
464 let db = sema.db; 476 let db = sema.db;
465 let mut binding_hash = None; 477 let mut binding_hash = None;
466 let highlight: Highlight = match element.kind() { 478 let highlight: Highlight = match element.kind() {
467 FN_DEF => { 479 FN => {
468 bindings_shadow_count.clear(); 480 bindings_shadow_count.clear();
469 return None; 481 return None;
470 } 482 }
@@ -484,10 +496,19 @@ fn highlight_element(
484 496
485 match name_kind { 497 match name_kind {
486 Some(NameClass::Definition(def)) => { 498 Some(NameClass::Definition(def)) => {
487 highlight_name(db, def) | HighlightModifier::Definition 499 highlight_name(db, def, false) | HighlightModifier::Definition
500 }
501 Some(NameClass::ConstReference(def)) => highlight_name(db, def, false),
502 Some(NameClass::FieldShorthand { field, .. }) => {
503 let mut h = HighlightTag::Field.into();
504 if let Definition::Field(field) = field {
505 if let VariantDef::Union(_) = field.parent_def(db) {
506 h |= HighlightModifier::Unsafe;
507 }
508 }
509
510 h
488 } 511 }
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, 512 None => highlight_name_by_syntax(name) | HighlightModifier::Definition,
492 } 513 }
493 } 514 }
@@ -498,6 +519,7 @@ fn highlight_element(
498 } 519 }
499 NAME_REF => { 520 NAME_REF => {
500 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);
501 match classify_name_ref(sema, &name_ref) { 523 match classify_name_ref(sema, &name_ref) {
502 Some(name_kind) => match name_kind { 524 Some(name_kind) => match name_kind {
503 NameRefClass::Definition(def) => { 525 NameRefClass::Definition(def) => {
@@ -508,11 +530,13 @@ fn highlight_element(
508 binding_hash = Some(calc_binding_hash(&name, *shadow_count)) 530 binding_hash = Some(calc_binding_hash(&name, *shadow_count))
509 } 531 }
510 }; 532 };
511 highlight_name(db, def) 533 highlight_name(db, def, possibly_unsafe)
512 } 534 }
513 NameRefClass::FieldShorthand { .. } => HighlightTag::Field.into(), 535 NameRefClass::FieldShorthand { .. } => HighlightTag::Field.into(),
514 }, 536 },
515 None if syntactic_name_ref_highlighting => highlight_name_ref_by_syntax(name_ref), 537 None if syntactic_name_ref_highlighting => {
538 highlight_name_ref_by_syntax(name_ref, sema)
539 }
516 None => HighlightTag::UnresolvedReference.into(), 540 None => HighlightTag::UnresolvedReference.into(),
517 } 541 }
518 } 542 }
@@ -546,7 +570,7 @@ fn highlight_element(
546 T![!] if element.parent().and_then(ast::MacroCall::cast).is_some() => { 570 T![!] if element.parent().and_then(ast::MacroCall::cast).is_some() => {
547 HighlightTag::Macro.into() 571 HighlightTag::Macro.into()
548 } 572 }
549 T![*] if element.parent().and_then(ast::PointerType::cast).is_some() => { 573 T![*] if element.parent().and_then(ast::PtrType::cast).is_some() => {
550 HighlightTag::Keyword.into() 574 HighlightTag::Keyword.into()
551 } 575 }
552 T![*] if element.parent().and_then(ast::PrefixExpr::cast).is_some() => { 576 T![*] if element.parent().and_then(ast::PrefixExpr::cast).is_some() => {
@@ -577,7 +601,7 @@ fn highlight_element(
577 _ if element.parent().and_then(ast::RangePat::cast).is_some() => { 601 _ if element.parent().and_then(ast::RangePat::cast).is_some() => {
578 HighlightTag::Operator.into() 602 HighlightTag::Operator.into()
579 } 603 }
580 _ if element.parent().and_then(ast::DotDotPat::cast).is_some() => { 604 _ if element.parent().and_then(ast::RestPat::cast).is_some() => {
581 HighlightTag::Operator.into() 605 HighlightTag::Operator.into()
582 } 606 }
583 _ if element.parent().and_then(ast::Attr::cast).is_some() => { 607 _ if element.parent().and_then(ast::Attr::cast).is_some() => {
@@ -647,15 +671,24 @@ fn highlight_element(
647 671
648fn is_child_of_impl(element: &SyntaxElement) -> bool { 672fn is_child_of_impl(element: &SyntaxElement) -> bool {
649 match element.parent() { 673 match element.parent() {
650 Some(e) => e.kind() == IMPL_DEF, 674 Some(e) => e.kind() == IMPL,
651 _ => false, 675 _ => false,
652 } 676 }
653} 677}
654 678
655fn highlight_name(db: &RootDatabase, def: Definition) -> Highlight { 679fn highlight_name(db: &RootDatabase, def: Definition, possibly_unsafe: bool) -> Highlight {
656 match def { 680 match def {
657 Definition::Macro(_) => HighlightTag::Macro, 681 Definition::Macro(_) => HighlightTag::Macro,
658 Definition::Field(_) => HighlightTag::Field, 682 Definition::Field(field) => {
683 let mut h = HighlightTag::Field.into();
684 if possibly_unsafe {
685 if let VariantDef::Union(_) = field.parent_def(db) {
686 h |= HighlightModifier::Unsafe;
687 }
688 }
689
690 return h;
691 }
659 Definition::ModuleDef(def) => match def { 692 Definition::ModuleDef(def) => match def {
660 hir::ModuleDef::Module(_) => HighlightTag::Module, 693 hir::ModuleDef::Module(_) => HighlightTag::Module,
661 hir::ModuleDef::Function(func) => { 694 hir::ModuleDef::Function(func) => {
@@ -677,6 +710,7 @@ fn highlight_name(db: &RootDatabase, def: Definition) -> Highlight {
677 let mut h = Highlight::new(HighlightTag::Static); 710 let mut h = Highlight::new(HighlightTag::Static);
678 if s.is_mut(db) { 711 if s.is_mut(db) {
679 h |= HighlightModifier::Mutable; 712 h |= HighlightModifier::Mutable;
713 h |= HighlightModifier::Unsafe;
680 } 714 }
681 return h; 715 return h;
682 } 716 }
@@ -705,26 +739,26 @@ fn highlight_name_by_syntax(name: ast::Name) -> Highlight {
705 }; 739 };
706 740
707 let tag = match parent.kind() { 741 let tag = match parent.kind() {
708 STRUCT_DEF => HighlightTag::Struct, 742 STRUCT => HighlightTag::Struct,
709 ENUM_DEF => HighlightTag::Enum, 743 ENUM => HighlightTag::Enum,
710 UNION_DEF => HighlightTag::Union, 744 UNION => HighlightTag::Union,
711 TRAIT_DEF => HighlightTag::Trait, 745 TRAIT => HighlightTag::Trait,
712 TYPE_ALIAS_DEF => HighlightTag::TypeAlias, 746 TYPE_ALIAS => HighlightTag::TypeAlias,
713 TYPE_PARAM => HighlightTag::TypeParam, 747 TYPE_PARAM => HighlightTag::TypeParam,
714 RECORD_FIELD_DEF => HighlightTag::Field, 748 RECORD_FIELD => HighlightTag::Field,
715 MODULE => HighlightTag::Module, 749 MODULE => HighlightTag::Module,
716 FN_DEF => HighlightTag::Function, 750 FN => HighlightTag::Function,
717 CONST_DEF => HighlightTag::Constant, 751 CONST => HighlightTag::Constant,
718 STATIC_DEF => HighlightTag::Static, 752 STATIC => HighlightTag::Static,
719 ENUM_VARIANT => HighlightTag::EnumVariant, 753 VARIANT => HighlightTag::EnumVariant,
720 BIND_PAT => HighlightTag::Local, 754 IDENT_PAT => HighlightTag::Local,
721 _ => default, 755 _ => default,
722 }; 756 };
723 757
724 tag.into() 758 tag.into()
725} 759}
726 760
727fn highlight_name_ref_by_syntax(name: ast::NameRef) -> Highlight { 761fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics<RootDatabase>) -> Highlight {
728 let default = HighlightTag::UnresolvedReference; 762 let default = HighlightTag::UnresolvedReference;
729 763
730 let parent = match name.syntax().parent() { 764 let parent = match name.syntax().parent() {
@@ -734,7 +768,20 @@ fn highlight_name_ref_by_syntax(name: ast::NameRef) -> Highlight {
734 768
735 let tag = match parent.kind() { 769 let tag = match parent.kind() {
736 METHOD_CALL_EXPR => HighlightTag::Function, 770 METHOD_CALL_EXPR => HighlightTag::Function,
737 FIELD_EXPR => HighlightTag::Field, 771 FIELD_EXPR => {
772 let h = HighlightTag::Field;
773 let is_union = ast::FieldExpr::cast(parent)
774 .and_then(|field_expr| {
775 let field = sema.resolve_field(&field_expr)?;
776 Some(if let VariantDef::Union(_) = field.parent_def(sema.db) {
777 true
778 } else {
779 false
780 })
781 })
782 .unwrap_or(false);
783 return if is_union { h | HighlightModifier::Unsafe } else { h.into() };
784 }
738 PATH_SEGMENT => { 785 PATH_SEGMENT => {
739 let path = match parent.parent().and_then(ast::Path::cast) { 786 let path = match parent.parent().and_then(ast::Path::cast) {
740 Some(it) => it, 787 Some(it) => it,