Line data Source code
1 : //===--- ClangTidyDiagnosticConsumer.h - clang-tidy -------------*- C++ -*-===//
2 : //
3 : // The LLVM Compiler Infrastructure
4 : //
5 : // This file is distributed under the University of Illinois Open Source
6 : // License. See LICENSE.TXT for details.
7 : //
8 : //===----------------------------------------------------------------------===//
9 :
10 : #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYDIAGNOSTICCONSUMER_H
11 : #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYDIAGNOSTICCONSUMER_H
12 :
13 : #include "ClangTidyOptions.h"
14 : #include "ClangTidyProfiling.h"
15 : #include "clang/Basic/Diagnostic.h"
16 : #include "clang/Basic/SourceManager.h"
17 : #include "clang/Tooling/Core/Diagnostic.h"
18 : #include "clang/Tooling/Refactoring.h"
19 : #include "llvm/ADT/DenseMap.h"
20 : #include "llvm/ADT/StringMap.h"
21 : #include "llvm/Support/Regex.h"
22 : #include "llvm/Support/Timer.h"
23 :
24 : namespace clang {
25 :
26 : class ASTContext;
27 : class CompilerInstance;
28 : namespace ast_matchers {
29 : class MatchFinder;
30 : }
31 : namespace tooling {
32 : class CompilationDatabase;
33 : }
34 :
35 : namespace tidy {
36 :
37 : /// \brief A detected error complete with information to display diagnostic and
38 : /// automatic fix.
39 : ///
40 : /// This is used as an intermediate format to transport Diagnostics without a
41 : /// dependency on a SourceManager.
42 : ///
43 : /// FIXME: Make Diagnostics flexible enough to support this directly.
44 47 : struct ClangTidyError : tooling::Diagnostic {
45 : ClangTidyError(StringRef CheckName, Level DiagLevel, StringRef BuildDirectory,
46 : bool IsWarningAsError);
47 :
48 : bool IsWarningAsError;
49 : };
50 :
51 : /// \brief Read-only set of strings represented as a list of positive and
52 : /// negative globs. Positive globs add all matched strings to the set, negative
53 : /// globs remove them in the order of appearance in the list.
54 : class GlobList {
55 : public:
56 : /// \brief \p GlobList is a comma-separated list of globs (only '*'
57 : /// metacharacter is supported) with optional '-' prefix to denote exclusion.
58 : GlobList(StringRef Globs);
59 :
60 : /// \brief Returns \c true if the pattern matches \p S. The result is the last
61 : /// matching glob's Positive flag.
62 29 : bool contains(StringRef S) { return contains(S, false); }
63 :
64 : private:
65 : bool contains(StringRef S, bool Contains);
66 :
67 : bool Positive;
68 : llvm::Regex Regex;
69 : std::unique_ptr<GlobList> NextGlob;
70 : };
71 :
72 : /// \brief Contains displayed and ignored diagnostic counters for a ClangTidy
73 : /// run.
74 : struct ClangTidyStats {
75 : ClangTidyStats()
76 : : ErrorsDisplayed(0), ErrorsIgnoredCheckFilter(0), ErrorsIgnoredNOLINT(0),
77 : ErrorsIgnoredNonUserCode(0), ErrorsIgnoredLineFilter(0) {}
78 :
79 : unsigned ErrorsDisplayed;
80 : unsigned ErrorsIgnoredCheckFilter;
81 : unsigned ErrorsIgnoredNOLINT;
82 : unsigned ErrorsIgnoredNonUserCode;
83 : unsigned ErrorsIgnoredLineFilter;
84 :
85 : unsigned errorsIgnored() const {
86 : return ErrorsIgnoredNOLINT + ErrorsIgnoredCheckFilter +
87 : ErrorsIgnoredNonUserCode + ErrorsIgnoredLineFilter;
88 : }
89 : };
90 :
91 : /// \brief Every \c ClangTidyCheck reports errors through a \c DiagnosticsEngine
92 : /// provided by this context.
93 : ///
94 : /// A \c ClangTidyCheck always has access to the active context to report
95 : /// warnings like:
96 : /// \code
97 : /// Context->Diag(Loc, "Single-argument constructors must be explicit")
98 : /// << FixItHint::CreateInsertion(Loc, "explicit ");
99 : /// \endcode
100 : class ClangTidyContext {
101 : public:
102 : /// \brief Initializes \c ClangTidyContext instance.
103 : ClangTidyContext(std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider,
104 : bool AllowEnablingAnalyzerAlphaCheckers = false);
105 :
106 : ~ClangTidyContext();
107 :
108 : /// \brief Report any errors detected using this method.
109 : ///
110 : /// This is still under heavy development and will likely change towards using
111 : /// tablegen'd diagnostic IDs.
112 : /// FIXME: Figure out a way to manage ID spaces.
113 : DiagnosticBuilder diag(StringRef CheckName, SourceLocation Loc,
114 : StringRef Message,
115 : DiagnosticIDs::Level Level = DiagnosticIDs::Warning);
116 :
117 : /// \brief Sets the \c SourceManager of the used \c DiagnosticsEngine.
118 : ///
119 : /// This is called from the \c ClangTidyCheck base class.
120 : void setSourceManager(SourceManager *SourceMgr);
121 :
122 : /// \brief Should be called when starting to process new translation unit.
123 : void setCurrentFile(StringRef File);
124 :
125 : /// \brief Returns the main file name of the current translation unit.
126 : StringRef getCurrentFile() const { return CurrentFile; }
127 :
128 : /// \brief Sets ASTContext for the current translation unit.
129 : void setASTContext(ASTContext *Context);
130 :
131 : /// \brief Gets the language options from the AST context.
132 : const LangOptions &getLangOpts() const { return LangOpts; }
133 :
134 : /// \brief Returns the name of the clang-tidy check which produced this
135 : /// diagnostic ID.
136 : StringRef getCheckName(unsigned DiagnosticID) const;
137 :
138 : /// \brief Returns \c true if the check is enabled for the \c CurrentFile.
139 : ///
140 : /// The \c CurrentFile can be changed using \c setCurrentFile.
141 : bool isCheckEnabled(StringRef CheckName) const;
142 :
143 : /// \brief Returns \c true if the check should be upgraded to error for the
144 : /// \c CurrentFile.
145 : bool treatAsError(StringRef CheckName) const;
146 :
147 : /// \brief Returns global options.
148 : const ClangTidyGlobalOptions &getGlobalOptions() const;
149 :
150 : /// \brief Returns options for \c CurrentFile.
151 : ///
152 : /// The \c CurrentFile can be changed using \c setCurrentFile.
153 : const ClangTidyOptions &getOptions() const;
154 :
155 : /// \brief Returns options for \c File. Does not change or depend on
156 : /// \c CurrentFile.
157 : ClangTidyOptions getOptionsForFile(StringRef File) const;
158 :
159 : /// \brief Returns \c ClangTidyStats containing issued and ignored diagnostic
160 : /// counters.
161 : const ClangTidyStats &getStats() const { return Stats; }
162 :
163 : /// \brief Returns all collected errors.
164 : ArrayRef<ClangTidyError> getErrors() const { return Errors; }
165 :
166 : /// \brief Clears collected errors.
167 : void clearErrors() { Errors.clear(); }
168 :
169 : /// \brief Control profile collection in clang-tidy.
170 : void setEnableProfiling(bool Profile);
171 : bool getEnableProfiling() const { return Profile; }
172 :
173 : /// \brief Control storage of profile date.
174 : void setProfileStoragePrefix(StringRef ProfilePrefix);
175 : llvm::Optional<ClangTidyProfiling::StorageParams>
176 : getProfileStorageParams() const;
177 :
178 : /// \brief Should be called when starting to process new translation unit.
179 : void setCurrentBuildDirectory(StringRef BuildDirectory) {
180 : CurrentBuildDirectory = BuildDirectory;
181 : }
182 :
183 : /// \brief Returns build directory of the current translation unit.
184 : const std::string &getCurrentBuildDirectory() {
185 : return CurrentBuildDirectory;
186 : }
187 :
188 : /// \brief If the experimental alpha checkers from the static analyzer can be
189 : /// enabled.
190 : bool canEnableAnalyzerAlphaCheckers() const {
191 : return AllowEnablingAnalyzerAlphaCheckers;
192 : }
193 :
194 : private:
195 : // Calls setDiagnosticsEngine() and storeError().
196 : friend class ClangTidyDiagnosticConsumer;
197 : friend class ClangTidyPluginAction;
198 :
199 : /// \brief Sets the \c DiagnosticsEngine so that Diagnostics can be generated
200 : /// correctly.
201 : void setDiagnosticsEngine(DiagnosticsEngine *Engine);
202 :
203 : /// \brief Store an \p Error.
204 : void storeError(const ClangTidyError &Error);
205 :
206 : std::vector<ClangTidyError> Errors;
207 : DiagnosticsEngine *DiagEngine;
208 : std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider;
209 :
210 : std::string CurrentFile;
211 : ClangTidyOptions CurrentOptions;
212 : class CachedGlobList;
213 : std::unique_ptr<CachedGlobList> CheckFilter;
214 : std::unique_ptr<CachedGlobList> WarningAsErrorFilter;
215 :
216 : LangOptions LangOpts;
217 :
218 : ClangTidyStats Stats;
219 :
220 : std::string CurrentBuildDirectory;
221 :
222 : llvm::DenseMap<unsigned, std::string> CheckNamesByDiagnosticID;
223 :
224 : bool Profile;
225 : std::string ProfilePrefix;
226 :
227 : bool AllowEnablingAnalyzerAlphaCheckers;
228 : };
229 :
230 : /// \brief A diagnostic consumer that turns each \c Diagnostic into a
231 : /// \c SourceManager-independent \c ClangTidyError.
232 : //
233 : // FIXME: If we move away from unit-tests, this can be moved to a private
234 : // implementation file.
235 : class ClangTidyDiagnosticConsumer : public DiagnosticConsumer {
236 : public:
237 : ClangTidyDiagnosticConsumer(ClangTidyContext &Ctx,
238 : bool RemoveIncompatibleErrors = true);
239 :
240 : // FIXME: The concept of converting between FixItHints and Replacements is
241 : // more generic and should be pulled out into a more useful Diagnostics
242 : // library.
243 : void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
244 : const Diagnostic &Info) override;
245 :
246 : /// \brief Flushes the internal diagnostics buffer to the ClangTidyContext.
247 : void finish() override;
248 :
249 : private:
250 : void finalizeLastError();
251 :
252 : void removeIncompatibleErrors(SmallVectorImpl<ClangTidyError> &Errors) const;
253 :
254 : /// \brief Returns the \c HeaderFilter constructed for the options set in the
255 : /// context.
256 : llvm::Regex *getHeaderFilter();
257 :
258 : /// \brief Updates \c LastErrorRelatesToUserCode and LastErrorPassesLineFilter
259 : /// according to the diagnostic \p Location.
260 : void checkFilters(SourceLocation Location);
261 : bool passesLineFilter(StringRef FileName, unsigned LineNumber) const;
262 :
263 : ClangTidyContext &Context;
264 : bool RemoveIncompatibleErrors;
265 : std::unique_ptr<DiagnosticsEngine> Diags;
266 : SmallVector<ClangTidyError, 8> Errors;
267 : std::unique_ptr<llvm::Regex> HeaderFilter;
268 : bool LastErrorRelatesToUserCode;
269 : bool LastErrorPassesLineFilter;
270 : bool LastErrorWasIgnored;
271 : };
272 :
273 : } // end namespace tidy
274 : } // end namespace clang
275 :
276 : #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYDIAGNOSTICCONSUMER_H
|