143356f56SNico Weber //===- IncludeFixerPlugin.cpp - clang-include-fixer as a clang plugin -----===// 243356f56SNico Weber // 343356f56SNico Weber // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 443356f56SNico Weber // See https://llvm.org/LICENSE.txt for license information. 543356f56SNico Weber // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 643356f56SNico Weber // 743356f56SNico Weber //===----------------------------------------------------------------------===// 843356f56SNico Weber 943356f56SNico Weber #include "../IncludeFixer.h" 1043356f56SNico Weber #include "../YamlSymbolIndex.h" 1143356f56SNico Weber #include "clang/Frontend/CompilerInstance.h" 1243356f56SNico Weber #include "clang/Frontend/FrontendPluginRegistry.h" 1343356f56SNico Weber #include "clang/Parse/ParseAST.h" 1443356f56SNico Weber #include "clang/Sema/Sema.h" 1543356f56SNico Weber #include "llvm/Support/Path.h" 1643356f56SNico Weber 1743356f56SNico Weber namespace clang { 1843356f56SNico Weber namespace include_fixer { 1943356f56SNico Weber 2043356f56SNico Weber /// The core include fixer plugin action. This just provides the AST consumer 2143356f56SNico Weber /// and command line flag parsing for using include fixer as a clang plugin. 2243356f56SNico Weber class ClangIncludeFixerPluginAction : public PluginASTAction { 2343356f56SNico Weber /// ASTConsumer to keep the symbol index alive. We don't really need an 2443356f56SNico Weber /// ASTConsumer for this plugin (everything is funneled on the side through 2543356f56SNico Weber /// Sema) but we have to keep the symbol index alive until sema is done. 2643356f56SNico Weber struct ASTConsumerManagerWrapper : public ASTConsumer { ASTConsumerManagerWrapperclang::include_fixer::ClangIncludeFixerPluginAction::ASTConsumerManagerWrapper2743356f56SNico Weber ASTConsumerManagerWrapper(std::shared_ptr<SymbolIndexManager> SIM) 2843356f56SNico Weber : SymbolIndexMgr(std::move(SIM)) {} 2943356f56SNico Weber std::shared_ptr<SymbolIndexManager> SymbolIndexMgr; 3043356f56SNico Weber }; 3143356f56SNico Weber 3243356f56SNico Weber public: ClangIncludeFixerPluginAction()3343356f56SNico Weber explicit ClangIncludeFixerPluginAction() 3443356f56SNico Weber : SymbolIndexMgr(std::make_shared<SymbolIndexManager>()), 3543356f56SNico Weber SemaSource(new IncludeFixerSemaSource(*SymbolIndexMgr, 3643356f56SNico Weber /*MinimizeIncludePaths=*/true, 3743356f56SNico Weber /*GenerateDiagnostics=*/true)) {} 3843356f56SNico Weber 3943356f56SNico Weber std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(clang::CompilerInstance & CI,StringRef InFile)4043356f56SNico Weber CreateASTConsumer(clang::CompilerInstance &CI, StringRef InFile) override { 4143356f56SNico Weber CI.setExternalSemaSource(SemaSource); 4243356f56SNico Weber SemaSource->setFilePath(InFile); 4343356f56SNico Weber SemaSource->setCompilerInstance(&CI); 441c705d9cSJonas Devlieghere return std::make_unique<ASTConsumerManagerWrapper>(SymbolIndexMgr); 4543356f56SNico Weber } 4643356f56SNico Weber ExecuteAction()4743356f56SNico Weber void ExecuteAction() override {} // Do nothing. 4843356f56SNico Weber ParseArgs(const CompilerInstance & CI,const std::vector<std::string> & Args)4943356f56SNico Weber bool ParseArgs(const CompilerInstance &CI, 5043356f56SNico Weber const std::vector<std::string> &Args) override { 5143356f56SNico Weber StringRef DB = "yaml"; 5243356f56SNico Weber StringRef Input; 5343356f56SNico Weber 5443356f56SNico Weber // Parse the extra command line args. 5543356f56SNico Weber // FIXME: This is very limited at the moment. 5643356f56SNico Weber for (StringRef Arg : Args) { 57*732bccb8SKazu Hirata if (Arg.starts_with("-db=")) 5843356f56SNico Weber DB = Arg.substr(strlen("-db=")); 59*732bccb8SKazu Hirata else if (Arg.starts_with("-input=")) 6043356f56SNico Weber Input = Arg.substr(strlen("-input=")); 6143356f56SNico Weber } 6243356f56SNico Weber 63adcd0268SBenjamin Kramer std::string InputFile = 64adcd0268SBenjamin Kramer std::string(CI.getFrontendOpts().Inputs[0].getFile()); 6543356f56SNico Weber auto CreateYamlIdx = [=]() -> std::unique_ptr<include_fixer::SymbolIndex> { 6643356f56SNico Weber llvm::ErrorOr<std::unique_ptr<include_fixer::YamlSymbolIndex>> SymbolIdx( 6743356f56SNico Weber nullptr); 6843356f56SNico Weber if (DB == "yaml") { 6943356f56SNico Weber if (!Input.empty()) { 7043356f56SNico Weber SymbolIdx = include_fixer::YamlSymbolIndex::createFromFile(Input); 7143356f56SNico Weber } else { 7243356f56SNico Weber // If we don't have any input file, look in the directory of the first 7343356f56SNico Weber // file and its parents. 7443356f56SNico Weber SmallString<128> AbsolutePath(tooling::getAbsolutePath(InputFile)); 7543356f56SNico Weber StringRef Directory = llvm::sys::path::parent_path(AbsolutePath); 7643356f56SNico Weber SymbolIdx = include_fixer::YamlSymbolIndex::createFromDirectory( 7743356f56SNico Weber Directory, "find_all_symbols_db.yaml"); 7843356f56SNico Weber } 7943356f56SNico Weber } 8043356f56SNico Weber return std::move(*SymbolIdx); 8143356f56SNico Weber }; 8243356f56SNico Weber 8343356f56SNico Weber SymbolIndexMgr->addSymbolIndex(std::move(CreateYamlIdx)); 8443356f56SNico Weber return true; 8543356f56SNico Weber } 8643356f56SNico Weber 8743356f56SNico Weber private: 8843356f56SNico Weber std::shared_ptr<SymbolIndexManager> SymbolIndexMgr; 8943356f56SNico Weber IntrusiveRefCntPtr<IncludeFixerSemaSource> SemaSource; 9043356f56SNico Weber }; 9143356f56SNico Weber } // namespace include_fixer 9243356f56SNico Weber } // namespace clang 9343356f56SNico Weber 9443356f56SNico Weber // This anchor is used to force the linker to link in the generated object file 9543356f56SNico Weber // and thus register the include fixer plugin. 9643356f56SNico Weber volatile int ClangIncludeFixerPluginAnchorSource = 0; 9743356f56SNico Weber 9843356f56SNico Weber static clang::FrontendPluginRegistry::Add< 9943356f56SNico Weber clang::include_fixer::ClangIncludeFixerPluginAction> 10043356f56SNico Weber X("clang-include-fixer", "clang-include-fixer"); 101