clang-tools 19.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 bool EnableModuleHeadersParsing = false);
75 /// Sets the DiagnosticsEngine that diag() will emit diagnostics to.
76 // FIXME: this is required initialization, and should be a constructor param.
77 // Fix the context -> diag engine -> consumer -> context initialization cycle.
78 void setDiagnosticsEngine(DiagnosticsEngine *DiagEngine) {
79 this->DiagEngine = DiagEngine;
80 }
81
83
84 /// Report any errors detected using this method.
85 ///
86 /// This is still under heavy development and will likely change towards using
87 /// tablegen'd diagnostic IDs.
88 /// FIXME: Figure out a way to manage ID spaces.
89 DiagnosticBuilder diag(StringRef CheckName, SourceLocation Loc,
90 StringRef Description,
91 DiagnosticIDs::Level Level = DiagnosticIDs::Warning);
92
93 DiagnosticBuilder diag(StringRef CheckName, StringRef Description,
94 DiagnosticIDs::Level Level = DiagnosticIDs::Warning);
95
96 DiagnosticBuilder diag(const tooling::Diagnostic &Error);
97
98 /// Report any errors to do with reading the configuration using this method.
99 DiagnosticBuilder
100 configurationDiag(StringRef Message,
101 DiagnosticIDs::Level Level = DiagnosticIDs::Warning);
102
103 /// Check whether a given diagnostic should be suppressed due to the presence
104 /// of a "NOLINT" suppression comment.
105 /// This is exposed so that other tools that present clang-tidy diagnostics
106 /// (such as clangd) can respect the same suppression rules as clang-tidy.
107 /// This does not handle suppression of notes following a suppressed
108 /// diagnostic; that is left to the caller as it requires maintaining state in
109 /// between calls to this function.
110 /// If any NOLINT is malformed, e.g. a BEGIN without a subsequent END, output
111 /// \param NoLintErrors will return an error about it.
112 /// If \param AllowIO is false, the function does not attempt to read source
113 /// files from disk which are not already mapped into memory; such files are
114 /// treated as not containing a suppression comment.
115 /// \param EnableNoLintBlocks controls whether to honor NOLINTBEGIN/NOLINTEND
116 /// blocks; if false, only considers line-level disabling.
117 bool
118 shouldSuppressDiagnostic(DiagnosticsEngine::Level DiagLevel,
119 const Diagnostic &Info,
120 SmallVectorImpl<tooling::Diagnostic> &NoLintErrors,
121 bool AllowIO = true, bool EnableNoLintBlocks = true);
122
123 /// Sets the \c SourceManager of the used \c DiagnosticsEngine.
124 ///
125 /// This is called from the \c ClangTidyCheck base class.
126 void setSourceManager(SourceManager *SourceMgr);
127
128 /// Should be called when starting to process new translation unit.
129 void setCurrentFile(StringRef File);
130
131 /// Returns the main file name of the current translation unit.
132 StringRef getCurrentFile() const { return CurrentFile; }
133
134 /// Sets ASTContext for the current translation unit.
135 void setASTContext(ASTContext *Context);
136
137 /// Gets the language options from the AST context.
138 const LangOptions &getLangOpts() const { return LangOpts; }
139
140 /// Returns the name of the clang-tidy check which produced this
141 /// diagnostic ID.
142 std::string getCheckName(unsigned DiagnosticID) const;
143
144 /// Returns \c true if the check is enabled for the \c CurrentFile.
145 ///
146 /// The \c CurrentFile can be changed using \c setCurrentFile.
147 bool isCheckEnabled(StringRef CheckName) const;
148
149 /// Returns \c true if the check should be upgraded to error for the
150 /// \c CurrentFile.
151 bool treatAsError(StringRef CheckName) const;
152
153 /// Returns global options.
155
156 /// Returns options for \c CurrentFile.
157 ///
158 /// The \c CurrentFile can be changed using \c setCurrentFile.
159 const ClangTidyOptions &getOptions() const;
160
161 /// Returns options for \c File. Does not change or depend on
162 /// \c CurrentFile.
163 ClangTidyOptions getOptionsForFile(StringRef File) const;
164
166 return HeaderFileExtensions;
167 }
168
170 return ImplementationFileExtensions;
171 }
172
173 /// Returns \c ClangTidyStats containing issued and ignored diagnostic
174 /// counters.
175 const ClangTidyStats &getStats() const { return Stats; }
176
177 /// Control profile collection in clang-tidy.
178 void setEnableProfiling(bool Profile);
179 bool getEnableProfiling() const { return Profile; }
180
181 /// Control storage of profile date.
182 void setProfileStoragePrefix(StringRef ProfilePrefix);
183 std::optional<ClangTidyProfiling::StorageParams>
185
186 /// Should be called when starting to process new translation unit.
187 void setCurrentBuildDirectory(StringRef BuildDirectory) {
188 CurrentBuildDirectory = std::string(BuildDirectory);
189 }
190
191 /// Returns build directory of the current translation unit.
192 const std::string &getCurrentBuildDirectory() const {
193 return CurrentBuildDirectory;
194 }
195
196 /// If the experimental alpha checkers from the static analyzer can be
197 /// enabled.
199 return AllowEnablingAnalyzerAlphaCheckers;
200 }
201
202 // This method determines whether preprocessor-level module header parsing is
203 // enabled using the `--experimental-enable-module-headers-parsing` option.
205 return EnableModuleHeadersParsing;
206 }
207
208 void setSelfContainedDiags(bool Value) { SelfContainedDiags = Value; }
209
210 bool areDiagsSelfContained() const { return SelfContainedDiags; }
211
212 using DiagLevelAndFormatString = std::pair<DiagnosticIDs::Level, std::string>;
214 SourceLocation Loc) {
215 return {
216 static_cast<DiagnosticIDs::Level>(
217 DiagEngine->getDiagnosticLevel(DiagnosticID, Loc)),
218 std::string(
219 DiagEngine->getDiagnosticIDs()->getDescription(DiagnosticID))};
220 }
221
222 void setOptionsCollector(llvm::StringSet<> *Collector) {
223 OptionsCollector = Collector;
224 }
225 llvm::StringSet<> *getOptionsCollector() const { return OptionsCollector; }
226
227private:
228 // Writes to Stats.
230
231 DiagnosticsEngine *DiagEngine = nullptr;
232 std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider;
233
234 std::string CurrentFile;
235 ClangTidyOptions CurrentOptions;
236
237 std::unique_ptr<CachedGlobList> CheckFilter;
238 std::unique_ptr<CachedGlobList> WarningAsErrorFilter;
239
240 FileExtensionsSet HeaderFileExtensions;
241 FileExtensionsSet ImplementationFileExtensions;
242
243 LangOptions LangOpts;
244
245 ClangTidyStats Stats;
246
247 std::string CurrentBuildDirectory;
248
249 llvm::DenseMap<unsigned, std::string> CheckNamesByDiagnosticID;
250
251 bool Profile = false;
252 std::string ProfilePrefix;
253
256
257 bool SelfContainedDiags = false;
258
259 NoLintDirectiveHandler NoLintHandler;
260 llvm::StringSet<> *OptionsCollector = nullptr;
261};
262
263/// Gets the Fix attached to \p Diagnostic.
264/// If there isn't a Fix attached to the diagnostic and \p AnyFix is true, Check
265/// to see if exactly one note has a Fix and return it. Otherwise return
266/// nullptr.
267const llvm::StringMap<tooling::Replacements> *
268getFixIt(const tooling::Diagnostic &Diagnostic, bool AnyFix);
269
270/// A diagnostic consumer that turns each \c Diagnostic into a
271/// \c SourceManager-independent \c ClangTidyError.
272// FIXME: If we move away from unit-tests, this can be moved to a private
273// implementation file.
275public:
276 /// \param EnableNolintBlocks Enables diagnostic-disabling inside blocks of
277 /// code, delimited by NOLINTBEGIN and NOLINTEND.
279 DiagnosticsEngine *ExternalDiagEngine = nullptr,
280 bool RemoveIncompatibleErrors = true,
281 bool GetFixesFromNotes = false,
282 bool EnableNolintBlocks = true);
283
284 // FIXME: The concept of converting between FixItHints and Replacements is
285 // more generic and should be pulled out into a more useful Diagnostics
286 // library.
287 void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
288 const Diagnostic &Info) override;
289
290 // Retrieve the diagnostics that were captured.
291 std::vector<ClangTidyError> take();
292
293private:
294 void finalizeLastError();
295 void removeIncompatibleErrors();
296 void removeDuplicatedDiagnosticsOfAliasCheckers();
297
298 /// Returns the \c HeaderFilter constructed for the options set in the
299 /// context.
300 llvm::Regex *getHeaderFilter();
301
302 /// Updates \c LastErrorRelatesToUserCode and LastErrorPassesLineFilter
303 /// according to the diagnostic \p Location.
304 void checkFilters(SourceLocation Location, const SourceManager &Sources);
305 bool passesLineFilter(StringRef FileName, unsigned LineNumber) const;
306
307 void forwardDiagnostic(const Diagnostic &Info);
308
309 ClangTidyContext &Context;
310 DiagnosticsEngine *ExternalDiagEngine;
311 bool RemoveIncompatibleErrors;
312 bool GetFixesFromNotes;
313 bool EnableNolintBlocks;
314 std::vector<ClangTidyError> Errors;
315 std::unique_ptr<llvm::Regex> HeaderFilter;
316 bool LastErrorRelatesToUserCode = false;
317 bool LastErrorPassesLineFilter = false;
318 bool LastErrorWasIgnored = false;
319};
320
321} // end namespace tidy
322} // end namespace clang
323
324#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 cl::opt< bool > EnableModuleHeadersParsing("enable-module-headers-parsing", desc(R"( Enables preprocessor-level module header parsing for C++20 and above, empowering specific checks to detect macro definitions within modules. This feature may cause performance and parsing issues and is therefore considered experimental. )"), cl::init(false), cl::cat(ClangTidyCategory))
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.
DiagnosticBuilder diag(StringRef CheckName, SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Report any errors detected using this method.
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.
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 AnyFix)
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.