• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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