| 1 | //===--- Execution.h - Executing clang frontend actions -*- C++ ---------*-===// |
|---|---|
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | // |
| 9 | // This file defines framework for executing clang frontend actions. |
| 10 | // |
| 11 | // The framework can be extended to support different execution plans including |
| 12 | // standalone execution on the given TUs or parallel execution on all TUs in |
| 13 | // the codebase. |
| 14 | // |
| 15 | // In order to enable multiprocessing execution, tool actions are expected to |
| 16 | // output result into the ToolResults provided by the executor. The |
| 17 | // `ToolResults` is an interface that abstracts how results are stored e.g. |
| 18 | // in-memory for standalone execution or on-disk for large-scale execution. |
| 19 | // |
| 20 | // New executors can be registered as ToolExecutorPlugins via the |
| 21 | // `ToolExecutorPluginRegistry`. CLI tools can use |
| 22 | // `createExecutorFromCommandLineArgs` to create a specific registered executor |
| 23 | // according to the command-line arguments. |
| 24 | // |
| 25 | //===----------------------------------------------------------------------===// |
| 26 | |
| 27 | #ifndef LLVM_CLANG_TOOLING_EXECUTION_H |
| 28 | #define LLVM_CLANG_TOOLING_EXECUTION_H |
| 29 | |
| 30 | #include "clang/Tooling/CommonOptionsParser.h" |
| 31 | #include "clang/Tooling/Tooling.h" |
| 32 | #include "llvm/Support/Error.h" |
| 33 | #include "llvm/Support/Registry.h" |
| 34 | #include "llvm/Support/StringSaver.h" |
| 35 | |
| 36 | namespace clang { |
| 37 | namespace tooling { |
| 38 | |
| 39 | extern llvm::cl::opt<std::string> ExecutorName; |
| 40 | |
| 41 | /// An abstraction for the result of a tool execution. For example, the |
| 42 | /// underlying result can be in-memory or on-disk. |
| 43 | /// |
| 44 | /// Results should be string key-value pairs. For example, a refactoring tool |
| 45 | /// can use source location as key and a replacement in YAML format as value. |
| 46 | class ToolResults { |
| 47 | public: |
| 48 | virtual ~ToolResults() = default; |
| 49 | virtual void addResult(StringRef Key, StringRef Value) = 0; |
| 50 | virtual std::vector<std::pair<llvm::StringRef, llvm::StringRef>> |
| 51 | AllKVResults() = 0; |
| 52 | virtual void forEachResult( |
| 53 | llvm::function_ref<void(StringRef Key, StringRef Value)> Callback) = 0; |
| 54 | }; |
| 55 | |
| 56 | /// Stores the key-value results in memory. It maintains the lifetime of |
| 57 | /// the result. Clang tools using this class are expected to generate a small |
| 58 | /// set of different results, or a large set of duplicated results. |
| 59 | class InMemoryToolResults : public ToolResults { |
| 60 | public: |
| 61 | InMemoryToolResults() : Strings(Arena) {} |
| 62 | void addResult(StringRef Key, StringRef Value) override; |
| 63 | std::vector<std::pair<llvm::StringRef, llvm::StringRef>> |
| 64 | AllKVResults() override; |
| 65 | void forEachResult(llvm::function_ref<void(StringRef Key, StringRef Value)> |
| 66 | Callback) override; |
| 67 | |
| 68 | private: |
| 69 | llvm::BumpPtrAllocator Arena; |
| 70 | llvm::UniqueStringSaver Strings; |
| 71 | |
| 72 | std::vector<std::pair<llvm::StringRef, llvm::StringRef>> KVResults; |
| 73 | }; |
| 74 | |
| 75 | /// The context of an execution, including the information about |
| 76 | /// compilation and results. |
| 77 | class ExecutionContext { |
| 78 | public: |
| 79 | virtual ~ExecutionContext() {} |
| 80 | |
| 81 | /// Initializes a context. This does not take ownership of `Results`. |
| 82 | explicit ExecutionContext(ToolResults *Results) : Results(Results) {} |
| 83 | |
| 84 | /// Adds a KV pair to the result container of this execution. |
| 85 | void reportResult(StringRef Key, StringRef Value); |
| 86 | |
| 87 | // Returns the source control system's revision number if applicable. |
| 88 | // Otherwise returns an empty string. |
| 89 | virtual std::string getRevision() { return ""; } |
| 90 | |
| 91 | // Returns the corpus being analyzed, e.g. "llvm" for the LLVM codebase, if |
| 92 | // applicable. |
| 93 | virtual std::string getCorpus() { return ""; } |
| 94 | |
| 95 | // Returns the currently processed compilation unit if available. |
| 96 | virtual std::string getCurrentCompilationUnit() { return ""; } |
| 97 | |
| 98 | private: |
| 99 | ToolResults *Results; |
| 100 | }; |
| 101 | |
| 102 | /// Interface for executing clang frontend actions. |
| 103 | /// |
| 104 | /// This can be extended to support running tool actions in different |
| 105 | /// execution mode, e.g. on a specific set of TUs or many TUs in parallel. |
| 106 | /// |
| 107 | /// New executors can be registered as ToolExecutorPlugins via the |
| 108 | /// `ToolExecutorPluginRegistry`. CLI tools can use |
| 109 | /// `createExecutorFromCommandLineArgs` to create a specific registered |
| 110 | /// executor according to the command-line arguments. |
| 111 | class ToolExecutor { |
| 112 | public: |
| 113 | virtual ~ToolExecutor() {} |
| 114 | |
| 115 | /// Returns the name of a specific executor. |
| 116 | virtual StringRef getExecutorName() const = 0; |
| 117 | |
| 118 | /// Should return true iff executor runs all actions in a single process. |
| 119 | /// Clients can use this signal to find out if they can collect results |
| 120 | /// in-memory (e.g. to avoid serialization costs of using ToolResults). |
| 121 | /// The single-process executors can still run multiple threads, but all |
| 122 | /// executions are guaranteed to share the same memory. |
| 123 | virtual bool isSingleProcess() const = 0; |
| 124 | |
| 125 | /// Executes each action with a corresponding arguments adjuster. |
| 126 | virtual llvm::Error |
| 127 | execute(llvm::ArrayRef< |
| 128 | std::pair<std::unique_ptr<FrontendActionFactory>, ArgumentsAdjuster>> |
| 129 | Actions) = 0; |
| 130 | |
| 131 | /// Convenient functions for the above `execute`. |
| 132 | llvm::Error execute(std::unique_ptr<FrontendActionFactory> Action); |
| 133 | /// Executes an action with an argument adjuster. |
| 134 | llvm::Error execute(std::unique_ptr<FrontendActionFactory> Action, |
| 135 | ArgumentsAdjuster Adjuster); |
| 136 | |
| 137 | /// Returns a reference to the execution context. |
| 138 | /// |
| 139 | /// This should be passed to tool callbacks, and tool callbacks should report |
| 140 | /// results via the returned context. |
| 141 | virtual ExecutionContext *getExecutionContext() = 0; |
| 142 | |
| 143 | /// Returns a reference to the result container. |
| 144 | /// |
| 145 | /// NOTE: This should only be used after the execution finishes. Tool |
| 146 | /// callbacks should report results via `ExecutionContext` instead. |
| 147 | virtual ToolResults *getToolResults() = 0; |
| 148 | |
| 149 | /// Map a virtual file to be used while running the tool. |
| 150 | /// |
| 151 | /// \param FilePath The path at which the content will be mapped. |
| 152 | /// \param Content A buffer of the file's content. |
| 153 | virtual void mapVirtualFile(StringRef FilePath, StringRef Content) = 0; |
| 154 | }; |
| 155 | |
| 156 | /// Interface for factories that create specific executors. This is also |
| 157 | /// used as a plugin to be registered into ToolExecutorPluginRegistry. |
| 158 | class ToolExecutorPlugin { |
| 159 | public: |
| 160 | virtual ~ToolExecutorPlugin() {} |
| 161 | |
| 162 | /// Create an `ToolExecutor`. |
| 163 | /// |
| 164 | /// `OptionsParser` can be consumed (e.g. moved) if the creation succeeds. |
| 165 | virtual llvm::Expected<std::unique_ptr<ToolExecutor>> |
| 166 | create(CommonOptionsParser &OptionsParser) = 0; |
| 167 | }; |
| 168 | |
| 169 | /// This creates a ToolExecutor that is in the global registry based on |
| 170 | /// commandline arguments. |
| 171 | /// |
| 172 | /// This picks the right executor based on the `--executor` option. This parses |
| 173 | /// the commandline arguments with `CommonOptionsParser`, so caller does not |
| 174 | /// need to parse again. |
| 175 | /// |
| 176 | /// By default, this creates a `StandaloneToolExecutor` ("standalone") if |
| 177 | /// `--executor` is not provided. |
| 178 | llvm::Expected<std::unique_ptr<ToolExecutor>> |
| 179 | createExecutorFromCommandLineArgs(int &argc, const char **argv, |
| 180 | llvm::cl::OptionCategory &Category, |
| 181 | const char *Overview = nullptr); |
| 182 | |
| 183 | namespace internal { |
| 184 | llvm::Expected<std::unique_ptr<ToolExecutor>> |
| 185 | createExecutorFromCommandLineArgsImpl(int &argc, const char **argv, |
| 186 | llvm::cl::OptionCategory &Category, |
| 187 | const char *Overview = nullptr); |
| 188 | } // end namespace internal |
| 189 | |
| 190 | } // end namespace tooling |
| 191 | } // end namespace clang |
| 192 | |
| 193 | #endif // LLVM_CLANG_TOOLING_EXECUTION_H |
| 194 |