#pragma once // // This file is distributed under the MIT License. See LICENSE.md for details. // #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" #include "revng/TupleTree/TupleTreePath.h" namespace model { class Binary; } namespace revng { class LocationBase { public: virtual std::string toString() const = 0; virtual ~LocationBase() = default; }; template class TupleTreeLocation : public LocationBase { private: TupleTreePath Path; public: TupleTreeLocation(TupleTreePath Path) : Path(Path) {} std::string toString() const override { auto AsString = pathAsString(Path); revng_assert(AsString.has_value()); return *AsString; } ~TupleTreeLocation() override = default; static std::string getTypeName() { return "TupleTreeLocation"; } }; class DocumentErrorBase : public llvm::ErrorInfo { public: inline static char ID = '0'; private: struct Entry { public: Entry(llvm::StringRef Reason, std::unique_ptr Location) : Reason(Reason.str()), Location(std::move(Location)) {} std::string Reason; std::unique_ptr Location; }; using iterator = llvm::SmallVector::iterator; using const_iterator = llvm::SmallVector::const_iterator; protected: using IDContainer = llvm::SmallVector; llvm::SmallVector Entries; IDContainer Ids; public: explicit DocumentErrorBase(const IDContainer &DerivedIds) : Entries(), Ids(std::move(DerivedIds)) { Ids.push_back(DocumentErrorBase::classID()); } DocumentErrorBase() { Ids.push_back(DocumentErrorBase::classID()); } virtual std::string getTypeName() const = 0; virtual std::string getLocationTypeName() const = 0; static llvm::Error concatenate(llvm::Error SourceError, llvm::StringRef NewReason, std::unique_ptr Loc) { if (not SourceError.isA()) return SourceError; llvm::Error ToReturn = llvm::Error::success(); return llvm::handleErrors(std::move(SourceError), [&](std::unique_ptr DocumentError) { DocumentError->Entries .emplace_back(NewReason.str(), std::move(Loc)); return llvm::Error(std::move(DocumentError)); }); } // Returns the class ID for this type. static const void *classID() { return &ID; } iterator begin() { return Entries.begin(); } iterator end() { return Entries.end(); } [[nodiscard]] const_iterator begin() const { return Entries.begin(); } [[nodiscard]] const_iterator end() const { return Entries.end(); } size_t size() const { return Entries.size(); } const std::string &getMessage(size_t I) const { return Entries[I].Reason; } std::string getLocation(size_t I) const { return Entries[I].Location->toString(); } virtual bool isA(const void *const ClassID) const { return llvm::find(Ids, ClassID) != Ids.end(); } public: std::error_code convertToErrorCode() const final { return llvm::inconvertibleErrorCode(); } void log(llvm::raw_ostream &OS) const final { OS << "Diff Errors\n"; for (auto &Reason : Entries) { OS << "\t" << Reason.Reason << "\n"; } } }; template class DocumentError : public DocumentErrorBase { private: static DocumentErrorBase::IDContainer getClassIds() { DocumentErrorBase::IDContainer Ids({ llvm::ErrorInfoBase::classID(), Derived::classID(), DocumentError::classID(), }); return Ids; } public: using LocationType = Location; inline static char ID = '0'; DocumentError(const DocumentErrorBase::IDContainer &Ids = getClassIds()) : DocumentErrorBase(Ids) {} DocumentError(llvm::StringRef Reason, const Location &ReasonLocation, const DocumentErrorBase::IDContainer &Ids = getClassIds()) : DocumentErrorBase(Ids) { addReason(Reason, ReasonLocation); } void addReason(llvm::StringRef NewReason, const Location &ReasonLocation) { Entries.emplace_back(NewReason.str(), std::make_unique(ReasonLocation)); } std::string getLocationTypeName() const override { return Location::getTypeName(); } void consumeAndAppend(llvm::Error Error, const Location &ReasonLocation) { if (!Error) return; std::string S; llvm::raw_string_ostream OS(S); OS << Error; OS.flush(); llvm::consumeError(std::move(Error)); addReason(S, ReasonLocation); } public: // Returns the class ID for this type. static const void *classID() { return &Derived::ID; } }; } // namespace revng