101 lines · cpp
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-exception6//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 consumer21/// 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 an24 /// ASTConsumer for this plugin (everything is funneled on the side through25 /// 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>(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("-db="))58 DB = Arg.substr(strlen("-db="));59 else if (Arg.starts_with("-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 first73 // 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 87private:88 std::shared_ptr<SymbolIndexManager> SymbolIndexMgr;89 IntrusiveRefCntPtr<IncludeFixerSemaSource> SemaSource;90};91} // namespace include_fixer92} // namespace clang93 94// This anchor is used to force the linker to link in the generated object file95// 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