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