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
17namespace clang {
18namespace 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.
22class 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 {
27 ASTConsumerManagerWrapper(std::shared_ptr<SymbolIndexManager> SIM)
28 : SymbolIndexMgr(std::move(SIM)) {}
29 std::shared_ptr<SymbolIndexManager> SymbolIndexMgr;
30 };
31
32public:
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>
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>(args&: SymbolIndexMgr);
45 }
46
47 void ExecuteAction() override {} // Do nothing.
48
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.starts_with(Prefix: "-db="))
58 DB = Arg.substr(Start: strlen(s: "-db="));
59 else if (Arg.starts_with(Prefix: "-input="))
60 Input = Arg.substr(Start: strlen(s: "-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(FilePath: 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(File: InputFile));
75 StringRef Directory = llvm::sys::path::parent_path(path: AbsolutePath);
76 SymbolIdx = include_fixer::YamlSymbolIndex::createFromDirectory(
77 Directory, Name: "find_all_symbols_db.yaml");
78 }
79 }
80 return std::move(*SymbolIdx);
81 };
82
83 SymbolIndexMgr->addSymbolIndex(F: std::move(CreateYamlIdx));
84 return true;
85 }
86
87private:
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.
96volatile int ClangIncludeFixerPluginAnchorSource = 0;
97
98static clang::FrontendPluginRegistry::Add<
99 clang::include_fixer::ClangIncludeFixerPluginAction>
100 X("clang-include-fixer", "clang-include-fixer");
101

source code of clang-tools-extra/clang-include-fixer/plugin/IncludeFixerPlugin.cpp