[TargetVersion] Only enable on RISC-V and AArch64 (#115991)
[llvm-project.git] / clang-tools-extra / clang-tidy / ClangTidyDiagnosticConsumer.h
blob97e16a12febd04a8b4f43ee215d49954a3721101
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 //===----------------------------------------------------------------------===//
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 "FileExtensionsSet.h"
15 #include "NoLintDirectiveHandler.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>
23 namespace clang {
25 class ASTContext;
26 class SourceManager;
28 namespace tidy {
29 class CachedGlobList;
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.
38 struct ClangTidyError : tooling::Diagnostic {
39 ClangTidyError(StringRef CheckName, Level DiagLevel, StringRef BuildDirectory,
40 bool IsWarningAsError);
42 bool IsWarningAsError;
43 std::vector<std::string> EnabledDiagnosticAliases;
46 /// Contains displayed and ignored diagnostic counters for a ClangTidy run.
47 struct ClangTidyStats {
48 unsigned ErrorsDisplayed = 0;
49 unsigned ErrorsIgnoredCheckFilter = 0;
50 unsigned ErrorsIgnoredNOLINT = 0;
51 unsigned ErrorsIgnoredNonUserCode = 0;
52 unsigned ErrorsIgnoredLineFilter = 0;
54 unsigned errorsIgnored() const {
55 return ErrorsIgnoredNOLINT + ErrorsIgnoredCheckFilter +
56 ErrorsIgnoredNonUserCode + ErrorsIgnoredLineFilter;
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
69 class ClangTidyContext {
70 public:
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;
82 ~ClangTidyContext();
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);
93 DiagnosticBuilder diag(StringRef CheckName, StringRef Description,
94 DiagnosticIDs::Level Level = DiagnosticIDs::Warning);
96 DiagnosticBuilder diag(const tooling::Diagnostic &Error);
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);
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);
123 /// Sets the \c SourceManager of the used \c DiagnosticsEngine.
125 /// This is called from the \c ClangTidyCheck base class.
126 void setSourceManager(SourceManager *SourceMgr);
128 /// Should be called when starting to process new translation unit.
129 void setCurrentFile(StringRef File);
131 /// Returns the main file name of the current translation unit.
132 StringRef getCurrentFile() const { return CurrentFile; }
134 /// Sets ASTContext for the current translation unit.
135 void setASTContext(ASTContext *Context);
137 /// Gets the language options from the AST context.
138 const LangOptions &getLangOpts() const { return LangOpts; }
140 /// Returns the name of the clang-tidy check which produced this
141 /// diagnostic ID.
142 std::string getCheckName(unsigned DiagnosticID) const;
144 /// Returns \c true if the check is enabled for the \c CurrentFile.
146 /// The \c CurrentFile can be changed using \c setCurrentFile.
147 bool isCheckEnabled(StringRef CheckName) const;
149 /// Returns \c true if the check should be upgraded to error for the
150 /// \c CurrentFile.
151 bool treatAsError(StringRef CheckName) const;
153 /// Returns global options.
154 const ClangTidyGlobalOptions &getGlobalOptions() const;
156 /// Returns options for \c CurrentFile.
158 /// The \c CurrentFile can be changed using \c setCurrentFile.
159 const ClangTidyOptions &getOptions() const;
161 /// Returns options for \c File. Does not change or depend on
162 /// \c CurrentFile.
163 ClangTidyOptions getOptionsForFile(StringRef File) const;
165 const FileExtensionsSet &getHeaderFileExtensions() const {
166 return HeaderFileExtensions;
169 const FileExtensionsSet &getImplementationFileExtensions() const {
170 return ImplementationFileExtensions;
173 /// Returns \c ClangTidyStats containing issued and ignored diagnostic
174 /// counters.
175 const ClangTidyStats &getStats() const { return Stats; }
177 /// Control profile collection in clang-tidy.
178 void setEnableProfiling(bool Profile);
179 bool getEnableProfiling() const { return Profile; }
181 /// Control storage of profile date.
182 void setProfileStoragePrefix(StringRef ProfilePrefix);
183 std::optional<ClangTidyProfiling::StorageParams>
184 getProfileStorageParams() const;
186 /// Should be called when starting to process new translation unit.
187 void setCurrentBuildDirectory(StringRef BuildDirectory) {
188 CurrentBuildDirectory = std::string(BuildDirectory);
191 /// Returns build directory of the current translation unit.
192 const std::string &getCurrentBuildDirectory() const {
193 return CurrentBuildDirectory;
196 /// If the experimental alpha checkers from the static analyzer can be
197 /// enabled.
198 bool canEnableAnalyzerAlphaCheckers() const {
199 return AllowEnablingAnalyzerAlphaCheckers;
202 // This method determines whether preprocessor-level module header parsing is
203 // enabled using the `--experimental-enable-module-headers-parsing` option.
204 bool canEnableModuleHeadersParsing() const {
205 return EnableModuleHeadersParsing;
208 void setSelfContainedDiags(bool Value) { SelfContainedDiags = Value; }
210 bool areDiagsSelfContained() const { return SelfContainedDiags; }
212 using DiagLevelAndFormatString = std::pair<DiagnosticIDs::Level, std::string>;
213 DiagLevelAndFormatString getDiagLevelAndFormatString(unsigned DiagnosticID,
214 SourceLocation Loc) {
215 return {
216 static_cast<DiagnosticIDs::Level>(
217 DiagEngine->getDiagnosticLevel(DiagnosticID, Loc)),
218 std::string(
219 DiagEngine->getDiagnosticIDs()->getDescription(DiagnosticID))};
222 void setOptionsCollector(llvm::StringSet<> *Collector) {
223 OptionsCollector = Collector;
225 llvm::StringSet<> *getOptionsCollector() const { return OptionsCollector; }
227 private:
228 // Writes to Stats.
229 friend class ClangTidyDiagnosticConsumer;
231 DiagnosticsEngine *DiagEngine = nullptr;
232 std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider;
234 std::string CurrentFile;
235 ClangTidyOptions CurrentOptions;
237 std::unique_ptr<CachedGlobList> CheckFilter;
238 std::unique_ptr<CachedGlobList> WarningAsErrorFilter;
240 FileExtensionsSet HeaderFileExtensions;
241 FileExtensionsSet ImplementationFileExtensions;
243 LangOptions LangOpts;
245 ClangTidyStats Stats;
247 std::string CurrentBuildDirectory;
249 llvm::DenseMap<unsigned, std::string> CheckNamesByDiagnosticID;
251 bool Profile = false;
252 std::string ProfilePrefix;
254 bool AllowEnablingAnalyzerAlphaCheckers;
255 bool EnableModuleHeadersParsing;
257 bool SelfContainedDiags = false;
259 NoLintDirectiveHandler NoLintHandler;
260 llvm::StringSet<> *OptionsCollector = nullptr;
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.
267 const llvm::StringMap<tooling::Replacements> *
268 getFixIt(const tooling::Diagnostic &Diagnostic, bool AnyFix);
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.
274 class ClangTidyDiagnosticConsumer : public DiagnosticConsumer {
275 public:
276 /// \param EnableNolintBlocks Enables diagnostic-disabling inside blocks of
277 /// code, delimited by NOLINTBEGIN and NOLINTEND.
278 ClangTidyDiagnosticConsumer(ClangTidyContext &Ctx,
279 DiagnosticsEngine *ExternalDiagEngine = nullptr,
280 bool RemoveIncompatibleErrors = true,
281 bool GetFixesFromNotes = false,
282 bool EnableNolintBlocks = true);
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;
290 // Retrieve the diagnostics that were captured.
291 std::vector<ClangTidyError> take();
293 private:
294 void finalizeLastError();
295 void removeIncompatibleErrors();
296 void removeDuplicatedDiagnosticsOfAliasCheckers();
298 /// Returns the \c HeaderFilter constructed for the options set in the
299 /// context.
300 llvm::Regex *getHeaderFilter();
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;
307 void forwardDiagnostic(const Diagnostic &Info);
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 std::unique_ptr<llvm::Regex> ExcludeHeaderFilter;
317 bool LastErrorRelatesToUserCode = false;
318 bool LastErrorPassesLineFilter = false;
319 bool LastErrorWasIgnored = false;
322 } // end namespace tidy
323 } // end namespace clang
325 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYDIAGNOSTICCONSUMER_H