[LoongArch] Use getLoc() directly to construct error message
[llvm-project.git] / clang-tools-extra / clang-tidy / ClangTidyDiagnosticConsumer.h
blob1b1866476c38bcc603af57f6b93e3ff0c44d1d4e
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 "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"
20 namespace clang {
22 class ASTContext;
23 class SourceManager;
25 namespace tidy {
26 class CachedGlobList;
28 /// A detected error complete with information to display diagnostic and
29 /// automatic fix.
30 ///
31 /// This is used as an intermediate format to transport Diagnostics without a
32 /// dependency on a SourceManager.
33 ///
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.
59 ///
60 /// A \c ClangTidyCheck always has access to the active context to report
61 /// warnings like:
62 /// \code
63 /// Context->Diag(Loc, "Single-argument constructors must be explicit")
64 /// << FixItHint::CreateInsertion(Loc, "explicit ");
65 /// \endcode
66 class ClangTidyContext {
67 public:
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;
78 ~ClangTidyContext();
80 /// Report any errors detected using this method.
81 ///
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,
86 StringRef Message,
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.
95 DiagnosticBuilder
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.
113 bool
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
137 /// diagnostic ID.
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
146 /// \c CurrentFile.
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
158 /// \c CurrentFile.
159 ClangTidyOptions getOptionsForFile(StringRef File) const;
161 /// Returns \c ClangTidyStats containing issued and ignored diagnostic
162 /// counters.
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
185 /// enabled.
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)),
196 std::string(
197 DiagEngine->getDiagnosticIDs()->getDescription(DiagnosticID)));
200 private:
201 // Writes to Stats.
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;
221 bool Profile;
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
232 /// nullptr.
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 {
241 public:
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
252 // library.
253 void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
254 const Diagnostic &Info) override;
256 // Retrieve the diagnostics that were captured.
257 std::vector<ClangTidyError> take();
259 private:
260 void finalizeLastError();
261 void removeIncompatibleErrors();
262 void removeDuplicatedDiagnosticsOfAliasCheckers();
264 /// Returns the \c HeaderFilter constructed for the options set in the
265 /// context.
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