/// Implementation of deduplication of colliding names. // // This file is distributed under the MIT License. See LICENSE.md for details. // #include #include "revng/Model/Binary.h" #include "revng/Model/Pass/DeduplicateCollidingNames.h" #include "revng/Model/Pass/RegisterModelPass.h" #include "../NamespaceBuilder.h" static RegisterModelPass R("deduplicate-colliding-names", "This looks for groups of names are duplicates of " "each other and appends arbitrary suffixes " "to prevent collisions.", model::deduplicateCollidingNames); static Logger Log("name-deduplication"); struct GlobalEntry { llvm::StringRef FirstModelPath; uint64_t NextIndex = 0; }; static llvm::DenseMap impl(std::vector> &Collisions, const model::Namespace &CurrentNamespace, const model::Namespace &ParentNamespace, const llvm::DenseMap &Renames) { revng_assert(not Collisions.empty()); llvm::StringRef Name = *Collisions.front().Name; uint64_t SuffixIndex = 1; llvm::StringRef FirstModelPath = Collisions.front().ModelPath; if (auto It = ParentNamespace.find(Name); It != ParentNamespace.end()) { FirstModelPath = It->second[0].ModelPath; ++SuffixIndex; } llvm::DenseMap NewRenames; for (auto &Collision : Collisions) { std::string Current = *Collision.Name; if (SuffixIndex != 1) { Current += "_" + std::to_string(SuffixIndex); while (CurrentNamespace.contains(Current) or ParentNamespace.contains(Current) or Renames.count(Current)) { Current = *Collision.Name + "_" + std::to_string(++SuffixIndex); } revng_log(Log, "Appending `_" + std::to_string(SuffixIndex) + "` suffix to `" + *Collision.Name + "` (`" + Collision.ModelPath + "`) because it collides with `" + FirstModelPath.str() + "`"); *Collision.Name += "_" + std::to_string(SuffixIndex); auto [_, Success] = NewRenames.try_emplace(*Collision.Name, Collision.ModelPath); revng_assert(Success); } ++SuffixIndex; } return NewRenames; } void model::deduplicateCollidingNames(TupleTree &Binary) { llvm::Expected Namespaces = collectNamespaces(*Binary); if (not Namespaces) { // TODO: This shouldn't probably be an abort. revng_abort(revng::unwrapError(Namespaces.takeError()).c_str()); } // Global names first, llvm::DenseMap GlobalRenames; for (auto &&[_, List] : Namespaces->Global) { auto NewRenames = impl(List, Namespaces->Global, {}, GlobalRenames); GlobalRenames.insert(NewRenames.begin(), NewRenames.end()); } // Then local ones. for (auto &&CurrentNamespace : Namespaces->Local) for (auto &&[_, List] : CurrentNamespace) impl(List, CurrentNamespace, Namespaces->Global, GlobalRenames); }