blob: e704b1a655c6abdea43c54c7de66d31056f6bcb4 [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 Kornienko175fefb2014-01-03 09:31:57 +000028#include "clang/Frontend/MultiplexConsumer.h"
Daniel Jasperd07c8402013-07-29 08:19:24 +000029#include "clang/Frontend/TextDiagnosticPrinter.h"
Chandler Carruth85e6e872014-01-07 20:05:01 +000030#include "clang/Lex/PPCallbacks.h"
31#include "clang/Lex/Preprocessor.h"
Daniel Jasperd07c8402013-07-29 08:19:24 +000032#include "clang/Rewrite/Frontend/FixItRewriter.h"
33#include "clang/Rewrite/Frontend/FrontendActions.h"
Alexander Kornienkod1199cb2014-01-03 17:24:20 +000034#include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
Daniel Jasperd07c8402013-07-29 08:19:24 +000035#include "clang/Tooling/Refactoring.h"
Chandler Carruth85e6e872014-01-07 20:05:01 +000036#include "clang/Tooling/Tooling.h"
Daniel Jasperd07c8402013-07-29 08:19:24 +000037#include "llvm/Support/Path.h"
Alexander Kornienko54461eb2014-02-06 14:50:10 +000038#include "llvm/Support/Process.h"
Daniel Jasperd07c8402013-07-29 08:19:24 +000039#include "llvm/Support/Signals.h"
Alexander Kornienkofb9e92b2013-12-19 19:57:05 +000040#include <algorithm>
Daniel Jasperd07c8402013-07-29 08:19:24 +000041#include <vector>
42
43using namespace clang::ast_matchers;
44using namespace clang::driver;
45using namespace clang::tooling;
46using namespace llvm;
47
48namespace clang {
49namespace tidy {
Alexander Kornienko175fefb2014-01-03 09:31:57 +000050
Daniel Jasperd07c8402013-07-29 08:19:24 +000051namespace {
Alexander Kornienko54461eb2014-02-06 14:50:10 +000052static const char *AnalyzerCheckNamePrefix = "clang-analyzer-";
Manuel Klimek814f9bd2013-11-14 15:49:44 +000053
Alexander Kornienko54461eb2014-02-06 14:50:10 +000054static StringRef StaticAnalyzerChecks[] = {
Alexander Kornienkofb9e92b2013-12-19 19:57:05 +000055#define GET_CHECKERS
56#define CHECKER(FULLNAME, CLASS, DESCFILE, HELPTEXT, GROUPINDEX, HIDDEN) \
57 FULLNAME,
NAKAMURA Takumi321b7d32014-01-03 10:24:51 +000058#include "../../../lib/StaticAnalyzer/Checkers/Checkers.inc"
Alexander Kornienkofb9e92b2013-12-19 19:57:05 +000059#undef CHECKER
60#undef GET_CHECKERS
61};
62
Alexander Kornienko54461eb2014-02-06 14:50:10 +000063class AnalyzerDiagnosticConsumer : public ento::PathDiagnosticConsumer {
64public:
65 AnalyzerDiagnosticConsumer(ClangTidyContext &Context) : Context(Context) {}
66
Alexander Kornienkocb9272f2014-02-27 13:14:51 +000067 void FlushDiagnosticsImpl(std::vector<const ento::PathDiagnostic *> &Diags,
Craig Toppera3dbe842014-03-02 10:20:11 +000068 FilesMade *filesMade) override {
Alexander Kornienkodf1e3cb2014-03-06 10:17:46 +000069 for (const ento::PathDiagnostic *PD : Diags) {
Alexander Kornienkod1afc702014-02-12 09:52:07 +000070 SmallString<64> CheckName(AnalyzerCheckNamePrefix);
71 CheckName += PD->getCheckName();
Alexander Kornienko95cd50f2014-03-06 13:24:28 +000072 Context.diag(CheckName, PD->getLocation().asLocation(),
73 PD->getShortDescription())
74 << PD->path.back()->getRanges();
Alexander Kornienko54461eb2014-02-06 14:50:10 +000075
Alexander Kornienkodf1e3cb2014-03-06 10:17:46 +000076 for (const auto &DiagPiece :
77 PD->path.flatten(/*ShouldFlattenMacros=*/true)) {
Alexander Kornienko95cd50f2014-03-06 13:24:28 +000078 Context.diag(CheckName, DiagPiece->getLocation().asLocation(),
79 DiagPiece->getString(), DiagnosticIDs::Note)
80 << DiagPiece->getRanges();
Alexander Kornienko54461eb2014-02-06 14:50:10 +000081 }
82 }
83 }
84
Craig Toppera3dbe842014-03-02 10:20:11 +000085 StringRef getName() const override { return "ClangTidyDiags"; }
86 bool supportsLogicalOpControlFlow() const override { return true; }
87 bool supportsCrossFileDiagnostics() const override { return true; }
Alexander Kornienko54461eb2014-02-06 14:50:10 +000088
89private:
90 ClangTidyContext &Context;
Alexander Kornienko54461eb2014-02-06 14:50:10 +000091};
92
Alexander Kornienko175fefb2014-01-03 09:31:57 +000093} // namespace
Alexander Kornienkofb9e92b2013-12-19 19:57:05 +000094
Alexander Kornienko175fefb2014-01-03 09:31:57 +000095ClangTidyASTConsumerFactory::ClangTidyASTConsumerFactory(
Alexander Kornienko175fefb2014-01-03 09:31:57 +000096 ClangTidyContext &Context)
Alexander Kornienko09952d22014-03-20 09:38:22 +000097 : Context(Context), CheckFactories(new ClangTidyCheckFactories) {
Alexander Kornienko175fefb2014-01-03 09:31:57 +000098 for (ClangTidyModuleRegistry::iterator I = ClangTidyModuleRegistry::begin(),
99 E = ClangTidyModuleRegistry::end();
100 I != E; ++I) {
Ahmed Charles6a2dc5c2014-03-09 09:24:40 +0000101 std::unique_ptr<ClangTidyModule> Module(I->instantiate());
Alexander Kornienko175fefb2014-01-03 09:31:57 +0000102 Module->addCheckFactories(*CheckFactories);
103 }
Alexander Kornienkofb9e92b2013-12-19 19:57:05 +0000104
Alexander Kornienko09952d22014-03-20 09:38:22 +0000105 CheckFactories->createChecks(Context.getChecksFilter(), Checks);
Alexander Kornienkofb9e92b2013-12-19 19:57:05 +0000106
Alexander Kornienkodf1e3cb2014-03-06 10:17:46 +0000107 for (ClangTidyCheck *Check : Checks) {
108 Check->setContext(&Context);
109 Check->registerMatchers(&Finder);
Alexander Kornienko175fefb2014-01-03 09:31:57 +0000110 }
111}
Alexander Kornienkofb9e92b2013-12-19 19:57:05 +0000112
Alexander Kornienko175fefb2014-01-03 09:31:57 +0000113ClangTidyASTConsumerFactory::~ClangTidyASTConsumerFactory() {
Alexander Kornienkodf1e3cb2014-03-06 10:17:46 +0000114 for (ClangTidyCheck *Check : Checks)
115 delete Check;
Alexander Kornienko175fefb2014-01-03 09:31:57 +0000116}
Alexander Kornienkofb9e92b2013-12-19 19:57:05 +0000117
Alexander Kornienko175fefb2014-01-03 09:31:57 +0000118clang::ASTConsumer *ClangTidyASTConsumerFactory::CreateASTConsumer(
119 clang::CompilerInstance &Compiler, StringRef File) {
120 // FIXME: Move this to a separate method, so that CreateASTConsumer doesn't
121 // modify Compiler.
122 Context.setSourceManager(&Compiler.getSourceManager());
Alexander Kornienkodf1e3cb2014-03-06 10:17:46 +0000123 for (ClangTidyCheck *Check : Checks)
124 Check->registerPPCallbacks(Compiler);
Alexander Kornienko175fefb2014-01-03 09:31:57 +0000125
Alexander Kornienko298b3822014-02-13 16:10:47 +0000126 SmallVector<ASTConsumer *, 2> Consumers;
Alexander Kornienkod68aa4c2014-02-13 16:29:39 +0000127 if (!CheckFactories->empty())
Alexander Kornienko298b3822014-02-13 16:10:47 +0000128 Consumers.push_back(Finder.newASTConsumer());
129
Alexander Kornienko175fefb2014-01-03 09:31:57 +0000130 AnalyzerOptionsRef Options = Compiler.getAnalyzerOpts();
131 Options->CheckersControlList = getCheckersControlList();
Alexander Kornienko298b3822014-02-13 16:10:47 +0000132 if (!Options->CheckersControlList.empty()) {
133 Options->AnalysisStoreOpt = RegionStoreModel;
134 Options->AnalysisDiagOpt = PD_NONE;
135 Options->AnalyzeNestedBlocks = true;
136 Options->eagerlyAssumeBinOpBifurcation = true;
137 ento::AnalysisASTConsumer *AnalysisConsumer = ento::CreateAnalysisConsumer(
138 Compiler.getPreprocessor(), Compiler.getFrontendOpts().OutputFile,
139 Options, Compiler.getFrontendOpts().Plugins);
140 AnalysisConsumer->AddDiagnosticConsumer(
141 new AnalyzerDiagnosticConsumer(Context));
142 Consumers.push_back(AnalysisConsumer);
143 }
Alexander Kornienko175fefb2014-01-03 09:31:57 +0000144 return new MultiplexConsumer(Consumers);
145}
146
147std::vector<std::string> ClangTidyASTConsumerFactory::getCheckNames() {
148 std::vector<std::string> CheckNames;
Alexander Kornienkodf1e3cb2014-03-06 10:17:46 +0000149 for (const auto &CheckFactory : *CheckFactories) {
Alexander Kornienko09952d22014-03-20 09:38:22 +0000150 if (Context.getChecksFilter().isCheckEnabled(CheckFactory.first))
Alexander Kornienkodf1e3cb2014-03-06 10:17:46 +0000151 CheckNames.push_back(CheckFactory.first);
Alexander Kornienko175fefb2014-01-03 09:31:57 +0000152 }
153
Alexander Kornienkodf1e3cb2014-03-06 10:17:46 +0000154 for (const auto &AnalyzerCheck : getCheckersControlList())
155 CheckNames.push_back(AnalyzerCheckNamePrefix + AnalyzerCheck.first);
Alexander Kornienko175fefb2014-01-03 09:31:57 +0000156
157 std::sort(CheckNames.begin(), CheckNames.end());
158 return CheckNames;
159}
160
161ClangTidyASTConsumerFactory::CheckersList
162ClangTidyASTConsumerFactory::getCheckersControlList() {
163 CheckersList List;
Alexander Kornienko175fefb2014-01-03 09:31:57 +0000164
165 bool AnalyzerChecksEnabled = false;
Alexander Kornienkodf1e3cb2014-03-06 10:17:46 +0000166 for (StringRef CheckName : StaticAnalyzerChecks) {
167 std::string Checker((AnalyzerCheckNamePrefix + CheckName).str());
Alexander Kornienko175fefb2014-01-03 09:31:57 +0000168 AnalyzerChecksEnabled |=
Alexander Kornienko09952d22014-03-20 09:38:22 +0000169 Context.getChecksFilter().isCheckEnabled(Checker) &&
170 !CheckName.startswith("debug");
Alexander Kornienko175fefb2014-01-03 09:31:57 +0000171 }
172
173 if (AnalyzerChecksEnabled) {
174 // Run our regex against all possible static analyzer checkers. Note that
175 // debug checkers print values / run programs to visualize the CFG and are
176 // thus not applicable to clang-tidy in general.
177 //
Alexander Kornienkofb9e92b2013-12-19 19:57:05 +0000178 // Always add all core checkers if any other static analyzer checks are
Alexander Kornienko175fefb2014-01-03 09:31:57 +0000179 // enabled. This is currently necessary, as other path sensitive checks
180 // rely on the core checkers.
Alexander Kornienkodf1e3cb2014-03-06 10:17:46 +0000181 for (StringRef CheckName : StaticAnalyzerChecks) {
182 std::string Checker((AnalyzerCheckNamePrefix + CheckName).str());
Alexander Kornienkofb9e92b2013-12-19 19:57:05 +0000183
Alexander Kornienkodf1e3cb2014-03-06 10:17:46 +0000184 if (CheckName.startswith("core") ||
Alexander Kornienko09952d22014-03-20 09:38:22 +0000185 (!CheckName.startswith("debug") &&
186 Context.getChecksFilter().isCheckEnabled(Checker)))
Alexander Kornienkodf1e3cb2014-03-06 10:17:46 +0000187 List.push_back(std::make_pair(CheckName, true));
Alexander Kornienkofb9e92b2013-12-19 19:57:05 +0000188 }
189 }
Alexander Kornienko175fefb2014-01-03 09:31:57 +0000190 return List;
191}
Daniel Jasperd07c8402013-07-29 08:19:24 +0000192
Peter Collingbourneb17a3b32014-03-02 23:34:48 +0000193DiagnosticBuilder ClangTidyCheck::diag(SourceLocation Loc, StringRef Message,
194 DiagnosticIDs::Level Level) {
195 return Context->diag(CheckName, Loc, Message, Level);
Alexander Kornienko41bfe8d2014-01-13 10:50:51 +0000196}
197
Daniel Jasperd07c8402013-07-29 08:19:24 +0000198void ClangTidyCheck::run(const ast_matchers::MatchFinder::MatchResult &Result) {
199 Context->setSourceManager(Result.SourceManager);
200 check(Result);
201}
202
Alexander Kornienko41bfe8d2014-01-13 10:50:51 +0000203void ClangTidyCheck::setName(StringRef Name) {
204 assert(CheckName.empty());
205 CheckName = Name.str();
206}
207
Alexander Kornienkofb9e92b2013-12-19 19:57:05 +0000208std::vector<std::string> getCheckNames(StringRef EnableChecksRegex,
209 StringRef DisableChecksRegex) {
210 SmallVector<ClangTidyError, 8> Errors;
Alexander Kornienko09952d22014-03-20 09:38:22 +0000211 clang::tidy::ClangTidyContext Context(&Errors, EnableChecksRegex,
212 DisableChecksRegex);
213 ClangTidyASTConsumerFactory Factory(Context);
Alexander Kornienkofb9e92b2013-12-19 19:57:05 +0000214 return Factory.getCheckNames();
215}
216
217void runClangTidy(StringRef EnableChecksRegex, StringRef DisableChecksRegex,
Daniel Jasperd07c8402013-07-29 08:19:24 +0000218 const tooling::CompilationDatabase &Compilations,
219 ArrayRef<std::string> Ranges,
220 SmallVectorImpl<ClangTidyError> *Errors) {
221 // FIXME: Ranges are currently full files. Support selecting specific
222 // (line-)ranges.
223 ClangTool Tool(Compilations, Ranges);
Alexander Kornienko09952d22014-03-20 09:38:22 +0000224 clang::tidy::ClangTidyContext Context(Errors, EnableChecksRegex,
225 DisableChecksRegex);
Daniel Jasperd07c8402013-07-29 08:19:24 +0000226 ClangTidyDiagnosticConsumer DiagConsumer(Context);
Manuel Klimek814f9bd2013-11-14 15:49:44 +0000227
228 Tool.setDiagnosticConsumer(&DiagConsumer);
Alexander Kornienko175fefb2014-01-03 09:31:57 +0000229
230 class ActionFactory : public FrontendActionFactory {
231 public:
232 ActionFactory(ClangTidyASTConsumerFactory *ConsumerFactory)
233 : ConsumerFactory(ConsumerFactory) {}
Alexander Kornienko21f3b772014-03-05 13:01:24 +0000234 FrontendAction *create() override { return new Action(ConsumerFactory); }
Alexander Kornienko175fefb2014-01-03 09:31:57 +0000235
236 private:
237 class Action : public ASTFrontendAction {
238 public:
239 Action(ClangTidyASTConsumerFactory *Factory) : Factory(Factory) {}
240 ASTConsumer *CreateASTConsumer(CompilerInstance &Compiler,
Craig Toppera3dbe842014-03-02 10:20:11 +0000241 StringRef File) override {
Alexander Kornienko175fefb2014-01-03 09:31:57 +0000242 return Factory->CreateASTConsumer(Compiler, File);
243 }
244
245 private:
246 ClangTidyASTConsumerFactory *Factory;
247 };
248
249 ClangTidyASTConsumerFactory *ConsumerFactory;
250 };
251
Alexander Kornienko09952d22014-03-20 09:38:22 +0000252 Tool.run(new ActionFactory(new ClangTidyASTConsumerFactory(Context)));
Manuel Klimek814f9bd2013-11-14 15:49:44 +0000253}
254
Alexander Kornienko54461eb2014-02-06 14:50:10 +0000255static SourceLocation getLocation(SourceManager &SourceMgr, StringRef FilePath,
256 unsigned Offset) {
257 if (FilePath.empty())
258 return SourceLocation();
259
260 const FileEntry *File = SourceMgr.getFileManager().getFile(FilePath);
261 FileID ID = SourceMgr.createFileID(File, SourceLocation(), SrcMgr::C_User);
262 return SourceMgr.getLocForStartOfFile(ID).getLocWithOffset(Offset);
263}
264
Manuel Klimek814f9bd2013-11-14 15:49:44 +0000265static void reportDiagnostic(const ClangTidyMessage &Message,
266 SourceManager &SourceMgr,
267 DiagnosticsEngine::Level Level,
Alexander Kornienko41bfe8d2014-01-13 10:50:51 +0000268 DiagnosticsEngine &Diags,
Alexander Kornienkodf1e3cb2014-03-06 10:17:46 +0000269 const tooling::Replacements *Fixes = NULL) {
Alexander Kornienko54461eb2014-02-06 14:50:10 +0000270 SourceLocation Loc =
271 getLocation(SourceMgr, Message.FilePath, Message.FileOffset);
272 DiagnosticBuilder Diag = Diags.Report(Loc, Diags.getCustomDiagID(Level, "%0"))
273 << Message.Message;
274 if (Fixes != NULL) {
Alexander Kornienkodf1e3cb2014-03-06 10:17:46 +0000275 for (const tooling::Replacement &Fix : *Fixes) {
Alexander Kornienko54461eb2014-02-06 14:50:10 +0000276 SourceLocation FixLoc =
Alexander Kornienkodf1e3cb2014-03-06 10:17:46 +0000277 getLocation(SourceMgr, Fix.getFilePath(), Fix.getOffset());
Alexander Kornienko54461eb2014-02-06 14:50:10 +0000278 Diag << FixItHint::CreateReplacement(
Alexander Kornienkodf1e3cb2014-03-06 10:17:46 +0000279 SourceRange(FixLoc, FixLoc.getLocWithOffset(Fix.getLength())),
280 Fix.getReplacementText());
Alexander Kornienko54461eb2014-02-06 14:50:10 +0000281 }
Daniel Jasperd07c8402013-07-29 08:19:24 +0000282 }
Daniel Jasperd07c8402013-07-29 08:19:24 +0000283}
284
285void handleErrors(SmallVectorImpl<ClangTidyError> &Errors, bool Fix) {
286 FileManager Files((FileSystemOptions()));
Nick Lewyckyccf8e292014-02-06 22:57:16 +0000287 LangOptions LangOpts; // FIXME: use langopts from each original file
Daniel Jasperd07c8402013-07-29 08:19:24 +0000288 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
Craig Topper6d73f442014-03-03 07:37:42 +0000289 DiagOpts->ShowColors = llvm::sys::Process::StandardOutHasColors();
Daniel Jasperd07c8402013-07-29 08:19:24 +0000290 DiagnosticConsumer *DiagPrinter =
291 new TextDiagnosticPrinter(llvm::outs(), &*DiagOpts);
292 DiagnosticsEngine Diags(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
293 &*DiagOpts, DiagPrinter);
Nick Lewyckyccf8e292014-02-06 22:57:16 +0000294 DiagPrinter->BeginSourceFile(LangOpts);
Daniel Jasperd07c8402013-07-29 08:19:24 +0000295 SourceManager SourceMgr(Diags, Files);
Nick Lewyckyccf8e292014-02-06 22:57:16 +0000296 Rewriter Rewrite(SourceMgr, LangOpts);
Alexander Kornienkodf1e3cb2014-03-06 10:17:46 +0000297 for (const ClangTidyError &Error : Errors) {
298 reportDiagnostic(Error.Message, SourceMgr, DiagnosticsEngine::Warning, Diags,
299 &Error.Fix);
300 for (const ClangTidyMessage &Note : Error.Notes)
301 reportDiagnostic(Note, SourceMgr, DiagnosticsEngine::Note, Diags);
302
303 tooling::applyAllReplacements(Error.Fix, Rewrite);
Daniel Jasperd07c8402013-07-29 08:19:24 +0000304 }
305 // FIXME: Run clang-format on changes.
306 if (Fix)
307 Rewrite.overwriteChangedFiles();
308}
309
Daniel Jasperd07c8402013-07-29 08:19:24 +0000310} // namespace tidy
311} // namespace clang