/// \file Processing.cpp /// A collection of helper functions to improve the quality of the model/make it /// valid. // // This file is distributed under the MIT License. See LICENSE.md for details. // #include "llvm/ADT/DepthFirstIterator.h" #include "revng/ADT/GenericGraph.h" #include "revng/Model/Processing.h" #include "revng/Support/Debug.h" using namespace llvm; namespace model { template void purgeFunctions(T &Functions, const std::set &ToDelete) { for (auto &F : Functions) if (F.prototype() == nullptr or ToDelete.contains(F.prototype())) F.Prototype().reset(); } using DefinitionPointerSet = std::set; unsigned dropTypesDependingOnDefinitions(TupleTree &Model, const DefinitionPointerSet &Types) { // TODO: in case we reach a StructField or UnionField, we should drop the // field and not proceed any further struct TypeNode { const model::TypeDefinition *T; }; using Graph = GenericGraph>; Graph ReverseDependencyGraph; // Create nodes in reverse dependency graph std::map *> TypeToNode; for (model::UpcastableTypeDefinition &T : Model->TypeDefinitions()) TypeToNode[T.get()] = ReverseDependencyGraph.addNode(TypeNode{ T.get() }); // Register edges for (model::UpcastableTypeDefinition &T : Model->TypeDefinitions()) { // Ignore dependencies of types we need to drop if (Types.contains(T.get())) continue; for (const model::Type *E : T->edges()) if (const model::TypeDefinition *Definition = E->skipToDefinition()) TypeToNode.at(Definition)->addSuccessor(TypeToNode.at(T.get())); } // Prepare for deletion all the nodes reachable from Types std::set ToDelete; for (const model::TypeDefinition *Type : Types) { for (const auto *Node : depth_first(TypeToNode.at(Type))) { ToDelete.insert(Node->T); } } // Purge both dynamic and local functions depending on Types purgeFunctions(Model->ImportedDynamicFunctions(), ToDelete); purgeFunctions(Model->Functions(), ToDelete); // Purge types depending on unresolved Types for (auto It = Model->TypeDefinitions().begin(); It != Model->TypeDefinitions().end();) { if (ToDelete.contains(It->get())) It = Model->TypeDefinitions().erase(It); else ++It; } return ToDelete.size(); } } // namespace model