blob: 3416905098b42aaf38b4364f8db6aae798e7517d [file] [log] [blame]
Benjamin Kramer6b236262016-04-20 12:43:43 +00001//===-- ClangIncludeFixer.cpp - Standalone include fixer ------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Benjamin Kramera3d82332016-05-13 09:27:54 +000010#include "InMemorySymbolIndex.h"
Benjamin Kramer6b236262016-04-20 12:43:43 +000011#include "IncludeFixer.h"
Benjamin Kramera3d82332016-05-13 09:27:54 +000012#include "SymbolIndexManager.h"
13#include "YamlSymbolIndex.h"
Benjamin Kramer6b236262016-04-20 12:43:43 +000014#include "clang/Frontend/TextDiagnosticPrinter.h"
15#include "clang/Rewrite/Core/Rewriter.h"
16#include "clang/Tooling/CommonOptionsParser.h"
17#include "clang/Tooling/Tooling.h"
18#include "llvm/Support/CommandLine.h"
Haojian Wud8c12ba2016-04-29 09:23:38 +000019
Benjamin Kramer6b236262016-04-20 12:43:43 +000020using namespace clang;
Benjamin Kramerf412e902016-04-27 14:24:32 +000021using namespace llvm;
Benjamin Kramer6b236262016-04-20 12:43:43 +000022
Benjamin Kramerf412e902016-04-27 14:24:32 +000023namespace {
24cl::OptionCategory IncludeFixerCategory("Tool options");
25
26enum DatabaseFormatTy {
Simon Pilgrimb9f25582016-04-27 20:43:32 +000027 fixed, ///< Hard-coded mapping.
Haojian Wud8c12ba2016-04-29 09:23:38 +000028 yaml, ///< Yaml database created by find-all-symbols.
Benjamin Kramerf412e902016-04-27 14:24:32 +000029};
30
31cl::opt<DatabaseFormatTy> DatabaseFormat(
32 "db", cl::desc("Specify input format"),
Haojian Wud8c12ba2016-04-29 09:23:38 +000033 cl::values(clEnumVal(fixed, "Hard-coded mapping"),
34 clEnumVal(yaml, "Yaml database created by find-all-symbols"),
35 clEnumValEnd),
Benjamin Kramer8fd85a52016-05-10 11:35:47 +000036 cl::init(yaml), cl::cat(IncludeFixerCategory));
Benjamin Kramerf412e902016-04-27 14:24:32 +000037
38cl::opt<std::string> Input("input",
39 cl::desc("String to initialize the database"),
40 cl::cat(IncludeFixerCategory));
Benjamin Kramer3a45fab2016-04-28 11:21:29 +000041
42cl::opt<bool>
43 MinimizeIncludePaths("minimize-paths",
44 cl::desc("Whether to minimize added include paths"),
45 cl::init(true), cl::cat(IncludeFixerCategory));
Benjamin Kramer6b236262016-04-20 12:43:43 +000046
Benjamin Kramer54718292016-05-10 08:36:56 +000047cl::opt<bool> Quiet("q", cl::desc("Reduce terminal output"), cl::init(false),
48 cl::cat(IncludeFixerCategory));
49
Haojian Wua315dcb2016-05-03 08:38:35 +000050int includeFixerMain(int argc, const char **argv) {
Benjamin Kramerf412e902016-04-27 14:24:32 +000051 tooling::CommonOptionsParser options(argc, argv, IncludeFixerCategory);
52 tooling::ClangTool tool(options.getCompilations(),
53 options.getSourcePathList());
54
Eric Liu692aca62016-05-04 08:22:35 +000055 // Set up data source.
Benjamin Kramera3d82332016-05-13 09:27:54 +000056 auto SymbolIndexMgr = llvm::make_unique<include_fixer::SymbolIndexManager>();
Benjamin Kramerf412e902016-04-27 14:24:32 +000057 switch (DatabaseFormat) {
58 case fixed: {
59 // Parse input and fill the database with it.
60 // <symbol>=<header><, header...>
61 // Multiple symbols can be given, separated by semicolons.
Benjamin Kramera3d82332016-05-13 09:27:54 +000062 std::map<std::string, std::vector<std::string>> SymbolsMap;
Benjamin Kramerf412e902016-04-27 14:24:32 +000063 SmallVector<StringRef, 4> SemicolonSplits;
64 StringRef(Input).split(SemicolonSplits, ";");
Haojian Wu631e5f22016-05-13 15:17:17 +000065 std::vector<find_all_symbols::SymbolInfo> Symbols;
Benjamin Kramerf412e902016-04-27 14:24:32 +000066 for (StringRef Pair : SemicolonSplits) {
67 auto Split = Pair.split('=');
68 std::vector<std::string> Headers;
69 SmallVector<StringRef, 4> CommaSplits;
70 Split.second.split(CommaSplits, ",");
71 for (StringRef Header : CommaSplits)
Haojian Wu631e5f22016-05-13 15:17:17 +000072 Symbols.push_back(find_all_symbols::SymbolInfo(
73 Split.first.trim(),
74 find_all_symbols::SymbolInfo::SymbolKind::Unknown, Header.trim(), 1,
75 {}));
Benjamin Kramerf412e902016-04-27 14:24:32 +000076 }
Benjamin Kramera3d82332016-05-13 09:27:54 +000077 SymbolIndexMgr->addSymbolIndex(
Haojian Wu631e5f22016-05-13 15:17:17 +000078 llvm::make_unique<include_fixer::InMemorySymbolIndex>(Symbols));
Benjamin Kramerf412e902016-04-27 14:24:32 +000079 break;
80 }
Haojian Wud8c12ba2016-04-29 09:23:38 +000081 case yaml: {
Benjamin Kramera3d82332016-05-13 09:27:54 +000082 llvm::ErrorOr<std::unique_ptr<include_fixer::YamlSymbolIndex>> DB(nullptr);
Benjamin Kramerb6aed5f42016-05-09 14:14:55 +000083 if (!Input.empty()) {
Benjamin Kramera3d82332016-05-13 09:27:54 +000084 DB = include_fixer::YamlSymbolIndex::createFromFile(Input);
Benjamin Kramerb6aed5f42016-05-09 14:14:55 +000085 } else {
86 // If we don't have any input file, look in the directory of the first
87 // file and its parents.
88 SmallString<128> AbsolutePath(
89 tooling::getAbsolutePath(options.getSourcePathList().front()));
90 StringRef Directory = llvm::sys::path::parent_path(AbsolutePath);
Benjamin Kramera3d82332016-05-13 09:27:54 +000091 DB = include_fixer::YamlSymbolIndex::createFromDirectory(
Benjamin Kramerb6aed5f42016-05-09 14:14:55 +000092 Directory, "find_all_symbols_db.yaml");
93 }
94
95 if (!DB) {
96 llvm::errs() << "Couldn't find YAML db: " << DB.getError().message()
97 << '\n';
98 return 1;
99 }
100
Benjamin Kramera3d82332016-05-13 09:27:54 +0000101 SymbolIndexMgr->addSymbolIndex(std::move(*DB));
Haojian Wud8c12ba2016-04-29 09:23:38 +0000102 break;
103 }
Benjamin Kramerf412e902016-04-27 14:24:32 +0000104 }
Benjamin Kramer6b236262016-04-20 12:43:43 +0000105
106 // Now run our tool.
Benjamin Kramerf412e902016-04-27 14:24:32 +0000107 std::vector<tooling::Replacement> Replacements;
Benjamin Kramera3d82332016-05-13 09:27:54 +0000108 include_fixer::IncludeFixerActionFactory Factory(
109 *SymbolIndexMgr, Replacements, MinimizeIncludePaths);
Benjamin Kramer6b236262016-04-20 12:43:43 +0000110
Benjamin Kramer6b5160a2016-05-18 13:32:38 +0000111 if (tool.run(&Factory) != 0) {
112 llvm::errs()
113 << "Clang died with a fatal error! (incorrect include paths?)\n";
114 return 1;
115 }
Benjamin Kramer6b236262016-04-20 12:43:43 +0000116
Benjamin Kramer54718292016-05-10 08:36:56 +0000117 if (!Quiet)
118 for (const tooling::Replacement &Replacement : Replacements)
119 llvm::errs() << "Added " << Replacement.getReplacementText();
120
Benjamin Kramer6b236262016-04-20 12:43:43 +0000121 // Set up a new source manager for applying the resulting replacements.
Benjamin Kramerf412e902016-04-27 14:24:32 +0000122 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions);
123 DiagnosticsEngine Diagnostics(new DiagnosticIDs, &*DiagOpts);
124 TextDiagnosticPrinter DiagnosticPrinter(outs(), &*DiagOpts);
125 SourceManager SM(Diagnostics, tool.getFiles());
Benjamin Kramer6b236262016-04-20 12:43:43 +0000126 Diagnostics.setClient(&DiagnosticPrinter, false);
127
128 // Write replacements to disk.
Benjamin Kramerf412e902016-04-27 14:24:32 +0000129 Rewriter Rewrites(SM, LangOptions());
130 tooling::applyAllReplacements(Replacements, Rewrites);
Benjamin Kramer6b236262016-04-20 12:43:43 +0000131 return Rewrites.overwriteChangedFiles();
132}
Haojian Wua315dcb2016-05-03 08:38:35 +0000133
134} // namespace
135
136int main(int argc, const char **argv) {
137 return includeFixerMain(argc, argv);
138}