blob: 0b9895bcf1776170ec01f925ebd9d0e9ccfa7394 [file] [log] [blame]
Daniel Jasperd07c8402013-07-29 08:19:24 +00001//===--- 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:24 +000025#include "clang/Frontend/ASTConsumers.h"
26#include "clang/Frontend/CompilerInstance.h"
27#include "clang/Frontend/FrontendActions.h"
Alexander Kornienko38d81b42014-03-27 10:24:11 +000028#include "clang/Frontend/FrontendDiagnostic.h"
Alexander Kornienko175fefb2014-01-03 09:31:57 +000029#include "clang/Frontend/MultiplexConsumer.h"
Daniel Jasperd07c8402013-07-29 08:19:24 +000030#include "clang/Frontend/TextDiagnosticPrinter.h"
Chandler Carruth85e6e872014-01-07 20:05:01 +000031#include "clang/Lex/PPCallbacks.h"
32#include "clang/Lex/Preprocessor.h"
Daniel Jasperd07c8402013-07-29 08:19:24 +000033#include "clang/Rewrite/Frontend/FixItRewriter.h"
34#include "clang/Rewrite/Frontend/FrontendActions.h"
Alexander Kornienkod1199cb2014-01-03 17:24:20 +000035#include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
Daniel Jasperd07c8402013-07-29 08:19:24 +000036#include "clang/Tooling/Refactoring.h"
Benjamin Kramerfb98b742014-09-04 10:31:23 +000037#include "clang/Tooling/ReplacementsYaml.h"
Chandler Carruth85e6e872014-01-07 20:05:01 +000038#include "clang/Tooling/Tooling.h"
Alexander Kornienko54461eb2014-02-06 14:50:10 +000039#include "llvm/Support/Process.h"
Daniel Jasperd07c8402013-07-29 08:19:24 +000040#include "llvm/Support/Signals.h"
Alexander Kornienkofb9e92b2013-12-19 19:57:05 +000041#include <algorithm>
Alexander Kornienko38d81b42014-03-27 10:24:11 +000042#include <utility>
Daniel Jasperd07c8402013-07-29 08:19:24 +000043
44using namespace clang::ast_matchers;
45using namespace clang::driver;
46using namespace clang::tooling;
47using namespace llvm;
48
NAKAMURA Takumi71b982b2014-07-03 14:12:47 +000049template class llvm::Registry<clang::tidy::ClangTidyModule>;
50
Daniel Jasperd07c8402013-07-29 08:19:24 +000051namespace clang {
52namespace tidy {
Alexander Kornienko175fefb2014-01-03 09:31:57 +000053
Daniel Jasperd07c8402013-07-29 08:19:24 +000054namespace {
Alexander Kornienko54461eb2014-02-06 14:50:10 +000055static const char *AnalyzerCheckNamePrefix = "clang-analyzer-";
Manuel Klimek814f9bd2013-11-14 15:49:44 +000056
Craig Topper45857d42015-10-18 05:14:41 +000057static const StringRef StaticAnalyzerChecks[] = {
Alexander Kornienkofb9e92b2013-12-19 19:57:05 +000058#define GET_CHECKERS
59#define CHECKER(FULLNAME, CLASS, DESCFILE, HELPTEXT, GROUPINDEX, HIDDEN) \
60 FULLNAME,
NAKAMURA Takumi321b7d32014-01-03 10:24:51 +000061#include "../../../lib/StaticAnalyzer/Checkers/Checkers.inc"
Alexander Kornienkofb9e92b2013-12-19 19:57:05 +000062#undef CHECKER
63#undef GET_CHECKERS
64};
65
Alexander Kornienko54461eb2014-02-06 14:50:10 +000066class AnalyzerDiagnosticConsumer : public ento::PathDiagnosticConsumer {
67public:
68 AnalyzerDiagnosticConsumer(ClangTidyContext &Context) : Context(Context) {}
69
Alexander Kornienkocb9272f2014-02-27 13:14:51 +000070 void FlushDiagnosticsImpl(std::vector<const ento::PathDiagnostic *> &Diags,
Craig Toppera3dbe842014-03-02 10:20:11 +000071 FilesMade *filesMade) override {
Alexander Kornienkodf1e3cb2014-03-06 10:17:46 +000072 for (const ento::PathDiagnostic *PD : Diags) {
Alexander Kornienkod1afc702014-02-12 09:52:07 +000073 SmallString<64> CheckName(AnalyzerCheckNamePrefix);
74 CheckName += PD->getCheckName();
Alexander Kornienko95cd50f2014-03-06 13:24:28 +000075 Context.diag(CheckName, PD->getLocation().asLocation(),
76 PD->getShortDescription())
77 << PD->path.back()->getRanges();
Alexander Kornienko54461eb2014-02-06 14:50:10 +000078
Alexander Kornienkodf1e3cb2014-03-06 10:17:46 +000079 for (const auto &DiagPiece :
80 PD->path.flatten(/*ShouldFlattenMacros=*/true)) {
Alexander Kornienko95cd50f2014-03-06 13:24:28 +000081 Context.diag(CheckName, DiagPiece->getLocation().asLocation(),
82 DiagPiece->getString(), DiagnosticIDs::Note)
83 << DiagPiece->getRanges();
Alexander Kornienko54461eb2014-02-06 14:50:10 +000084 }
85 }
86 }
87
Craig Toppera3dbe842014-03-02 10:20:11 +000088 StringRef getName() const override { return "ClangTidyDiags"; }
89 bool supportsLogicalOpControlFlow() const override { return true; }
90 bool supportsCrossFileDiagnostics() const override { return true; }
Alexander Kornienko54461eb2014-02-06 14:50:10 +000091
92private:
93 ClangTidyContext &Context;
Alexander Kornienko54461eb2014-02-06 14:50:10 +000094};
95
Alexander Kornienko38d81b42014-03-27 10:24:11 +000096class ErrorReporter {
97public:
98 ErrorReporter(bool ApplyFixes)
99 : Files(FileSystemOptions()), DiagOpts(new DiagnosticOptions()),
100 DiagPrinter(new TextDiagnosticPrinter(llvm::outs(), &*DiagOpts)),
101 Diags(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), &*DiagOpts,
102 DiagPrinter),
103 SourceMgr(Diags, Files), Rewrite(SourceMgr, LangOpts),
NAKAMURA Takumi4dd18132014-03-27 14:53:37 +0000104 ApplyFixes(ApplyFixes), TotalFixes(0), AppliedFixes(0) {
Alexander Kornienko38d81b42014-03-27 10:24:11 +0000105 DiagOpts->ShowColors = llvm::sys::Process::StandardOutHasColors();
106 DiagPrinter->BeginSourceFile(LangOpts);
107 }
108
Alexander Kornienko742790c2014-07-02 15:05:04 +0000109 void reportDiagnostic(const ClangTidyError &Error) {
110 const ClangTidyMessage &Message = Error.Message;
Alexander Kornienko38d81b42014-03-27 10:24:11 +0000111 SourceLocation Loc = getLocation(Message.FilePath, Message.FileOffset);
112 // Contains a pair for each attempted fix: location and whether the fix was
113 // applied successfully.
114 SmallVector<std::pair<SourceLocation, bool>, 4> FixLocations;
115 {
Alexander Kornienko742790c2014-07-02 15:05:04 +0000116 auto Level = static_cast<DiagnosticsEngine::Level>(Error.DiagLevel);
Alexander Kornienko58fe57a2015-11-16 13:06:15 +0000117 auto Diag = Diags.Report(Loc, Diags.getCustomDiagID(Level, "%0 [%1]"))
118 << Message.Message << Error.CheckName;
Alexander Kornienko742790c2014-07-02 15:05:04 +0000119 for (const tooling::Replacement &Fix : Error.Fix) {
120 SourceLocation FixLoc = getLocation(Fix.getFilePath(), Fix.getOffset());
121 SourceLocation FixEndLoc = FixLoc.getLocWithOffset(Fix.getLength());
122 Diag << FixItHint::CreateReplacement(SourceRange(FixLoc, FixEndLoc),
123 Fix.getReplacementText());
124 ++TotalFixes;
125 if (ApplyFixes) {
126 bool Success = Fix.isApplicable() && Fix.apply(Rewrite);
127 if (Success)
128 ++AppliedFixes;
129 FixLocations.push_back(std::make_pair(FixLoc, Success));
Alexander Kornienko38d81b42014-03-27 10:24:11 +0000130 }
131 }
132 }
133 for (auto Fix : FixLocations) {
134 Diags.Report(Fix.first, Fix.second ? diag::note_fixit_applied
135 : diag::note_fixit_failed);
136 }
Alexander Kornienko742790c2014-07-02 15:05:04 +0000137 for (const ClangTidyMessage &Note : Error.Notes)
138 reportNote(Note);
Alexander Kornienko38d81b42014-03-27 10:24:11 +0000139 }
140
141 void Finish() {
142 // FIXME: Run clang-format on changes.
143 if (ApplyFixes && TotalFixes > 0) {
144 llvm::errs() << "clang-tidy applied " << AppliedFixes << " of "
145 << TotalFixes << " suggested fixes.\n";
146 Rewrite.overwriteChangedFiles();
147 }
148 }
149
150private:
151 SourceLocation getLocation(StringRef FilePath, unsigned Offset) {
152 if (FilePath.empty())
153 return SourceLocation();
154
155 const FileEntry *File = SourceMgr.getFileManager().getFile(FilePath);
156 FileID ID = SourceMgr.createFileID(File, SourceLocation(), SrcMgr::C_User);
157 return SourceMgr.getLocForStartOfFile(ID).getLocWithOffset(Offset);
158 }
159
Alexander Kornienko742790c2014-07-02 15:05:04 +0000160 void reportNote(const ClangTidyMessage &Message) {
161 SourceLocation Loc = getLocation(Message.FilePath, Message.FileOffset);
162 DiagnosticBuilder Diag =
163 Diags.Report(Loc, Diags.getCustomDiagID(DiagnosticsEngine::Note, "%0"))
164 << Message.Message;
165 }
166
Alexander Kornienko38d81b42014-03-27 10:24:11 +0000167 FileManager Files;
168 LangOptions LangOpts; // FIXME: use langopts from each original file
169 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
170 DiagnosticConsumer *DiagPrinter;
171 DiagnosticsEngine Diags;
172 SourceManager SourceMgr;
173 Rewriter Rewrite;
174 bool ApplyFixes;
NAKAMURA Takumi4dd18132014-03-27 14:53:37 +0000175 unsigned TotalFixes;
176 unsigned AppliedFixes;
Alexander Kornienko38d81b42014-03-27 10:24:11 +0000177};
178
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000179class ClangTidyASTConsumer : public MultiplexConsumer {
180public:
David Blaikie680c4c82014-08-10 19:56:59 +0000181 ClangTidyASTConsumer(std::vector<std::unique_ptr<ASTConsumer>> Consumers,
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000182 std::unique_ptr<ast_matchers::MatchFinder> Finder,
183 std::vector<std::unique_ptr<ClangTidyCheck>> Checks)
David Blaikie680c4c82014-08-10 19:56:59 +0000184 : MultiplexConsumer(std::move(Consumers)), Finder(std::move(Finder)),
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000185 Checks(std::move(Checks)) {}
186
187private:
188 std::unique_ptr<ast_matchers::MatchFinder> Finder;
189 std::vector<std::unique_ptr<ClangTidyCheck>> Checks;
190};
191
Alexander Kornienko175fefb2014-01-03 09:31:57 +0000192} // namespace
Alexander Kornienkofb9e92b2013-12-19 19:57:05 +0000193
Alexander Kornienko175fefb2014-01-03 09:31:57 +0000194ClangTidyASTConsumerFactory::ClangTidyASTConsumerFactory(
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000195 ClangTidyContext &Context)
196 : Context(Context), CheckFactories(new ClangTidyCheckFactories) {
Alexander Kornienko175fefb2014-01-03 09:31:57 +0000197 for (ClangTidyModuleRegistry::iterator I = ClangTidyModuleRegistry::begin(),
198 E = ClangTidyModuleRegistry::end();
199 I != E; ++I) {
Ahmed Charles6a2dc5c2014-03-09 09:24:40 +0000200 std::unique_ptr<ClangTidyModule> Module(I->instantiate());
Alexander Kornienko175fefb2014-01-03 09:31:57 +0000201 Module->addCheckFactories(*CheckFactories);
202 }
Alexander Kornienko175fefb2014-01-03 09:31:57 +0000203}
Alexander Kornienkofb9e92b2013-12-19 19:57:05 +0000204
Gabor Horvath34383212015-03-11 17:25:22 +0000205static void setStaticAnalyzerCheckerOpts(const ClangTidyOptions &Opts,
206 AnalyzerOptionsRef AnalyzerOptions) {
207 StringRef AnalyzerPrefix(AnalyzerCheckNamePrefix);
208 for (const auto &Opt : Opts.CheckOptions) {
209 StringRef OptName(Opt.first);
210 if (!OptName.startswith(AnalyzerPrefix))
211 continue;
212 AnalyzerOptions->Config[OptName.substr(AnalyzerPrefix.size())] = Opt.second;
213 }
214}
215
David Blaikie680c4c82014-08-10 19:56:59 +0000216std::unique_ptr<clang::ASTConsumer>
217ClangTidyASTConsumerFactory::CreateASTConsumer(
Alexander Kornienko175fefb2014-01-03 09:31:57 +0000218 clang::CompilerInstance &Compiler, StringRef File) {
219 // FIXME: Move this to a separate method, so that CreateASTConsumer doesn't
220 // modify Compiler.
221 Context.setSourceManager(&Compiler.getSourceManager());
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000222 Context.setCurrentFile(File);
Alexander Kornienkoad216882014-07-14 14:10:03 +0000223 Context.setASTContext(&Compiler.getASTContext());
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000224
225 std::vector<std::unique_ptr<ClangTidyCheck>> Checks;
Alexander Kornienko6e0cbc82014-09-12 08:53:36 +0000226 CheckFactories->createChecks(&Context, Checks);
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000227
Samuel Benzaquenaedd9942014-10-23 17:23:20 +0000228 ast_matchers::MatchFinder::MatchFinderOptions FinderOptions;
229 if (auto *P = Context.getCheckProfileData())
230 FinderOptions.CheckProfiling.emplace(P->Records);
231
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000232 std::unique_ptr<ast_matchers::MatchFinder> Finder(
Samuel Benzaquenaedd9942014-10-23 17:23:20 +0000233 new ast_matchers::MatchFinder(std::move(FinderOptions)));
234
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000235 for (auto &Check : Checks) {
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000236 Check->registerMatchers(&*Finder);
Alexander Kornienkodf1e3cb2014-03-06 10:17:46 +0000237 Check->registerPPCallbacks(Compiler);
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000238 }
Alexander Kornienko175fefb2014-01-03 09:31:57 +0000239
David Blaikie680c4c82014-08-10 19:56:59 +0000240 std::vector<std::unique_ptr<ASTConsumer>> Consumers;
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000241 if (!Checks.empty())
242 Consumers.push_back(Finder->newASTConsumer());
Alexander Kornienko298b3822014-02-13 16:10:47 +0000243
Alex McCarthyfec08c72014-04-30 14:09:24 +0000244 AnalyzerOptionsRef AnalyzerOptions = Compiler.getAnalyzerOpts();
245 // FIXME: Remove this option once clang's cfg-temporary-dtors option defaults
246 // to true.
247 AnalyzerOptions->Config["cfg-temporary-dtors"] =
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000248 Context.getOptions().AnalyzeTemporaryDtors ? "true" : "false";
Alex McCarthyfec08c72014-04-30 14:09:24 +0000249
Alexander Kornienko6e0cbc82014-09-12 08:53:36 +0000250 GlobList &Filter = Context.getChecksFilter();
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000251 AnalyzerOptions->CheckersControlList = getCheckersControlList(Filter);
Alex McCarthyfec08c72014-04-30 14:09:24 +0000252 if (!AnalyzerOptions->CheckersControlList.empty()) {
Gabor Horvath34383212015-03-11 17:25:22 +0000253 setStaticAnalyzerCheckerOpts(Context.getOptions(), AnalyzerOptions);
Alex McCarthyfec08c72014-04-30 14:09:24 +0000254 AnalyzerOptions->AnalysisStoreOpt = RegionStoreModel;
255 AnalyzerOptions->AnalysisDiagOpt = PD_NONE;
256 AnalyzerOptions->AnalyzeNestedBlocks = true;
257 AnalyzerOptions->eagerlyAssumeBinOpBifurcation = true;
David Blaikie680c4c82014-08-10 19:56:59 +0000258 std::unique_ptr<ento::AnalysisASTConsumer> AnalysisConsumer =
Ted Kremenek4d1692f2014-08-27 15:14:47 +0000259 ento::CreateAnalysisConsumer(Compiler);
Alexander Kornienko298b3822014-02-13 16:10:47 +0000260 AnalysisConsumer->AddDiagnosticConsumer(
261 new AnalyzerDiagnosticConsumer(Context));
David Blaikie680c4c82014-08-10 19:56:59 +0000262 Consumers.push_back(std::move(AnalysisConsumer));
Alexander Kornienko298b3822014-02-13 16:10:47 +0000263 }
David Blaikie680c4c82014-08-10 19:56:59 +0000264 return llvm::make_unique<ClangTidyASTConsumer>(
265 std::move(Consumers), std::move(Finder), std::move(Checks));
Alexander Kornienko175fefb2014-01-03 09:31:57 +0000266}
267
Alexander Kornienko6e0cbc82014-09-12 08:53:36 +0000268std::vector<std::string> ClangTidyASTConsumerFactory::getCheckNames() {
Alexander Kornienko175fefb2014-01-03 09:31:57 +0000269 std::vector<std::string> CheckNames;
Alexander Kornienko6e0cbc82014-09-12 08:53:36 +0000270 GlobList &Filter = Context.getChecksFilter();
Alexander Kornienkodf1e3cb2014-03-06 10:17:46 +0000271 for (const auto &CheckFactory : *CheckFactories) {
Alexander Kornienkob3d331d2014-08-06 11:49:10 +0000272 if (Filter.contains(CheckFactory.first))
Alexander Kornienkodf1e3cb2014-03-06 10:17:46 +0000273 CheckNames.push_back(CheckFactory.first);
Alexander Kornienko175fefb2014-01-03 09:31:57 +0000274 }
275
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000276 for (const auto &AnalyzerCheck : getCheckersControlList(Filter))
Alexander Kornienkodf1e3cb2014-03-06 10:17:46 +0000277 CheckNames.push_back(AnalyzerCheckNamePrefix + AnalyzerCheck.first);
Alexander Kornienko175fefb2014-01-03 09:31:57 +0000278
279 std::sort(CheckNames.begin(), CheckNames.end());
280 return CheckNames;
281}
282
Alexander Kornienko6e0cbc82014-09-12 08:53:36 +0000283ClangTidyOptions::OptionMap ClangTidyASTConsumerFactory::getCheckOptions() {
284 ClangTidyOptions::OptionMap Options;
285 std::vector<std::unique_ptr<ClangTidyCheck>> Checks;
286 CheckFactories->createChecks(&Context, Checks);
287 for (const auto &Check : Checks)
288 Check->storeOptions(Options);
289 return Options;
290}
291
Alexander Kornienko175fefb2014-01-03 09:31:57 +0000292ClangTidyASTConsumerFactory::CheckersList
Alexander Kornienkob3d331d2014-08-06 11:49:10 +0000293ClangTidyASTConsumerFactory::getCheckersControlList(GlobList &Filter) {
Alexander Kornienko175fefb2014-01-03 09:31:57 +0000294 CheckersList List;
Alexander Kornienko175fefb2014-01-03 09:31:57 +0000295
296 bool AnalyzerChecksEnabled = false;
Alexander Kornienkodf1e3cb2014-03-06 10:17:46 +0000297 for (StringRef CheckName : StaticAnalyzerChecks) {
298 std::string Checker((AnalyzerCheckNamePrefix + CheckName).str());
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000299 AnalyzerChecksEnabled =
300 AnalyzerChecksEnabled ||
Alexander Kornienkob3d331d2014-08-06 11:49:10 +0000301 (!CheckName.startswith("debug") && Filter.contains(Checker));
Alexander Kornienko175fefb2014-01-03 09:31:57 +0000302 }
303
304 if (AnalyzerChecksEnabled) {
305 // Run our regex against all possible static analyzer checkers. Note that
306 // debug checkers print values / run programs to visualize the CFG and are
307 // thus not applicable to clang-tidy in general.
308 //
Alexander Kornienkofb9e92b2013-12-19 19:57:05 +0000309 // Always add all core checkers if any other static analyzer checks are
Alexander Kornienko175fefb2014-01-03 09:31:57 +0000310 // enabled. This is currently necessary, as other path sensitive checks
311 // rely on the core checkers.
Alexander Kornienkodf1e3cb2014-03-06 10:17:46 +0000312 for (StringRef CheckName : StaticAnalyzerChecks) {
313 std::string Checker((AnalyzerCheckNamePrefix + CheckName).str());
Alexander Kornienkofb9e92b2013-12-19 19:57:05 +0000314
Alexander Kornienkodf1e3cb2014-03-06 10:17:46 +0000315 if (CheckName.startswith("core") ||
Alexander Kornienkob3d331d2014-08-06 11:49:10 +0000316 (!CheckName.startswith("debug") && Filter.contains(Checker)))
Alexander Kornienkodf1e3cb2014-03-06 10:17:46 +0000317 List.push_back(std::make_pair(CheckName, true));
Alexander Kornienkofb9e92b2013-12-19 19:57:05 +0000318 }
319 }
Alexander Kornienko175fefb2014-01-03 09:31:57 +0000320 return List;
321}
Daniel Jasperd07c8402013-07-29 08:19:24 +0000322
Peter Collingbourneb17a3b32014-03-02 23:34:48 +0000323DiagnosticBuilder ClangTidyCheck::diag(SourceLocation Loc, StringRef Message,
324 DiagnosticIDs::Level Level) {
325 return Context->diag(CheckName, Loc, Message, Level);
Alexander Kornienko41bfe8d2014-01-13 10:50:51 +0000326}
327
Daniel Jasperd07c8402013-07-29 08:19:24 +0000328void ClangTidyCheck::run(const ast_matchers::MatchFinder::MatchResult &Result) {
329 Context->setSourceManager(Result.SourceManager);
330 check(Result);
331}
332
Alexander Kornienko6e0cbc82014-09-12 08:53:36 +0000333OptionsView::OptionsView(StringRef CheckName,
334 const ClangTidyOptions::OptionMap &CheckOptions)
335 : NamePrefix(CheckName.str() + "."), CheckOptions(CheckOptions) {}
336
337std::string OptionsView::get(StringRef LocalName, std::string Default) const {
338 const auto &Iter = CheckOptions.find(NamePrefix + LocalName.str());
339 if (Iter != CheckOptions.end())
340 return Iter->second;
341 return Default;
342}
343
344void OptionsView::store(ClangTidyOptions::OptionMap &Options,
345 StringRef LocalName, StringRef Value) const {
346 Options[NamePrefix + LocalName.str()] = Value;
347}
348
349void OptionsView::store(ClangTidyOptions::OptionMap &Options,
350 StringRef LocalName, int64_t Value) const {
351 store(Options, LocalName, llvm::itostr(Value));
Alexander Kornienko41bfe8d2014-01-13 10:50:51 +0000352}
353
Alexander Kornienko33a9bcc2014-04-29 15:20:10 +0000354std::vector<std::string> getCheckNames(const ClangTidyOptions &Options) {
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000355 clang::tidy::ClangTidyContext Context(
Alexander Kornienkod53d2682014-09-04 14:23:36 +0000356 llvm::make_unique<DefaultOptionsProvider>(ClangTidyGlobalOptions(),
357 Options));
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000358 ClangTidyASTConsumerFactory Factory(Context);
Alexander Kornienko6e0cbc82014-09-12 08:53:36 +0000359 return Factory.getCheckNames();
360}
361
362ClangTidyOptions::OptionMap getCheckOptions(const ClangTidyOptions &Options) {
363 clang::tidy::ClangTidyContext Context(
364 llvm::make_unique<DefaultOptionsProvider>(ClangTidyGlobalOptions(),
365 Options));
366 ClangTidyASTConsumerFactory Factory(Context);
367 return Factory.getCheckOptions();
Alexander Kornienkofb9e92b2013-12-19 19:57:05 +0000368}
369
Alexander Kornienkod53d2682014-09-04 14:23:36 +0000370ClangTidyStats
371runClangTidy(std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider,
372 const tooling::CompilationDatabase &Compilations,
373 ArrayRef<std::string> InputFiles,
Samuel Benzaquenaedd9942014-10-23 17:23:20 +0000374 std::vector<ClangTidyError> *Errors, ProfileData *Profile) {
Alexander Kornienko1e1ad5c2014-05-28 15:21:14 +0000375 ClangTool Tool(Compilations, InputFiles);
Alexander Kornienkod53d2682014-09-04 14:23:36 +0000376 clang::tidy::ClangTidyContext Context(std::move(OptionsProvider));
Alexander Kornienko64956b52015-11-09 16:28:11 +0000377 ArgumentsAdjuster PerFileExtraArgumentsInserter = [&Context](
378 const CommandLineArguments &Args, StringRef Filename) {
379 ClangTidyOptions Opts = Context.getOptionsForFile(Filename);
380 CommandLineArguments AdjustedArgs;
381 if (Opts.ExtraArgsBefore)
382 AdjustedArgs = *Opts.ExtraArgsBefore;
383 AdjustedArgs.insert(AdjustedArgs.begin(), Args.begin(), Args.end());
384 if (Opts.ExtraArgs)
385 AdjustedArgs.insert(AdjustedArgs.end(), Opts.ExtraArgs->begin(),
386 Opts.ExtraArgs->end());
387 return AdjustedArgs;
388 };
389 Tool.appendArgumentsAdjuster(PerFileExtraArgumentsInserter);
Samuel Benzaquenaedd9942014-10-23 17:23:20 +0000390 if (Profile)
391 Context.setCheckProfileData(Profile);
392
Daniel Jasperd07c8402013-07-29 08:19:24 +0000393 ClangTidyDiagnosticConsumer DiagConsumer(Context);
Manuel Klimek814f9bd2013-11-14 15:49:44 +0000394
395 Tool.setDiagnosticConsumer(&DiagConsumer);
Alexander Kornienko175fefb2014-01-03 09:31:57 +0000396
397 class ActionFactory : public FrontendActionFactory {
398 public:
Benjamin Kramer6e914242014-07-24 10:23:33 +0000399 ActionFactory(ClangTidyContext &Context) : ConsumerFactory(Context) {}
400 FrontendAction *create() override { return new Action(&ConsumerFactory); }
Alexander Kornienko175fefb2014-01-03 09:31:57 +0000401
402 private:
403 class Action : public ASTFrontendAction {
404 public:
405 Action(ClangTidyASTConsumerFactory *Factory) : Factory(Factory) {}
David Blaikie680c4c82014-08-10 19:56:59 +0000406 std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
407 StringRef File) override {
Alexander Kornienko175fefb2014-01-03 09:31:57 +0000408 return Factory->CreateASTConsumer(Compiler, File);
409 }
410
411 private:
412 ClangTidyASTConsumerFactory *Factory;
413 };
414
Benjamin Kramer6e914242014-07-24 10:23:33 +0000415 ClangTidyASTConsumerFactory ConsumerFactory;
Alexander Kornienko175fefb2014-01-03 09:31:57 +0000416 };
417
Benjamin Kramer6e914242014-07-24 10:23:33 +0000418 ActionFactory Factory(Context);
419 Tool.run(&Factory);
Alexander Kornienko826b5ad2014-05-09 12:24:09 +0000420 *Errors = Context.getErrors();
Alexander Kornienko5d174542014-05-07 09:06:53 +0000421 return Context.getStats();
Manuel Klimek814f9bd2013-11-14 15:49:44 +0000422}
423
Alexander Kornienko826b5ad2014-05-09 12:24:09 +0000424void handleErrors(const std::vector<ClangTidyError> &Errors, bool Fix) {
Alexander Kornienko38d81b42014-03-27 10:24:11 +0000425 ErrorReporter Reporter(Fix);
Alexander Kornienko742790c2014-07-02 15:05:04 +0000426 for (const ClangTidyError &Error : Errors)
427 Reporter.reportDiagnostic(Error);
Alexander Kornienko38d81b42014-03-27 10:24:11 +0000428 Reporter.Finish();
Daniel Jasperd07c8402013-07-29 08:19:24 +0000429}
430
Benjamin Kramerfb98b742014-09-04 10:31:23 +0000431void exportReplacements(const std::vector<ClangTidyError> &Errors,
432 raw_ostream &OS) {
433 tooling::TranslationUnitReplacements TUR;
434 for (const ClangTidyError &Error : Errors)
435 TUR.Replacements.insert(TUR.Replacements.end(), Error.Fix.begin(),
436 Error.Fix.end());
437
438 yaml::Output YAML(OS);
439 YAML << TUR;
440}
441
Daniel Jasperd07c8402013-07-29 08:19:24 +0000442} // namespace tidy
443} // namespace clang