clang-tools  10.0.0svn
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 "clang/Basic/Diagnostic.h"
15 #include "clang/Basic/SourceManager.h"
16 #include "clang/Tooling/Core/Diagnostic.h"
17 #include "clang/Tooling/Refactoring.h"
18 #include "llvm/ADT/DenseMap.h"
19 #include "llvm/ADT/StringMap.h"
20 #include "llvm/Support/Timer.h"
21 
22 namespace clang {
23 
24 class ASTContext;
25 class CompilerInstance;
26 namespace ast_matchers {
27 class MatchFinder;
28 }
29 namespace tooling {
30 class CompilationDatabase;
31 }
32 
33 namespace tidy {
34 
35 /// A detected error complete with information to display diagnostic and
36 /// automatic fix.
37 ///
38 /// This is used as an intermediate format to transport Diagnostics without a
39 /// dependency on a SourceManager.
40 ///
41 /// FIXME: Make Diagnostics flexible enough to support this directly.
42 struct ClangTidyError : tooling::Diagnostic {
43  ClangTidyError(StringRef CheckName, Level DiagLevel, StringRef BuildDirectory,
44  bool IsWarningAsError);
45 
47 };
48 
49 /// Contains displayed and ignored diagnostic counters for a ClangTidy
50 /// run.
53  : ErrorsDisplayed(0), ErrorsIgnoredCheckFilter(0), ErrorsIgnoredNOLINT(0),
54  ErrorsIgnoredNonUserCode(0), ErrorsIgnoredLineFilter(0) {}
55 
56  unsigned ErrorsDisplayed;
61 
62  unsigned errorsIgnored() const {
63  return ErrorsIgnoredNOLINT + ErrorsIgnoredCheckFilter +
64  ErrorsIgnoredNonUserCode + ErrorsIgnoredLineFilter;
65  }
66 };
67 
68 /// Every \c ClangTidyCheck reports errors through a \c DiagnosticsEngine
69 /// provided by this context.
70 ///
71 /// A \c ClangTidyCheck always has access to the active context to report
72 /// warnings like:
73 /// \code
74 /// Context->Diag(Loc, "Single-argument constructors must be explicit")
75 /// << FixItHint::CreateInsertion(Loc, "explicit ");
76 /// \endcode
78 public:
79  /// Initializes \c ClangTidyContext instance.
80  ClangTidyContext(std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider,
82  /// Sets the DiagnosticsEngine that diag() will emit diagnostics to.
83  // FIXME: this is required initialization, and should be a constructor param.
84  // Fix the context -> diag engine -> consumer -> context initialization cycle.
85  void setDiagnosticsEngine(DiagnosticsEngine *DiagEngine) {
86  this->DiagEngine = DiagEngine;
87  }
88 
90 
91  /// Report any errors detected using this method.
92  ///
93  /// This is still under heavy development and will likely change towards using
94  /// tablegen'd diagnostic IDs.
95  /// FIXME: Figure out a way to manage ID spaces.
96  DiagnosticBuilder diag(StringRef CheckName, SourceLocation Loc,
97  StringRef Message,
98  DiagnosticIDs::Level Level = DiagnosticIDs::Warning);
99 
100  /// Sets the \c SourceManager of the used \c DiagnosticsEngine.
101  ///
102  /// This is called from the \c ClangTidyCheck base class.
103  void setSourceManager(SourceManager *SourceMgr);
104 
105  /// Should be called when starting to process new translation unit.
106  void setCurrentFile(StringRef File);
107 
108  /// Returns the main file name of the current translation unit.
109  StringRef getCurrentFile() const { return CurrentFile; }
110 
111  /// Sets ASTContext for the current translation unit.
112  void setASTContext(ASTContext *Context);
113 
114  /// Gets the language options from the AST context.
115  const LangOptions &getLangOpts() const { return LangOpts; }
116 
117  /// Returns the name of the clang-tidy check which produced this
118  /// diagnostic ID.
119  std::string getCheckName(unsigned DiagnosticID) const;
120 
121  /// Returns \c true if the check is enabled for the \c CurrentFile.
122  ///
123  /// The \c CurrentFile can be changed using \c setCurrentFile.
124  bool isCheckEnabled(StringRef CheckName) const;
125 
126  /// Returns \c true if the check should be upgraded to error for the
127  /// \c CurrentFile.
128  bool treatAsError(StringRef CheckName) const;
129 
130  /// Returns global options.
131  const ClangTidyGlobalOptions &getGlobalOptions() const;
132 
133  /// Returns options for \c CurrentFile.
134  ///
135  /// The \c CurrentFile can be changed using \c setCurrentFile.
136  const ClangTidyOptions &getOptions() const;
137 
138  /// Returns options for \c File. Does not change or depend on
139  /// \c CurrentFile.
140  ClangTidyOptions getOptionsForFile(StringRef File) const;
141 
142  /// Returns \c ClangTidyStats containing issued and ignored diagnostic
143  /// counters.
144  const ClangTidyStats &getStats() const { return Stats; }
145 
146  /// Control profile collection in clang-tidy.
147  void setEnableProfiling(bool Profile);
148  bool getEnableProfiling() const { return Profile; }
149 
150  /// Control storage of profile date.
151  void setProfileStoragePrefix(StringRef ProfilePrefix);
152  llvm::Optional<ClangTidyProfiling::StorageParams>
153  getProfileStorageParams() const;
154 
155  /// Should be called when starting to process new translation unit.
156  void setCurrentBuildDirectory(StringRef BuildDirectory) {
157  CurrentBuildDirectory = BuildDirectory;
158  }
159 
160  /// Returns build directory of the current translation unit.
161  const std::string &getCurrentBuildDirectory() {
162  return CurrentBuildDirectory;
163  }
164 
165  /// If the experimental alpha checkers from the static analyzer can be
166  /// enabled.
169  }
170 
171  using DiagLevelAndFormatString = std::pair<DiagnosticIDs::Level, std::string>;
173  SourceLocation Loc) {
175  static_cast<DiagnosticIDs::Level>(
176  DiagEngine->getDiagnosticLevel(DiagnosticID, Loc)),
177  DiagEngine->getDiagnosticIDs()->getDescription(DiagnosticID));
178  }
179 
180 private:
181  // Writes to Stats.
183 
184  DiagnosticsEngine *DiagEngine;
185  std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider;
186 
187  std::string CurrentFile;
188  ClangTidyOptions CurrentOptions;
189  class CachedGlobList;
190  std::unique_ptr<CachedGlobList> CheckFilter;
191  std::unique_ptr<CachedGlobList> WarningAsErrorFilter;
192 
193  LangOptions LangOpts;
194 
195  ClangTidyStats Stats;
196 
197  std::string CurrentBuildDirectory;
198 
199  llvm::DenseMap<unsigned, std::string> CheckNamesByDiagnosticID;
200 
201  bool Profile;
202  std::string ProfilePrefix;
203 
205 };
206 
207 /// Check whether a given diagnostic should be suppressed due to the presence
208 /// of a "NOLINT" suppression comment.
209 /// This is exposed so that other tools that present clang-tidy diagnostics
210 /// (such as clangd) can respect the same suppression rules as clang-tidy.
211 /// This does not handle suppression of notes following a suppressed diagnostic;
212 /// that is left to the caller is it requires maintaining state in between calls
213 /// to this function.
214 /// The `CheckMacroExpansion` parameter determines whether the function should
215 /// handle the case where the diagnostic is inside a macro expansion. A degree
216 /// of control over this is needed because handling this case can require
217 /// examining source files other than the one in which the diagnostic is
218 /// located, and in some use cases we cannot rely on such other files being
219 /// mapped in the SourceMapper.
220 bool ShouldSuppressDiagnostic(DiagnosticsEngine::Level DiagLevel,
221  const Diagnostic &Info, ClangTidyContext &Context,
222  bool CheckMacroExpansion = true);
223 
224 /// A diagnostic consumer that turns each \c Diagnostic into a
225 /// \c SourceManager-independent \c ClangTidyError.
226 //
227 // FIXME: If we move away from unit-tests, this can be moved to a private
228 // implementation file.
230 public:
232  DiagnosticsEngine *ExternalDiagEngine = nullptr,
233  bool RemoveIncompatibleErrors = true);
234 
235  // FIXME: The concept of converting between FixItHints and Replacements is
236  // more generic and should be pulled out into a more useful Diagnostics
237  // library.
238  void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
239  const Diagnostic &Info) override;
240 
241  // Retrieve the diagnostics that were captured.
242  std::vector<ClangTidyError> take();
243 
244 private:
245  void finalizeLastError();
246  void removeIncompatibleErrors();
247 
248  /// Returns the \c HeaderFilter constructed for the options set in the
249  /// context.
250  llvm::Regex *getHeaderFilter();
251 
252  /// Updates \c LastErrorRelatesToUserCode and LastErrorPassesLineFilter
253  /// according to the diagnostic \p Location.
254  void checkFilters(SourceLocation Location, const SourceManager &Sources);
255  bool passesLineFilter(StringRef FileName, unsigned LineNumber) const;
256 
257  void forwardDiagnostic(const Diagnostic &Info);
258 
259  ClangTidyContext &Context;
260  DiagnosticsEngine *ExternalDiagEngine;
261  bool RemoveIncompatibleErrors;
262  std::vector<ClangTidyError> Errors;
263  std::unique_ptr<llvm::Regex> HeaderFilter;
264  bool LastErrorRelatesToUserCode;
265  bool LastErrorPassesLineFilter;
266  bool LastErrorWasIgnored;
267 };
268 
269 } // end namespace tidy
270 } // end namespace clang
271 
272 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYDIAGNOSTICCONSUMER_H
SourceLocation Loc
&#39;#&#39; location in the include directive
bool ShouldSuppressDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info, ClangTidyContext &Context, bool CheckMacroExpansion)
Check whether a given diagnostic should be suppressed due to the presence of a "NOLINT" suppression c...
bool canEnableAnalyzerAlphaCheckers() const
If the experimental alpha checkers from the static analyzer can be enabled.
DiagLevelAndFormatString getDiagLevelAndFormatString(unsigned DiagnosticID, SourceLocation Loc)
constexpr llvm::StringLiteral Message
Contains options for clang-tidy.
Context Ctx
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.
const LangOptions & getLangOpts() const
Gets the language options from the AST context.
StringRef getCurrentFile() const
Returns the main file name of the current translation unit.
A diagnostic consumer that turns each Diagnostic into a SourceManager-independent ClangTidyError...
PathRef FileName
FunctionInfo Info
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
void setDiagnosticsEngine(DiagnosticsEngine *DiagEngine)
Sets the DiagnosticsEngine that diag() will emit diagnostics to.
static cl::opt< std::string > HeaderFilter("header-filter", cl::desc(R"( Regular expression matching the names of the headers to output diagnostics from. Diagnostics from the main file of each translation unit are always displayed. Can be used together with -line-filter. This option overrides the 'HeaderFilterRegex' option in .clang-tidy file, if any. )"), cl::init(""), cl::cat(ClangTidyCategory))
A detected error complete with information to display diagnostic and automatic fix.
Contains displayed and ignored diagnostic counters for a ClangTidy run.
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
const ClangTidyStats & getStats() const
Returns ClangTidyStats containing issued and ignored diagnostic counters.
void setCurrentBuildDirectory(StringRef BuildDirectory)
Should be called when starting to process new translation unit.
const std::string & getCurrentBuildDirectory()
Returns build directory of the current translation unit.
std::pair< DiagnosticIDs::Level, std::string > DiagLevelAndFormatString