| Daniel Jasper | d07c840 | 2013-07-29 08:19:24 +0000 | [diff] [blame] | 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 |  | 
| Alexander Kornienko | 6658055 | 2015-03-09 16:52:33 +0000 | [diff] [blame] | 10 | #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYDIAGNOSTICCONSUMER_H | 
|  | 11 | #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYDIAGNOSTICCONSUMER_H | 
| Daniel Jasper | d07c840 | 2013-07-29 08:19:24 +0000 | [diff] [blame] | 12 |  | 
| Alexander Kornienko | 9ff5b6f | 2014-05-05 14:54:47 +0000 | [diff] [blame] | 13 | #include "ClangTidyOptions.h" | 
| Daniel Jasper | d07c840 | 2013-07-29 08:19:24 +0000 | [diff] [blame] | 14 | #include "clang/Basic/Diagnostic.h" | 
|  | 15 | #include "clang/Basic/SourceManager.h" | 
|  | 16 | #include "clang/Tooling/Refactoring.h" | 
| Alexander Kornienko | 41bfe8d | 2014-01-13 10:50:51 +0000 | [diff] [blame] | 17 | #include "llvm/ADT/DenseMap.h" | 
| Samuel Benzaquen | aedd994 | 2014-10-23 17:23:20 +0000 | [diff] [blame] | 18 | #include "llvm/ADT/StringMap.h" | 
| Alexander Kornienko | 09952d2 | 2014-03-20 09:38:22 +0000 | [diff] [blame] | 19 | #include "llvm/Support/Regex.h" | 
| Samuel Benzaquen | aedd994 | 2014-10-23 17:23:20 +0000 | [diff] [blame] | 20 | #include "llvm/Support/Timer.h" | 
| Daniel Jasper | d07c840 | 2013-07-29 08:19:24 +0000 | [diff] [blame] | 21 |  | 
|  | 22 | namespace clang { | 
|  | 23 |  | 
| Alexander Kornienko | ad21688 | 2014-07-14 14:10:03 +0000 | [diff] [blame] | 24 | class ASTContext; | 
| Daniel Jasper | d07c840 | 2013-07-29 08:19:24 +0000 | [diff] [blame] | 25 | class CompilerInstance; | 
|  | 26 | namespace ast_matchers { | 
|  | 27 | class MatchFinder; | 
|  | 28 | } | 
|  | 29 | namespace tooling { | 
|  | 30 | class CompilationDatabase; | 
|  | 31 | } | 
|  | 32 |  | 
|  | 33 | namespace tidy { | 
|  | 34 |  | 
| Manuel Klimek | 814f9bd | 2013-11-14 15:49:44 +0000 | [diff] [blame] | 35 | /// \brief A message from a clang-tidy check. | 
|  | 36 | /// | 
|  | 37 | /// Note that this is independent of a \c SourceManager. | 
|  | 38 | struct ClangTidyMessage { | 
|  | 39 | ClangTidyMessage(StringRef Message = ""); | 
|  | 40 | ClangTidyMessage(StringRef Message, const SourceManager &Sources, | 
|  | 41 | SourceLocation Loc); | 
|  | 42 | std::string Message; | 
|  | 43 | std::string FilePath; | 
|  | 44 | unsigned FileOffset; | 
|  | 45 | }; | 
|  | 46 |  | 
|  | 47 | /// \brief A detected error complete with information to display diagnostic and | 
|  | 48 | /// automatic fix. | 
|  | 49 | /// | 
|  | 50 | /// This is used as an intermediate format to transport Diagnostics without a | 
|  | 51 | /// dependency on a SourceManager. | 
|  | 52 | /// | 
|  | 53 | /// FIXME: Make Diagnostics flexible enough to support this directly. | 
|  | 54 | struct ClangTidyError { | 
| Alexander Kornienko | 348cae8 | 2014-06-02 20:44:32 +0000 | [diff] [blame] | 55 | enum Level { | 
|  | 56 | Warning = DiagnosticsEngine::Warning, | 
|  | 57 | Error = DiagnosticsEngine::Error | 
|  | 58 | }; | 
|  | 59 |  | 
|  | 60 | ClangTidyError(StringRef CheckName, Level DiagLevel); | 
| Manuel Klimek | 814f9bd | 2013-11-14 15:49:44 +0000 | [diff] [blame] | 61 |  | 
| Alexander Kornienko | 41bfe8d | 2014-01-13 10:50:51 +0000 | [diff] [blame] | 62 | std::string CheckName; | 
| Manuel Klimek | 814f9bd | 2013-11-14 15:49:44 +0000 | [diff] [blame] | 63 | ClangTidyMessage Message; | 
|  | 64 | tooling::Replacements Fix; | 
|  | 65 | SmallVector<ClangTidyMessage, 1> Notes; | 
| Alexander Kornienko | 348cae8 | 2014-06-02 20:44:32 +0000 | [diff] [blame] | 66 |  | 
|  | 67 | Level DiagLevel; | 
| Manuel Klimek | 814f9bd | 2013-11-14 15:49:44 +0000 | [diff] [blame] | 68 | }; | 
|  | 69 |  | 
| Alexander Kornienko | b3d331d | 2014-08-06 11:49:10 +0000 | [diff] [blame] | 70 | /// \brief Read-only set of strings represented as a list of positive and | 
|  | 71 | /// negative globs. Positive globs add all matched strings to the set, negative | 
|  | 72 | /// globs remove them in the order of appearance in the list. | 
|  | 73 | class GlobList { | 
| Alexander Kornienko | 09952d2 | 2014-03-20 09:38:22 +0000 | [diff] [blame] | 74 | public: | 
| Alexander Kornienko | a469522 | 2014-06-05 13:31:45 +0000 | [diff] [blame] | 75 | /// \brief \p GlobList is a comma-separated list of globs (only '*' | 
|  | 76 | /// metacharacter is supported) with optional '-' prefix to denote exclusion. | 
| Alexander Kornienko | b3d331d | 2014-08-06 11:49:10 +0000 | [diff] [blame] | 77 | GlobList(StringRef Globs); | 
| Alexander Kornienko | a469522 | 2014-06-05 13:31:45 +0000 | [diff] [blame] | 78 |  | 
| Alexander Kornienko | b3d331d | 2014-08-06 11:49:10 +0000 | [diff] [blame] | 79 | /// \brief Returns \c true if the pattern matches \p S. The result is the last | 
|  | 80 | /// matching glob's Positive flag. | 
|  | 81 | bool contains(StringRef S) { return contains(S, false); } | 
| Alexander Kornienko | 09952d2 | 2014-03-20 09:38:22 +0000 | [diff] [blame] | 82 |  | 
|  | 83 | private: | 
| Alexander Kornienko | b3d331d | 2014-08-06 11:49:10 +0000 | [diff] [blame] | 84 | bool contains(StringRef S, bool Contains); | 
| Alexander Kornienko | 23fe959 | 2014-05-15 14:27:36 +0000 | [diff] [blame] | 85 |  | 
|  | 86 | bool Positive; | 
|  | 87 | llvm::Regex Regex; | 
| Alexander Kornienko | b3d331d | 2014-08-06 11:49:10 +0000 | [diff] [blame] | 88 | std::unique_ptr<GlobList> NextGlob; | 
| Alexander Kornienko | 09952d2 | 2014-03-20 09:38:22 +0000 | [diff] [blame] | 89 | }; | 
|  | 90 |  | 
| Alexander Kornienko | a469522 | 2014-06-05 13:31:45 +0000 | [diff] [blame] | 91 | /// \brief Contains displayed and ignored diagnostic counters for a ClangTidy | 
|  | 92 | /// run. | 
| Alexander Kornienko | 5d17454 | 2014-05-07 09:06:53 +0000 | [diff] [blame] | 93 | struct ClangTidyStats { | 
|  | 94 | ClangTidyStats() | 
|  | 95 | : ErrorsDisplayed(0), ErrorsIgnoredCheckFilter(0), ErrorsIgnoredNOLINT(0), | 
| Alexander Kornienko | dad4acb | 2014-05-22 16:07:11 +0000 | [diff] [blame] | 96 | ErrorsIgnoredNonUserCode(0), ErrorsIgnoredLineFilter(0) {} | 
| Alexander Kornienko | 5d17454 | 2014-05-07 09:06:53 +0000 | [diff] [blame] | 97 |  | 
|  | 98 | unsigned ErrorsDisplayed; | 
|  | 99 | unsigned ErrorsIgnoredCheckFilter; | 
|  | 100 | unsigned ErrorsIgnoredNOLINT; | 
|  | 101 | unsigned ErrorsIgnoredNonUserCode; | 
| Alexander Kornienko | dad4acb | 2014-05-22 16:07:11 +0000 | [diff] [blame] | 102 | unsigned ErrorsIgnoredLineFilter; | 
|  | 103 |  | 
|  | 104 | unsigned errorsIgnored() const { | 
|  | 105 | return ErrorsIgnoredNOLINT + ErrorsIgnoredCheckFilter + | 
|  | 106 | ErrorsIgnoredNonUserCode + ErrorsIgnoredLineFilter; | 
|  | 107 | } | 
| Alexander Kornienko | 5d17454 | 2014-05-07 09:06:53 +0000 | [diff] [blame] | 108 | }; | 
|  | 109 |  | 
| Samuel Benzaquen | aedd994 | 2014-10-23 17:23:20 +0000 | [diff] [blame] | 110 | /// \brief Container for clang-tidy profiling data. | 
|  | 111 | struct ProfileData { | 
|  | 112 | llvm::StringMap<llvm::TimeRecord> Records; | 
|  | 113 | }; | 
|  | 114 |  | 
| Alexander Kornienko | 284c249 | 2014-12-19 15:37:02 +0000 | [diff] [blame] | 115 | /// \brief Every \c ClangTidyCheck reports errors through a \c DiagnosticsEngine | 
| Manuel Klimek | 814f9bd | 2013-11-14 15:49:44 +0000 | [diff] [blame] | 116 | /// provided by this context. | 
|  | 117 | /// | 
|  | 118 | /// A \c ClangTidyCheck always has access to the active context to report | 
|  | 119 | /// warnings like: | 
|  | 120 | /// \code | 
|  | 121 | /// Context->Diag(Loc, "Single-argument constructors must be explicit") | 
|  | 122 | ///     << FixItHint::CreateInsertion(Loc, "explicit "); | 
|  | 123 | /// \endcode | 
|  | 124 | class ClangTidyContext { | 
|  | 125 | public: | 
| Alexander Kornienko | a469522 | 2014-06-05 13:31:45 +0000 | [diff] [blame] | 126 | /// \brief Initializes \c ClangTidyContext instance. | 
| Alexander Kornienko | d53d268 | 2014-09-04 14:23:36 +0000 | [diff] [blame] | 127 | ClangTidyContext(std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider); | 
| Manuel Klimek | 814f9bd | 2013-11-14 15:49:44 +0000 | [diff] [blame] | 128 |  | 
|  | 129 | /// \brief Report any errors detected using this method. | 
|  | 130 | /// | 
|  | 131 | /// This is still under heavy development and will likely change towards using | 
|  | 132 | /// tablegen'd diagnostic IDs. | 
|  | 133 | /// FIXME: Figure out a way to manage ID spaces. | 
| Alexander Kornienko | 41bfe8d | 2014-01-13 10:50:51 +0000 | [diff] [blame] | 134 | DiagnosticBuilder diag(StringRef CheckName, SourceLocation Loc, | 
| Alexander Kornienko | 54461eb | 2014-02-06 14:50:10 +0000 | [diff] [blame] | 135 | StringRef Message, | 
|  | 136 | DiagnosticIDs::Level Level = DiagnosticIDs::Warning); | 
| Manuel Klimek | 814f9bd | 2013-11-14 15:49:44 +0000 | [diff] [blame] | 137 |  | 
| Manuel Klimek | 814f9bd | 2013-11-14 15:49:44 +0000 | [diff] [blame] | 138 | /// \brief Sets the \c SourceManager of the used \c DiagnosticsEngine. | 
|  | 139 | /// | 
|  | 140 | /// This is called from the \c ClangTidyCheck base class. | 
|  | 141 | void setSourceManager(SourceManager *SourceMgr); | 
|  | 142 |  | 
| Alexander Kornienko | a469522 | 2014-06-05 13:31:45 +0000 | [diff] [blame] | 143 | /// \brief Should be called when starting to process new translation unit. | 
|  | 144 | void setCurrentFile(StringRef File); | 
|  | 145 |  | 
| Alexander Kornienko | 19bbeaf | 2015-05-21 14:08:56 +0000 | [diff] [blame] | 146 | /// \brief Returns the main file name of the current translation unit. | 
|  | 147 | StringRef getCurrentFile() const { return CurrentFile; } | 
|  | 148 |  | 
| Alexander Kornienko | ad21688 | 2014-07-14 14:10:03 +0000 | [diff] [blame] | 149 | /// \brief Sets ASTContext for the current translation unit. | 
|  | 150 | void setASTContext(ASTContext *Context); | 
|  | 151 |  | 
| Alexander Kornienko | 41bfe8d | 2014-01-13 10:50:51 +0000 | [diff] [blame] | 152 | /// \brief Returns the name of the clang-tidy check which produced this | 
|  | 153 | /// diagnostic ID. | 
|  | 154 | StringRef getCheckName(unsigned DiagnosticID) const; | 
|  | 155 |  | 
| Alexander Kornienko | a469522 | 2014-06-05 13:31:45 +0000 | [diff] [blame] | 156 | /// \brief Returns check filter for the \c CurrentFile. | 
| Alexander Kornienko | b3d331d | 2014-08-06 11:49:10 +0000 | [diff] [blame] | 157 | GlobList &getChecksFilter(); | 
| Alexander Kornienko | a469522 | 2014-06-05 13:31:45 +0000 | [diff] [blame] | 158 |  | 
|  | 159 | /// \brief Returns global options. | 
|  | 160 | const ClangTidyGlobalOptions &getGlobalOptions() const; | 
|  | 161 |  | 
|  | 162 | /// \brief Returns options for \c CurrentFile. | 
|  | 163 | const ClangTidyOptions &getOptions() const; | 
|  | 164 |  | 
|  | 165 | /// \brief Returns \c ClangTidyStats containing issued and ignored diagnostic | 
|  | 166 | /// counters. | 
| Alexander Kornienko | 5d17454 | 2014-05-07 09:06:53 +0000 | [diff] [blame] | 167 | const ClangTidyStats &getStats() const { return Stats; } | 
| Alexander Kornienko | a469522 | 2014-06-05 13:31:45 +0000 | [diff] [blame] | 168 |  | 
|  | 169 | /// \brief Returns all collected errors. | 
| Alexander Kornienko | 826b5ad | 2014-05-09 12:24:09 +0000 | [diff] [blame] | 170 | const std::vector<ClangTidyError> &getErrors() const { return Errors; } | 
| Alexander Kornienko | a469522 | 2014-06-05 13:31:45 +0000 | [diff] [blame] | 171 |  | 
|  | 172 | /// \brief Clears collected errors. | 
| Alexander Kornienko | c009360 | 2014-05-09 15:50:15 +0000 | [diff] [blame] | 173 | void clearErrors() { Errors.clear(); } | 
| Alexander Kornienko | 09952d2 | 2014-03-20 09:38:22 +0000 | [diff] [blame] | 174 |  | 
| Samuel Benzaquen | aedd994 | 2014-10-23 17:23:20 +0000 | [diff] [blame] | 175 | /// \brief Set the output struct for profile data. | 
|  | 176 | /// | 
|  | 177 | /// Setting a non-null pointer here will enable profile collection in | 
|  | 178 | /// clang-tidy. | 
|  | 179 | void setCheckProfileData(ProfileData* Profile); | 
|  | 180 | ProfileData* getCheckProfileData() const { return Profile; } | 
|  | 181 |  | 
| Manuel Klimek | 814f9bd | 2013-11-14 15:49:44 +0000 | [diff] [blame] | 182 | private: | 
| Alexander Kornienko | a469522 | 2014-06-05 13:31:45 +0000 | [diff] [blame] | 183 | // Calls setDiagnosticsEngine() and storeError(). | 
|  | 184 | friend class ClangTidyDiagnosticConsumer; | 
| Manuel Klimek | 814f9bd | 2013-11-14 15:49:44 +0000 | [diff] [blame] | 185 |  | 
| Alexander Kornienko | a469522 | 2014-06-05 13:31:45 +0000 | [diff] [blame] | 186 | /// \brief Sets the \c DiagnosticsEngine so that Diagnostics can be generated | 
|  | 187 | /// correctly. | 
|  | 188 | void setDiagnosticsEngine(DiagnosticsEngine *Engine); | 
|  | 189 |  | 
|  | 190 | /// \brief Store an \p Error. | 
| Manuel Klimek | 814f9bd | 2013-11-14 15:49:44 +0000 | [diff] [blame] | 191 | void storeError(const ClangTidyError &Error); | 
|  | 192 |  | 
| Alexander Kornienko | 826b5ad | 2014-05-09 12:24:09 +0000 | [diff] [blame] | 193 | std::vector<ClangTidyError> Errors; | 
| NAKAMURA Takumi | 338eee1 | 2014-03-20 10:53:03 +0000 | [diff] [blame] | 194 | DiagnosticsEngine *DiagEngine; | 
| Alexander Kornienko | a469522 | 2014-06-05 13:31:45 +0000 | [diff] [blame] | 195 | std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider; | 
|  | 196 |  | 
|  | 197 | std::string CurrentFile; | 
| Alexander Kornienko | d53d268 | 2014-09-04 14:23:36 +0000 | [diff] [blame] | 198 | ClangTidyOptions CurrentOptions; | 
| Alexander Kornienko | b3d331d | 2014-08-06 11:49:10 +0000 | [diff] [blame] | 199 | std::unique_ptr<GlobList> CheckFilter; | 
| Alexander Kornienko | a469522 | 2014-06-05 13:31:45 +0000 | [diff] [blame] | 200 |  | 
| Alexander Kornienko | 5d17454 | 2014-05-07 09:06:53 +0000 | [diff] [blame] | 201 | ClangTidyStats Stats; | 
| Alexander Kornienko | 09952d2 | 2014-03-20 09:38:22 +0000 | [diff] [blame] | 202 |  | 
| Alexander Kornienko | 41bfe8d | 2014-01-13 10:50:51 +0000 | [diff] [blame] | 203 | llvm::DenseMap<unsigned, std::string> CheckNamesByDiagnosticID; | 
| Samuel Benzaquen | aedd994 | 2014-10-23 17:23:20 +0000 | [diff] [blame] | 204 |  | 
|  | 205 | ProfileData *Profile; | 
| Manuel Klimek | 814f9bd | 2013-11-14 15:49:44 +0000 | [diff] [blame] | 206 | }; | 
|  | 207 |  | 
| Daniel Jasper | d07c840 | 2013-07-29 08:19:24 +0000 | [diff] [blame] | 208 | /// \brief A diagnostic consumer that turns each \c Diagnostic into a | 
|  | 209 | /// \c SourceManager-independent \c ClangTidyError. | 
|  | 210 | // | 
|  | 211 | // FIXME: If we move away from unit-tests, this can be moved to a private | 
|  | 212 | // implementation file. | 
|  | 213 | class ClangTidyDiagnosticConsumer : public DiagnosticConsumer { | 
|  | 214 | public: | 
| Alexander Kornienko | 0ba86b7 | 2014-01-09 16:31:25 +0000 | [diff] [blame] | 215 | ClangTidyDiagnosticConsumer(ClangTidyContext &Ctx); | 
| Daniel Jasper | d07c840 | 2013-07-29 08:19:24 +0000 | [diff] [blame] | 216 |  | 
|  | 217 | // FIXME: The concept of converting between FixItHints and Replacements is | 
|  | 218 | // more generic and should be pulled out into a more useful Diagnostics | 
|  | 219 | // library. | 
| Alexander Kornienko | cb9272f | 2014-02-27 13:14:51 +0000 | [diff] [blame] | 220 | void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, | 
| Craig Topper | a3dbe84 | 2014-03-02 10:20:11 +0000 | [diff] [blame] | 221 | const Diagnostic &Info) override; | 
| Manuel Klimek | 814f9bd | 2013-11-14 15:49:44 +0000 | [diff] [blame] | 222 |  | 
| Alexander Kornienko | a469522 | 2014-06-05 13:31:45 +0000 | [diff] [blame] | 223 | /// \brief Sets \c HeaderFilter to the value configured for this file. | 
|  | 224 | void BeginSourceFile(const LangOptions &LangOpts, | 
|  | 225 | const Preprocessor *PP) override; | 
|  | 226 |  | 
|  | 227 | /// \brief Flushes the internal diagnostics buffer to the ClangTidyContext. | 
| Craig Topper | a3dbe84 | 2014-03-02 10:20:11 +0000 | [diff] [blame] | 228 | void finish() override; | 
| Daniel Jasper | d07c840 | 2013-07-29 08:19:24 +0000 | [diff] [blame] | 229 |  | 
|  | 230 | private: | 
| Alexander Kornienko | 54461eb | 2014-02-06 14:50:10 +0000 | [diff] [blame] | 231 | void finalizeLastError(); | 
| Alexander Kornienko | a469522 | 2014-06-05 13:31:45 +0000 | [diff] [blame] | 232 |  | 
|  | 233 | /// \brief Updates \c LastErrorRelatesToUserCode and LastErrorPassesLineFilter | 
|  | 234 | /// according to the diagnostic \p Location. | 
| Alexander Kornienko | dad4acb | 2014-05-22 16:07:11 +0000 | [diff] [blame] | 235 | void checkFilters(SourceLocation Location); | 
|  | 236 | bool passesLineFilter(StringRef FileName, unsigned LineNumber) const; | 
| Manuel Klimek | 814f9bd | 2013-11-14 15:49:44 +0000 | [diff] [blame] | 237 |  | 
| Daniel Jasper | d07c840 | 2013-07-29 08:19:24 +0000 | [diff] [blame] | 238 | ClangTidyContext &Context; | 
| Ahmed Charles | 6a2dc5c | 2014-03-09 09:24:40 +0000 | [diff] [blame] | 239 | std::unique_ptr<DiagnosticsEngine> Diags; | 
| Manuel Klimek | 814f9bd | 2013-11-14 15:49:44 +0000 | [diff] [blame] | 240 | SmallVector<ClangTidyError, 8> Errors; | 
| Alexander Kornienko | a469522 | 2014-06-05 13:31:45 +0000 | [diff] [blame] | 241 | std::unique_ptr<llvm::Regex> HeaderFilter; | 
| Alexander Kornienko | 54461eb | 2014-02-06 14:50:10 +0000 | [diff] [blame] | 242 | bool LastErrorRelatesToUserCode; | 
| Alexander Kornienko | dad4acb | 2014-05-22 16:07:11 +0000 | [diff] [blame] | 243 | bool LastErrorPassesLineFilter; | 
| Daniel Jasper | d07c840 | 2013-07-29 08:19:24 +0000 | [diff] [blame] | 244 | }; | 
|  | 245 |  | 
|  | 246 | } // end namespace tidy | 
|  | 247 | } // end namespace clang | 
|  | 248 |  | 
| Alexander Kornienko | 6658055 | 2015-03-09 16:52:33 +0000 | [diff] [blame] | 249 | #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYDIAGNOSTICCONSUMER_H |