1 //===- IncludeFixerPlugin.cpp - clang-include-fixer as a clang plugin -----===// 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 #include "../IncludeFixer.h" 10 #include "../YamlSymbolIndex.h" 11 #include "clang/Frontend/CompilerInstance.h" 12 #include "clang/Frontend/FrontendPluginRegistry.h" 13 #include "clang/Parse/ParseAST.h" 14 #include "clang/Sema/Sema.h" 15 #include "llvm/Support/Path.h" 16 17 namespace clang { 18 namespace include_fixer { 19 20 /// The core include fixer plugin action. This just provides the AST consumer 21 /// and command line flag parsing for using include fixer as a clang plugin. 22 class ClangIncludeFixerPluginAction : public PluginASTAction { 23 /// ASTConsumer to keep the symbol index alive. We don't really need an 24 /// ASTConsumer for this plugin (everything is funneled on the side through 25 /// Sema) but we have to keep the symbol index alive until sema is done. 26 struct ASTConsumerManagerWrapper : public ASTConsumer { ASTConsumerManagerWrapperclang::include_fixer::ClangIncludeFixerPluginAction::ASTConsumerManagerWrapper27 ASTConsumerManagerWrapper(std::shared_ptr<SymbolIndexManager> SIM) 28 : SymbolIndexMgr(std::move(SIM)) {} 29 std::shared_ptr<SymbolIndexManager> SymbolIndexMgr; 30 }; 31 32 public: ClangIncludeFixerPluginAction()33 explicit ClangIncludeFixerPluginAction() 34 : SymbolIndexMgr(std::make_shared<SymbolIndexManager>()), 35 SemaSource(new IncludeFixerSemaSource(*SymbolIndexMgr, 36 /*MinimizeIncludePaths=*/true, 37 /*GenerateDiagnostics=*/true)) {} 38 39 std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(clang::CompilerInstance & CI,StringRef InFile)40 CreateASTConsumer(clang::CompilerInstance &CI, StringRef InFile) override { 41 CI.setExternalSemaSource(SemaSource); 42 SemaSource->setFilePath(InFile); 43 SemaSource->setCompilerInstance(&CI); 44 return std::make_unique<ASTConsumerManagerWrapper>(SymbolIndexMgr); 45 } 46 ExecuteAction()47 void ExecuteAction() override {} // Do nothing. 48 ParseArgs(const CompilerInstance & CI,const std::vector<std::string> & Args)49 bool ParseArgs(const CompilerInstance &CI, 50 const std::vector<std::string> &Args) override { 51 StringRef DB = "yaml"; 52 StringRef Input; 53 54 // Parse the extra command line args. 55 // FIXME: This is very limited at the moment. 56 for (StringRef Arg : Args) { 57 if (Arg.startswith("-db=")) 58 DB = Arg.substr(strlen("-db=")); 59 else if (Arg.startswith("-input=")) 60 Input = Arg.substr(strlen("-input=")); 61 } 62 63 std::string InputFile = 64 std::string(CI.getFrontendOpts().Inputs[0].getFile()); 65 auto CreateYamlIdx = [=]() -> std::unique_ptr<include_fixer::SymbolIndex> { 66 llvm::ErrorOr<std::unique_ptr<include_fixer::YamlSymbolIndex>> SymbolIdx( 67 nullptr); 68 if (DB == "yaml") { 69 if (!Input.empty()) { 70 SymbolIdx = include_fixer::YamlSymbolIndex::createFromFile(Input); 71 } else { 72 // If we don't have any input file, look in the directory of the first 73 // file and its parents. 74 SmallString<128> AbsolutePath(tooling::getAbsolutePath(InputFile)); 75 StringRef Directory = llvm::sys::path::parent_path(AbsolutePath); 76 SymbolIdx = include_fixer::YamlSymbolIndex::createFromDirectory( 77 Directory, "find_all_symbols_db.yaml"); 78 } 79 } 80 return std::move(*SymbolIdx); 81 }; 82 83 SymbolIndexMgr->addSymbolIndex(std::move(CreateYamlIdx)); 84 return true; 85 } 86 87 private: 88 std::shared_ptr<SymbolIndexManager> SymbolIndexMgr; 89 IntrusiveRefCntPtr<IncludeFixerSemaSource> SemaSource; 90 }; 91 } // namespace include_fixer 92 } // namespace clang 93 94 // This anchor is used to force the linker to link in the generated object file 95 // and thus register the include fixer plugin. 96 volatile int ClangIncludeFixerPluginAnchorSource = 0; 97 98 static clang::FrontendPluginRegistry::Add< 99 clang::include_fixer::ClangIncludeFixerPluginAction> 100 X("clang-include-fixer", "clang-include-fixer"); 101