diff options
Diffstat (limited to 'crates/ra_ide/src/syntax_highlighting.rs')
-rw-r--r-- | crates/ra_ide/src/syntax_highlighting.rs | 148 |
1 files changed, 123 insertions, 25 deletions
diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs index a32ae0165..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)] |
5 | mod tests; | 5 | mod tests; |
6 | 6 | ||
7 | use hir::{Name, Semantics}; | 7 | use hir::{Name, Semantics, VariantDef}; |
8 | use ra_ide_db::{ | 8 | use 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 | ||
458 | fn 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 | |||
458 | fn highlight_element( | 470 | fn 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,9 +566,20 @@ 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 | } |
@@ -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 | ||
655 | fn highlight_name(db: &RootDatabase, def: Definition) -> Highlight { | 704 | fn 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 | ||
727 | fn highlight_name_ref_by_syntax(name: ast::NameRef) -> Highlight { | 801 | fn 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 | } |