blob: ac1859f06efeb70f2736a39b66ec344bcd1f9a89 [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"
Alexander Kornienko54461eb2014-02-06 14:50:1039#include "llvm/Support/Process.h"
Daniel Jasperd07c8402013-07-29 08:19:2440#include "llvm/Support/Signals.h"
Alexander Kornienkofb9e92b2013-12-19 19:57:0541#include <algorithm>
Alexander Kornienko38d81b42014-03-27 10:24:1142#include <utility>
Daniel Jasperd07c8402013-07-29 08:19:2443
44using namespace clang::ast_matchers;
45using namespace clang::driver;
46using namespace clang::tooling;
47using namespace llvm;
48
NAKAMURA Takumi71b982b2014-07-03 14:12:4749template class llvm::Registry<clang::tidy::ClangTidyModule>;
50
Daniel Jasperd07c8402013-07-29 08:19:2451namespace clang {
52namespace tidy {
Alexander Kornienko175fefb2014-01-03 09:31:5753
Daniel Jasperd07c8402013-07-29 08:19:2454namespace {
Alexander Kornienko54461eb2014-02-06 14:50:1055static const char *AnalyzerCheckNamePrefix = "clang-analyzer-";
Manuel Klimek814f9bd2013-11-14 15:49:4456
Craig Topper45857d42015-10-18 05:14:4157static const StringRef StaticAnalyzerChecks[] = {
Alexander Kornienkofb9e92b2013-12-19 19:57:0558#define GET_CHECKERS
59#define CHECKER(FULLNAME, CLASS, DESCFILE, HELPTEXT, GROUPINDEX, HIDDEN) \
60 FULLNAME,
NAKAMURA Takumi321b7d32014-01-03 10:24:5161#include "../../../lib/StaticAnalyzer/Checkers/Checkers.inc"
Alexander Kornienkofb9e92b2013-12-19 19:57:0562#undef CHECKER
63#undef GET_CHECKERS
64};
65
Alexander Kornienko54461eb2014-02-06 14:50:1066class AnalyzerDiagnosticConsumer : public ento::PathDiagnosticConsumer {
67public:
68 AnalyzerDiagnosticConsumer(ClangTidyContext &Context) : Context(Context) {}
69
Alexander Kornienkocb9272f2014-02-27 13:14:5170 void FlushDiagnosticsImpl(std::vector<const ento::PathDiagnostic *> &Diags,
Craig Toppera3dbe842014-03-02 10:20:1171 FilesMade *filesMade) override {
Alexander Kornienkodf1e3cb2014-03-06 10:17:4672 for (const ento::PathDiagnostic *PD : Diags) {
Alexander Kornienkod1afc702014-02-12 09:52:0773 SmallString<64> CheckName(AnalyzerCheckNamePrefix);
74 CheckName += PD->getCheckName();
Alexander Kornienko95cd50f2014-03-06 13:24:2875 Context.diag(CheckName, PD->getLocation().asLocation(),
76 PD->getShortDescription())
77 << PD->path.back()->getRanges();
Alexander Kornienko54461eb2014-02-06 14:50:1078
Alexander Kornienkodf1e3cb2014-03-06 10:17:4679 for (const auto &DiagPiece :
80 PD->path.flatten(/*ShouldFlattenMacros=*/true)) {
Alexander Kornienko95cd50f2014-03-06 13:24:2881 Context.diag(CheckName, DiagPiece->getLocation().asLocation(),
82 DiagPiece->getString(), DiagnosticIDs::Note)
83 << DiagPiece->getRanges();
Alexander Kornienko54461eb2014-02-06 14:50:1084 }
85 }
86 }
87
Craig Toppera3dbe842014-03-02 10:20:1188 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:1091
92private:
93 ClangTidyContext &Context;
Alexander Kornienko54461eb2014-02-06 14:50:1094};
95
Alexander Kornienko38d81b42014-03-27 10:24:1196class 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),
Jonathan Roelofsd60388a2016-01-13 17:36:41104 ApplyFixes(ApplyFixes), TotalFixes(0), AppliedFixes(0),
105 WarningsAsErrors(0) {
Alexander Kornienko38d81b42014-03-27 10:24:11106 DiagOpts->ShowColors = llvm::sys::Process::StandardOutHasColors();
107 DiagPrinter->BeginSourceFile(LangOpts);
108 }
109
Etienne Bergeron4eaeace2016-04-06 14:07:51110 SourceManager &getSourceManager() { return SourceMgr; }
Haojian Wuf7692a22016-02-26 09:19:33111
Alexander Kornienko742790c2014-07-02 15:05:04112 void reportDiagnostic(const ClangTidyError &Error) {
113 const ClangTidyMessage &Message = Error.Message;
Alexander Kornienko38d81b42014-03-27 10:24:11114 SourceLocation Loc = getLocation(Message.FilePath, Message.FileOffset);
115 // Contains a pair for each attempted fix: location and whether the fix was
116 // applied successfully.
117 SmallVector<std::pair<SourceLocation, bool>, 4> FixLocations;
118 {
Alexander Kornienko742790c2014-07-02 15:05:04119 auto Level = static_cast<DiagnosticsEngine::Level>(Error.DiagLevel);
Jonathan Roelofsd60388a2016-01-13 17:36:41120 std::string Name = Error.CheckName;
121 if (Error.IsWarningAsError) {
122 Name += ",-warnings-as-errors";
123 Level = DiagnosticsEngine::Error;
124 WarningsAsErrors++;
125 }
Alexander Kornienko58fe57a2015-11-16 13:06:15126 auto Diag = Diags.Report(Loc, Diags.getCustomDiagID(Level, "%0 [%1]"))
Jonathan Roelofsd60388a2016-01-13 17:36:41127 << Message.Message << Name;
Alexander Kornienko742790c2014-07-02 15:05:04128 for (const tooling::Replacement &Fix : Error.Fix) {
Etienne Bergeron6feeb652016-03-22 17:51:27129 // Retrieve the source range for applicable fixes. Macro definitions
130 // on the command line have locations in a virtual buffer and don't
131 // have valid file paths and are therefore not applicable.
132 SourceRange Range;
133 SourceLocation FixLoc;
134 if (Fix.isApplicable()) {
135 SmallString<128> FixAbsoluteFilePath = Fix.getFilePath();
136 Files.makeAbsolutePath(FixAbsoluteFilePath);
137 FixLoc = getLocation(FixAbsoluteFilePath, Fix.getOffset());
138 SourceLocation FixEndLoc = FixLoc.getLocWithOffset(Fix.getLength());
139 Range = SourceRange(FixLoc, FixEndLoc);
140 Diag << FixItHint::CreateReplacement(Range, Fix.getReplacementText());
141 }
Etienne Bergeron4eaeace2016-04-06 14:07:51142
Alexander Kornienko742790c2014-07-02 15:05:04143 ++TotalFixes;
144 if (ApplyFixes) {
145 bool Success = Fix.isApplicable() && Fix.apply(Rewrite);
146 if (Success)
147 ++AppliedFixes;
148 FixLocations.push_back(std::make_pair(FixLoc, Success));
Alexander Kornienko38d81b42014-03-27 10:24:11149 }
150 }
151 }
152 for (auto Fix : FixLocations) {
153 Diags.Report(Fix.first, Fix.second ? diag::note_fixit_applied
154 : diag::note_fixit_failed);
155 }
Alexander Kornienko742790c2014-07-02 15:05:04156 for (const ClangTidyMessage &Note : Error.Notes)
157 reportNote(Note);
Alexander Kornienko38d81b42014-03-27 10:24:11158 }
159
160 void Finish() {
161 // FIXME: Run clang-format on changes.
162 if (ApplyFixes && TotalFixes > 0) {
163 llvm::errs() << "clang-tidy applied " << AppliedFixes << " of "
164 << TotalFixes << " suggested fixes.\n";
165 Rewrite.overwriteChangedFiles();
166 }
167 }
168
Jonathan Roelofsd60388a2016-01-13 17:36:41169 unsigned getWarningsAsErrorsCount() const { return WarningsAsErrors; }
170
Alexander Kornienko38d81b42014-03-27 10:24:11171private:
172 SourceLocation getLocation(StringRef FilePath, unsigned Offset) {
173 if (FilePath.empty())
174 return SourceLocation();
175
176 const FileEntry *File = SourceMgr.getFileManager().getFile(FilePath);
177 FileID ID = SourceMgr.createFileID(File, SourceLocation(), SrcMgr::C_User);
178 return SourceMgr.getLocForStartOfFile(ID).getLocWithOffset(Offset);
179 }
180
Alexander Kornienko742790c2014-07-02 15:05:04181 void reportNote(const ClangTidyMessage &Message) {
182 SourceLocation Loc = getLocation(Message.FilePath, Message.FileOffset);
183 DiagnosticBuilder Diag =
184 Diags.Report(Loc, Diags.getCustomDiagID(DiagnosticsEngine::Note, "%0"))
185 << Message.Message;
186 }
187
Alexander Kornienko38d81b42014-03-27 10:24:11188 FileManager Files;
189 LangOptions LangOpts; // FIXME: use langopts from each original file
190 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
191 DiagnosticConsumer *DiagPrinter;
192 DiagnosticsEngine Diags;
193 SourceManager SourceMgr;
194 Rewriter Rewrite;
195 bool ApplyFixes;
NAKAMURA Takumi4dd18132014-03-27 14:53:37196 unsigned TotalFixes;
197 unsigned AppliedFixes;
Jonathan Roelofsd60388a2016-01-13 17:36:41198 unsigned WarningsAsErrors;
Alexander Kornienko38d81b42014-03-27 10:24:11199};
200
Alexander Kornienkoa4695222014-06-05 13:31:45201class ClangTidyASTConsumer : public MultiplexConsumer {
202public:
David Blaikie680c4c82014-08-10 19:56:59203 ClangTidyASTConsumer(std::vector<std::unique_ptr<ASTConsumer>> Consumers,
Alexander Kornienkoa4695222014-06-05 13:31:45204 std::unique_ptr<ast_matchers::MatchFinder> Finder,
205 std::vector<std::unique_ptr<ClangTidyCheck>> Checks)
David Blaikie680c4c82014-08-10 19:56:59206 : MultiplexConsumer(std::move(Consumers)), Finder(std::move(Finder)),
Alexander Kornienkoa4695222014-06-05 13:31:45207 Checks(std::move(Checks)) {}
208
209private:
210 std::unique_ptr<ast_matchers::MatchFinder> Finder;
211 std::vector<std::unique_ptr<ClangTidyCheck>> Checks;
212};
213
Alexander Kornienko175fefb2014-01-03 09:31:57214} // namespace
Alexander Kornienkofb9e92b2013-12-19 19:57:05215
Alexander Kornienko175fefb2014-01-03 09:31:57216ClangTidyASTConsumerFactory::ClangTidyASTConsumerFactory(
Alexander Kornienkoa4695222014-06-05 13:31:45217 ClangTidyContext &Context)
218 : Context(Context), CheckFactories(new ClangTidyCheckFactories) {
Alexander Kornienko175fefb2014-01-03 09:31:57219 for (ClangTidyModuleRegistry::iterator I = ClangTidyModuleRegistry::begin(),
220 E = ClangTidyModuleRegistry::end();
221 I != E; ++I) {
Ahmed Charles6a2dc5c2014-03-09 09:24:40222 std::unique_ptr<ClangTidyModule> Module(I->instantiate());
Alexander Kornienko175fefb2014-01-03 09:31:57223 Module->addCheckFactories(*CheckFactories);
224 }
Alexander Kornienko175fefb2014-01-03 09:31:57225}
Alexander Kornienkofb9e92b2013-12-19 19:57:05226
Gabor Horvath34383212015-03-11 17:25:22227static void setStaticAnalyzerCheckerOpts(const ClangTidyOptions &Opts,
228 AnalyzerOptionsRef AnalyzerOptions) {
229 StringRef AnalyzerPrefix(AnalyzerCheckNamePrefix);
230 for (const auto &Opt : Opts.CheckOptions) {
231 StringRef OptName(Opt.first);
232 if (!OptName.startswith(AnalyzerPrefix))
233 continue;
234 AnalyzerOptions->Config[OptName.substr(AnalyzerPrefix.size())] = Opt.second;
235 }
236}
237
David Blaikie680c4c82014-08-10 19:56:59238std::unique_ptr<clang::ASTConsumer>
239ClangTidyASTConsumerFactory::CreateASTConsumer(
Alexander Kornienko175fefb2014-01-03 09:31:57240 clang::CompilerInstance &Compiler, StringRef File) {
241 // FIXME: Move this to a separate method, so that CreateASTConsumer doesn't
242 // modify Compiler.
243 Context.setSourceManager(&Compiler.getSourceManager());
Alexander Kornienkoa4695222014-06-05 13:31:45244 Context.setCurrentFile(File);
Alexander Kornienkoad216882014-07-14 14:10:03245 Context.setASTContext(&Compiler.getASTContext());
Alexander Kornienkoa4695222014-06-05 13:31:45246
Haojian Wuf7692a22016-02-26 09:19:33247 auto WorkingDir = Compiler.getSourceManager()
248 .getFileManager()
249 .getVirtualFileSystem()
250 ->getCurrentWorkingDirectory();
251 if (WorkingDir)
252 Context.setCurrentBuildDirectory(WorkingDir.get());
253
Alexander Kornienkoa4695222014-06-05 13:31:45254 std::vector<std::unique_ptr<ClangTidyCheck>> Checks;
Alexander Kornienko6e0cbc82014-09-12 08:53:36255 CheckFactories->createChecks(&Context, Checks);
Alexander Kornienkoa4695222014-06-05 13:31:45256
Samuel Benzaquenaedd9942014-10-23 17:23:20257 ast_matchers::MatchFinder::MatchFinderOptions FinderOptions;
258 if (auto *P = Context.getCheckProfileData())
259 FinderOptions.CheckProfiling.emplace(P->Records);
260
Alexander Kornienkoa4695222014-06-05 13:31:45261 std::unique_ptr<ast_matchers::MatchFinder> Finder(
Samuel Benzaquenaedd9942014-10-23 17:23:20262 new ast_matchers::MatchFinder(std::move(FinderOptions)));
263
Alexander Kornienkoa4695222014-06-05 13:31:45264 for (auto &Check : Checks) {
Alexander Kornienkoa4695222014-06-05 13:31:45265 Check->registerMatchers(&*Finder);
Alexander Kornienkodf1e3cb2014-03-06 10:17:46266 Check->registerPPCallbacks(Compiler);
Alexander Kornienkoa4695222014-06-05 13:31:45267 }
Alexander Kornienko175fefb2014-01-03 09:31:57268
David Blaikie680c4c82014-08-10 19:56:59269 std::vector<std::unique_ptr<ASTConsumer>> Consumers;
Alexander Kornienkoa4695222014-06-05 13:31:45270 if (!Checks.empty())
271 Consumers.push_back(Finder->newASTConsumer());
Alexander Kornienko298b3822014-02-13 16:10:47272
Alex McCarthyfec08c72014-04-30 14:09:24273 AnalyzerOptionsRef AnalyzerOptions = Compiler.getAnalyzerOpts();
274 // FIXME: Remove this option once clang's cfg-temporary-dtors option defaults
275 // to true.
276 AnalyzerOptions->Config["cfg-temporary-dtors"] =
Alexander Kornienkoa4695222014-06-05 13:31:45277 Context.getOptions().AnalyzeTemporaryDtors ? "true" : "false";
Alex McCarthyfec08c72014-04-30 14:09:24278
Alexander Kornienko6e0cbc82014-09-12 08:53:36279 GlobList &Filter = Context.getChecksFilter();
Alexander Kornienkoa4695222014-06-05 13:31:45280 AnalyzerOptions->CheckersControlList = getCheckersControlList(Filter);
Alex McCarthyfec08c72014-04-30 14:09:24281 if (!AnalyzerOptions->CheckersControlList.empty()) {
Gabor Horvath34383212015-03-11 17:25:22282 setStaticAnalyzerCheckerOpts(Context.getOptions(), AnalyzerOptions);
Alex McCarthyfec08c72014-04-30 14:09:24283 AnalyzerOptions->AnalysisStoreOpt = RegionStoreModel;
284 AnalyzerOptions->AnalysisDiagOpt = PD_NONE;
285 AnalyzerOptions->AnalyzeNestedBlocks = true;
286 AnalyzerOptions->eagerlyAssumeBinOpBifurcation = true;
David Blaikie680c4c82014-08-10 19:56:59287 std::unique_ptr<ento::AnalysisASTConsumer> AnalysisConsumer =
Ted Kremenek4d1692f2014-08-27 15:14:47288 ento::CreateAnalysisConsumer(Compiler);
Alexander Kornienko298b3822014-02-13 16:10:47289 AnalysisConsumer->AddDiagnosticConsumer(
290 new AnalyzerDiagnosticConsumer(Context));
David Blaikie680c4c82014-08-10 19:56:59291 Consumers.push_back(std::move(AnalysisConsumer));
Alexander Kornienko298b3822014-02-13 16:10:47292 }
David Blaikie680c4c82014-08-10 19:56:59293 return llvm::make_unique<ClangTidyASTConsumer>(
294 std::move(Consumers), std::move(Finder), std::move(Checks));
Alexander Kornienko175fefb2014-01-03 09:31:57295}
296
Alexander Kornienko6e0cbc82014-09-12 08:53:36297std::vector<std::string> ClangTidyASTConsumerFactory::getCheckNames() {
Alexander Kornienko175fefb2014-01-03 09:31:57298 std::vector<std::string> CheckNames;
Alexander Kornienko6e0cbc82014-09-12 08:53:36299 GlobList &Filter = Context.getChecksFilter();
Alexander Kornienkodf1e3cb2014-03-06 10:17:46300 for (const auto &CheckFactory : *CheckFactories) {
Alexander Kornienkob3d331d2014-08-06 11:49:10301 if (Filter.contains(CheckFactory.first))
Alexander Kornienkodf1e3cb2014-03-06 10:17:46302 CheckNames.push_back(CheckFactory.first);
Alexander Kornienko175fefb2014-01-03 09:31:57303 }
304
Alexander Kornienkoa4695222014-06-05 13:31:45305 for (const auto &AnalyzerCheck : getCheckersControlList(Filter))
Alexander Kornienkodf1e3cb2014-03-06 10:17:46306 CheckNames.push_back(AnalyzerCheckNamePrefix + AnalyzerCheck.first);
Alexander Kornienko175fefb2014-01-03 09:31:57307
308 std::sort(CheckNames.begin(), CheckNames.end());
309 return CheckNames;
310}
311
Alexander Kornienko6e0cbc82014-09-12 08:53:36312ClangTidyOptions::OptionMap ClangTidyASTConsumerFactory::getCheckOptions() {
313 ClangTidyOptions::OptionMap Options;
314 std::vector<std::unique_ptr<ClangTidyCheck>> Checks;
315 CheckFactories->createChecks(&Context, Checks);
316 for (const auto &Check : Checks)
317 Check->storeOptions(Options);
318 return Options;
319}
320
Alexander Kornienko175fefb2014-01-03 09:31:57321ClangTidyASTConsumerFactory::CheckersList
Alexander Kornienkob3d331d2014-08-06 11:49:10322ClangTidyASTConsumerFactory::getCheckersControlList(GlobList &Filter) {
Alexander Kornienko175fefb2014-01-03 09:31:57323 CheckersList List;
Alexander Kornienko175fefb2014-01-03 09:31:57324
325 bool AnalyzerChecksEnabled = false;
Alexander Kornienkodf1e3cb2014-03-06 10:17:46326 for (StringRef CheckName : StaticAnalyzerChecks) {
327 std::string Checker((AnalyzerCheckNamePrefix + CheckName).str());
Alexander Kornienkoa4695222014-06-05 13:31:45328 AnalyzerChecksEnabled =
329 AnalyzerChecksEnabled ||
Alexander Kornienkob3d331d2014-08-06 11:49:10330 (!CheckName.startswith("debug") && Filter.contains(Checker));
Alexander Kornienko175fefb2014-01-03 09:31:57331 }
332
333 if (AnalyzerChecksEnabled) {
334 // Run our regex against all possible static analyzer checkers. Note that
335 // debug checkers print values / run programs to visualize the CFG and are
336 // thus not applicable to clang-tidy in general.
337 //
Alexander Kornienkofb9e92b2013-12-19 19:57:05338 // Always add all core checkers if any other static analyzer checks are
Alexander Kornienko175fefb2014-01-03 09:31:57339 // enabled. This is currently necessary, as other path sensitive checks
340 // rely on the core checkers.
Alexander Kornienkodf1e3cb2014-03-06 10:17:46341 for (StringRef CheckName : StaticAnalyzerChecks) {
342 std::string Checker((AnalyzerCheckNamePrefix + CheckName).str());
Alexander Kornienkofb9e92b2013-12-19 19:57:05343
Alexander Kornienkodf1e3cb2014-03-06 10:17:46344 if (CheckName.startswith("core") ||
Alexander Kornienkob3d331d2014-08-06 11:49:10345 (!CheckName.startswith("debug") && Filter.contains(Checker)))
Alexander Kornienkodf1e3cb2014-03-06 10:17:46346 List.push_back(std::make_pair(CheckName, true));
Alexander Kornienkofb9e92b2013-12-19 19:57:05347 }
348 }
Alexander Kornienko175fefb2014-01-03 09:31:57349 return List;
350}
Daniel Jasperd07c8402013-07-29 08:19:24351
Peter Collingbourneb17a3b32014-03-02 23:34:48352DiagnosticBuilder ClangTidyCheck::diag(SourceLocation Loc, StringRef Message,
353 DiagnosticIDs::Level Level) {
354 return Context->diag(CheckName, Loc, Message, Level);
Alexander Kornienko41bfe8d2014-01-13 10:50:51355}
356
Daniel Jasperd07c8402013-07-29 08:19:24357void ClangTidyCheck::run(const ast_matchers::MatchFinder::MatchResult &Result) {
358 Context->setSourceManager(Result.SourceManager);
359 check(Result);
360}
361
Alexander Kornienko6e0cbc82014-09-12 08:53:36362OptionsView::OptionsView(StringRef CheckName,
363 const ClangTidyOptions::OptionMap &CheckOptions)
364 : NamePrefix(CheckName.str() + "."), CheckOptions(CheckOptions) {}
365
Haojian Wuc2d75772016-02-05 11:23:59366std::string OptionsView::get(StringRef LocalName, StringRef Default) const {
Alexander Kornienko6e0cbc82014-09-12 08:53:36367 const auto &Iter = CheckOptions.find(NamePrefix + LocalName.str());
368 if (Iter != CheckOptions.end())
369 return Iter->second;
370 return Default;
371}
372
Haojian Wuc2d75772016-02-05 11:23:59373std::string OptionsView::getLocalOrGlobal(StringRef LocalName,
374 StringRef Default) const {
375 auto Iter = CheckOptions.find(NamePrefix + LocalName.str());
376 if (Iter != CheckOptions.end())
377 return Iter->second;
378 // Fallback to global setting, if present.
379 Iter = CheckOptions.find(LocalName.str());
380 if (Iter != CheckOptions.end())
381 return Iter->second;
382 return Default;
383}
384
Alexander Kornienko6e0cbc82014-09-12 08:53:36385void OptionsView::store(ClangTidyOptions::OptionMap &Options,
386 StringRef LocalName, StringRef Value) const {
387 Options[NamePrefix + LocalName.str()] = Value;
388}
389
390void OptionsView::store(ClangTidyOptions::OptionMap &Options,
391 StringRef LocalName, int64_t Value) const {
392 store(Options, LocalName, llvm::itostr(Value));
Alexander Kornienko41bfe8d2014-01-13 10:50:51393}
394
Alexander Kornienko33a9bcc2014-04-29 15:20:10395std::vector<std::string> getCheckNames(const ClangTidyOptions &Options) {
Alexander Kornienkoa4695222014-06-05 13:31:45396 clang::tidy::ClangTidyContext Context(
Alexander Kornienkod53d2682014-09-04 14:23:36397 llvm::make_unique<DefaultOptionsProvider>(ClangTidyGlobalOptions(),
398 Options));
Alexander Kornienkoa4695222014-06-05 13:31:45399 ClangTidyASTConsumerFactory Factory(Context);
Alexander Kornienko6e0cbc82014-09-12 08:53:36400 return Factory.getCheckNames();
401}
402
403ClangTidyOptions::OptionMap getCheckOptions(const ClangTidyOptions &Options) {
404 clang::tidy::ClangTidyContext Context(
405 llvm::make_unique<DefaultOptionsProvider>(ClangTidyGlobalOptions(),
406 Options));
407 ClangTidyASTConsumerFactory Factory(Context);
408 return Factory.getCheckOptions();
Alexander Kornienkofb9e92b2013-12-19 19:57:05409}
410
Alexander Kornienkod53d2682014-09-04 14:23:36411ClangTidyStats
412runClangTidy(std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider,
413 const tooling::CompilationDatabase &Compilations,
414 ArrayRef<std::string> InputFiles,
Samuel Benzaquenaedd9942014-10-23 17:23:20415 std::vector<ClangTidyError> *Errors, ProfileData *Profile) {
Alexander Kornienko1e1ad5c2014-05-28 15:21:14416 ClangTool Tool(Compilations, InputFiles);
Alexander Kornienkod53d2682014-09-04 14:23:36417 clang::tidy::ClangTidyContext Context(std::move(OptionsProvider));
Etienne Bergeron4eaeace2016-04-06 14:07:51418
419 // Add extra arguments passed by the clang-tidy command-line.
420 ArgumentsAdjuster PerFileExtraArgumentsInserter =
421 [&Context](const CommandLineArguments &Args, StringRef Filename) {
422 ClangTidyOptions Opts = Context.getOptionsForFile(Filename);
423 CommandLineArguments AdjustedArgs;
424 if (Opts.ExtraArgsBefore)
425 AdjustedArgs = *Opts.ExtraArgsBefore;
426 AdjustedArgs.insert(AdjustedArgs.begin(), Args.begin(), Args.end());
427 if (Opts.ExtraArgs)
428 AdjustedArgs.insert(AdjustedArgs.end(), Opts.ExtraArgs->begin(),
429 Opts.ExtraArgs->end());
430 return AdjustedArgs;
431 };
432
433 // Remove plugins arguments.
434 ArgumentsAdjuster PluginArgumentsRemover =
435 [&Context](const CommandLineArguments &Args, StringRef Filename) {
436 CommandLineArguments AdjustedArgs;
437 for (size_t I = 0, E = Args.size(); I < E; ++I) {
438 if (I + 4 < Args.size() && Args[I] == "-Xclang" &&
439 (Args[I + 1] == "-load" || Args[I + 1] == "-add-plugin" ||
440 StringRef(Args[I + 1]).startswith("-plugin-arg-")) &&
441 Args[I + 2] == "-Xclang") {
442 I += 3;
443 } else
444 AdjustedArgs.push_back(Args[I]);
445 }
446 return AdjustedArgs;
447 };
448
Alexander Kornienko64956b52015-11-09 16:28:11449 Tool.appendArgumentsAdjuster(PerFileExtraArgumentsInserter);
Etienne Bergeron4eaeace2016-04-06 14:07:51450 Tool.appendArgumentsAdjuster(PluginArgumentsRemover);
Samuel Benzaquenaedd9942014-10-23 17:23:20451 if (Profile)
452 Context.setCheckProfileData(Profile);
453
Daniel Jasperd07c8402013-07-29 08:19:24454 ClangTidyDiagnosticConsumer DiagConsumer(Context);
Manuel Klimek814f9bd2013-11-14 15:49:44455
456 Tool.setDiagnosticConsumer(&DiagConsumer);
Alexander Kornienko175fefb2014-01-03 09:31:57457
458 class ActionFactory : public FrontendActionFactory {
459 public:
Benjamin Kramer6e914242014-07-24 10:23:33460 ActionFactory(ClangTidyContext &Context) : ConsumerFactory(Context) {}
461 FrontendAction *create() override { return new Action(&ConsumerFactory); }
Alexander Kornienko175fefb2014-01-03 09:31:57462
463 private:
464 class Action : public ASTFrontendAction {
465 public:
466 Action(ClangTidyASTConsumerFactory *Factory) : Factory(Factory) {}
David Blaikie680c4c82014-08-10 19:56:59467 std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
468 StringRef File) override {
Alexander Kornienko175fefb2014-01-03 09:31:57469 return Factory->CreateASTConsumer(Compiler, File);
470 }
471
472 private:
473 ClangTidyASTConsumerFactory *Factory;
474 };
475
Benjamin Kramer6e914242014-07-24 10:23:33476 ClangTidyASTConsumerFactory ConsumerFactory;
Alexander Kornienko175fefb2014-01-03 09:31:57477 };
478
Benjamin Kramer6e914242014-07-24 10:23:33479 ActionFactory Factory(Context);
480 Tool.run(&Factory);
Alexander Kornienko826b5ad2014-05-09 12:24:09481 *Errors = Context.getErrors();
Alexander Kornienko5d174542014-05-07 09:06:53482 return Context.getStats();
Manuel Klimek814f9bd2013-11-14 15:49:44483}
484
Jonathan Roelofsd60388a2016-01-13 17:36:41485void handleErrors(const std::vector<ClangTidyError> &Errors, bool Fix,
486 unsigned &WarningsAsErrorsCount) {
Alexander Kornienko38d81b42014-03-27 10:24:11487 ErrorReporter Reporter(Fix);
Haojian Wuf7692a22016-02-26 09:19:33488 vfs::FileSystem &FileSystem =
489 *Reporter.getSourceManager().getFileManager().getVirtualFileSystem();
490 auto InitialWorkingDir = FileSystem.getCurrentWorkingDirectory();
491 if (!InitialWorkingDir)
492 llvm::report_fatal_error("Cannot get current working path.");
493
494 for (const ClangTidyError &Error : Errors) {
495 if (!Error.BuildDirectory.empty()) {
496 // By default, the working directory of file system is the current
497 // clang-tidy running directory.
498 //
499 // Change the directory to the one used during the analysis.
500 FileSystem.setCurrentWorkingDirectory(Error.BuildDirectory);
501 }
Alexander Kornienko742790c2014-07-02 15:05:04502 Reporter.reportDiagnostic(Error);
Haojian Wuf7692a22016-02-26 09:19:33503 // Return to the initial directory to correctly resolve next Error.
504 FileSystem.setCurrentWorkingDirectory(InitialWorkingDir.get());
505 }
Alexander Kornienko38d81b42014-03-27 10:24:11506 Reporter.Finish();
Jonathan Roelofsd60388a2016-01-13 17:36:41507 WarningsAsErrorsCount += Reporter.getWarningsAsErrorsCount();
Daniel Jasperd07c8402013-07-29 08:19:24508}
509
Benjamin Kramerfb98b742014-09-04 10:31:23510void exportReplacements(const std::vector<ClangTidyError> &Errors,
511 raw_ostream &OS) {
512 tooling::TranslationUnitReplacements TUR;
513 for (const ClangTidyError &Error : Errors)
514 TUR.Replacements.insert(TUR.Replacements.end(), Error.Fix.begin(),
515 Error.Fix.end());
516
517 yaml::Output YAML(OS);
518 YAML << TUR;
519}
520
Daniel Jasperd07c8402013-07-29 08:19:24521} // namespace tidy
522} // namespace clang