blob: 0712f69e9fdcd52b1e2ea587f8ec95cd47299d77 [file] [log] [blame]
Daniel Jasperd07c8402013-07-29 08:19:241//===--- tools/extra/clang-tidy/ClangTidy.cpp - Clang tidy tool -----------===//
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///
10/// \file This file implements a clang-tidy tool.
11///
12/// This tool uses the Clang Tooling infrastructure, see
13/// http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
14/// for details on setting it up with LLVM source tree.
15///
16//===----------------------------------------------------------------------===//
17
18#include "ClangTidy.h"
19#include "ClangTidyDiagnosticConsumer.h"
20#include "ClangTidyModuleRegistry.h"
21#include "clang/AST/ASTConsumer.h"
22#include "clang/AST/ASTContext.h"
23#include "clang/AST/Decl.h"
24#include "clang/ASTMatchers/ASTMatchFinder.h"
Daniel Jasperd07c8402013-07-29 08:19:2425#include "clang/Frontend/ASTConsumers.h"
26#include "clang/Frontend/CompilerInstance.h"
27#include "clang/Frontend/FrontendActions.h"
Alexander Kornienko38d81b42014-03-27 10:24:1128#include "clang/Frontend/FrontendDiagnostic.h"
Alexander Kornienko175fefb2014-01-03 09:31:5729#include "clang/Frontend/MultiplexConsumer.h"
Daniel Jasperd07c8402013-07-29 08:19:2430#include "clang/Frontend/TextDiagnosticPrinter.h"
Chandler Carruth85e6e872014-01-07 20:05:0131#include "clang/Lex/PPCallbacks.h"
32#include "clang/Lex/Preprocessor.h"
Daniel Jasperd07c8402013-07-29 08:19:2433#include "clang/Rewrite/Frontend/FixItRewriter.h"
34#include "clang/Rewrite/Frontend/FrontendActions.h"
Alexander Kornienkod1199cb2014-01-03 17:24:2035#include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
Daniel Jasperd07c8402013-07-29 08:19:2436#include "clang/Tooling/Refactoring.h"
Benjamin Kramerfb98b742014-09-04 10:31:2337#include "clang/Tooling/ReplacementsYaml.h"
Chandler Carruth85e6e872014-01-07 20:05:0138#include "clang/Tooling/Tooling.h"
Daniel Jasperd07c8402013-07-29 08:19:2439#include "llvm/Support/Path.h"
Alexander Kornienko54461eb2014-02-06 14:50:1040#include "llvm/Support/Process.h"
Daniel Jasperd07c8402013-07-29 08:19:2441#include "llvm/Support/Signals.h"
Alexander Kornienkofb9e92b2013-12-19 19:57:0542#include <algorithm>
Alexander Kornienko38d81b42014-03-27 10:24:1143#include <utility>
Daniel Jasperd07c8402013-07-29 08:19:2444
45using namespace clang::ast_matchers;
46using namespace clang::driver;
47using namespace clang::tooling;
48using namespace llvm;
49
NAKAMURA Takumi71b982b2014-07-03 14:12:4750template class llvm::Registry<clang::tidy::ClangTidyModule>;
51
Daniel Jasperd07c8402013-07-29 08:19:2452namespace clang {
53namespace tidy {
Alexander Kornienko175fefb2014-01-03 09:31:5754
Daniel Jasperd07c8402013-07-29 08:19:2455namespace {
Alexander Kornienko54461eb2014-02-06 14:50:1056static const char *AnalyzerCheckNamePrefix = "clang-analyzer-";
Manuel Klimek814f9bd2013-11-14 15:49:4457
Alexander Kornienko54461eb2014-02-06 14:50:1058static StringRef StaticAnalyzerChecks[] = {
Alexander Kornienkofb9e92b2013-12-19 19:57:0559#define GET_CHECKERS
60#define CHECKER(FULLNAME, CLASS, DESCFILE, HELPTEXT, GROUPINDEX, HIDDEN) \
61 FULLNAME,
NAKAMURA Takumi321b7d32014-01-03 10:24:5162#include "../../../lib/StaticAnalyzer/Checkers/Checkers.inc"
Alexander Kornienkofb9e92b2013-12-19 19:57:0563#undef CHECKER
64#undef GET_CHECKERS
65};
66
Alexander Kornienko54461eb2014-02-06 14:50:1067class AnalyzerDiagnosticConsumer : public ento::PathDiagnosticConsumer {
68public:
69 AnalyzerDiagnosticConsumer(ClangTidyContext &Context) : Context(Context) {}
70
Alexander Kornienkocb9272f2014-02-27 13:14:5171 void FlushDiagnosticsImpl(std::vector<const ento::PathDiagnostic *> &Diags,
Craig Toppera3dbe842014-03-02 10:20:1172 FilesMade *filesMade) override {
Alexander Kornienkodf1e3cb2014-03-06 10:17:4673 for (const ento::PathDiagnostic *PD : Diags) {
Alexander Kornienkod1afc702014-02-12 09:52:0774 SmallString<64> CheckName(AnalyzerCheckNamePrefix);
75 CheckName += PD->getCheckName();
Alexander Kornienko95cd50f2014-03-06 13:24:2876 Context.diag(CheckName, PD->getLocation().asLocation(),
77 PD->getShortDescription())
78 << PD->path.back()->getRanges();
Alexander Kornienko54461eb2014-02-06 14:50:1079
Alexander Kornienkodf1e3cb2014-03-06 10:17:4680 for (const auto &DiagPiece :
81 PD->path.flatten(/*ShouldFlattenMacros=*/true)) {
Alexander Kornienko95cd50f2014-03-06 13:24:2882 Context.diag(CheckName, DiagPiece->getLocation().asLocation(),
83 DiagPiece->getString(), DiagnosticIDs::Note)
84 << DiagPiece->getRanges();
Alexander Kornienko54461eb2014-02-06 14:50:1085 }
86 }
87 }
88
Craig Toppera3dbe842014-03-02 10:20:1189 StringRef getName() const override { return "ClangTidyDiags"; }
90 bool supportsLogicalOpControlFlow() const override { return true; }
91 bool supportsCrossFileDiagnostics() const override { return true; }
Alexander Kornienko54461eb2014-02-06 14:50:1092
93private:
94 ClangTidyContext &Context;
Alexander Kornienko54461eb2014-02-06 14:50:1095};
96
Alexander Kornienko38d81b42014-03-27 10:24:1197class ErrorReporter {
98public:
99 ErrorReporter(bool ApplyFixes)
100 : Files(FileSystemOptions()), DiagOpts(new DiagnosticOptions()),
101 DiagPrinter(new TextDiagnosticPrinter(llvm::outs(), &*DiagOpts)),
102 Diags(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), &*DiagOpts,
103 DiagPrinter),
104 SourceMgr(Diags, Files), Rewrite(SourceMgr, LangOpts),
NAKAMURA Takumi4dd18132014-03-27 14:53:37105 ApplyFixes(ApplyFixes), TotalFixes(0), AppliedFixes(0) {
Alexander Kornienko38d81b42014-03-27 10:24:11106 DiagOpts->ShowColors = llvm::sys::Process::StandardOutHasColors();
107 DiagPrinter->BeginSourceFile(LangOpts);
108 }
109
Alexander Kornienko742790c2014-07-02 15:05:04110 void reportDiagnostic(const ClangTidyError &Error) {
111 const ClangTidyMessage &Message = Error.Message;
Alexander Kornienko38d81b42014-03-27 10:24:11112 SourceLocation Loc = getLocation(Message.FilePath, Message.FileOffset);
113 // Contains a pair for each attempted fix: location and whether the fix was
114 // applied successfully.
115 SmallVector<std::pair<SourceLocation, bool>, 4> FixLocations;
116 {
Alexander Kornienko742790c2014-07-02 15:05:04117 auto Level = static_cast<DiagnosticsEngine::Level>(Error.DiagLevel);
Alexander Kornienko38d81b42014-03-27 10:24:11118 DiagnosticBuilder Diag =
Alexander Kornienko742790c2014-07-02 15:05:04119 Diags.Report(Loc, Diags.getCustomDiagID(Level, "%0 [%1]"))
120 << Message.Message << Error.CheckName;
121 for (const tooling::Replacement &Fix : Error.Fix) {
122 SourceLocation FixLoc = getLocation(Fix.getFilePath(), Fix.getOffset());
123 SourceLocation FixEndLoc = FixLoc.getLocWithOffset(Fix.getLength());
124 Diag << FixItHint::CreateReplacement(SourceRange(FixLoc, FixEndLoc),
125 Fix.getReplacementText());
126 ++TotalFixes;
127 if (ApplyFixes) {
128 bool Success = Fix.isApplicable() && Fix.apply(Rewrite);
129 if (Success)
130 ++AppliedFixes;
131 FixLocations.push_back(std::make_pair(FixLoc, Success));
Alexander Kornienko38d81b42014-03-27 10:24:11132 }
133 }
134 }
135 for (auto Fix : FixLocations) {
136 Diags.Report(Fix.first, Fix.second ? diag::note_fixit_applied
137 : diag::note_fixit_failed);
138 }
Alexander Kornienko742790c2014-07-02 15:05:04139 for (const ClangTidyMessage &Note : Error.Notes)
140 reportNote(Note);
Alexander Kornienko38d81b42014-03-27 10:24:11141 }
142
143 void Finish() {
144 // FIXME: Run clang-format on changes.
145 if (ApplyFixes && TotalFixes > 0) {
146 llvm::errs() << "clang-tidy applied " << AppliedFixes << " of "
147 << TotalFixes << " suggested fixes.\n";
148 Rewrite.overwriteChangedFiles();
149 }
150 }
151
152private:
153 SourceLocation getLocation(StringRef FilePath, unsigned Offset) {
154 if (FilePath.empty())
155 return SourceLocation();
156
157 const FileEntry *File = SourceMgr.getFileManager().getFile(FilePath);
158 FileID ID = SourceMgr.createFileID(File, SourceLocation(), SrcMgr::C_User);
159 return SourceMgr.getLocForStartOfFile(ID).getLocWithOffset(Offset);
160 }
161
Alexander Kornienko742790c2014-07-02 15:05:04162 void reportNote(const ClangTidyMessage &Message) {
163 SourceLocation Loc = getLocation(Message.FilePath, Message.FileOffset);
164 DiagnosticBuilder Diag =
165 Diags.Report(Loc, Diags.getCustomDiagID(DiagnosticsEngine::Note, "%0"))
166 << Message.Message;
167 }
168
Alexander Kornienko38d81b42014-03-27 10:24:11169 FileManager Files;
170 LangOptions LangOpts; // FIXME: use langopts from each original file
171 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
172 DiagnosticConsumer *DiagPrinter;
173 DiagnosticsEngine Diags;
174 SourceManager SourceMgr;
175 Rewriter Rewrite;
176 bool ApplyFixes;
NAKAMURA Takumi4dd18132014-03-27 14:53:37177 unsigned TotalFixes;
178 unsigned AppliedFixes;
Alexander Kornienko38d81b42014-03-27 10:24:11179};
180
Alexander Kornienkoa4695222014-06-05 13:31:45181class ClangTidyASTConsumer : public MultiplexConsumer {
182public:
David Blaikie680c4c82014-08-10 19:56:59183 ClangTidyASTConsumer(std::vector<std::unique_ptr<ASTConsumer>> Consumers,
Alexander Kornienkoa4695222014-06-05 13:31:45184 std::unique_ptr<ast_matchers::MatchFinder> Finder,
185 std::vector<std::unique_ptr<ClangTidyCheck>> Checks)
David Blaikie680c4c82014-08-10 19:56:59186 : MultiplexConsumer(std::move(Consumers)), Finder(std::move(Finder)),
Alexander Kornienkoa4695222014-06-05 13:31:45187 Checks(std::move(Checks)) {}
188
189private:
190 std::unique_ptr<ast_matchers::MatchFinder> Finder;
191 std::vector<std::unique_ptr<ClangTidyCheck>> Checks;
192};
193
Alexander Kornienko175fefb2014-01-03 09:31:57194} // namespace
Alexander Kornienkofb9e92b2013-12-19 19:57:05195
Alexander Kornienko175fefb2014-01-03 09:31:57196ClangTidyASTConsumerFactory::ClangTidyASTConsumerFactory(
Alexander Kornienkoa4695222014-06-05 13:31:45197 ClangTidyContext &Context)
198 : Context(Context), CheckFactories(new ClangTidyCheckFactories) {
Alexander Kornienko175fefb2014-01-03 09:31:57199 for (ClangTidyModuleRegistry::iterator I = ClangTidyModuleRegistry::begin(),
200 E = ClangTidyModuleRegistry::end();
201 I != E; ++I) {
Ahmed Charles6a2dc5c2014-03-09 09:24:40202 std::unique_ptr<ClangTidyModule> Module(I->instantiate());
Alexander Kornienko175fefb2014-01-03 09:31:57203 Module->addCheckFactories(*CheckFactories);
204 }
Alexander Kornienko175fefb2014-01-03 09:31:57205}
Alexander Kornienkofb9e92b2013-12-19 19:57:05206
David Blaikie680c4c82014-08-10 19:56:59207std::unique_ptr<clang::ASTConsumer>
208ClangTidyASTConsumerFactory::CreateASTConsumer(
Alexander Kornienko175fefb2014-01-03 09:31:57209 clang::CompilerInstance &Compiler, StringRef File) {
210 // FIXME: Move this to a separate method, so that CreateASTConsumer doesn't
211 // modify Compiler.
212 Context.setSourceManager(&Compiler.getSourceManager());
Alexander Kornienkoa4695222014-06-05 13:31:45213 Context.setCurrentFile(File);
Alexander Kornienkoad216882014-07-14 14:10:03214 Context.setASTContext(&Compiler.getASTContext());
Alexander Kornienkoa4695222014-06-05 13:31:45215
216 std::vector<std::unique_ptr<ClangTidyCheck>> Checks;
Alexander Kornienko6e0cbc82014-09-12 08:53:36217 CheckFactories->createChecks(&Context, Checks);
Alexander Kornienkoa4695222014-06-05 13:31:45218
219 std::unique_ptr<ast_matchers::MatchFinder> Finder(
220 new ast_matchers::MatchFinder);
221 for (auto &Check : Checks) {
Alexander Kornienkoa4695222014-06-05 13:31:45222 Check->registerMatchers(&*Finder);
Alexander Kornienkodf1e3cb2014-03-06 10:17:46223 Check->registerPPCallbacks(Compiler);
Alexander Kornienkoa4695222014-06-05 13:31:45224 }
Alexander Kornienko175fefb2014-01-03 09:31:57225
David Blaikie680c4c82014-08-10 19:56:59226 std::vector<std::unique_ptr<ASTConsumer>> Consumers;
Alexander Kornienkoa4695222014-06-05 13:31:45227 if (!Checks.empty())
228 Consumers.push_back(Finder->newASTConsumer());
Alexander Kornienko298b3822014-02-13 16:10:47229
Alex McCarthyfec08c72014-04-30 14:09:24230 AnalyzerOptionsRef AnalyzerOptions = Compiler.getAnalyzerOpts();
231 // FIXME: Remove this option once clang's cfg-temporary-dtors option defaults
232 // to true.
233 AnalyzerOptions->Config["cfg-temporary-dtors"] =
Alexander Kornienkoa4695222014-06-05 13:31:45234 Context.getOptions().AnalyzeTemporaryDtors ? "true" : "false";
Alex McCarthyfec08c72014-04-30 14:09:24235
Alexander Kornienko6e0cbc82014-09-12 08:53:36236 GlobList &Filter = Context.getChecksFilter();
Alexander Kornienkoa4695222014-06-05 13:31:45237 AnalyzerOptions->CheckersControlList = getCheckersControlList(Filter);
Alex McCarthyfec08c72014-04-30 14:09:24238 if (!AnalyzerOptions->CheckersControlList.empty()) {
239 AnalyzerOptions->AnalysisStoreOpt = RegionStoreModel;
240 AnalyzerOptions->AnalysisDiagOpt = PD_NONE;
241 AnalyzerOptions->AnalyzeNestedBlocks = true;
242 AnalyzerOptions->eagerlyAssumeBinOpBifurcation = true;
David Blaikie680c4c82014-08-10 19:56:59243 std::unique_ptr<ento::AnalysisASTConsumer> AnalysisConsumer =
Ted Kremenek4d1692f2014-08-27 15:14:47244 ento::CreateAnalysisConsumer(Compiler);
Alexander Kornienko298b3822014-02-13 16:10:47245 AnalysisConsumer->AddDiagnosticConsumer(
246 new AnalyzerDiagnosticConsumer(Context));
David Blaikie680c4c82014-08-10 19:56:59247 Consumers.push_back(std::move(AnalysisConsumer));
Alexander Kornienko298b3822014-02-13 16:10:47248 }
David Blaikie680c4c82014-08-10 19:56:59249 return llvm::make_unique<ClangTidyASTConsumer>(
250 std::move(Consumers), std::move(Finder), std::move(Checks));
Alexander Kornienko175fefb2014-01-03 09:31:57251}
252
Alexander Kornienko6e0cbc82014-09-12 08:53:36253std::vector<std::string> ClangTidyASTConsumerFactory::getCheckNames() {
Alexander Kornienko175fefb2014-01-03 09:31:57254 std::vector<std::string> CheckNames;
Alexander Kornienko6e0cbc82014-09-12 08:53:36255 GlobList &Filter = Context.getChecksFilter();
Alexander Kornienkodf1e3cb2014-03-06 10:17:46256 for (const auto &CheckFactory : *CheckFactories) {
Alexander Kornienkob3d331d2014-08-06 11:49:10257 if (Filter.contains(CheckFactory.first))
Alexander Kornienkodf1e3cb2014-03-06 10:17:46258 CheckNames.push_back(CheckFactory.first);
Alexander Kornienko175fefb2014-01-03 09:31:57259 }
260
Alexander Kornienkoa4695222014-06-05 13:31:45261 for (const auto &AnalyzerCheck : getCheckersControlList(Filter))
Alexander Kornienkodf1e3cb2014-03-06 10:17:46262 CheckNames.push_back(AnalyzerCheckNamePrefix + AnalyzerCheck.first);
Alexander Kornienko175fefb2014-01-03 09:31:57263
264 std::sort(CheckNames.begin(), CheckNames.end());
265 return CheckNames;
266}
267
Alexander Kornienko6e0cbc82014-09-12 08:53:36268ClangTidyOptions::OptionMap ClangTidyASTConsumerFactory::getCheckOptions() {
269 ClangTidyOptions::OptionMap Options;
270 std::vector<std::unique_ptr<ClangTidyCheck>> Checks;
271 CheckFactories->createChecks(&Context, Checks);
272 for (const auto &Check : Checks)
273 Check->storeOptions(Options);
274 return Options;
275}
276
Alexander Kornienko175fefb2014-01-03 09:31:57277ClangTidyASTConsumerFactory::CheckersList
Alexander Kornienkob3d331d2014-08-06 11:49:10278ClangTidyASTConsumerFactory::getCheckersControlList(GlobList &Filter) {
Alexander Kornienko175fefb2014-01-03 09:31:57279 CheckersList List;
Alexander Kornienko175fefb2014-01-03 09:31:57280
281 bool AnalyzerChecksEnabled = false;
Alexander Kornienkodf1e3cb2014-03-06 10:17:46282 for (StringRef CheckName : StaticAnalyzerChecks) {
283 std::string Checker((AnalyzerCheckNamePrefix + CheckName).str());
Alexander Kornienkoa4695222014-06-05 13:31:45284 AnalyzerChecksEnabled =
285 AnalyzerChecksEnabled ||
Alexander Kornienkob3d331d2014-08-06 11:49:10286 (!CheckName.startswith("debug") && Filter.contains(Checker));
Alexander Kornienko175fefb2014-01-03 09:31:57287 }
288
289 if (AnalyzerChecksEnabled) {
290 // Run our regex against all possible static analyzer checkers. Note that
291 // debug checkers print values / run programs to visualize the CFG and are
292 // thus not applicable to clang-tidy in general.
293 //
Alexander Kornienkofb9e92b2013-12-19 19:57:05294 // Always add all core checkers if any other static analyzer checks are
Alexander Kornienko175fefb2014-01-03 09:31:57295 // enabled. This is currently necessary, as other path sensitive checks
296 // rely on the core checkers.
Alexander Kornienkodf1e3cb2014-03-06 10:17:46297 for (StringRef CheckName : StaticAnalyzerChecks) {
298 std::string Checker((AnalyzerCheckNamePrefix + CheckName).str());
Alexander Kornienkofb9e92b2013-12-19 19:57:05299
Alexander Kornienkodf1e3cb2014-03-06 10:17:46300 if (CheckName.startswith("core") ||
Alexander Kornienkob3d331d2014-08-06 11:49:10301 (!CheckName.startswith("debug") && Filter.contains(Checker)))
Alexander Kornienkodf1e3cb2014-03-06 10:17:46302 List.push_back(std::make_pair(CheckName, true));
Alexander Kornienkofb9e92b2013-12-19 19:57:05303 }
304 }
Alexander Kornienko175fefb2014-01-03 09:31:57305 return List;
306}
Daniel Jasperd07c8402013-07-29 08:19:24307
Peter Collingbourneb17a3b32014-03-02 23:34:48308DiagnosticBuilder ClangTidyCheck::diag(SourceLocation Loc, StringRef Message,
309 DiagnosticIDs::Level Level) {
310 return Context->diag(CheckName, Loc, Message, Level);
Alexander Kornienko41bfe8d2014-01-13 10:50:51311}
312
Daniel Jasperd07c8402013-07-29 08:19:24313void ClangTidyCheck::run(const ast_matchers::MatchFinder::MatchResult &Result) {
314 Context->setSourceManager(Result.SourceManager);
315 check(Result);
316}
317
Alexander Kornienko6e0cbc82014-09-12 08:53:36318OptionsView::OptionsView(StringRef CheckName,
319 const ClangTidyOptions::OptionMap &CheckOptions)
320 : NamePrefix(CheckName.str() + "."), CheckOptions(CheckOptions) {}
321
322std::string OptionsView::get(StringRef LocalName, std::string Default) const {
323 const auto &Iter = CheckOptions.find(NamePrefix + LocalName.str());
324 if (Iter != CheckOptions.end())
325 return Iter->second;
326 return Default;
327}
328
329void OptionsView::store(ClangTidyOptions::OptionMap &Options,
330 StringRef LocalName, StringRef Value) const {
331 Options[NamePrefix + LocalName.str()] = Value;
332}
333
334void OptionsView::store(ClangTidyOptions::OptionMap &Options,
335 StringRef LocalName, int64_t Value) const {
336 store(Options, LocalName, llvm::itostr(Value));
Alexander Kornienko41bfe8d2014-01-13 10:50:51337}
338
Alexander Kornienko33a9bcc2014-04-29 15:20:10339std::vector<std::string> getCheckNames(const ClangTidyOptions &Options) {
Alexander Kornienkoa4695222014-06-05 13:31:45340 clang::tidy::ClangTidyContext Context(
Alexander Kornienkod53d2682014-09-04 14:23:36341 llvm::make_unique<DefaultOptionsProvider>(ClangTidyGlobalOptions(),
342 Options));
Alexander Kornienkoa4695222014-06-05 13:31:45343 ClangTidyASTConsumerFactory Factory(Context);
Alexander Kornienko6e0cbc82014-09-12 08:53:36344 return Factory.getCheckNames();
345}
346
347ClangTidyOptions::OptionMap getCheckOptions(const ClangTidyOptions &Options) {
348 clang::tidy::ClangTidyContext Context(
349 llvm::make_unique<DefaultOptionsProvider>(ClangTidyGlobalOptions(),
350 Options));
351 ClangTidyASTConsumerFactory Factory(Context);
352 return Factory.getCheckOptions();
Alexander Kornienkofb9e92b2013-12-19 19:57:05353}
354
Alexander Kornienkod53d2682014-09-04 14:23:36355ClangTidyStats
356runClangTidy(std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider,
357 const tooling::CompilationDatabase &Compilations,
358 ArrayRef<std::string> InputFiles,
359 std::vector<ClangTidyError> *Errors) {
Alexander Kornienko1e1ad5c2014-05-28 15:21:14360 ClangTool Tool(Compilations, InputFiles);
Alexander Kornienkod53d2682014-09-04 14:23:36361 clang::tidy::ClangTidyContext Context(std::move(OptionsProvider));
Daniel Jasperd07c8402013-07-29 08:19:24362 ClangTidyDiagnosticConsumer DiagConsumer(Context);
Manuel Klimek814f9bd2013-11-14 15:49:44363
364 Tool.setDiagnosticConsumer(&DiagConsumer);
Alexander Kornienko175fefb2014-01-03 09:31:57365
366 class ActionFactory : public FrontendActionFactory {
367 public:
Benjamin Kramer6e914242014-07-24 10:23:33368 ActionFactory(ClangTidyContext &Context) : ConsumerFactory(Context) {}
369 FrontendAction *create() override { return new Action(&ConsumerFactory); }
Alexander Kornienko175fefb2014-01-03 09:31:57370
371 private:
372 class Action : public ASTFrontendAction {
373 public:
374 Action(ClangTidyASTConsumerFactory *Factory) : Factory(Factory) {}
David Blaikie680c4c82014-08-10 19:56:59375 std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
376 StringRef File) override {
Alexander Kornienko175fefb2014-01-03 09:31:57377 return Factory->CreateASTConsumer(Compiler, File);
378 }
379
380 private:
381 ClangTidyASTConsumerFactory *Factory;
382 };
383
Benjamin Kramer6e914242014-07-24 10:23:33384 ClangTidyASTConsumerFactory ConsumerFactory;
Alexander Kornienko175fefb2014-01-03 09:31:57385 };
386
Benjamin Kramer6e914242014-07-24 10:23:33387 ActionFactory Factory(Context);
388 Tool.run(&Factory);
Alexander Kornienko826b5ad2014-05-09 12:24:09389 *Errors = Context.getErrors();
Alexander Kornienko5d174542014-05-07 09:06:53390 return Context.getStats();
Manuel Klimek814f9bd2013-11-14 15:49:44391}
392
Alexander Kornienko826b5ad2014-05-09 12:24:09393void handleErrors(const std::vector<ClangTidyError> &Errors, bool Fix) {
Alexander Kornienko38d81b42014-03-27 10:24:11394 ErrorReporter Reporter(Fix);
Alexander Kornienko742790c2014-07-02 15:05:04395 for (const ClangTidyError &Error : Errors)
396 Reporter.reportDiagnostic(Error);
Alexander Kornienko38d81b42014-03-27 10:24:11397 Reporter.Finish();
Daniel Jasperd07c8402013-07-29 08:19:24398}
399
Benjamin Kramerfb98b742014-09-04 10:31:23400void exportReplacements(const std::vector<ClangTidyError> &Errors,
401 raw_ostream &OS) {
402 tooling::TranslationUnitReplacements TUR;
403 for (const ClangTidyError &Error : Errors)
404 TUR.Replacements.insert(TUR.Replacements.end(), Error.Fix.begin(),
405 Error.Fix.end());
406
407 yaml::Output YAML(OS);
408 YAML << TUR;
409}
410
Daniel Jasperd07c8402013-07-29 08:19:24411} // namespace tidy
412} // namespace clang