#[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,
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>,
};
match name_kind {
+ Some(NameClass::ExternCrate(_)) => HighlightTag::Module.into(),
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,
}
}
}
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::ExternCrate(_) => HighlightTag::Module.into(),
NameRefClass::Definition(def) => {
if let Definition::Local(local) = &def {
if let Some(name) = local.name(db) {
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(),
}
}
_ => h,
}
}
+ REF_EXPR => {
+ let ref_expr = element.into_node().and_then(ast::RefExpr::cast)?;
+ let expr = ref_expr.expr()?;
+ let field_expr = match expr {
+ ast::Expr::FieldExpr(fe) => fe,
+ _ => return None,
+ };
+
+ let expr = field_expr.expr()?;
+ let ty = sema.type_of_expr(&expr)?;
+ if !ty.is_packed(db) {
+ return None;
+ }
+
+ // FIXME account for alignment... somehow
+
+ Highlight::new(HighlightTag::Operator) | HighlightModifier::Unsafe
+ }
p if p.is_punct() => match p {
T![::] | T![->] | T![=>] | T![&] | T![..] | T![=] | T![@] => {
HighlightTag::Operator.into()
T![!] if element.parent().and_then(ast::MacroCall::cast).is_some() => {
HighlightTag::Macro.into()
}
- T![*] if element.parent().and_then(ast::PointerType::cast).is_some() => {
+ T![*] if element.parent().and_then(ast::PtrType::cast).is_some() => {
HighlightTag::Keyword.into()
}
T![*] if element.parent().and_then(ast::PrefixExpr::cast).is_some() => {
_ if element.parent().and_then(ast::RangePat::cast).is_some() => {
HighlightTag::Operator.into()
}
- _ if element.parent().and_then(ast::DotDotPat::cast).is_some() => {
+ _ if element.parent().and_then(ast::RestPat::cast).is_some() => {
HighlightTag::Operator.into()
}
_ if element.parent().and_then(ast::Attr::cast).is_some() => {
}
}
-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) => {
let mut h = Highlight::new(HighlightTag::Static);
if s.is_mut(db) {
h |= HighlightModifier::Mutable;
+ h |= HighlightModifier::Unsafe;
}
return h;
}
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() {
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,