blob: b484794676d17714d24af334d16454f49e0a2b89 [file] [log] [blame]
Daniel Jasperd07c8402013-07-29 08:19:24 +00001//===--- ClangTidyDiagnosticConsumer.h - clang-tidy -------------*- C++ -*-===//
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
Alexander Kornienko66580552015-03-09 16:52:33 +000010#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYDIAGNOSTICCONSUMER_H
11#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYDIAGNOSTICCONSUMER_H
Daniel Jasperd07c8402013-07-29 08:19:24 +000012
Alexander Kornienko9ff5b6f2014-05-05 14:54:47 +000013#include "ClangTidyOptions.h"
Daniel Jasperd07c8402013-07-29 08:19:24 +000014#include "clang/Basic/Diagnostic.h"
15#include "clang/Basic/SourceManager.h"
Alexander Kornienko563de792017-01-03 14:36:13 +000016#include "clang/Tooling/Core/Diagnostic.h"
Daniel Jasperd07c8402013-07-29 08:19:24 +000017#include "clang/Tooling/Refactoring.h"
Alexander Kornienko41bfe8d2014-01-13 10:50:51 +000018#include "llvm/ADT/DenseMap.h"
Samuel Benzaquenaedd9942014-10-23 17:23:20 +000019#include "llvm/ADT/StringMap.h"
Alexander Kornienko09952d22014-03-20 09:38:22 +000020#include "llvm/Support/Regex.h"
Samuel Benzaquenaedd9942014-10-23 17:23:20 +000021#include "llvm/Support/Timer.h"
Daniel Jasperd07c8402013-07-29 08:19:24 +000022
23namespace clang {
24
Alexander Kornienkoad216882014-07-14 14:10:03 +000025class ASTContext;
Daniel Jasperd07c8402013-07-29 08:19:24 +000026class CompilerInstance;
27namespace ast_matchers {
28class MatchFinder;
29}
30namespace tooling {
31class CompilationDatabase;
32}
33
34namespace tidy {
35
Manuel Klimek814f9bd2013-11-14 15:49:44 +000036/// \brief A detected error complete with information to display diagnostic and
37/// automatic fix.
38///
39/// This is used as an intermediate format to transport Diagnostics without a
40/// dependency on a SourceManager.
41///
42/// FIXME: Make Diagnostics flexible enough to support this directly.
Alexander Kornienko563de792017-01-03 14:36:13 +000043struct ClangTidyError : tooling::Diagnostic {
44 ClangTidyError(StringRef CheckName, Level DiagLevel, StringRef BuildDirectory,
45 bool IsWarningAsError);
Alexander Kornienko348cae82014-06-02 20:44:32 +000046
Jonathan Roelofsd60388a2016-01-13 17:36:41 +000047 bool IsWarningAsError;
Manuel Klimek814f9bd2013-11-14 15:49:44 +000048};
49
Alexander Kornienkob3d331d2014-08-06 11:49:10 +000050/// \brief Read-only set of strings represented as a list of positive and
51/// negative globs. Positive globs add all matched strings to the set, negative
52/// globs remove them in the order of appearance in the list.
53class GlobList {
Alexander Kornienko09952d22014-03-20 09:38:22 +000054public:
Alexander Kornienkoa4695222014-06-05 13:31:45 +000055 /// \brief \p GlobList is a comma-separated list of globs (only '*'
56 /// metacharacter is supported) with optional '-' prefix to denote exclusion.
Alexander Kornienkob3d331d2014-08-06 11:49:10 +000057 GlobList(StringRef Globs);
Alexander Kornienkoa4695222014-06-05 13:31:45 +000058
Alexander Kornienkob3d331d2014-08-06 11:49:10 +000059 /// \brief Returns \c true if the pattern matches \p S. The result is the last
60 /// matching glob's Positive flag.
61 bool contains(StringRef S) { return contains(S, false); }
Alexander Kornienko09952d22014-03-20 09:38:22 +000062
63private:
Alexander Kornienkob3d331d2014-08-06 11:49:10 +000064 bool contains(StringRef S, bool Contains);
Alexander Kornienko23fe9592014-05-15 14:27:36 +000065
66 bool Positive;
67 llvm::Regex Regex;
Alexander Kornienkob3d331d2014-08-06 11:49:10 +000068 std::unique_ptr<GlobList> NextGlob;
Alexander Kornienko09952d22014-03-20 09:38:22 +000069};
70
Alexander Kornienkoa4695222014-06-05 13:31:45 +000071/// \brief Contains displayed and ignored diagnostic counters for a ClangTidy
72/// run.
Alexander Kornienko5d174542014-05-07 09:06:53 +000073struct ClangTidyStats {
74 ClangTidyStats()
75 : ErrorsDisplayed(0), ErrorsIgnoredCheckFilter(0), ErrorsIgnoredNOLINT(0),
Alexander Kornienkodad4acb2014-05-22 16:07:11 +000076 ErrorsIgnoredNonUserCode(0), ErrorsIgnoredLineFilter(0) {}
Alexander Kornienko5d174542014-05-07 09:06:53 +000077
78 unsigned ErrorsDisplayed;
79 unsigned ErrorsIgnoredCheckFilter;
80 unsigned ErrorsIgnoredNOLINT;
81 unsigned ErrorsIgnoredNonUserCode;
Alexander Kornienkodad4acb2014-05-22 16:07:11 +000082 unsigned ErrorsIgnoredLineFilter;
83
84 unsigned errorsIgnored() const {
85 return ErrorsIgnoredNOLINT + ErrorsIgnoredCheckFilter +
86 ErrorsIgnoredNonUserCode + ErrorsIgnoredLineFilter;
87 }
Alexander Kornienko5d174542014-05-07 09:06:53 +000088};
89
Samuel Benzaquenaedd9942014-10-23 17:23:20 +000090/// \brief Container for clang-tidy profiling data.
91struct ProfileData {
92 llvm::StringMap<llvm::TimeRecord> Records;
93};
94
Alexander Kornienko284c2492014-12-19 15:37:02 +000095/// \brief Every \c ClangTidyCheck reports errors through a \c DiagnosticsEngine
Manuel Klimek814f9bd2013-11-14 15:49:44 +000096/// provided by this context.
97///
98/// A \c ClangTidyCheck always has access to the active context to report
99/// warnings like:
100/// \code
101/// Context->Diag(Loc, "Single-argument constructors must be explicit")
102/// << FixItHint::CreateInsertion(Loc, "explicit ");
103/// \endcode
104class ClangTidyContext {
105public:
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000106 /// \brief Initializes \c ClangTidyContext instance.
Alexander Kornienkod53d2682014-09-04 14:23:36 +0000107 ClangTidyContext(std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider);
Manuel Klimek814f9bd2013-11-14 15:49:44 +0000108
Alexander Kornienko61803372017-05-18 01:13:51 +0000109 ~ClangTidyContext();
110
Manuel Klimek814f9bd2013-11-14 15:49:44 +0000111 /// \brief Report any errors detected using this method.
112 ///
113 /// This is still under heavy development and will likely change towards using
114 /// tablegen'd diagnostic IDs.
115 /// FIXME: Figure out a way to manage ID spaces.
Alexander Kornienko41bfe8d2014-01-13 10:50:51 +0000116 DiagnosticBuilder diag(StringRef CheckName, SourceLocation Loc,
Alexander Kornienko54461eb2014-02-06 14:50:10 +0000117 StringRef Message,
118 DiagnosticIDs::Level Level = DiagnosticIDs::Warning);
Manuel Klimek814f9bd2013-11-14 15:49:44 +0000119
Manuel Klimek814f9bd2013-11-14 15:49:44 +0000120 /// \brief Sets the \c SourceManager of the used \c DiagnosticsEngine.
121 ///
122 /// This is called from the \c ClangTidyCheck base class.
123 void setSourceManager(SourceManager *SourceMgr);
124
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000125 /// \brief Should be called when starting to process new translation unit.
126 void setCurrentFile(StringRef File);
127
Alexander Kornienko19bbeaf2015-05-21 14:08:56 +0000128 /// \brief Returns the main file name of the current translation unit.
129 StringRef getCurrentFile() const { return CurrentFile; }
130
Alexander Kornienkoad216882014-07-14 14:10:03 +0000131 /// \brief Sets ASTContext for the current translation unit.
132 void setASTContext(ASTContext *Context);
133
Alexander Kornienko64956b52015-11-09 16:28:11 +0000134 /// \brief Gets the language options from the AST context.
Alexander Kornienko1612fa02016-02-25 23:57:23 +0000135 const LangOptions &getLangOpts() const { return LangOpts; }
Aaron Ballmanf36a4252015-08-28 13:20:46 +0000136
Alexander Kornienko41bfe8d2014-01-13 10:50:51 +0000137 /// \brief Returns the name of the clang-tidy check which produced this
138 /// diagnostic ID.
139 StringRef getCheckName(unsigned DiagnosticID) const;
140
Alexander Kornienko21375182017-05-17 14:39:47 +0000141 /// \brief Returns \c true if the check is enabled for the \c CurrentFile.
Alexander Kornienko64956b52015-11-09 16:28:11 +0000142 ///
143 /// The \c CurrentFile can be changed using \c setCurrentFile.
Alexander Kornienko21375182017-05-17 14:39:47 +0000144 bool isCheckEnabled(StringRef CheckName) const;
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000145
Alexander Kornienko21375182017-05-17 14:39:47 +0000146 /// \brief Returns \c true if the check should be upgraded to error for the
147 /// \c CurrentFile.
148 bool treatAsError(StringRef CheckName) const;
Jonathan Roelofsd60388a2016-01-13 17:36:41 +0000149
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000150 /// \brief Returns global options.
151 const ClangTidyGlobalOptions &getGlobalOptions() const;
152
153 /// \brief Returns options for \c CurrentFile.
Alexander Kornienko64956b52015-11-09 16:28:11 +0000154 ///
155 /// The \c CurrentFile can be changed using \c setCurrentFile.
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000156 const ClangTidyOptions &getOptions() const;
157
Alexander Kornienko64956b52015-11-09 16:28:11 +0000158 /// \brief Returns options for \c File. Does not change or depend on
159 /// \c CurrentFile.
160 ClangTidyOptions getOptionsForFile(StringRef File) const;
161
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000162 /// \brief Returns \c ClangTidyStats containing issued and ignored diagnostic
163 /// counters.
Alexander Kornienko5d174542014-05-07 09:06:53 +0000164 const ClangTidyStats &getStats() const { return Stats; }
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000165
166 /// \brief Returns all collected errors.
Alexander Kornienko25613202017-04-06 13:41:29 +0000167 ArrayRef<ClangTidyError> getErrors() const { return Errors; }
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000168
169 /// \brief Clears collected errors.
Alexander Kornienkoc0093602014-05-09 15:50:15 +0000170 void clearErrors() { Errors.clear(); }
Alexander Kornienko09952d22014-03-20 09:38:22 +0000171
Samuel Benzaquenaedd9942014-10-23 17:23:20 +0000172 /// \brief Set the output struct for profile data.
173 ///
174 /// Setting a non-null pointer here will enable profile collection in
175 /// clang-tidy.
Angel Garcia Gomez16693572015-10-16 11:43:49 +0000176 void setCheckProfileData(ProfileData *Profile);
177 ProfileData *getCheckProfileData() const { return Profile; }
Samuel Benzaquenaedd9942014-10-23 17:23:20 +0000178
Haojian Wuf7692a22016-02-26 09:19:33 +0000179 /// \brief Should be called when starting to process new translation unit.
180 void setCurrentBuildDirectory(StringRef BuildDirectory) {
181 CurrentBuildDirectory = BuildDirectory;
182 }
183
184 /// \brief Returns build directory of the current translation unit.
185 const std::string &getCurrentBuildDirectory() {
186 return CurrentBuildDirectory;
187 }
188
Manuel Klimek814f9bd2013-11-14 15:49:44 +0000189private:
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000190 // Calls setDiagnosticsEngine() and storeError().
191 friend class ClangTidyDiagnosticConsumer;
Benjamin Kramer8f5eb562016-03-03 08:58:12 +0000192 friend class ClangTidyPluginAction;
Manuel Klimek814f9bd2013-11-14 15:49:44 +0000193
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000194 /// \brief Sets the \c DiagnosticsEngine so that Diagnostics can be generated
195 /// correctly.
196 void setDiagnosticsEngine(DiagnosticsEngine *Engine);
197
198 /// \brief Store an \p Error.
Manuel Klimek814f9bd2013-11-14 15:49:44 +0000199 void storeError(const ClangTidyError &Error);
200
Alexander Kornienko826b5ad2014-05-09 12:24:09 +0000201 std::vector<ClangTidyError> Errors;
NAKAMURA Takumi338eee12014-03-20 10:53:03 +0000202 DiagnosticsEngine *DiagEngine;
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000203 std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider;
204
205 std::string CurrentFile;
Alexander Kornienkod53d2682014-09-04 14:23:36 +0000206 ClangTidyOptions CurrentOptions;
Alexander Kornienko61803372017-05-18 01:13:51 +0000207 class CachedGlobList;
208 std::unique_ptr<CachedGlobList> CheckFilter;
209 std::unique_ptr<CachedGlobList> WarningAsErrorFilter;
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000210
Aaron Ballmanf36a4252015-08-28 13:20:46 +0000211 LangOptions LangOpts;
212
Alexander Kornienko5d174542014-05-07 09:06:53 +0000213 ClangTidyStats Stats;
Alexander Kornienko09952d22014-03-20 09:38:22 +0000214
Haojian Wuf7692a22016-02-26 09:19:33 +0000215 std::string CurrentBuildDirectory;
216
Alexander Kornienko41bfe8d2014-01-13 10:50:51 +0000217 llvm::DenseMap<unsigned, std::string> CheckNamesByDiagnosticID;
Samuel Benzaquenaedd9942014-10-23 17:23:20 +0000218
219 ProfileData *Profile;
Manuel Klimek814f9bd2013-11-14 15:49:44 +0000220};
221
Daniel Jasperd07c8402013-07-29 08:19:24 +0000222/// \brief A diagnostic consumer that turns each \c Diagnostic into a
223/// \c SourceManager-independent \c ClangTidyError.
224//
225// FIXME: If we move away from unit-tests, this can be moved to a private
226// implementation file.
227class ClangTidyDiagnosticConsumer : public DiagnosticConsumer {
228public:
Alexander Kornienko9660d4d2017-05-09 15:10:26 +0000229 ClangTidyDiagnosticConsumer(ClangTidyContext &Ctx,
230 bool RemoveIncompatibleErrors = true);
Daniel Jasperd07c8402013-07-29 08:19:24 +0000231
232 // FIXME: The concept of converting between FixItHints and Replacements is
233 // more generic and should be pulled out into a more useful Diagnostics
234 // library.
Alexander Kornienkocb9272f2014-02-27 13:14:51 +0000235 void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
Craig Toppera3dbe842014-03-02 10:20:11 +0000236 const Diagnostic &Info) override;
Manuel Klimek814f9bd2013-11-14 15:49:44 +0000237
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000238 /// \brief Flushes the internal diagnostics buffer to the ClangTidyContext.
Craig Toppera3dbe842014-03-02 10:20:11 +0000239 void finish() override;
Daniel Jasperd07c8402013-07-29 08:19:24 +0000240
241private:
Alexander Kornienko54461eb2014-02-06 14:50:10 +0000242 void finalizeLastError();
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000243
Angel Garcia Gomez16693572015-10-16 11:43:49 +0000244 void removeIncompatibleErrors(SmallVectorImpl<ClangTidyError> &Errors) const;
245
Daniel Jasper4d871f92015-08-12 13:16:41 +0000246 /// \brief Returns the \c HeaderFilter constructed for the options set in the
247 /// context.
Angel Garcia Gomez16693572015-10-16 11:43:49 +0000248 llvm::Regex *getHeaderFilter();
Daniel Jasper4d871f92015-08-12 13:16:41 +0000249
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000250 /// \brief Updates \c LastErrorRelatesToUserCode and LastErrorPassesLineFilter
251 /// according to the diagnostic \p Location.
Alexander Kornienkodad4acb2014-05-22 16:07:11 +0000252 void checkFilters(SourceLocation Location);
253 bool passesLineFilter(StringRef FileName, unsigned LineNumber) const;
Manuel Klimek814f9bd2013-11-14 15:49:44 +0000254
Daniel Jasperd07c8402013-07-29 08:19:24 +0000255 ClangTidyContext &Context;
Alexander Kornienko9660d4d2017-05-09 15:10:26 +0000256 bool RemoveIncompatibleErrors;
Ahmed Charles6a2dc5c2014-03-09 09:24:40 +0000257 std::unique_ptr<DiagnosticsEngine> Diags;
Manuel Klimek814f9bd2013-11-14 15:49:44 +0000258 SmallVector<ClangTidyError, 8> Errors;
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000259 std::unique_ptr<llvm::Regex> HeaderFilter;
Alexander Kornienko54461eb2014-02-06 14:50:10 +0000260 bool LastErrorRelatesToUserCode;
Alexander Kornienkodad4acb2014-05-22 16:07:11 +0000261 bool LastErrorPassesLineFilter;
Malcolm Parsonscb2e7492016-11-02 21:14:22 +0000262 bool LastErrorWasIgnored;
Daniel Jasperd07c8402013-07-29 08:19:24 +0000263};
264
265} // end namespace tidy
266} // end namespace clang
267
Alexander Kornienko66580552015-03-09 16:52:33 +0000268#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYDIAGNOSTICCONSUMER_H