blob: 4dac7b6cd8ee3ea2e1f838a57986430d8d453df7 [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
10#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANG_TIDY_DIAGNOSTIC_CONSUMER_H
11#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANG_TIDY_DIAGNOSTIC_CONSUMER_H
12
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"
16#include "clang/Tooling/Refactoring.h"
Alexander Kornienko41bfe8d2014-01-13 10:50:51 +000017#include "llvm/ADT/DenseMap.h"
Alexander Kornienko09952d22014-03-20 09:38:22 +000018#include "llvm/Support/Regex.h"
Daniel Jasperd07c8402013-07-29 08:19:24 +000019
20namespace clang {
21
22class CompilerInstance;
23namespace ast_matchers {
24class MatchFinder;
25}
26namespace tooling {
27class CompilationDatabase;
28}
29
30namespace tidy {
31
Manuel Klimek814f9bd2013-11-14 15:49:44 +000032/// \brief A message from a clang-tidy check.
33///
34/// Note that this is independent of a \c SourceManager.
35struct ClangTidyMessage {
36 ClangTidyMessage(StringRef Message = "");
37 ClangTidyMessage(StringRef Message, const SourceManager &Sources,
38 SourceLocation Loc);
39 std::string Message;
40 std::string FilePath;
41 unsigned FileOffset;
42};
43
44/// \brief A detected error complete with information to display diagnostic and
45/// automatic fix.
46///
47/// This is used as an intermediate format to transport Diagnostics without a
48/// dependency on a SourceManager.
49///
50/// FIXME: Make Diagnostics flexible enough to support this directly.
51struct ClangTidyError {
Alexander Kornienko348cae82014-06-02 20:44:32 +000052 enum Level {
53 Warning = DiagnosticsEngine::Warning,
54 Error = DiagnosticsEngine::Error
55 };
56
57 ClangTidyError(StringRef CheckName, Level DiagLevel);
Manuel Klimek814f9bd2013-11-14 15:49:44 +000058
Alexander Kornienko41bfe8d2014-01-13 10:50:51 +000059 std::string CheckName;
Manuel Klimek814f9bd2013-11-14 15:49:44 +000060 ClangTidyMessage Message;
61 tooling::Replacements Fix;
62 SmallVector<ClangTidyMessage, 1> Notes;
Alexander Kornienko348cae82014-06-02 20:44:32 +000063
64 Level DiagLevel;
Manuel Klimek814f9bd2013-11-14 15:49:44 +000065};
66
Alexander Kornienko09952d22014-03-20 09:38:22 +000067/// \brief Filters checks by name.
68class ChecksFilter {
69public:
Alexander Kornienkoa4695222014-06-05 13:31:45 +000070 /// \brief \p GlobList is a comma-separated list of globs (only '*'
71 /// metacharacter is supported) with optional '-' prefix to denote exclusion.
Alexander Kornienko23fe9592014-05-15 14:27:36 +000072 ChecksFilter(StringRef GlobList);
Alexander Kornienkoa4695222014-06-05 13:31:45 +000073
74 /// \brief Returns \c true if the check with the specified \p Name should be
75 /// enabled. The result is the last matching glob's Positive flag. If \p Name
76 /// is not matched by any globs, the check is not enabled.
Alexander Kornienko23fe9592014-05-15 14:27:36 +000077 bool isCheckEnabled(StringRef Name) { return isCheckEnabled(Name, false); }
Alexander Kornienko09952d22014-03-20 09:38:22 +000078
79private:
Alexander Kornienko23fe9592014-05-15 14:27:36 +000080 bool isCheckEnabled(StringRef Name, bool Enabled);
81
82 bool Positive;
83 llvm::Regex Regex;
84 std::unique_ptr<ChecksFilter> NextFilter;
Alexander Kornienko09952d22014-03-20 09:38:22 +000085};
86
Alexander Kornienkoa4695222014-06-05 13:31:45 +000087/// \brief Contains displayed and ignored diagnostic counters for a ClangTidy
88/// run.
Alexander Kornienko5d174542014-05-07 09:06:53 +000089struct ClangTidyStats {
90 ClangTidyStats()
91 : ErrorsDisplayed(0), ErrorsIgnoredCheckFilter(0), ErrorsIgnoredNOLINT(0),
Alexander Kornienkodad4acb2014-05-22 16:07:11 +000092 ErrorsIgnoredNonUserCode(0), ErrorsIgnoredLineFilter(0) {}
Alexander Kornienko5d174542014-05-07 09:06:53 +000093
94 unsigned ErrorsDisplayed;
95 unsigned ErrorsIgnoredCheckFilter;
96 unsigned ErrorsIgnoredNOLINT;
97 unsigned ErrorsIgnoredNonUserCode;
Alexander Kornienkodad4acb2014-05-22 16:07:11 +000098 unsigned ErrorsIgnoredLineFilter;
99
100 unsigned errorsIgnored() const {
101 return ErrorsIgnoredNOLINT + ErrorsIgnoredCheckFilter +
102 ErrorsIgnoredNonUserCode + ErrorsIgnoredLineFilter;
103 }
Alexander Kornienko5d174542014-05-07 09:06:53 +0000104};
105
Manuel Klimek814f9bd2013-11-14 15:49:44 +0000106/// \brief Every \c ClangTidyCheck reports errors through a \c DiagnosticEngine
107/// provided by this context.
108///
109/// A \c ClangTidyCheck always has access to the active context to report
110/// warnings like:
111/// \code
112/// Context->Diag(Loc, "Single-argument constructors must be explicit")
113/// << FixItHint::CreateInsertion(Loc, "explicit ");
114/// \endcode
115class ClangTidyContext {
116public:
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000117 /// \brief Initializes \c ClangTidyContext instance.
118 ///
119 /// Takes ownership of the \c OptionsProvider.
120 ClangTidyContext(ClangTidyOptionsProvider *OptionsProvider);
Manuel Klimek814f9bd2013-11-14 15:49:44 +0000121
122 /// \brief Report any errors detected using this method.
123 ///
124 /// This is still under heavy development and will likely change towards using
125 /// tablegen'd diagnostic IDs.
126 /// FIXME: Figure out a way to manage ID spaces.
Alexander Kornienko41bfe8d2014-01-13 10:50:51 +0000127 DiagnosticBuilder diag(StringRef CheckName, SourceLocation Loc,
Alexander Kornienko54461eb2014-02-06 14:50:10 +0000128 StringRef Message,
129 DiagnosticIDs::Level Level = DiagnosticIDs::Warning);
Manuel Klimek814f9bd2013-11-14 15:49:44 +0000130
Manuel Klimek814f9bd2013-11-14 15:49:44 +0000131 /// \brief Sets the \c SourceManager of the used \c DiagnosticsEngine.
132 ///
133 /// This is called from the \c ClangTidyCheck base class.
134 void setSourceManager(SourceManager *SourceMgr);
135
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000136 /// \brief Should be called when starting to process new translation unit.
137 void setCurrentFile(StringRef File);
138
Alexander Kornienko41bfe8d2014-01-13 10:50:51 +0000139 /// \brief Returns the name of the clang-tidy check which produced this
140 /// diagnostic ID.
141 StringRef getCheckName(unsigned DiagnosticID) const;
142
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000143 /// \brief Returns check filter for the \c CurrentFile.
144 ChecksFilter &getChecksFilter();
145
146 /// \brief Returns global options.
147 const ClangTidyGlobalOptions &getGlobalOptions() const;
148
149 /// \brief Returns options for \c CurrentFile.
150 const ClangTidyOptions &getOptions() const;
151
152 /// \brief Returns \c ClangTidyStats containing issued and ignored diagnostic
153 /// counters.
Alexander Kornienko5d174542014-05-07 09:06:53 +0000154 const ClangTidyStats &getStats() const { return Stats; }
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000155
156 /// \brief Returns all collected errors.
Alexander Kornienko826b5ad2014-05-09 12:24:09 +0000157 const std::vector<ClangTidyError> &getErrors() const { return Errors; }
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000158
159 /// \brief Clears collected errors.
Alexander Kornienkoc0093602014-05-09 15:50:15 +0000160 void clearErrors() { Errors.clear(); }
Alexander Kornienko09952d22014-03-20 09:38:22 +0000161
Manuel Klimek814f9bd2013-11-14 15:49:44 +0000162private:
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000163 // Calls setDiagnosticsEngine() and storeError().
164 friend class ClangTidyDiagnosticConsumer;
Manuel Klimek814f9bd2013-11-14 15:49:44 +0000165
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000166 /// \brief Sets the \c DiagnosticsEngine so that Diagnostics can be generated
167 /// correctly.
168 void setDiagnosticsEngine(DiagnosticsEngine *Engine);
169
170 /// \brief Store an \p Error.
Manuel Klimek814f9bd2013-11-14 15:49:44 +0000171 void storeError(const ClangTidyError &Error);
172
Alexander Kornienko826b5ad2014-05-09 12:24:09 +0000173 std::vector<ClangTidyError> Errors;
NAKAMURA Takumi338eee12014-03-20 10:53:03 +0000174 DiagnosticsEngine *DiagEngine;
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000175 std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider;
176
177 std::string CurrentFile;
178 std::unique_ptr<ChecksFilter> CheckFilter;
179
Alexander Kornienko5d174542014-05-07 09:06:53 +0000180 ClangTidyStats Stats;
Alexander Kornienko09952d22014-03-20 09:38:22 +0000181
Alexander Kornienko41bfe8d2014-01-13 10:50:51 +0000182 llvm::DenseMap<unsigned, std::string> CheckNamesByDiagnosticID;
Manuel Klimek814f9bd2013-11-14 15:49:44 +0000183};
184
Daniel Jasperd07c8402013-07-29 08:19:24 +0000185/// \brief A diagnostic consumer that turns each \c Diagnostic into a
186/// \c SourceManager-independent \c ClangTidyError.
187//
188// FIXME: If we move away from unit-tests, this can be moved to a private
189// implementation file.
190class ClangTidyDiagnosticConsumer : public DiagnosticConsumer {
191public:
Alexander Kornienko0ba86b72014-01-09 16:31:25 +0000192 ClangTidyDiagnosticConsumer(ClangTidyContext &Ctx);
Daniel Jasperd07c8402013-07-29 08:19:24 +0000193
194 // FIXME: The concept of converting between FixItHints and Replacements is
195 // more generic and should be pulled out into a more useful Diagnostics
196 // library.
Alexander Kornienkocb9272f2014-02-27 13:14:51 +0000197 void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
Craig Toppera3dbe842014-03-02 10:20:11 +0000198 const Diagnostic &Info) override;
Manuel Klimek814f9bd2013-11-14 15:49:44 +0000199
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000200 /// \brief Sets \c HeaderFilter to the value configured for this file.
201 void BeginSourceFile(const LangOptions &LangOpts,
202 const Preprocessor *PP) override;
203
204 /// \brief Flushes the internal diagnostics buffer to the ClangTidyContext.
Craig Toppera3dbe842014-03-02 10:20:11 +0000205 void finish() override;
Daniel Jasperd07c8402013-07-29 08:19:24 +0000206
207private:
Alexander Kornienko54461eb2014-02-06 14:50:10 +0000208 void finalizeLastError();
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000209
210 /// \brief Updates \c LastErrorRelatesToUserCode and LastErrorPassesLineFilter
211 /// according to the diagnostic \p Location.
Alexander Kornienkodad4acb2014-05-22 16:07:11 +0000212 void checkFilters(SourceLocation Location);
213 bool passesLineFilter(StringRef FileName, unsigned LineNumber) const;
Manuel Klimek814f9bd2013-11-14 15:49:44 +0000214
Daniel Jasperd07c8402013-07-29 08:19:24 +0000215 ClangTidyContext &Context;
Ahmed Charles6a2dc5c2014-03-09 09:24:40 +0000216 std::unique_ptr<DiagnosticsEngine> Diags;
Manuel Klimek814f9bd2013-11-14 15:49:44 +0000217 SmallVector<ClangTidyError, 8> Errors;
Alexander Kornienkoa4695222014-06-05 13:31:45 +0000218 std::unique_ptr<llvm::Regex> HeaderFilter;
Alexander Kornienko54461eb2014-02-06 14:50:10 +0000219 bool LastErrorRelatesToUserCode;
Alexander Kornienkodad4acb2014-05-22 16:07:11 +0000220 bool LastErrorPassesLineFilter;
Daniel Jasperd07c8402013-07-29 08:19:24 +0000221};
222
223} // end namespace tidy
224} // end namespace clang
225
226#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANG_TIDY_DIAGNOSTIC_CONSUMER_H