1 //===- Tooling.h - Framework for standalone Clang tools ---------*- 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 implements functions to run clang tools standalone instead 10 // of running them as a plugin. 11 // 12 // A ClangTool is initialized with a CompilationDatabase and a set of files 13 // to run over. The tool will then run a user-specified FrontendAction over 14 // all TUs in which the given files are compiled. 15 // 16 // It is also possible to run a FrontendAction over a snippet of code by 17 // calling runToolOnCode, which is useful for unit testing. 18 // 19 // Applications that need more fine grained control over how to run 20 // multiple FrontendActions over code can use ToolInvocation. 21 // 22 // Example tools: 23 // - running clang -fsyntax-only over source code from an editor to get 24 // fast syntax checks 25 // - running match/replace tools over C++ code 26 // 27 //===----------------------------------------------------------------------===// 28 29 #ifndef LLVM_CLANG_TOOLING_TOOLING_H 30 #define LLVM_CLANG_TOOLING_TOOLING_H 31 32 #include "clang/AST/ASTConsumer.h" 33 #include "clang/Basic/FileManager.h" 34 #include "clang/Basic/LLVM.h" 35 #include "clang/Frontend/FrontendAction.h" 36 #include "clang/Frontend/PCHContainerOperations.h" 37 #include "clang/Tooling/ArgumentsAdjusters.h" 38 #include "llvm/ADT/ArrayRef.h" 39 #include "llvm/ADT/IntrusiveRefCntPtr.h" 40 #include "llvm/ADT/StringMap.h" 41 #include "llvm/ADT/StringRef.h" 42 #include "llvm/ADT/StringSet.h" 43 #include "llvm/ADT/Twine.h" 44 #include "llvm/Option/Option.h" 45 #include "llvm/Support/VirtualFileSystem.h" 46 #include <memory> 47 #include <string> 48 #include <utility> 49 #include <vector> 50 51 namespace clang { 52 53 class CompilerInstance; 54 class CompilerInvocation; 55 class DiagnosticConsumer; 56 class DiagnosticsEngine; 57 58 namespace driver { 59 60 class Compilation; 61 62 } // namespace driver 63 64 namespace tooling { 65 66 class CompilationDatabase; 67 68 /// Retrieves the flags of the `-cc1` job in `Compilation` that has only source 69 /// files as its inputs. 70 /// Returns nullptr if there are no such jobs or multiple of them. Note that 71 /// offloading jobs are ignored. 72 const llvm::opt::ArgStringList * 73 getCC1Arguments(DiagnosticsEngine *Diagnostics, 74 driver::Compilation *Compilation); 75 76 /// Interface to process a clang::CompilerInvocation. 77 /// 78 /// If your tool is based on FrontendAction, you should be deriving from 79 /// FrontendActionFactory instead. 80 class ToolAction { 81 public: 82 virtual ~ToolAction(); 83 84 /// Perform an action for an invocation. 85 virtual bool 86 runInvocation(std::shared_ptr<CompilerInvocation> Invocation, 87 FileManager *Files, 88 std::shared_ptr<PCHContainerOperations> PCHContainerOps, 89 DiagnosticConsumer *DiagConsumer) = 0; 90 }; 91 92 /// Interface to generate clang::FrontendActions. 93 /// 94 /// Having a factory interface allows, for example, a new FrontendAction to be 95 /// created for each translation unit processed by ClangTool. This class is 96 /// also a ToolAction which uses the FrontendActions created by create() to 97 /// process each translation unit. 98 class FrontendActionFactory : public ToolAction { 99 public: 100 ~FrontendActionFactory() override; 101 102 /// Invokes the compiler with a FrontendAction created by create(). 103 bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation, 104 FileManager *Files, 105 std::shared_ptr<PCHContainerOperations> PCHContainerOps, 106 DiagnosticConsumer *DiagConsumer) override; 107 108 /// Returns a new clang::FrontendAction. 109 virtual std::unique_ptr<FrontendAction> create() = 0; 110 }; 111 112 /// Returns a new FrontendActionFactory for a given type. 113 /// 114 /// T must derive from clang::FrontendAction. 115 /// 116 /// Example: 117 /// std::unique_ptr<FrontendActionFactory> Factory = 118 /// newFrontendActionFactory<clang::SyntaxOnlyAction>(); 119 template <typename T> 120 std::unique_ptr<FrontendActionFactory> newFrontendActionFactory(); 121 122 /// Callbacks called before and after each source file processed by a 123 /// FrontendAction created by the FrontedActionFactory returned by \c 124 /// newFrontendActionFactory. 125 class SourceFileCallbacks { 126 public: 127 virtual ~SourceFileCallbacks() = default; 128 129 /// Called before a source file is processed by a FrontEndAction. 130 /// \see clang::FrontendAction::BeginSourceFileAction 131 virtual bool handleBeginSource(CompilerInstance &CI) { 132 return true; 133 } 134 135 /// Called after a source file is processed by a FrontendAction. 136 /// \see clang::FrontendAction::EndSourceFileAction 137 virtual void handleEndSource() {} 138 }; 139 140 /// Returns a new FrontendActionFactory for any type that provides an 141 /// implementation of newASTConsumer(). 142 /// 143 /// FactoryT must implement: ASTConsumer *newASTConsumer(). 144 /// 145 /// Example: 146 /// struct ProvidesASTConsumers { 147 /// std::unique_ptr<clang::ASTConsumer> newASTConsumer(); 148 /// } Factory; 149 /// std::unique_ptr<FrontendActionFactory> FactoryAdapter( 150 /// newFrontendActionFactory(&Factory)); 151 template <typename FactoryT> 152 inline std::unique_ptr<FrontendActionFactory> newFrontendActionFactory( 153 FactoryT *ConsumerFactory, SourceFileCallbacks *Callbacks = nullptr); 154 155 /// Runs (and deletes) the tool on 'Code' with the -fsyntax-only flag. 156 /// 157 /// \param ToolAction The action to run over the code. 158 /// \param Code C++ code. 159 /// \param FileName The file name which 'Code' will be mapped as. 160 /// \param PCHContainerOps The PCHContainerOperations for loading and creating 161 /// clang modules. 162 /// 163 /// \return - True if 'ToolAction' was successfully executed. 164 bool runToolOnCode(std::unique_ptr<FrontendAction> ToolAction, const Twine &Code, 165 const Twine &FileName = "input.cc", 166 std::shared_ptr<PCHContainerOperations> PCHContainerOps = 167 std::make_shared<PCHContainerOperations>()); 168 169 /// The first part of the pair is the filename, the second part the 170 /// file-content. 171 using FileContentMappings = std::vector<std::pair<std::string, std::string>>; 172 173 /// Runs (and deletes) the tool on 'Code' with the -fsyntax-only flag and 174 /// with additional other flags. 175 /// 176 /// \param ToolAction The action to run over the code. 177 /// \param Code C++ code. 178 /// \param Args Additional flags to pass on. 179 /// \param FileName The file name which 'Code' will be mapped as. 180 /// \param ToolName The name of the binary running the tool. Standard library 181 /// header paths will be resolved relative to this. 182 /// \param PCHContainerOps The PCHContainerOperations for loading and creating 183 /// clang modules. 184 /// 185 /// \return - True if 'ToolAction' was successfully executed. 186 bool runToolOnCodeWithArgs( 187 std::unique_ptr<FrontendAction> ToolAction, const Twine &Code, 188 const std::vector<std::string> &Args, const Twine &FileName = "input.cc", 189 const Twine &ToolName = "clang-tool", 190 std::shared_ptr<PCHContainerOperations> PCHContainerOps = 191 std::make_shared<PCHContainerOperations>(), 192 const FileContentMappings &VirtualMappedFiles = FileContentMappings()); 193 194 // Similar to the overload except this takes a VFS. 195 bool runToolOnCodeWithArgs( 196 std::unique_ptr<FrontendAction> ToolAction, const Twine &Code, 197 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, 198 const std::vector<std::string> &Args, const Twine &FileName = "input.cc", 199 const Twine &ToolName = "clang-tool", 200 std::shared_ptr<PCHContainerOperations> PCHContainerOps = 201 std::make_shared<PCHContainerOperations>()); 202 203 /// Builds an AST for 'Code'. 204 /// 205 /// \param Code C++ code. 206 /// \param FileName The file name which 'Code' will be mapped as. 207 /// \param PCHContainerOps The PCHContainerOperations for loading and creating 208 /// clang modules. 209 /// 210 /// \return The resulting AST or null if an error occurred. 211 std::unique_ptr<ASTUnit> 212 buildASTFromCode(StringRef Code, StringRef FileName = "input.cc", 213 std::shared_ptr<PCHContainerOperations> PCHContainerOps = 214 std::make_shared<PCHContainerOperations>()); 215 216 /// Builds an AST for 'Code' with additional flags. 217 /// 218 /// \param Code C++ code. 219 /// \param Args Additional flags to pass on. 220 /// \param FileName The file name which 'Code' will be mapped as. 221 /// \param ToolName The name of the binary running the tool. Standard library 222 /// header paths will be resolved relative to this. 223 /// \param PCHContainerOps The PCHContainerOperations for loading and creating 224 /// clang modules. 225 /// 226 /// \param Adjuster A function to filter the command line arguments as 227 /// specified. 228 /// 229 /// \param BaseFS FileSystem for managing and looking up files. 230 /// VirtualMappedFiles takes precedence. 231 /// 232 /// \return The resulting AST or null if an error occurred. 233 std::unique_ptr<ASTUnit> buildASTFromCodeWithArgs( 234 StringRef Code, const std::vector<std::string> &Args, 235 StringRef FileName = "input.cc", StringRef ToolName = "clang-tool", 236 std::shared_ptr<PCHContainerOperations> PCHContainerOps = 237 std::make_shared<PCHContainerOperations>(), 238 ArgumentsAdjuster Adjuster = getClangStripDependencyFileAdjuster(), 239 const FileContentMappings &VirtualMappedFiles = FileContentMappings(), 240 DiagnosticConsumer *DiagConsumer = nullptr, 241 IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS = 242 llvm::vfs::getRealFileSystem()); 243 244 /// Utility to run a FrontendAction in a single clang invocation. 245 class ToolInvocation { 246 public: 247 /// Create a tool invocation. 248 /// 249 /// \param CommandLine The command line arguments to clang. Note that clang 250 /// uses its binary name (CommandLine[0]) to locate its builtin headers. 251 /// Callers have to ensure that they are installed in a compatible location 252 /// (see clang driver implementation) or mapped in via mapVirtualFile. 253 /// \param FAction The action to be executed. 254 /// \param Files The FileManager used for the execution. Class does not take 255 /// ownership. 256 /// \param PCHContainerOps The PCHContainerOperations for loading and creating 257 /// clang modules. 258 ToolInvocation(std::vector<std::string> CommandLine, 259 std::unique_ptr<FrontendAction> FAction, FileManager *Files, 260 std::shared_ptr<PCHContainerOperations> PCHContainerOps = 261 std::make_shared<PCHContainerOperations>()); 262 263 /// Create a tool invocation. 264 /// 265 /// \param CommandLine The command line arguments to clang. 266 /// \param Action The action to be executed. 267 /// \param Files The FileManager used for the execution. 268 /// \param PCHContainerOps The PCHContainerOperations for loading and creating 269 /// clang modules. 270 ToolInvocation(std::vector<std::string> CommandLine, ToolAction *Action, 271 FileManager *Files, 272 std::shared_ptr<PCHContainerOperations> PCHContainerOps); 273 274 ~ToolInvocation(); 275 276 ToolInvocation(const ToolInvocation &) = delete; 277 ToolInvocation &operator=(const ToolInvocation &) = delete; 278 279 /// Set a \c DiagnosticConsumer to use during driver command-line parsing and 280 /// the action invocation itself. 281 void setDiagnosticConsumer(DiagnosticConsumer *DiagConsumer) { 282 this->DiagConsumer = DiagConsumer; 283 } 284 285 /// Set a \c DiagnosticOptions to use during driver command-line parsing. 286 void setDiagnosticOptions(DiagnosticOptions *DiagOpts) { 287 this->DiagOpts = DiagOpts; 288 } 289 290 /// Run the clang invocation. 291 /// 292 /// \returns True if there were no errors during execution. 293 bool run(); 294 295 private: 296 bool runInvocation(const char *BinaryName, 297 driver::Compilation *Compilation, 298 std::shared_ptr<CompilerInvocation> Invocation, 299 std::shared_ptr<PCHContainerOperations> PCHContainerOps); 300 301 std::vector<std::string> CommandLine; 302 ToolAction *Action; 303 bool OwnsAction; 304 FileManager *Files; 305 std::shared_ptr<PCHContainerOperations> PCHContainerOps; 306 DiagnosticConsumer *DiagConsumer = nullptr; 307 DiagnosticOptions *DiagOpts = nullptr; 308 }; 309 310 /// Utility to run a FrontendAction over a set of files. 311 /// 312 /// This class is written to be usable for command line utilities. 313 /// By default the class uses ClangSyntaxOnlyAdjuster to modify 314 /// command line arguments before the arguments are used to run 315 /// a frontend action. One could install an additional command line 316 /// arguments adjuster by calling the appendArgumentsAdjuster() method. 317 class ClangTool { 318 public: 319 /// Constructs a clang tool to run over a list of files. 320 /// 321 /// \param Compilations The CompilationDatabase which contains the compile 322 /// command lines for the given source paths. 323 /// \param SourcePaths The source files to run over. If a source files is 324 /// not found in Compilations, it is skipped. 325 /// \param PCHContainerOps The PCHContainerOperations for loading and creating 326 /// clang modules. 327 /// \param BaseFS VFS used for all underlying file accesses when running the 328 /// tool. 329 /// \param Files The file manager to use for underlying file operations when 330 /// running the tool. 331 ClangTool(const CompilationDatabase &Compilations, 332 ArrayRef<std::string> SourcePaths, 333 std::shared_ptr<PCHContainerOperations> PCHContainerOps = 334 std::make_shared<PCHContainerOperations>(), 335 IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS = 336 llvm::vfs::getRealFileSystem(), 337 IntrusiveRefCntPtr<FileManager> Files = nullptr); 338 339 ~ClangTool(); 340 341 /// Set a \c DiagnosticConsumer to use during parsing. 342 void setDiagnosticConsumer(DiagnosticConsumer *DiagConsumer) { 343 this->DiagConsumer = DiagConsumer; 344 } 345 346 /// Map a virtual file to be used while running the tool. 347 /// 348 /// \param FilePath The path at which the content will be mapped. 349 /// \param Content A null terminated buffer of the file's content. 350 void mapVirtualFile(StringRef FilePath, StringRef Content); 351 352 /// Append a command line arguments adjuster to the adjuster chain. 353 /// 354 /// \param Adjuster An argument adjuster, which will be run on the output of 355 /// previous argument adjusters. 356 void appendArgumentsAdjuster(ArgumentsAdjuster Adjuster); 357 358 /// Clear the command line arguments adjuster chain. 359 void clearArgumentsAdjusters(); 360 361 /// Runs an action over all files specified in the command line. 362 /// 363 /// \param Action Tool action. 364 /// 365 /// \returns 0 on success; 1 if any error occurred; 2 if there is no error but 366 /// some files are skipped due to missing compile commands. 367 int run(ToolAction *Action); 368 369 /// Create an AST for each file specified in the command line and 370 /// append them to ASTs. 371 int buildASTs(std::vector<std::unique_ptr<ASTUnit>> &ASTs); 372 373 /// Sets whether an error message should be printed out if an action fails. By 374 /// default, if an action fails, a message is printed out to stderr. 375 void setPrintErrorMessage(bool PrintErrorMessage); 376 377 /// Returns the file manager used in the tool. 378 /// 379 /// The file manager is shared between all translation units. 380 FileManager &getFiles() { return *Files; } 381 382 llvm::ArrayRef<std::string> getSourcePaths() const { return SourcePaths; } 383 384 private: 385 const CompilationDatabase &Compilations; 386 std::vector<std::string> SourcePaths; 387 std::shared_ptr<PCHContainerOperations> PCHContainerOps; 388 389 llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFileSystem; 390 llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem; 391 llvm::IntrusiveRefCntPtr<FileManager> Files; 392 393 // Contains a list of pairs (<file name>, <file content>). 394 std::vector<std::pair<StringRef, StringRef>> MappedFileContents; 395 396 llvm::StringSet<> SeenWorkingDirectories; 397 398 ArgumentsAdjuster ArgsAdjuster; 399 400 DiagnosticConsumer *DiagConsumer = nullptr; 401 402 bool PrintErrorMessage = true; 403 }; 404 405 template <typename T> 406 std::unique_ptr<FrontendActionFactory> newFrontendActionFactory() { 407 class SimpleFrontendActionFactory : public FrontendActionFactory { 408 public: 409 std::unique_ptr<FrontendAction> create() override { 410 return std::make_unique<T>(); 411 } 412 }; 413 414 return std::unique_ptr<FrontendActionFactory>( 415 new SimpleFrontendActionFactory); 416 } 417 418 template <typename FactoryT> 419 inline std::unique_ptr<FrontendActionFactory> newFrontendActionFactory( 420 FactoryT *ConsumerFactory, SourceFileCallbacks *Callbacks) { 421 class FrontendActionFactoryAdapter : public FrontendActionFactory { 422 public: 423 explicit FrontendActionFactoryAdapter(FactoryT *ConsumerFactory, 424 SourceFileCallbacks *Callbacks) 425 : ConsumerFactory(ConsumerFactory), Callbacks(Callbacks) {} 426 427 std::unique_ptr<FrontendAction> create() override { 428 return std::make_unique<ConsumerFactoryAdaptor>(ConsumerFactory, 429 Callbacks); 430 } 431 432 private: 433 class ConsumerFactoryAdaptor : public ASTFrontendAction { 434 public: 435 ConsumerFactoryAdaptor(FactoryT *ConsumerFactory, 436 SourceFileCallbacks *Callbacks) 437 : ConsumerFactory(ConsumerFactory), Callbacks(Callbacks) {} 438 439 std::unique_ptr<ASTConsumer> 440 CreateASTConsumer(CompilerInstance &, StringRef) override { 441 return ConsumerFactory->newASTConsumer(); 442 } 443 444 protected: 445 bool BeginSourceFileAction(CompilerInstance &CI) override { 446 if (!ASTFrontendAction::BeginSourceFileAction(CI)) 447 return false; 448 if (Callbacks) 449 return Callbacks->handleBeginSource(CI); 450 return true; 451 } 452 453 void EndSourceFileAction() override { 454 if (Callbacks) 455 Callbacks->handleEndSource(); 456 ASTFrontendAction::EndSourceFileAction(); 457 } 458 459 private: 460 FactoryT *ConsumerFactory; 461 SourceFileCallbacks *Callbacks; 462 }; 463 FactoryT *ConsumerFactory; 464 SourceFileCallbacks *Callbacks; 465 }; 466 467 return std::unique_ptr<FrontendActionFactory>( 468 new FrontendActionFactoryAdapter(ConsumerFactory, Callbacks)); 469 } 470 471 /// Returns the absolute path of \c File, by prepending it with 472 /// the current directory if \c File is not absolute. 473 /// 474 /// Otherwise returns \c File. 475 /// If 'File' starts with "./", the returned path will not contain the "./". 476 /// Otherwise, the returned path will contain the literal path-concatenation of 477 /// the current directory and \c File. 478 /// 479 /// The difference to llvm::sys::fs::make_absolute is the canonicalization this 480 /// does by removing "./" and computing native paths. 481 /// 482 /// \param File Either an absolute or relative path. 483 std::string getAbsolutePath(StringRef File); 484 485 /// An overload of getAbsolutePath that works over the provided \p FS. 486 llvm::Expected<std::string> getAbsolutePath(llvm::vfs::FileSystem &FS, 487 StringRef File); 488 489 /// Changes CommandLine to contain implicit flags that would have been 490 /// defined had the compiler driver been invoked through the path InvokedAs. 491 /// 492 /// For example, when called with \c InvokedAs set to `i686-linux-android-g++`, 493 /// the arguments '-target', 'i686-linux-android`, `--driver-mode=g++` will 494 /// be inserted after the first argument in \c CommandLine. 495 /// 496 /// This function will not add new `-target` or `--driver-mode` flags if they 497 /// are already present in `CommandLine` (even if they have different settings 498 /// than would have been inserted). 499 /// 500 /// \pre `llvm::InitializeAllTargets()` has been called. 501 /// 502 /// \param CommandLine the command line used to invoke the compiler driver or 503 /// Clang tool, including the path to the executable as \c CommandLine[0]. 504 /// \param InvokedAs the path to the driver used to infer implicit flags. 505 /// 506 /// \note This will not set \c CommandLine[0] to \c InvokedAs. The tooling 507 /// infrastructure expects that CommandLine[0] is a tool path relative to which 508 /// the builtin headers can be found. 509 void addTargetAndModeForProgramName(std::vector<std::string> &CommandLine, 510 StringRef InvokedAs); 511 512 /// Helper function that expands response files in command line. 513 void addExpandedResponseFiles(std::vector<std::string> &CommandLine, 514 llvm::StringRef WorkingDir, 515 llvm::cl::TokenizerCallback Tokenizer, 516 llvm::vfs::FileSystem &FS); 517 518 /// Creates a \c CompilerInvocation. 519 CompilerInvocation *newInvocation(DiagnosticsEngine *Diagnostics, 520 ArrayRef<const char *> CC1Args, 521 const char *const BinaryName); 522 523 } // namespace tooling 524 525 } // namespace clang 526 527 #endif // LLVM_CLANG_TOOLING_TOOLING_H 528