1 //===--- ClangTidyDiagnosticConsumer.h - clang-tidy -------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYDIAGNOSTICCONSUMER_H
10 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYDIAGNOSTICCONSUMER_H
12 #include "ClangTidyOptions.h"
13 #include "ClangTidyProfiling.h"
14 #include "NoLintDirectiveHandler.h"
15 #include "clang/Basic/Diagnostic.h"
16 #include "clang/Tooling/Core/Diagnostic.h"
17 #include "llvm/ADT/DenseMap.h"
18 #include "llvm/Support/Regex.h"
28 /// A detected error complete with information to display diagnostic and
31 /// This is used as an intermediate format to transport Diagnostics without a
32 /// dependency on a SourceManager.
34 /// FIXME: Make Diagnostics flexible enough to support this directly.
35 struct ClangTidyError
: tooling::Diagnostic
{
36 ClangTidyError(StringRef CheckName
, Level DiagLevel
, StringRef BuildDirectory
,
37 bool IsWarningAsError
);
39 bool IsWarningAsError
;
40 std::vector
<std::string
> EnabledDiagnosticAliases
;
43 /// Contains displayed and ignored diagnostic counters for a ClangTidy run.
44 struct ClangTidyStats
{
45 unsigned ErrorsDisplayed
= 0;
46 unsigned ErrorsIgnoredCheckFilter
= 0;
47 unsigned ErrorsIgnoredNOLINT
= 0;
48 unsigned ErrorsIgnoredNonUserCode
= 0;
49 unsigned ErrorsIgnoredLineFilter
= 0;
51 unsigned errorsIgnored() const {
52 return ErrorsIgnoredNOLINT
+ ErrorsIgnoredCheckFilter
+
53 ErrorsIgnoredNonUserCode
+ ErrorsIgnoredLineFilter
;
57 /// Every \c ClangTidyCheck reports errors through a \c DiagnosticsEngine
58 /// provided by this context.
60 /// A \c ClangTidyCheck always has access to the active context to report
63 /// Context->Diag(Loc, "Single-argument constructors must be explicit")
64 /// << FixItHint::CreateInsertion(Loc, "explicit ");
66 class ClangTidyContext
{
68 /// Initializes \c ClangTidyContext instance.
69 ClangTidyContext(std::unique_ptr
<ClangTidyOptionsProvider
> OptionsProvider
,
70 bool AllowEnablingAnalyzerAlphaCheckers
= false);
71 /// Sets the DiagnosticsEngine that diag() will emit diagnostics to.
72 // FIXME: this is required initialization, and should be a constructor param.
73 // Fix the context -> diag engine -> consumer -> context initialization cycle.
74 void setDiagnosticsEngine(DiagnosticsEngine
*DiagEngine
) {
75 this->DiagEngine
= DiagEngine
;
80 /// Report any errors detected using this method.
82 /// This is still under heavy development and will likely change towards using
83 /// tablegen'd diagnostic IDs.
84 /// FIXME: Figure out a way to manage ID spaces.
85 DiagnosticBuilder
diag(StringRef CheckName
, SourceLocation Loc
,
87 DiagnosticIDs::Level Level
= DiagnosticIDs::Warning
);
89 DiagnosticBuilder
diag(StringRef CheckName
, StringRef Message
,
90 DiagnosticIDs::Level Level
= DiagnosticIDs::Warning
);
92 DiagnosticBuilder
diag(const tooling::Diagnostic
&Error
);
94 /// Report any errors to do with reading the configuration using this method.
96 configurationDiag(StringRef Message
,
97 DiagnosticIDs::Level Level
= DiagnosticIDs::Warning
);
99 /// Check whether a given diagnostic should be suppressed due to the presence
100 /// of a "NOLINT" suppression comment.
101 /// This is exposed so that other tools that present clang-tidy diagnostics
102 /// (such as clangd) can respect the same suppression rules as clang-tidy.
103 /// This does not handle suppression of notes following a suppressed
104 /// diagnostic; that is left to the caller as it requires maintaining state in
105 /// between calls to this function.
106 /// If any NOLINT is malformed, e.g. a BEGIN without a subsequent END, output
107 /// \param NoLintErrors will return an error about it.
108 /// If \param AllowIO is false, the function does not attempt to read source
109 /// files from disk which are not already mapped into memory; such files are
110 /// treated as not containing a suppression comment.
111 /// \param EnableNoLintBlocks controls whether to honor NOLINTBEGIN/NOLINTEND
112 /// blocks; if false, only considers line-level disabling.
114 shouldSuppressDiagnostic(DiagnosticsEngine::Level DiagLevel
,
115 const Diagnostic
&Info
,
116 SmallVectorImpl
<tooling::Diagnostic
> &NoLintErrors
,
117 bool AllowIO
= true, bool EnableNoLintBlocks
= true);
119 /// Sets the \c SourceManager of the used \c DiagnosticsEngine.
121 /// This is called from the \c ClangTidyCheck base class.
122 void setSourceManager(SourceManager
*SourceMgr
);
124 /// Should be called when starting to process new translation unit.
125 void setCurrentFile(StringRef File
);
127 /// Returns the main file name of the current translation unit.
128 StringRef
getCurrentFile() const { return CurrentFile
; }
130 /// Sets ASTContext for the current translation unit.
131 void setASTContext(ASTContext
*Context
);
133 /// Gets the language options from the AST context.
134 const LangOptions
&getLangOpts() const { return LangOpts
; }
136 /// Returns the name of the clang-tidy check which produced this
138 std::string
getCheckName(unsigned DiagnosticID
) const;
140 /// Returns \c true if the check is enabled for the \c CurrentFile.
142 /// The \c CurrentFile can be changed using \c setCurrentFile.
143 bool isCheckEnabled(StringRef CheckName
) const;
145 /// Returns \c true if the check should be upgraded to error for the
147 bool treatAsError(StringRef CheckName
) const;
149 /// Returns global options.
150 const ClangTidyGlobalOptions
&getGlobalOptions() const;
152 /// Returns options for \c CurrentFile.
154 /// The \c CurrentFile can be changed using \c setCurrentFile.
155 const ClangTidyOptions
&getOptions() const;
157 /// Returns options for \c File. Does not change or depend on
159 ClangTidyOptions
getOptionsForFile(StringRef File
) const;
161 /// Returns \c ClangTidyStats containing issued and ignored diagnostic
163 const ClangTidyStats
&getStats() const { return Stats
; }
165 /// Control profile collection in clang-tidy.
166 void setEnableProfiling(bool Profile
);
167 bool getEnableProfiling() const { return Profile
; }
169 /// Control storage of profile date.
170 void setProfileStoragePrefix(StringRef ProfilePrefix
);
171 llvm::Optional
<ClangTidyProfiling::StorageParams
>
172 getProfileStorageParams() const;
174 /// Should be called when starting to process new translation unit.
175 void setCurrentBuildDirectory(StringRef BuildDirectory
) {
176 CurrentBuildDirectory
= std::string(BuildDirectory
);
179 /// Returns build directory of the current translation unit.
180 const std::string
&getCurrentBuildDirectory() const {
181 return CurrentBuildDirectory
;
184 /// If the experimental alpha checkers from the static analyzer can be
186 bool canEnableAnalyzerAlphaCheckers() const {
187 return AllowEnablingAnalyzerAlphaCheckers
;
190 using DiagLevelAndFormatString
= std::pair
<DiagnosticIDs::Level
, std::string
>;
191 DiagLevelAndFormatString
getDiagLevelAndFormatString(unsigned DiagnosticID
,
192 SourceLocation Loc
) {
193 return DiagLevelAndFormatString(
194 static_cast<DiagnosticIDs::Level
>(
195 DiagEngine
->getDiagnosticLevel(DiagnosticID
, Loc
)),
197 DiagEngine
->getDiagnosticIDs()->getDescription(DiagnosticID
)));
202 friend class ClangTidyDiagnosticConsumer
;
204 DiagnosticsEngine
*DiagEngine
;
205 std::unique_ptr
<ClangTidyOptionsProvider
> OptionsProvider
;
207 std::string CurrentFile
;
208 ClangTidyOptions CurrentOptions
;
210 std::unique_ptr
<CachedGlobList
> CheckFilter
;
211 std::unique_ptr
<CachedGlobList
> WarningAsErrorFilter
;
213 LangOptions LangOpts
;
215 ClangTidyStats Stats
;
217 std::string CurrentBuildDirectory
;
219 llvm::DenseMap
<unsigned, std::string
> CheckNamesByDiagnosticID
;
222 std::string ProfilePrefix
;
224 bool AllowEnablingAnalyzerAlphaCheckers
;
226 NoLintDirectiveHandler NoLintHandler
;
229 /// Gets the Fix attached to \p Diagnostic.
230 /// If there isn't a Fix attached to the diagnostic and \p AnyFix is true, Check
231 /// to see if exactly one note has a Fix and return it. Otherwise return
233 const llvm::StringMap
<tooling::Replacements
> *
234 getFixIt(const tooling::Diagnostic
&Diagnostic
, bool AnyFix
);
236 /// A diagnostic consumer that turns each \c Diagnostic into a
237 /// \c SourceManager-independent \c ClangTidyError.
238 // FIXME: If we move away from unit-tests, this can be moved to a private
239 // implementation file.
240 class ClangTidyDiagnosticConsumer
: public DiagnosticConsumer
{
242 /// \param EnableNolintBlocks Enables diagnostic-disabling inside blocks of
243 /// code, delimited by NOLINTBEGIN and NOLINTEND.
244 ClangTidyDiagnosticConsumer(ClangTidyContext
&Ctx
,
245 DiagnosticsEngine
*ExternalDiagEngine
= nullptr,
246 bool RemoveIncompatibleErrors
= true,
247 bool GetFixesFromNotes
= false,
248 bool EnableNolintBlocks
= true);
250 // FIXME: The concept of converting between FixItHints and Replacements is
251 // more generic and should be pulled out into a more useful Diagnostics
253 void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel
,
254 const Diagnostic
&Info
) override
;
256 // Retrieve the diagnostics that were captured.
257 std::vector
<ClangTidyError
> take();
260 void finalizeLastError();
261 void removeIncompatibleErrors();
262 void removeDuplicatedDiagnosticsOfAliasCheckers();
264 /// Returns the \c HeaderFilter constructed for the options set in the
266 llvm::Regex
*getHeaderFilter();
268 /// Updates \c LastErrorRelatesToUserCode and LastErrorPassesLineFilter
269 /// according to the diagnostic \p Location.
270 void checkFilters(SourceLocation Location
, const SourceManager
&Sources
);
271 bool passesLineFilter(StringRef FileName
, unsigned LineNumber
) const;
273 void forwardDiagnostic(const Diagnostic
&Info
);
275 ClangTidyContext
&Context
;
276 DiagnosticsEngine
*ExternalDiagEngine
;
277 bool RemoveIncompatibleErrors
;
278 bool GetFixesFromNotes
;
279 bool EnableNolintBlocks
;
280 std::vector
<ClangTidyError
> Errors
;
281 std::unique_ptr
<llvm::Regex
> HeaderFilter
;
282 bool LastErrorRelatesToUserCode
;
283 bool LastErrorPassesLineFilter
;
284 bool LastErrorWasIgnored
;
287 } // end namespace tidy
288 } // end namespace clang
290 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYDIAGNOSTICCONSUMER_H