void remove_unused_fields(Scope& scope, const std::vector<std::string>& remove_members) { std::vector<DexField*> moveable_fields; std::vector<DexClass*> smallscope; uint32_t aflags = ACC_STATIC | ACC_FINAL; for (auto clazz : scope) { bool found = can_delete(clazz); if (!found) { auto name = clazz->get_name()->c_str(); for (const auto& name_prefix : remove_members) { if (strstr(name, name_prefix.c_str()) != nullptr) { found = true; break; } } if (!found) { TRACE(FINALINLINE, 2, "Cannot delete: %s\n", SHOW(clazz)); continue; } } auto sfields = clazz->get_sfields(); for (auto sfield : sfields) { if ((sfield->get_access() & aflags) != aflags) continue; auto value = sfield->get_static_value(); if (value == nullptr && !is_primitive(sfield->get_type())) continue; if (!found && !can_delete(sfield)) continue; moveable_fields.push_back(sfield); smallscope.push_back(clazz); } } sort_unique(smallscope); std::unordered_set<DexField*> field_target = get_field_target(scope, moveable_fields); std::unordered_set<DexField*> dead_fields; for (auto field : moveable_fields) { if (field_target.count(field) == 0) { dead_fields.insert(field); } } TRACE(FINALINLINE, 1, "Removable fields %lu/%lu\n", dead_fields.size(), moveable_fields.size()); TRACE(FINALINLINE, 1, "Unhandled inline %ld\n", unhandled_inline); for (auto clazz : smallscope) { auto& sfields = clazz->get_sfields(); auto iter = sfields.begin(); while (iter != sfields.end()) { auto todel = iter++; if (dead_fields.count(*todel) > 0) { sfields.erase(todel); } } } }
void remove_unused_fields(Scope& scope, const std::unordered_set<DexType*>& keep_annos, const std::unordered_set<DexField*>& keep_members) { std::vector<DexField*> moveable_fields; std::vector<DexClass*> smallscope; uint32_t aflags = ACC_STATIC | ACC_FINAL; for (auto clazz : scope) { if (!can_delete(clazz)) { continue; } auto sfields = clazz->get_sfields(); for (auto sfield : sfields) { if ((sfield->get_access() & aflags) != aflags) continue; auto value = sfield->get_static_value(); if (value == nullptr && !is_primitive(sfield->get_type())) continue; if (is_kept_by_annotation(sfield, keep_annos)) continue; if (is_kept_member(sfield, keep_members)) continue; moveable_fields.push_back(sfield); smallscope.push_back(clazz); } } sort_unique(smallscope); std::unordered_set<DexField*> field_target = get_field_target(scope, moveable_fields); std::unordered_set<DexField*> dead_fields; for (auto field : moveable_fields) { if (field_target.count(field) == 0) { dead_fields.insert(field); } } TRACE(FINALINLINE, 1, "Removable fields %lu/%lu\n", dead_fields.size(), moveable_fields.size()); TRACE(FINALINLINE, 1, "Unhandled inline %ld\n", unhandled_inline); for (auto clazz : smallscope) { auto& sfields = clazz->get_sfields(); auto iter = sfields.begin(); while (iter != sfields.end()) { auto todel = iter++; if (dead_fields.count(*todel) > 0) { sfields.erase(todel); } } } }