| //===--- ClangTidyDiagnosticConsumer.h - clang-tidy -------------*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYDIAGNOSTICCONSUMER_H |
| #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYDIAGNOSTICCONSUMER_H |
| |
| #include "ClangTidyOptions.h" |
| #include "ClangTidyProfiling.h" |
| #include "clang/Basic/Diagnostic.h" |
| #include "clang/Basic/SourceManager.h" |
| #include "clang/Tooling/Core/Diagnostic.h" |
| #include "clang/Tooling/Refactoring.h" |
| #include "llvm/ADT/DenseMap.h" |
| #include "llvm/ADT/StringMap.h" |
| #include "llvm/Support/Regex.h" |
| #include "llvm/Support/Timer.h" |
| |
| namespace clang { |
| |
| class ASTContext; |
| class CompilerInstance; |
| namespace ast_matchers { |
| class MatchFinder; |
| } |
| namespace tooling { |
| class CompilationDatabase; |
| } |
| |
| namespace tidy { |
| |
| /// \brief A detected error complete with information to display diagnostic and |
| /// automatic fix. |
| /// |
| /// This is used as an intermediate format to transport Diagnostics without a |
| /// dependency on a SourceManager. |
| /// |
| /// FIXME: Make Diagnostics flexible enough to support this directly. |
| struct ClangTidyError : tooling::Diagnostic { |
| ClangTidyError(StringRef CheckName, Level DiagLevel, StringRef BuildDirectory, |
| bool IsWarningAsError); |
| |
| bool IsWarningAsError; |
| }; |
| |
| /// \brief Read-only set of strings represented as a list of positive and |
| /// negative globs. Positive globs add all matched strings to the set, negative |
| /// globs remove them in the order of appearance in the list. |
| class GlobList { |
| public: |
| /// \brief \p GlobList is a comma-separated list of globs (only '*' |
| /// metacharacter is supported) with optional '-' prefix to denote exclusion. |
| GlobList(StringRef Globs); |
| |
| /// \brief Returns \c true if the pattern matches \p S. The result is the last |
| /// matching glob's Positive flag. |
| bool contains(StringRef S) { return contains(S, false); } |
| |
| private: |
| bool contains(StringRef S, bool Contains); |
| |
| bool Positive; |
| llvm::Regex Regex; |
| std::unique_ptr<GlobList> NextGlob; |
| }; |
| |
| /// \brief Contains displayed and ignored diagnostic counters for a ClangTidy |
| /// run. |
| struct ClangTidyStats { |
| ClangTidyStats() |
| : ErrorsDisplayed(0), ErrorsIgnoredCheckFilter(0), ErrorsIgnoredNOLINT(0), |
| ErrorsIgnoredNonUserCode(0), ErrorsIgnoredLineFilter(0) {} |
| |
| unsigned ErrorsDisplayed; |
| unsigned ErrorsIgnoredCheckFilter; |
| unsigned ErrorsIgnoredNOLINT; |
| unsigned ErrorsIgnoredNonUserCode; |
| unsigned ErrorsIgnoredLineFilter; |
| |
| unsigned errorsIgnored() const { |
| return ErrorsIgnoredNOLINT + ErrorsIgnoredCheckFilter + |
| ErrorsIgnoredNonUserCode + ErrorsIgnoredLineFilter; |
| } |
| }; |
| |
| /// \brief Every \c ClangTidyCheck reports errors through a \c DiagnosticsEngine |
| /// provided by this context. |
| /// |
| /// A \c ClangTidyCheck always has access to the active context to report |
| /// warnings like: |
| /// \code |
| /// Context->Diag(Loc, "Single-argument constructors must be explicit") |
| /// << FixItHint::CreateInsertion(Loc, "explicit "); |
| /// \endcode |
| class ClangTidyContext { |
| public: |
| /// \brief Initializes \c ClangTidyContext instance. |
| ClangTidyContext(std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider, |
| bool AllowEnablingAnalyzerAlphaCheckers = false); |
| |
| ~ClangTidyContext(); |
| |
| /// \brief Report any errors detected using this method. |
| /// |
| /// This is still under heavy development and will likely change towards using |
| /// tablegen'd diagnostic IDs. |
| /// FIXME: Figure out a way to manage ID spaces. |
| DiagnosticBuilder diag(StringRef CheckName, SourceLocation Loc, |
| StringRef Message, |
| DiagnosticIDs::Level Level = DiagnosticIDs::Warning); |
| |
| /// \brief Sets the \c SourceManager of the used \c DiagnosticsEngine. |
| /// |
| /// This is called from the \c ClangTidyCheck base class. |
| void setSourceManager(SourceManager *SourceMgr); |
| |
| /// \brief Should be called when starting to process new translation unit. |
| void setCurrentFile(StringRef File); |
| |
| /// \brief Returns the main file name of the current translation unit. |
| StringRef getCurrentFile() const { return CurrentFile; } |
| |
| /// \brief Sets ASTContext for the current translation unit. |
| void setASTContext(ASTContext *Context); |
| |
| /// \brief Gets the language options from the AST context. |
| const LangOptions &getLangOpts() const { return LangOpts; } |
| |
| /// \brief Returns the name of the clang-tidy check which produced this |
| /// diagnostic ID. |
| StringRef getCheckName(unsigned DiagnosticID) const; |
| |
| /// \brief Returns \c true if the check is enabled for the \c CurrentFile. |
| /// |
| /// The \c CurrentFile can be changed using \c setCurrentFile. |
| bool isCheckEnabled(StringRef CheckName) const; |
| |
| /// \brief Returns \c true if the check should be upgraded to error for the |
| /// \c CurrentFile. |
| bool treatAsError(StringRef CheckName) const; |
| |
| /// \brief Returns global options. |
| const ClangTidyGlobalOptions &getGlobalOptions() const; |
| |
| /// \brief Returns options for \c CurrentFile. |
| /// |
| /// The \c CurrentFile can be changed using \c setCurrentFile. |
| const ClangTidyOptions &getOptions() const; |
| |
| /// \brief Returns options for \c File. Does not change or depend on |
| /// \c CurrentFile. |
| ClangTidyOptions getOptionsForFile(StringRef File) const; |
| |
| /// \brief Returns \c ClangTidyStats containing issued and ignored diagnostic |
| /// counters. |
| const ClangTidyStats &getStats() const { return Stats; } |
| |
| /// \brief Returns all collected errors. |
| ArrayRef<ClangTidyError> getErrors() const { return Errors; } |
| |
| /// \brief Clears collected errors. |
| void clearErrors() { Errors.clear(); } |
| |
| /// \brief Control profile collection in clang-tidy. |
| void setEnableProfiling(bool Profile); |
| bool getEnableProfiling() const { return Profile; } |
| |
| /// \brief Control storage of profile date. |
| void setProfileStoragePrefix(StringRef ProfilePrefix); |
| llvm::Optional<ClangTidyProfiling::StorageParams> |
| getProfileStorageParams() const; |
| |
| /// \brief Should be called when starting to process new translation unit. |
| void setCurrentBuildDirectory(StringRef BuildDirectory) { |
| CurrentBuildDirectory = BuildDirectory; |
| } |
| |
| /// \brief Returns build directory of the current translation unit. |
| const std::string &getCurrentBuildDirectory() { |
| return CurrentBuildDirectory; |
| } |
| |
| /// \brief If the experimental alpha checkers from the static analyzer can be |
| /// enabled. |
| bool canEnableAnalyzerAlphaCheckers() const { |
| return AllowEnablingAnalyzerAlphaCheckers; |
| } |
| |
| private: |
| // Calls setDiagnosticsEngine() and storeError(). |
| friend class ClangTidyDiagnosticConsumer; |
| friend class ClangTidyPluginAction; |
| |
| /// \brief Sets the \c DiagnosticsEngine so that Diagnostics can be generated |
| /// correctly. |
| void setDiagnosticsEngine(DiagnosticsEngine *Engine); |
| |
| /// \brief Store an \p Error. |
| void storeError(const ClangTidyError &Error); |
| |
| std::vector<ClangTidyError> Errors; |
| DiagnosticsEngine *DiagEngine; |
| std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider; |
| |
| std::string CurrentFile; |
| ClangTidyOptions CurrentOptions; |
| class CachedGlobList; |
| std::unique_ptr<CachedGlobList> CheckFilter; |
| std::unique_ptr<CachedGlobList> WarningAsErrorFilter; |
| |
| LangOptions LangOpts; |
| |
| ClangTidyStats Stats; |
| |
| std::string CurrentBuildDirectory; |
| |
| llvm::DenseMap<unsigned, std::string> CheckNamesByDiagnosticID; |
| |
| bool Profile; |
| std::string ProfilePrefix; |
| |
| bool AllowEnablingAnalyzerAlphaCheckers; |
| }; |
| |
| /// \brief A diagnostic consumer that turns each \c Diagnostic into a |
| /// \c SourceManager-independent \c ClangTidyError. |
| // |
| // FIXME: If we move away from unit-tests, this can be moved to a private |
| // implementation file. |
| class ClangTidyDiagnosticConsumer : public DiagnosticConsumer { |
| public: |
| ClangTidyDiagnosticConsumer(ClangTidyContext &Ctx, |
| bool RemoveIncompatibleErrors = true); |
| |
| // FIXME: The concept of converting between FixItHints and Replacements is |
| // more generic and should be pulled out into a more useful Diagnostics |
| // library. |
| void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, |
| const Diagnostic &Info) override; |
| |
| /// \brief Flushes the internal diagnostics buffer to the ClangTidyContext. |
| void finish() override; |
| |
| private: |
| void finalizeLastError(); |
| |
| void removeIncompatibleErrors(SmallVectorImpl<ClangTidyError> &Errors) const; |
| |
| /// \brief Returns the \c HeaderFilter constructed for the options set in the |
| /// context. |
| llvm::Regex *getHeaderFilter(); |
| |
| /// \brief Updates \c LastErrorRelatesToUserCode and LastErrorPassesLineFilter |
| /// according to the diagnostic \p Location. |
| void checkFilters(SourceLocation Location); |
| bool passesLineFilter(StringRef FileName, unsigned LineNumber) const; |
| |
| ClangTidyContext &Context; |
| bool RemoveIncompatibleErrors; |
| std::unique_ptr<DiagnosticsEngine> Diags; |
| SmallVector<ClangTidyError, 8> Errors; |
| std::unique_ptr<llvm::Regex> HeaderFilter; |
| bool LastErrorRelatesToUserCode; |
| bool LastErrorPassesLineFilter; |
| bool LastErrorWasIgnored; |
| }; |
| |
| } // end namespace tidy |
| } // end namespace clang |
| |
| #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYDIAGNOSTICCONSUMER_H |