From be935b2b56dcbda5a5918d8c600552b0adbb3a96 Mon Sep 17 00:00:00 2001 From: Paul Daniel Faria Date: Fri, 7 Aug 2020 09:33:40 -0400 Subject: [PATCH] Apply unsafe semantic highlighting to union field access --- crates/ra_ide/src/syntax_highlighting.rs | 66 ++++++++++++++++--- crates/ra_ide/test_data/highlight_unsafe.html | 6 +- 2 files changed, 59 insertions(+), 13 deletions(-) diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs index a32ae0165e..bfe6143ca5 100644 --- a/crates/ra_ide/src/syntax_highlighting.rs +++ b/crates/ra_ide/src/syntax_highlighting.rs @@ -4,7 +4,7 @@ mod injection; #[cfg(test)] mod tests; -use hir::{Name, Semantics}; +use hir::{Name, Semantics, VariantDef}; use ra_ide_db::{ defs::{classify_name, classify_name_ref, Definition, NameClass, NameRefClass}, RootDatabase, @@ -455,6 +455,18 @@ fn macro_call_range(macro_call: &ast::MacroCall) -> Option { Some(TextRange::new(range_start, range_end)) } +fn is_possibly_unsafe(name_ref: &ast::NameRef) -> bool { + name_ref + .syntax() + .parent() + .and_then(|parent| { + ast::FieldExpr::cast(parent.clone()) + .map(|_| true) + .or_else(|| ast::RecordPatField::cast(parent).map(|_| true)) + }) + .unwrap_or(false) +} + fn highlight_element( sema: &Semantics, bindings_shadow_count: &mut FxHashMap, @@ -484,10 +496,19 @@ fn highlight_element( match name_kind { Some(NameClass::Definition(def)) => { - highlight_name(db, def) | HighlightModifier::Definition + highlight_name(db, def, false) | HighlightModifier::Definition + } + Some(NameClass::ConstReference(def)) => highlight_name(db, def, false), + Some(NameClass::FieldShorthand { field, .. }) => { + let mut h = HighlightTag::Field.into(); + if let Definition::Field(field) = field { + if let VariantDef::Union(_) = field.parent_def(db) { + h |= HighlightModifier::Unsafe; + } + } + + h } - Some(NameClass::ConstReference(def)) => highlight_name(db, def), - Some(NameClass::FieldShorthand { .. }) => HighlightTag::Field.into(), None => highlight_name_by_syntax(name) | HighlightModifier::Definition, } } @@ -498,6 +519,7 @@ 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::Definition(def) => { @@ -508,11 +530,13 @@ fn highlight_element( binding_hash = Some(calc_binding_hash(&name, *shadow_count)) } }; - highlight_name(db, def) + highlight_name(db, def, possibly_unsafe) } NameRefClass::FieldShorthand { .. } => HighlightTag::Field.into(), }, - None if syntactic_name_ref_highlighting => highlight_name_ref_by_syntax(name_ref), + None if syntactic_name_ref_highlighting => { + highlight_name_ref_by_syntax(name_ref, sema) + } None => HighlightTag::UnresolvedReference.into(), } } @@ -652,10 +676,19 @@ fn is_child_of_impl(element: &SyntaxElement) -> bool { } } -fn highlight_name(db: &RootDatabase, def: Definition) -> Highlight { +fn highlight_name(db: &RootDatabase, def: Definition, possibly_unsafe: bool) -> Highlight { match def { Definition::Macro(_) => HighlightTag::Macro, - Definition::Field(_) => HighlightTag::Field, + Definition::Field(field) => { + let mut h = HighlightTag::Field.into(); + if possibly_unsafe { + if let VariantDef::Union(_) = field.parent_def(db) { + h |= HighlightModifier::Unsafe; + } + } + + return h; + } Definition::ModuleDef(def) => match def { hir::ModuleDef::Module(_) => HighlightTag::Module, hir::ModuleDef::Function(func) => { @@ -724,7 +757,7 @@ fn highlight_name_by_syntax(name: ast::Name) -> Highlight { tag.into() } -fn highlight_name_ref_by_syntax(name: ast::NameRef) -> Highlight { +fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics) -> Highlight { let default = HighlightTag::UnresolvedReference; let parent = match name.syntax().parent() { @@ -734,7 +767,20 @@ fn highlight_name_ref_by_syntax(name: ast::NameRef) -> Highlight { let tag = match parent.kind() { METHOD_CALL_EXPR => HighlightTag::Function, - FIELD_EXPR => HighlightTag::Field, + FIELD_EXPR => { + let h = HighlightTag::Field; + let is_union = ast::FieldExpr::cast(parent) + .and_then(|field_expr| { + let field = sema.resolve_field(&field_expr)?; + Some(if let VariantDef::Union(_) = field.parent_def(sema.db) { + true + } else { + false + }) + }) + .unwrap_or(false); + return if is_union { h | HighlightModifier::Unsafe } else { h.into() }; + } PATH_SEGMENT => { let path = match parent.parent().and_then(ast::Path::cast) { Some(it) => it, diff --git a/crates/ra_ide/test_data/highlight_unsafe.html b/crates/ra_ide/test_data/highlight_unsafe.html index de70363da2..cfc872832a 100644 --- a/crates/ra_ide/test_data/highlight_unsafe.html +++ b/crates/ra_ide/test_data/highlight_unsafe.html @@ -53,10 +53,10 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd let u = Union { b: 0 }; unsafe { unsafe_fn(); - let b = u.b; + let b = u.b; match u { - Union { b: 0 } => (), - Union { a } => (), + Union { b: 0 } => (), + Union { a } => (), } HasUnsafeFn.unsafe_method(); let y = *(x);