Merge #5684
5684: Semantic highlighting for unsafe union field access r=jonas-schievink a=Nashenas88 This change adds support for unions in inference and lowering, then extends on that to add the unsafe semantic modifier on field access only. The `is_possibly_unsafe` function in `syntax_highlighting.rs` could be extended to support fns and static muts so that their definitions are not highlighted as unsafe, but only their usage. Also, each commit of this PR updates the tests. By reviewing the files by commit, it's easy to see how the changes in the code affected the tests. Co-authored-by: Paul Daniel Faria <Nashenas88@users.noreply.github.com>
This commit is contained in:
@@ -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<TextRange> {
|
||||
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<RootDatabase>,
|
||||
bindings_shadow_count: &mut FxHashMap<Name, u32>,
|
||||
@@ -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) => {
|
||||
@@ -725,7 +758,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<RootDatabase>) -> Highlight {
|
||||
let default = HighlightTag::UnresolvedReference;
|
||||
|
||||
let parent = match name.syntax().parent() {
|
||||
@@ -735,7 +768,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,
|
||||
|
||||
Reference in New Issue
Block a user