#pragma once // // This file is distributed under the MIT License. See LICENSE.md for details. // #include "revng/ADT/RecursiveCoroutine.h" #include "revng/Model/ArrayType.h" #include "revng/Model/CABIFunctionDefinition.h" #include "revng/Model/EnumDefinition.h" #include "revng/Model/Function.h" #include "revng/Model/Identifier.h" #include "revng/Model/NamingConfiguration.h" #include "revng/Model/RawFunctionDefinition.h" #include "revng/Model/StructDefinition.h" #include "revng/Model/UnionDefinition.h" #include "revng/Support/CommonOptions.h" namespace model { namespace detail { struct TransparentStringHash { using is_transparent = void; std::size_t operator()(const char *Value) const { return std::hash{}(Value); } std::size_t operator()(const std::string &Value) const { return std::hash{}(Value); } std::size_t operator()(std::string_view Value) const { return std::hash{}(Value); } std::size_t operator()(llvm::StringRef Value) const { return std::hash{}(Value); } std::size_t operator()(const model::Identifier &Value) const { return std::hash{}(Value.str()); } }; } // namespace detail class Binary; class VerifyHelper; class NameBuilder { private: using GlobalNamespaceMap = std::unordered_map>; std::optional GlobalNamespace = std::nullopt; public: const Binary &Binary; private: using RFT = model::RawFunctionDefinition; public: NameBuilder(const model::Binary &Binary) : Binary(Binary) {} private: llvm::Error isNameForbidden(llvm::StringRef Name); public: const model::NamingConfiguration &configuration() const; public: // This function is triggered automatically the first time a name is // requested. // // There's no need to call it manually unless you expect it to fail, // for example, when verifying a binary. llvm::Error populateGlobalNamespace(); bool isGlobalNamespacePopulated() const { return GlobalNamespace.has_value(); } private: const GlobalNamespaceMap &globalNamespace() { if (not GlobalNamespace.has_value()) { auto MaybeError = populateGlobalNamespace(); revng_check(not MaybeError); revng_assert(GlobalNamespace.has_value()); } return *GlobalNamespace; } public: [[nodiscard]] bool isGlobalSymbol(llvm::StringRef Name) { return globalNamespace().contains(Name); } public: Identifier name(const model::Segment &Segment); Identifier name(const model::Function &Function); Identifier name(const model::DynamicFunction &Function); std::string llvmName(const model::Function &Function) { std::string Result = "local_"; if (DebugNames) Result += name(Function).str().str(); else Result += Function.Entry().toString(); return Result; } public: Identifier name(const model::TypeDefinition &Definition); Identifier name(const model::EnumDefinition &Definition, const model::EnumEntry &Entry); Identifier name(const model::EnumDefinition &Definition, uint64_t Value) { return name(Definition, Definition.Entries().at(Value)); } Identifier name(const model::StructDefinition &Definition, const model::StructField &Field); Identifier name(const model::StructDefinition &Definition, uint64_t Offset) { revng_assert(Offset <= Definition.Size()); return name(Definition, Definition.Fields().at(Offset)); } Identifier name(const model::UnionDefinition &Definition, const model::UnionField &Field); Identifier name(const model::UnionDefinition &Definition, uint64_t Index) { revng_assert(Index <= Definition.Fields().size()); return name(Definition, Definition.Fields().at(Index)); } Identifier paddingFieldName(uint64_t Offset) const { // Not checking anything here since the relevant checks should have already // been done when constructing the helper. return Identifier(std::string(configuration().structPaddingPrefix()) + std::to_string(Offset)); } public: Identifier argumentName(const model::CABIFunctionDefinition &Function, const model::Argument &Argument); Identifier argumentName(const model::CABIFunctionDefinition &Function, uint64_t ArgumentIndex) { revng_assert(ArgumentIndex <= Function.Arguments().size()); return argumentName(Function, Function.Arguments().at(ArgumentIndex)); } Identifier argumentName(const model::RawFunctionDefinition &Function, const model::NamedTypedRegister &Argument); Identifier argumentName(const model::RawFunctionDefinition &Function, const model::Register::Values &Register) { return argumentName(Function, Function.Arguments().at(Register)); } Identifier returnValueName(const model::RawFunctionDefinition &Function, const model::NamedTypedRegister &ReturnValue); Identifier returnValueName(const model::RawFunctionDefinition &Function, const model::Register::Values &Register) { return returnValueName(Function, Function.ReturnValues().at(Register)); } public: Identifier artificialReturnValueWrapperName(const RFT &Function) { // Not checking anything here since the relevant checks should have already // been done when constructing the helper. auto R = configuration().artificialReturnValuePrefix() + name(Function); return Identifier(R.str()); } private: RecursiveCoroutine artificialArrayWrapperNameImpl(const model::Type &Type); public: Identifier artificialArrayWrapperName(const model::ArrayType &Type) { // Not checking anything here since the relevant checks should have already // been done when constructing the helper. llvm::StringRef Prefix = configuration().artificialArrayWrapperPrefix(); return Identifier(std::string(Prefix) + std::string(artificialArrayWrapperNameImpl(Type))); } Identifier artificialArrayWrapperFieldName(); }; } // namespace model