xref: /llvm-project/clang-tools-extra/clang-include-fixer/plugin/IncludeFixerPlugin.cpp (revision 732bccb8c1b4ea724919db6ff02b1188e20850e7)
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