Improve dead code detection for unions

This commit is contained in:
Guillaume Gomez 2017-07-30 19:08:26 +02:00
parent 46fe8e9966
commit 59fcac6fa9
2 changed files with 32 additions and 16 deletions

View File

@ -877,7 +877,7 @@ pub fn walk_impl_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, impl_item_ref: &'
pub fn walk_struct_def<'v, V: Visitor<'v>>(visitor: &mut V, struct_definition: &'v VariantData) {
visitor.visit_id(struct_definition.id());
walk_list!(visitor, visit_struct_field, struct_definition.fields());
walk_list!(visitor, visit_struct_field, struct_definition.fields().iter().rev());
}
pub fn walk_struct_field<'v, V: Visitor<'v>>(visitor: &mut V, struct_field: &'v StructField) {

View File

@ -422,6 +422,7 @@ fn get_struct_ctor_id(item: &hir::Item) -> Option<ast::NodeId> {
struct DeadVisitor<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
live_symbols: Box<FxHashSet<ast::NodeId>>,
need_check_next_union_field: bool,
}
impl<'a, 'tcx> DeadVisitor<'a, 'tcx> {
@ -537,6 +538,16 @@ impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> {
}
}
fn visit_variant_data(&mut self,
s: &'tcx hir::VariantData,
_: ast::Name,
_: &'tcx hir::Generics,
_parent_id: ast::NodeId,
_: syntax_pos::Span) {
self.need_check_next_union_field = true;
intravisit::walk_struct_def(self, s)
}
fn visit_variant(&mut self,
variant: &'tcx hir::Variant,
g: &'tcx hir::Generics,
@ -557,23 +568,24 @@ impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> {
}
fn visit_struct_field(&mut self, field: &'tcx hir::StructField) {
if self.should_warn_about_field(&field) {
let did = self.tcx.hir.get_parent_did(field.id);
if if let Some(node_id) = self.tcx.hir.as_local_node_id(did) {
match self.tcx.hir.find(node_id) {
Some(hir_map::NodeItem(item)) => match item.node {
Item_::ItemUnion(_, _) => false,
_ => true,
},
_ => true,
}
} else {
true
} {
if self.need_check_next_union_field {
if self.should_warn_about_field(&field) {
self.warn_dead_code(field.id, field.span, field.name, "field");
} else {
let did = self.tcx.hir.get_parent_did(field.id);
if let Some(node_id) = self.tcx.hir.as_local_node_id(did) {
match self.tcx.hir.find(node_id) {
Some(hir_map::NodeItem(item)) => match item.node {
// If this is an union's field, it means all previous fields
// have been used as well so no need to check further.
Item_::ItemUnion(_, _) => self.need_check_next_union_field = false,
_ => {}
},
_ => {}
}
}
}
}
intravisit::walk_struct_field(self, field);
}
@ -615,6 +627,10 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE);
let krate = tcx.hir.krate();
let live_symbols = find_live(tcx, access_levels, krate);
let mut visitor = DeadVisitor { tcx: tcx, live_symbols: live_symbols };
let mut visitor = DeadVisitor {
tcx: tcx,
live_symbols: live_symbols,
need_check_next_union_field: true,
};
intravisit::walk_crate(&mut visitor, krate);
}