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