clang-tools 17.0.0git
ClangTidyDiagnosticConsumer.h
Go to the documentation of this file.
1//===--- ClangTidyDiagnosticConsumer.h - clang-tidy -------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYDIAGNOSTICCONSUMER_H
10#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYDIAGNOSTICCONSUMER_H
11
12#include "ClangTidyOptions.h"
13#include "ClangTidyProfiling.h"
14#include "FileExtensionsSet.h"
16#include "clang/Basic/Diagnostic.h"
17#include "clang/Tooling/Core/Diagnostic.h"
18#include "llvm/ADT/DenseMap.h"
19#include "llvm/ADT/StringSet.h"
20#include "llvm/Support/Regex.h"
21#include <optional>
22
23namespace clang {
24
25class ASTContext;
26class SourceManager;
27
28namespace tidy {
29class CachedGlobList;
30
31/// A detected error complete with information to display diagnostic and
32/// automatic fix.
33///
34/// This is used as an intermediate format to transport Diagnostics without a
35/// dependency on a SourceManager.
36///
37/// FIXME: Make Diagnostics flexible enough to support this directly.
38struct ClangTidyError : tooling::Diagnostic {
39 ClangTidyError(StringRef CheckName, Level DiagLevel, StringRef BuildDirectory,
40 bool IsWarningAsError);
41
43 std::vector<std::string> EnabledDiagnosticAliases;
44};
45
46/// Contains displayed and ignored diagnostic counters for a ClangTidy run.
48 unsigned ErrorsDisplayed = 0;
50 unsigned ErrorsIgnoredNOLINT = 0;
53
54 unsigned errorsIgnored() const {
57 }
58};
59
60/// Every \c ClangTidyCheck reports errors through a \c DiagnosticsEngine
61/// provided by this context.
62///
63/// A \c ClangTidyCheck always has access to the active context to report
64/// warnings like:
65/// \code
66/// Context->Diag(Loc, "Single-argument constructors must be explicit")
67/// << FixItHint::CreateInsertion(Loc, "explicit ");
68/// \endcode
70public:
71 /// Initializes \c ClangTidyContext instance.
72 ClangTidyContext(std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider,
73 bool AllowEnablingAnalyzerAlphaCheckers = false);
74 /// Sets the DiagnosticsEngine that diag() will emit diagnostics to.
75 // FIXME: this is required initialization, and should be a constructor param.
76 // Fix the context -> diag engine -> consumer -> context initialization cycle.
77 void setDiagnosticsEngine(DiagnosticsEngine *DiagEngine) {
78 this->DiagEngine = DiagEngine;
79 }
80
82
83 /// Report any errors detected using this method.
84 ///
85 /// This is still under heavy development and will likely change towards using
86 /// tablegen'd diagnostic IDs.
87 /// FIXME: Figure out a way to manage ID spaces.
88 DiagnosticBuilder diag(StringRef CheckName, SourceLocation Loc,
89 StringRef Message,
90 DiagnosticIDs::Level Level = DiagnosticIDs::Warning);
91
92 DiagnosticBuilder diag(StringRef CheckName, StringRef Message,
93 DiagnosticIDs::Level Level = DiagnosticIDs::Warning);
94
95 DiagnosticBuilder diag(const tooling::Diagnostic &Error);
96
97 /// Report any errors to do with reading the configuration using this method.
98 DiagnosticBuilder
99 configurationDiag(StringRef Message,
100 DiagnosticIDs::Level Level = DiagnosticIDs::Warning);
101
102 /// Check whether a given diagnostic should be suppressed due to the presence
103 /// of a "NOLINT" suppression comment.
104 /// This is exposed so that other tools that present clang-tidy diagnostics
105 /// (such as clangd) can respect the same suppression rules as clang-tidy.
106 /// This does not handle suppression of notes following a suppressed
107 /// diagnostic; that is left to the caller as it requires maintaining state in
108 /// between calls to this function.
109 /// If any NOLINT is malformed, e.g. a BEGIN without a subsequent END, output
110 /// \param NoLintErrors will return an error about it.
111 /// If \param AllowIO is false, the function does not attempt to read source
112 /// files from disk which are not already mapped into memory; such files are
113 /// treated as not containing a suppression comment.
114 /// \param EnableNoLintBlocks controls whether to honor NOLINTBEGIN/NOLINTEND
115 /// blocks; if false, only considers line-level disabling.
116 bool
117 shouldSuppressDiagnostic(DiagnosticsEngine::Level DiagLevel,
118 const Diagnostic &Info,
119 SmallVectorImpl<tooling::Diagnostic> &NoLintErrors,
120 bool AllowIO = true, bool EnableNoLintBlocks = true);
121
122 /// Sets the \c SourceManager of the used \c DiagnosticsEngine.
123 ///
124 /// This is called from the \c ClangTidyCheck base class.
125 void setSourceManager(SourceManager *SourceMgr);
126
127 /// Should be called when starting to process new translation unit.
128 void setCurrentFile(StringRef File);
129
130 /// Returns the main file name of the current translation unit.
131 StringRef getCurrentFile() const { return CurrentFile; }
132
133 /// Sets ASTContext for the current translation unit.
134 void setASTContext(ASTContext *Context);
135
136 /// Gets the language options from the AST context.
137 const LangOptions &getLangOpts() const { return LangOpts; }
138
139 /// Returns the name of the clang-tidy check which produced this
140 /// diagnostic ID.
141 std::string getCheckName(unsigned DiagnosticID) const;
142
143 /// Returns \c true if the check is enabled for the \c CurrentFile.
144 ///
145 /// The \c CurrentFile can be changed using \c setCurrentFile.
146 bool isCheckEnabled(StringRef CheckName) const;
147
148 /// Returns \c true if the check should be upgraded to error for the
149 /// \c CurrentFile.
150 bool treatAsError(StringRef CheckName) const;
151
152 /// Returns global options.
154
155 /// Returns options for \c CurrentFile.
156 ///
157 /// The \c CurrentFile can be changed using \c setCurrentFile.
158 const ClangTidyOptions &getOptions() const;
159
160 /// Returns options for \c File. Does not change or depend on
161 /// \c CurrentFile.
162 ClangTidyOptions getOptionsForFile(StringRef File) const;
163
165 return HeaderFileExtensions;
166 }
167
169 return ImplementationFileExtensions;
170 }
171
172 /// Returns \c ClangTidyStats containing issued and ignored diagnostic
173 /// counters.
174 const ClangTidyStats &getStats() const { return Stats; }
175
176 /// Control profile collection in clang-tidy.
177 void setEnableProfiling(bool Profile);
178 bool getEnableProfiling() const { return Profile; }
179
180 /// Control storage of profile date.
181 void setProfileStoragePrefix(StringRef ProfilePrefix);
182 std::optional<ClangTidyProfiling::StorageParams>
184
185 /// Should be called when starting to process new translation unit.
186 void setCurrentBuildDirectory(StringRef BuildDirectory) {
187 CurrentBuildDirectory = std::string(BuildDirectory);
188 }
189
190 /// Returns build directory of the current translation unit.
191 const std::string &getCurrentBuildDirectory() const {
192 return CurrentBuildDirectory;
193 }
194
195 /// If the experimental alpha checkers from the static analyzer can be
196 /// enabled.
198 return AllowEnablingAnalyzerAlphaCheckers;
199 }
200
201 void setSelfContainedDiags(bool Value) { SelfContainedDiags = Value; }
202
203 bool areDiagsSelfContained() const { return SelfContainedDiags; }
204
205 using DiagLevelAndFormatString = std::pair<DiagnosticIDs::Level, std::string>;
207 SourceLocation Loc) {
209 static_cast<DiagnosticIDs::Level>(
210 DiagEngine->getDiagnosticLevel(DiagnosticID, Loc)),
211 std::string(
212 DiagEngine->getDiagnosticIDs()->getDescription(DiagnosticID)));
213 }
214
215 void setOptionsCollector(llvm::StringSet<> *Collector) {
216 OptionsCollector = Collector;
217 }
218 llvm::StringSet<> *getOptionsCollector() const { return OptionsCollector; }
219
220private:
221 // Writes to Stats.
223
224 DiagnosticsEngine *DiagEngine;
225 std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider;
226
227 std::string CurrentFile;
228 ClangTidyOptions CurrentOptions;
229
230 std::unique_ptr<CachedGlobList> CheckFilter;
231 std::unique_ptr<CachedGlobList> WarningAsErrorFilter;
232
233 FileExtensionsSet HeaderFileExtensions;
234 FileExtensionsSet ImplementationFileExtensions;
235
236 LangOptions LangOpts;
237
238 ClangTidyStats Stats;
239
240 std::string CurrentBuildDirectory;
241
242 llvm::DenseMap<unsigned, std::string> CheckNamesByDiagnosticID;
243
244 bool Profile;
245 std::string ProfilePrefix;
246
248
249 bool SelfContainedDiags;
250
251 NoLintDirectiveHandler NoLintHandler;
252 llvm::StringSet<> *OptionsCollector = nullptr;
253};
254
255/// Gets the Fix attached to \p Diagnostic.
256/// If there isn't a Fix attached to the diagnostic and \p AnyFix is true, Check
257/// to see if exactly one note has a Fix and return it. Otherwise return
258/// nullptr.
259const llvm::StringMap<tooling::Replacements> *
260getFixIt(const tooling::Diagnostic &Diagnostic, bool AnyFix);
261
262/// A diagnostic consumer that turns each \c Diagnostic into a
263/// \c SourceManager-independent \c ClangTidyError.
264// FIXME: If we move away from unit-tests, this can be moved to a private
265// implementation file.
267public:
268 /// \param EnableNolintBlocks Enables diagnostic-disabling inside blocks of
269 /// code, delimited by NOLINTBEGIN and NOLINTEND.
271 DiagnosticsEngine *ExternalDiagEngine = nullptr,
272 bool RemoveIncompatibleErrors = true,
273 bool GetFixesFromNotes = false,
274 bool EnableNolintBlocks = true);
275
276 // FIXME: The concept of converting between FixItHints and Replacements is
277 // more generic and should be pulled out into a more useful Diagnostics
278 // library.
279 void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
280 const Diagnostic &Info) override;
281
282 // Retrieve the diagnostics that were captured.
283 std::vector<ClangTidyError> take();
284
285private:
286 void finalizeLastError();
287 void removeIncompatibleErrors();
288 void removeDuplicatedDiagnosticsOfAliasCheckers();
289
290 /// Returns the \c HeaderFilter constructed for the options set in the
291 /// context.
292 llvm::Regex *getHeaderFilter();
293
294 /// Updates \c LastErrorRelatesToUserCode and LastErrorPassesLineFilter
295 /// according to the diagnostic \p Location.
296 void checkFilters(SourceLocation Location, const SourceManager &Sources);
297 bool passesLineFilter(StringRef FileName, unsigned LineNumber) const;
298
299 void forwardDiagnostic(const Diagnostic &Info);
300
301 ClangTidyContext &Context;
302 DiagnosticsEngine *ExternalDiagEngine;
303 bool RemoveIncompatibleErrors;
304 bool GetFixesFromNotes;
305 bool EnableNolintBlocks;
306 std::vector<ClangTidyError> Errors;
307 std::unique_ptr<llvm::Regex> HeaderFilter;
308 bool LastErrorRelatesToUserCode;
309 bool LastErrorPassesLineFilter;
310 bool LastErrorWasIgnored;
311};
312
313} // end namespace tidy
314} // end namespace clang
315
316#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYDIAGNOSTICCONSUMER_H
static cl::opt< bool > AllowEnablingAnalyzerAlphaCheckers("allow-enabling-analyzer-alpha-checkers", cl::init(false), cl::Hidden, cl::cat(ClangTidyCategory))
This option allows enabling the experimental alpha checkers from the static analyzer.
static constexpr llvm::SourceMgr::DiagKind Error
DiagnosticCallback Diagnostic
FunctionInfo Info
StringRef FileName
SourceLocation Loc
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
const ClangTidyStats & getStats() const
Returns ClangTidyStats containing issued and ignored diagnostic counters.
bool canEnableAnalyzerAlphaCheckers() const
If the experimental alpha checkers from the static analyzer can be enabled.
bool isCheckEnabled(StringRef CheckName) const
Returns true if the check is enabled for the CurrentFile.
std::string getCheckName(unsigned DiagnosticID) const
Returns the name of the clang-tidy check which produced this diagnostic ID.
void setOptionsCollector(llvm::StringSet<> *Collector)
const ClangTidyOptions & getOptions() const
Returns options for CurrentFile.
llvm::StringSet * getOptionsCollector() const
const std::string & getCurrentBuildDirectory() const
Returns build directory of the current translation unit.
void setCurrentBuildDirectory(StringRef BuildDirectory)
Should be called when starting to process new translation unit.
const LangOptions & getLangOpts() const
Gets the language options from the AST context.
DiagnosticBuilder configurationDiag(StringRef Message, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Report any errors to do with reading the configuration using this method.
void setASTContext(ASTContext *Context)
Sets ASTContext for the current translation unit.
const FileExtensionsSet & getHeaderFileExtensions() const
void setProfileStoragePrefix(StringRef ProfilePrefix)
Control storage of profile date.
void setDiagnosticsEngine(DiagnosticsEngine *DiagEngine)
Sets the DiagnosticsEngine that diag() will emit diagnostics to.
void setEnableProfiling(bool Profile)
Control profile collection in clang-tidy.
DiagLevelAndFormatString getDiagLevelAndFormatString(unsigned DiagnosticID, SourceLocation Loc)
std::pair< DiagnosticIDs::Level, std::string > DiagLevelAndFormatString
void setCurrentFile(StringRef File)
Should be called when starting to process new translation unit.
bool shouldSuppressDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info, SmallVectorImpl< tooling::Diagnostic > &NoLintErrors, bool AllowIO=true, bool EnableNoLintBlocks=true)
Check whether a given diagnostic should be suppressed due to the presence of a "NOLINT" suppression c...
bool treatAsError(StringRef CheckName) const
Returns true if the check should be upgraded to error for the CurrentFile.
ClangTidyOptions getOptionsForFile(StringRef File) const
Returns options for File.
std::optional< ClangTidyProfiling::StorageParams > getProfileStorageParams() const
StringRef getCurrentFile() const
Returns the main file name of the current translation unit.
const ClangTidyGlobalOptions & getGlobalOptions() const
Returns global options.
DiagnosticBuilder diag(StringRef CheckName, SourceLocation Loc, StringRef Message, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Report any errors detected using this method.
void setSourceManager(SourceManager *SourceMgr)
Sets the SourceManager of the used DiagnosticsEngine.
const FileExtensionsSet & getImplementationFileExtensions() const
A diagnostic consumer that turns each Diagnostic into a SourceManager-independent ClangTidyError.
void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) override
This class is used to locate NOLINT comments in the file being analyzed, to decide whether a diagnost...
const llvm::StringMap< tooling::Replacements > * getFixIt(const tooling::Diagnostic &Diagnostic, bool GetFixFromNotes)
Gets the Fix attached to Diagnostic.
llvm::SmallSet< llvm::StringRef, 5 > FileExtensionsSet
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
A detected error complete with information to display diagnostic and automatic fix.
std::vector< std::string > EnabledDiagnosticAliases
Contains options for clang-tidy.
Contains displayed and ignored diagnostic counters for a ClangTidy run.