From 41f82f657a7f24d2c4de87f2ed732c4e59e66ceb Mon Sep 17 00:00:00 2001 From: Antonio Frighetto Date: Mon, 12 Sep 2022 10:16:48 +0000 Subject: [PATCH] `revng.daemon`: accept no arguments for analysis Let GraphQL accept zero or more parameters for analyses. --- include/revng/Model/Binary.h | 2 +- include/revng/Pipeline/Analysis.h | 7 +-- include/revng/Pipeline/Global.h | 16 +++--- include/revng/Pipeline/GlobalsMap.h | 4 +- include/revng/Pipeline/Invokable.h | 52 +++++++++++++------ include/revng/Pipeline/Pipe.h | 7 +-- include/revng/Pipeline/Step.h | 9 ++-- include/revng/PipelineC/ForwardDeclarations.h | 2 +- include/revng/Support/ErrorList.h | 37 ++++++++++++- include/revng/TupleTree/TupleTreeCompatible.h | 2 +- include/revng/TupleTree/TupleTreeDiff.h | 11 ++-- include/revng/TupleTree/Visits.h | 14 ++--- include/revng/TupleTree/VisitsImpl.h | 2 +- lib/Model/Binary.cpp | 2 +- lib/Pipeline/Runner.cpp | 2 +- lib/Pipeline/Step.cpp | 9 ++-- lib/PipelineC/PipelineC.cpp | 6 +-- python/revng/daemon/schema.graphql.tpl | 2 +- python/revng/daemon/schema_generator.py | 8 ++- tools/model/apply/Main.cpp | 2 +- 20 files changed, 131 insertions(+), 65 deletions(-) diff --git a/include/revng/Model/Binary.h b/include/revng/Model/Binary.h index 7c53e2886..94f8b365f 100644 --- a/include/revng/Model/Binary.h +++ b/include/revng/Model/Binary.h @@ -132,7 +132,7 @@ public: bool verify() const debug_function; bool verify(bool Assert) const debug_function; bool verify(VerifyHelper &VH) const; - void verify(ErrorList &EL) const; + void verify(revng::ErrorList &EL) const; void dump() const debug_function; void dumpTypeGraph(const char *Path) const debug_function; std::string toString() const debug_function; diff --git a/include/revng/Pipeline/Analysis.h b/include/revng/Pipeline/Analysis.h index 91a0fa687..1fb8b4633 100644 --- a/include/revng/Pipeline/Analysis.h +++ b/include/revng/Pipeline/Analysis.h @@ -8,6 +8,7 @@ #include "revng/Pipeline/Invokable.h" #include "revng/Pipeline/Pipe.h" +#include "revng/Support/ErrorList.h" namespace pipeline { @@ -74,9 +75,9 @@ public: Invokable.print(Ctx, OS, Indentation); } - llvm::Error run(Context &Ctx, - ContainerSet &Containers, - const llvm::StringMap &ExtraArgs) override { + revng::ErrorList run(Context &Ctx, + ContainerSet &Containers, + const llvm::StringMap &ExtraArgs) override { return Invokable.run(Ctx, Containers, ExtraArgs); } diff --git a/include/revng/Pipeline/Global.h b/include/revng/Pipeline/Global.h index bb0fce430..4fa9a626f 100644 --- a/include/revng/Pipeline/Global.h +++ b/include/revng/Pipeline/Global.h @@ -37,15 +37,17 @@ public: public: virtual GlobalTupleTreeDiff diff(const Global &Other) const = 0; - virtual void applyDiff(const llvm::MemoryBuffer &Diff, ErrorList &EL) = 0; - virtual void applyDiff(const GlobalTupleTreeDiff &Diff, ErrorList &EL) = 0; + virtual void + applyDiff(const llvm::MemoryBuffer &Diff, revng::ErrorList &EL) = 0; + virtual void + applyDiff(const GlobalTupleTreeDiff &Diff, revng::ErrorList &EL) = 0; virtual llvm::Error serialize(llvm::raw_ostream &OS) const = 0; virtual llvm::Error deserialize(const llvm::MemoryBuffer &Buffer) = 0; virtual llvm::Expected deserializeDiff(const llvm::MemoryBuffer &Diff) = 0; - virtual void verify(ErrorList &EL) const = 0; + virtual void verify(revng::ErrorList &EL) const = 0; virtual void clear() = 0; virtual llvm::Expected> @@ -117,7 +119,7 @@ public: return ::deserialize>(Buffer.getBuffer()); } - void verify(ErrorList &EL) const override { Value->verify(EL); } + void verify(revng::ErrorList &EL) const override { Value->verify(EL); } GlobalTupleTreeDiff diff(const Global &Other) const override { const TupleTreeGlobal &Casted = llvm::cast(Other); @@ -125,7 +127,8 @@ public: return GlobalTupleTreeDiff(std::move(Diff)); } - void applyDiff(const llvm::MemoryBuffer &Diff, ErrorList &EL) override { + void + applyDiff(const llvm::MemoryBuffer &Diff, revng::ErrorList &EL) override { auto MaybeDiff = TupleTreeDiff::deserialize(Diff.getBuffer(), EL); if (not MaybeDiff) { EL.push_back(MaybeDiff.takeError()); @@ -134,7 +137,8 @@ public: MaybeDiff->apply(Value, EL); } - void applyDiff(const GlobalTupleTreeDiff &Diff, ErrorList &EL) override { + void + applyDiff(const GlobalTupleTreeDiff &Diff, revng::ErrorList &EL) override { Diff.getAs()->apply(Value, EL); } diff --git a/include/revng/Pipeline/GlobalsMap.h b/include/revng/Pipeline/GlobalsMap.h index 54d3353c9..3bab881f8 100644 --- a/include/revng/Pipeline/GlobalsMap.h +++ b/include/revng/Pipeline/GlobalsMap.h @@ -83,8 +83,8 @@ public: return MaybeGlobal.get()->deserialize(Buffer); } - ErrorList verify(llvm::StringRef GlobalName) const { - ErrorList EL; + revng::ErrorList verify(llvm::StringRef GlobalName) const { + revng::ErrorList EL; auto MaybeGlobal = get(GlobalName); if (!MaybeGlobal) return MaybeGlobal.takeError(); diff --git a/include/revng/Pipeline/Invokable.h b/include/revng/Pipeline/Invokable.h index 5a7337dad..0e1a20eab 100644 --- a/include/revng/Pipeline/Invokable.h +++ b/include/revng/Pipeline/Invokable.h @@ -28,6 +28,7 @@ #include "revng/Pipeline/Target.h" #include "revng/Support/Assert.h" #include "revng/Support/Debug.h" +#include "revng/Support/ErrorList.h" #include "revng/Support/YAMLTraits.h" namespace pipeline { @@ -43,26 +44,32 @@ concept IsContainer = derived_from, ContainerBase>; template concept IsNotContainer = not IsContainer; -template -constexpr bool -invokableTypeReturnsErrorImpl(void (InvokableType::*F)(Args...)) { - return false; +template +constexpr ReturnType +invokableReturnTypeImpl(ReturnType (InvokableType::*F)(Args...)) { + return ReturnType(); } -template -constexpr bool -invokableTypeReturnsErrorImpl(llvm::Error (InvokableType::*F)(Args...)) { - return true; -} +template +using invokableReturnType = + decltype(invokableReturnTypeImpl(&InvokableType::run)); template constexpr bool invokableTypeReturnsError() { - return invokableTypeReturnsErrorImpl(&Invokable::run); + return std::is_same_v, llvm::Error>; +} + +template +constexpr bool invokableTypeReturnsErrorList() { + return std::is_same_v, revng::ErrorList>; } template concept ReturnsError = invokableTypeReturnsError(); +template +concept ReturnsErrorList = invokableTypeReturnsErrorList(); + /// A Invokable is a class with the following characteristics: /// /// * It must have a static constexpr field named Name that is a string @@ -346,9 +353,10 @@ concept Printable = requires(InvokableType Pipe) { class InvokableWrapperBase { public: - virtual llvm::Error run(Context &Ctx, - ContainerSet &Containers, - const llvm::StringMap &Options = {}) = 0; + virtual revng::ErrorList + run(Context &Ctx, + ContainerSet &Containers, + const llvm::StringMap &Options = {}) = 0; virtual ~InvokableWrapperBase() = default; virtual std::vector getRunningContainersNames() const = 0; virtual std::string getName() const = 0; @@ -387,10 +395,20 @@ public: std::string getName() const override { return InvokableType::Name; } public: - llvm::Error run(Context &Ctx, - ContainerSet &Containers, - const llvm::StringMap &OptionArgs) override { + revng::ErrorList + run(Context &Ctx, + ContainerSet &Containers, + const llvm::StringMap &OptionArgs) override { if constexpr (invokableTypeReturnsError()) { + revng::ErrorList ToReturn; + ToReturn.push_back(invokePipeFunction(Ctx, + ActualPipe, + &InvokableType::run, + Containers, + RunningContainersNames, + OptionArgs)); + return ToReturn; + } else if constexpr (invokableTypeReturnsErrorList()) { return invokePipeFunction(Ctx, ActualPipe, &InvokableType::run, @@ -405,7 +423,7 @@ public: RunningContainersNames, OptionArgs); } - return llvm::Error::success(); + return revng::ErrorList(); } public: diff --git a/include/revng/Pipeline/Pipe.h b/include/revng/Pipeline/Pipe.h index 56f0e8232..6241d6e55 100644 --- a/include/revng/Pipeline/Pipe.h +++ b/include/revng/Pipeline/Pipe.h @@ -25,6 +25,7 @@ #include "revng/Pipeline/Invokable.h" #include "revng/Pipeline/Target.h" #include "revng/Support/Debug.h" +#include "revng/Support/ErrorList.h" namespace pipeline { @@ -172,9 +173,9 @@ public: Invokable.print(Ctx, OS, Indentation); } - llvm::Error run(Context &Ctx, - ContainerSet &Containers, - const llvm::StringMap &ExtraArgs) override { + revng::ErrorList run(Context &Ctx, + ContainerSet &Containers, + const llvm::StringMap &ExtraArgs) override { return Invokable.run(Ctx, Containers, ExtraArgs); } diff --git a/include/revng/Pipeline/Step.h b/include/revng/Pipeline/Step.h index a67793849..83121074b 100644 --- a/include/revng/Pipeline/Step.h +++ b/include/revng/Pipeline/Step.h @@ -179,10 +179,11 @@ public: } public: - llvm::Error runAnalysis(llvm::StringRef AnalysisName, - Context &Ctx, - const ContainerToTargetsMap &Targets, - const llvm::StringMap &ExtraArgs = {}); + revng::ErrorList + runAnalysis(llvm::StringRef AnalysisName, + Context &Ctx, + const ContainerToTargetsMap &Targets, + const llvm::StringMap &ExtraArgs = {}); /// Clones the Targets from the backing containers of this step /// and excutes all the pipes in sequence contained by this step diff --git a/include/revng/PipelineC/ForwardDeclarations.h b/include/revng/PipelineC/ForwardDeclarations.h index 8230a252c..84e631296 100644 --- a/include/revng/PipelineC/ForwardDeclarations.h +++ b/include/revng/PipelineC/ForwardDeclarations.h @@ -18,6 +18,6 @@ typedef const pipeline::Target rp_target; typedef const pipeline::TargetsList rp_targets_list; typedef const pipeline::Step::AnalysisValueType rp_analysis; typedef const pipeline::DiffMap rp_diff_map; -typedef ErrorList rp_error_list; +typedef revng::ErrorList rp_error_list; typedef llvm::StringMap rp_string_map; typedef pipeline::InvalidationMap rp_invalidations; diff --git a/include/revng/Support/ErrorList.h b/include/revng/Support/ErrorList.h index 0ca50f8af..d95ef7642 100644 --- a/include/revng/Support/ErrorList.h +++ b/include/revng/Support/ErrorList.h @@ -6,12 +6,15 @@ #include +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/Error.h" #include "revng/Support/Assert.h" #include "revng/Support/Debug.h" -class ErrorList { +namespace revng { + +class [[nodiscard]] ErrorList { private: std::vector Errors; @@ -30,6 +33,17 @@ public: } } + using iterator = std::vector::iterator; + using const_iterator = std::vector::const_iterator; + + iterator begin() { return Errors.begin(); } + + const_iterator begin() const { return Errors.begin(); } + + iterator end() { return Errors.end(); } + + const_iterator end() const { return Errors.end(); } + operator bool() const { return !empty(); } bool empty() const { return Errors.empty(); } @@ -86,6 +100,17 @@ public: void dump() const debug_function { dump(dbg); } + llvm::Error asLLVMError() { + if (empty()) + return llvm::Error::success(); + llvm::Error Error = std::move(Errors.front()); + for (auto &Error2 : llvm::drop_begin(Errors)) + Error = llvm::joinErrors(std::move(Error), std::move(Error2)); + Errors.clear(); + + return Error; + } + friend llvm::raw_ostream & operator<<(llvm::raw_ostream &OS, const ErrorList &EL) { EL.dump(OS); @@ -97,3 +122,13 @@ public: return OS; } }; + +inline void cantFail(ErrorList &&List) { + if (not List.empty()) { + for (auto &Error : List) { + llvm::cantFail(std::move(Error)); + } + } +} + +} // namespace revng diff --git a/include/revng/TupleTree/TupleTreeCompatible.h b/include/revng/TupleTree/TupleTreeCompatible.h index 62d0d15db..97ec8ed62 100644 --- a/include/revng/TupleTree/TupleTreeCompatible.h +++ b/include/revng/TupleTree/TupleTreeCompatible.h @@ -19,7 +19,7 @@ concept NotTupleTreeCompatible = not TupleTreeCompatible; // clang-format on template -concept Verifiable = requires(const T &TT, ErrorList &EL) { +concept Verifiable = requires(const T &TT, revng::ErrorList &EL) { { TT.verify(EL) }; { TT.verify() } -> std::same_as; }; diff --git a/include/revng/TupleTree/TupleTreeDiff.h b/include/revng/TupleTree/TupleTreeDiff.h index 044f6506e..b07e5bf68 100644 --- a/include/revng/TupleTree/TupleTreeDiff.h +++ b/include/revng/TupleTree/TupleTreeDiff.h @@ -156,7 +156,7 @@ template struct TupleTreeDiff { public: static llvm::Expected> - deserialize(llvm::StringRef Input, ErrorList &EL) { + deserialize(llvm::StringRef Input, revng::ErrorList &EL) { return ::deserialize>(Input, &EL); } @@ -199,7 +199,7 @@ public: dump(OutputStream); } - void apply(TupleTree &M, ErrorList &EL) const; + void apply(TupleTree &M, revng::ErrorList &EL) const; }; /// TODO: use non-strict specialization after it's available. @@ -299,7 +299,7 @@ struct llvm::yaml::MappingTraits { IO.mapRequired("Path", SerializedPath); auto MaybePath = stringAsPath(SerializedPath); if (!MaybePath.has_value()) { - ::ErrorList *EL = static_cast<::ErrorList *>(IO.getContext()); + revng::ErrorList *EL = static_cast(IO.getContext()); std::string ErrorMessage = "Path " + SerializedPath + " is invalid"; EL->push_back(llvm::createStringError(llvm::inconvertibleErrorCode(), ErrorMessage)); @@ -414,7 +414,7 @@ struct ApplyDiffVisitor { public: using Change = typename TupleTreeDiff::Change; const Change *C; - ErrorList *EL; + revng::ErrorList *EL; private: void generateError() { generateError(""); } @@ -506,7 +506,8 @@ public: } // namespace tupletreediff::detail template -inline void TupleTreeDiff::apply(TupleTree &M, ErrorList &EL) const { +inline void +TupleTreeDiff::apply(TupleTree &M, revng::ErrorList &EL) const { for (const Change &C : Changes) { if (C.Path.size() == 0) { // Change failed to deserialize, skip it diff --git a/include/revng/TupleTree/Visits.h b/include/revng/TupleTree/Visits.h index 080c1ee3e..5b5e8cf8c 100644 --- a/include/revng/TupleTree/Visits.h +++ b/include/revng/TupleTree/Visits.h @@ -223,7 +223,7 @@ template bool callOnPathSteps(Visitor &, llvm::ArrayRef, T &, - ErrorList &, + revng::ErrorList &, const llvm::StringRef) { return false; } @@ -232,7 +232,7 @@ template bool callOnPathStepsTuple(Visitor &V, llvm::ArrayRef Path, RootT &M, - ErrorList &EL, + revng::ErrorList &EL, const llvm::StringRef FullPath) { if constexpr (I < std::tuple_size_v) { if (Path[0].get() == I) { @@ -256,7 +256,7 @@ template bool callOnPathSteps(Visitor &V, llvm::ArrayRef Path, RootT &M, - ErrorList &EL, + revng::ErrorList &EL, const llvm::StringRef FullPath) { auto Dispatcher = [&](auto &Upcasted) { return callOnPathStepsTuple(V, Path, Upcasted, EL, FullPath); @@ -269,7 +269,7 @@ template bool callOnPathSteps(Visitor &V, llvm::ArrayRef Path, RootT &M, - ErrorList &EL, + revng::ErrorList &EL, const llvm::StringRef FullPath) { return tupletree::detail::callOnPathStepsTuple(V, Path, M, EL, FullPath); } @@ -278,7 +278,7 @@ template bool callOnPathSteps(Visitor &V, llvm::ArrayRef Path, RootT &M, - ErrorList &EL, + revng::ErrorList &EL, const llvm::StringRef FullPath) { using value_type = typename RootT::value_type; using KOT = KeyedObjectTraits; @@ -391,7 +391,7 @@ template bool callByPath(Visitor &V, const TupleTreePath &Path, RootT &M, - ErrorList &EL) { + revng::ErrorList &EL) { return callByPath(V, Path, M, EL, ""); } @@ -399,7 +399,7 @@ template bool callByPath(Visitor &V, const TupleTreePath &Path, RootT &M, - ErrorList &EL, + revng::ErrorList &EL, const llvm::StringRef OriginalPath) { using namespace tupletree::detail; CallByPathVisitorWithInstance CBPV{ Path.size(), V }; diff --git a/include/revng/TupleTree/VisitsImpl.h b/include/revng/TupleTree/VisitsImpl.h index 95ece0341..cf48c8f1e 100644 --- a/include/revng/TupleTree/VisitsImpl.h +++ b/include/revng/TupleTree/VisitsImpl.h @@ -42,7 +42,7 @@ struct GetByPathVisitor { template ResultT *getByPath(const TupleTreePath &Path, RootT &M) { using namespace tupletree::detail; - ErrorList EL; + revng::ErrorList EL; GetByPathVisitor GBPV; if (not callByPath(GBPV, Path, M, EL)) return nullptr; diff --git a/lib/Model/Binary.cpp b/lib/Model/Binary.cpp index c3f4e180b..c6ff2b8a8 100644 --- a/lib/Model/Binary.cpp +++ b/lib/Model/Binary.cpp @@ -104,7 +104,7 @@ bool Binary::verify(bool Assert) const { return verify(VH); } -void Binary::verify(::ErrorList &EL) const { +void Binary::verify(revng::ErrorList &EL) const { VerifyHelper VH(false); bool Result = verify(VH); if (not Result) diff --git a/lib/Pipeline/Runner.cpp b/lib/Pipeline/Runner.cpp index 7557a97c2..d7ceec220 100644 --- a/lib/Pipeline/Runner.cpp +++ b/lib/Pipeline/Runner.cpp @@ -261,7 +261,7 @@ Runner::runAnalysis(llvm::StringRef AnalysisName, Targets, Options); Error) - return std::move(Error); + return Error.asLLVMError(); auto &After = getContext().getGlobals(); auto Map = Before.diff(After); diff --git a/lib/Pipeline/Step.cpp b/lib/Pipeline/Step.cpp index 1ec05ddd2..13c5f7caa 100644 --- a/lib/Pipeline/Step.cpp +++ b/lib/Pipeline/Step.cpp @@ -101,10 +101,11 @@ ContainerSet Step::cloneAndRun(Context &Ctx, ContainerSet &&Input) { return Cloned; } -llvm::Error Step::runAnalysis(llvm::StringRef AnalysisName, - Context &Ctx, - const ContainerToTargetsMap &Targets, - const llvm::StringMap &ExtraArgs) { +revng::ErrorList +Step::runAnalysis(llvm::StringRef AnalysisName, + Context &Ctx, + const ContainerToTargetsMap &Targets, + const llvm::StringMap &ExtraArgs) { auto Stream = ExplanationLogger.getAsLLVMStream(); ContainerToTargetsMap Map = Containers.enumerate(); diff --git a/lib/PipelineC/PipelineC.cpp b/lib/PipelineC/PipelineC.cpp index 046da9892..1d5eb75e7 100644 --- a/lib/PipelineC/PipelineC.cpp +++ b/lib/PipelineC/PipelineC.cpp @@ -626,7 +626,7 @@ inline bool rp_manager_set_global_impl(rp_manager *manager, revng_check(manager != nullptr); revng_check(serialized != nullptr); revng_check(global_name != nullptr); - ExistingOrNew ErrorList(error_list); + ExistingOrNew ErrorList(error_list); revng_check(ErrorList->empty()); auto &GlobalsMap = manager->context().getGlobals(); @@ -691,7 +691,7 @@ inline bool rp_manager_apply_diff_impl(rp_manager *manager, revng_check(manager != nullptr); revng_check(diff != nullptr); revng_check(global_name != nullptr); - ExistingOrNew ErrorList(error_list); + ExistingOrNew ErrorList(error_list); revng_check(ErrorList->empty()); auto &GlobalsMap = manager->context().getGlobals(); @@ -873,7 +873,7 @@ bool rp_diff_map_is_empty(rp_diff_map *map) { } rp_error_list *rp_make_error_list() { - return new ErrorList(); + return new revng::ErrorList(); } bool rp_error_list_is_empty(rp_error_list *error_list) { diff --git a/python/revng/daemon/schema.graphql.tpl b/python/revng/daemon/schema.graphql.tpl index 9de294e09..18e15b285 100644 --- a/python/revng/daemon/schema.graphql.tpl +++ b/python/revng/daemon/schema.graphql.tpl @@ -117,7 +117,7 @@ type {{ rank.name | capitalize }} { {%- if step.analyses_count() > 0 %} type {{ step.name }}Analyses { {%- for analysis in step.analyses() %} - {{ analysis.name | normalize }}({{ analysis | generate_analysis_parameters }}): String! + {{ analysis.name | normalize }}{{ analysis | generate_analysis_parameters }}: String! {%- endfor %} } {%- endif %} diff --git a/python/revng/daemon/schema_generator.py b/python/revng/daemon/schema_generator.py index 2db024498..d88b21fea 100644 --- a/python/revng/daemon/schema_generator.py +++ b/python/revng/daemon/schema_generator.py @@ -55,8 +55,12 @@ class SchemaGenerator: @staticmethod def _generate_analysis_parameters(analysis: Analysis) -> str: - return ", ".join( - f"{normalize(argument.name)}: String!" for argument in analysis.arguments() + if len(list(analysis.arguments())) == 0: + return "" + return ( + "(" + + ", ".join(f"{normalize(argument.name)}: String!" for argument in analysis.arguments()) + + ")" ) @staticmethod diff --git a/tools/model/apply/Main.cpp b/tools/model/apply/Main.cpp index 25e63e0eb..0d5061c6b 100644 --- a/tools/model/apply/Main.cpp +++ b/tools/model/apply/Main.cpp @@ -47,7 +47,7 @@ int main(int Argc, char *Argv[]) { if (not Model) ExitOnError(Model.takeError()); - ::ErrorList EL; + revng::ErrorList EL; auto Diff = deserializeFileOrSTDIN>(DiffPath, &EL); if (not Diff)