Index: clang-tools-extra/clang-tidy/CMakeLists.txt =================================================================== --- clang-tools-extra/clang-tidy/CMakeLists.txt +++ clang-tools-extra/clang-tidy/CMakeLists.txt @@ -11,6 +11,8 @@ add_clang_library(clangTidy ClangTidy.cpp ClangTidyCheck.cpp + ClangTidyContext.cpp + ClangTidyError.cpp ClangTidyModule.cpp ClangTidyDiagnosticConsumer.cpp ClangTidyOptions.cpp Index: clang-tools-extra/clang-tidy/ClangTidy.cpp =================================================================== --- clang-tools-extra/clang-tidy/ClangTidy.cpp +++ clang-tools-extra/clang-tidy/ClangTidy.cpp @@ -17,6 +17,7 @@ #include "ClangTidy.h" #include "ClangTidyCheck.h" #include "ClangTidyDiagnosticConsumer.h" +#include "ClangTidyError.h" #include "ClangTidyModuleRegistry.h" #include "ClangTidyProfiling.h" #include "ExpandModularHeadersPPCallbacks.h" Index: clang-tools-extra/clang-tidy/ClangTidyCheck.h =================================================================== --- clang-tools-extra/clang-tidy/ClangTidyCheck.h +++ clang-tools-extra/clang-tidy/ClangTidyCheck.h @@ -9,7 +9,7 @@ #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYCHECK_H #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYCHECK_H -#include "ClangTidyDiagnosticConsumer.h" +#include "ClangTidyContext.h" #include "ClangTidyOptions.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/Basic/Diagnostic.h" Index: clang-tools-extra/clang-tidy/ClangTidyContext.h =================================================================== --- /dev/null +++ clang-tools-extra/clang-tidy/ClangTidyContext.h @@ -0,0 +1,194 @@ +//===--- ClangTidyContext.h - clang-tidy ------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYCONTEXT_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYCONTEXT_H + +#include "ClangTidyOptions.h" +#include "ClangTidyProfiling.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Tooling/Core/Diagnostic.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/Support/Regex.h" + +namespace clang { + +class ASTContext; +class SourceManager; + +namespace tidy { +struct ClangTidyError; + +/// Contains displayed and ignored diagnostic counters for a ClangTidy run. +struct ClangTidyStats { + unsigned ErrorsDisplayed = 0; + unsigned ErrorsIgnoredCheckFilter = 0; + unsigned ErrorsIgnoredNOLINT = 0; + unsigned ErrorsIgnoredNonUserCode = 0; + unsigned ErrorsIgnoredLineFilter = 0; + + unsigned errorsIgnored() const { + return ErrorsIgnoredNOLINT + ErrorsIgnoredCheckFilter + + ErrorsIgnoredNonUserCode + ErrorsIgnoredLineFilter; + } +}; + +/// 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: + /// Initializes \c ClangTidyContext instance. + ClangTidyContext(std::unique_ptr OptionsProvider, + bool AllowEnablingAnalyzerAlphaCheckers = false); + /// Sets the DiagnosticsEngine that diag() will emit diagnostics to. + // FIXME: this is required initialization, and should be a constructor param. + // Fix the context -> diag engine -> consumer -> context initialization cycle. + void setDiagnosticsEngine(DiagnosticsEngine *DiagEngine) { + this->DiagEngine = DiagEngine; + } + + ~ClangTidyContext(); + + /// 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); + + DiagnosticBuilder diag(StringRef CheckName, StringRef Message, + DiagnosticIDs::Level Level = DiagnosticIDs::Warning); + + DiagnosticBuilder diag(const ClangTidyError &Error); + + /// Report any errors to do with reading the configuration using this method. + DiagnosticBuilder + configurationDiag(StringRef Message, + DiagnosticIDs::Level Level = DiagnosticIDs::Warning); + + /// Sets the \c SourceManager of the used \c DiagnosticsEngine. + /// + /// This is called from the \c ClangTidyCheck base class. + void setSourceManager(SourceManager *SourceMgr); + + /// Should be called when starting to process new translation unit. + void setCurrentFile(StringRef File); + + /// Returns the main file name of the current translation unit. + StringRef getCurrentFile() const { return CurrentFile; } + + /// Sets ASTContext for the current translation unit. + void setASTContext(ASTContext *Context); + + /// Gets the language options from the AST context. + const LangOptions &getLangOpts() const { return LangOpts; } + + /// Returns the name of the clang-tidy check which produced this + /// diagnostic ID. + std::string getCheckName(unsigned DiagnosticID) const; + + /// 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; + + /// Returns \c true if the check should be upgraded to error for the + /// \c CurrentFile. + bool treatAsError(StringRef CheckName) const; + + /// Returns global options. + const ClangTidyGlobalOptions &getGlobalOptions() const; + + /// Returns options for \c CurrentFile. + /// + /// The \c CurrentFile can be changed using \c setCurrentFile. + const ClangTidyOptions &getOptions() const; + + /// Returns options for \c File. Does not change or depend on + /// \c CurrentFile. + ClangTidyOptions getOptionsForFile(StringRef File) const; + + /// Returns \c ClangTidyStats containing issued and ignored diagnostic + /// counters. + const ClangTidyStats &getStats() const { return Stats; } + + /// Control profile collection in clang-tidy. + void setEnableProfiling(bool Profile); + bool getEnableProfiling() const { return Profile; } + + /// Control storage of profile date. + void setProfileStoragePrefix(StringRef ProfilePrefix); + llvm::Optional + getProfileStorageParams() const; + + /// Should be called when starting to process new translation unit. + void setCurrentBuildDirectory(StringRef BuildDirectory) { + CurrentBuildDirectory = std::string(BuildDirectory); + } + + /// Returns build directory of the current translation unit. + const std::string &getCurrentBuildDirectory() const { + return CurrentBuildDirectory; + } + + /// If the experimental alpha checkers from the static analyzer can be + /// enabled. + bool canEnableAnalyzerAlphaCheckers() const { + return AllowEnablingAnalyzerAlphaCheckers; + } + + using DiagLevelAndFormatString = std::pair; + DiagLevelAndFormatString getDiagLevelAndFormatString(unsigned DiagnosticID, + SourceLocation Loc) { + return DiagLevelAndFormatString( + static_cast( + DiagEngine->getDiagnosticLevel(DiagnosticID, Loc)), + std::string( + DiagEngine->getDiagnosticIDs()->getDescription(DiagnosticID))); + } + +private: + // Writes to Stats. + friend class ClangTidyDiagnosticConsumer; + + DiagnosticsEngine *DiagEngine; + std::unique_ptr OptionsProvider; + + std::string CurrentFile; + ClangTidyOptions CurrentOptions; + class CachedGlobList; + std::unique_ptr CheckFilter; + std::unique_ptr WarningAsErrorFilter; + + LangOptions LangOpts; + + ClangTidyStats Stats; + + std::string CurrentBuildDirectory; + + llvm::DenseMap CheckNamesByDiagnosticID; + + bool Profile; + std::string ProfilePrefix; + + bool AllowEnablingAnalyzerAlphaCheckers; +}; + +} // end namespace tidy +} // end namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYCONTEXT_H Index: clang-tools-extra/clang-tidy/ClangTidyContext.cpp =================================================================== --- /dev/null +++ clang-tools-extra/clang-tidy/ClangTidyContext.cpp @@ -0,0 +1,185 @@ +//===--- tools/extra/clang-tidy/ClangTidyContext.cpp ---------------------=== // +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file This file implements the ClangTidyContext class. +/// +/// This tool uses the Clang Tooling infrastructure, see +/// http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html +/// for details on setting it up with LLVM source tree. +/// +//===----------------------------------------------------------------------===// + +#include "ClangTidyContext.h" +#include "ClangTidyError.h" +#include "ClangTidyOptions.h" +#include "GlobList.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/ASTDiagnostic.h" +#include "clang/AST/Attr.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticOptions.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Frontend/DiagnosticRenderer.h" +#include "clang/Lex/Lexer.h" +#include "clang/Tooling/Core/Diagnostic.h" +#include "clang/Tooling/Core/Replacement.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/Regex.h" +#include +#include +#include + +namespace clang { +namespace tidy { + +class ClangTidyContext::CachedGlobList { +public: + CachedGlobList(StringRef Globs) : Globs(Globs) {} + + bool contains(StringRef S) { + switch (auto &Result = Cache[S]) { + case Yes: + return true; + case No: + return false; + case None: + Result = Globs.contains(S) ? Yes : No; + return Result == Yes; + } + llvm_unreachable("invalid enum"); + } + +private: + GlobList Globs; + enum Tristate { None, Yes, No }; + llvm::StringMap Cache; +}; + +ClangTidyContext::ClangTidyContext( + std::unique_ptr OptionsProvider, + bool AllowEnablingAnalyzerAlphaCheckers) + : DiagEngine(nullptr), OptionsProvider(std::move(OptionsProvider)), + Profile(false), + AllowEnablingAnalyzerAlphaCheckers(AllowEnablingAnalyzerAlphaCheckers) { + // Before the first translation unit we can get errors related to command-line + // parsing, use empty string for the file name in this case. + setCurrentFile(""); +} + +ClangTidyContext::~ClangTidyContext() = default; + +DiagnosticBuilder ClangTidyContext::diag( + StringRef CheckName, SourceLocation Loc, StringRef Description, + DiagnosticIDs::Level Level /* = DiagnosticIDs::Warning*/) { + assert(Loc.isValid()); + unsigned ID = DiagEngine->getDiagnosticIDs()->getCustomDiagID( + Level, (Description + " [" + CheckName + "]").str()); + CheckNamesByDiagnosticID.try_emplace(ID, CheckName); + return DiagEngine->Report(Loc, ID); +} + +DiagnosticBuilder ClangTidyContext::diag( + StringRef CheckName, StringRef Description, + DiagnosticIDs::Level Level /* = DiagnosticIDs::Warning*/) { + unsigned ID = DiagEngine->getDiagnosticIDs()->getCustomDiagID( + Level, (Description + " [" + CheckName + "]").str()); + CheckNamesByDiagnosticID.try_emplace(ID, CheckName); + return DiagEngine->Report(ID); +} + +DiagnosticBuilder ClangTidyContext::diag(const ClangTidyError &Error) { + SourceManager &SM = DiagEngine->getSourceManager(); + llvm::ErrorOr File = + SM.getFileManager().getFile(Error.Message.FilePath); + FileID ID = SM.getOrCreateFileID(*File, SrcMgr::C_User); + SourceLocation FileStartLoc = SM.getLocForStartOfFile(ID); + SourceLocation Loc = FileStartLoc.getLocWithOffset(Error.Message.FileOffset); + return diag(Error.DiagnosticName, Loc, Error.Message.Message, + static_cast(Error.DiagLevel)); +} + +DiagnosticBuilder ClangTidyContext::configurationDiag( + StringRef Message, + DiagnosticIDs::Level Level /* = DiagnosticIDs::Warning*/) { + return diag("clang-tidy-config", Message, Level); +} + +void ClangTidyContext::setSourceManager(SourceManager *SourceMgr) { + DiagEngine->setSourceManager(SourceMgr); +} + +void ClangTidyContext::setCurrentFile(StringRef File) { + CurrentFile = std::string(File); + CurrentOptions = getOptionsForFile(CurrentFile); + CheckFilter = std::make_unique(*getOptions().Checks); + WarningAsErrorFilter = + std::make_unique(*getOptions().WarningsAsErrors); +} + +void ClangTidyContext::setASTContext(ASTContext *Context) { + DiagEngine->SetArgToStringFn(&FormatASTNodeDiagnosticArgument, Context); + LangOpts = Context->getLangOpts(); +} + +const ClangTidyGlobalOptions &ClangTidyContext::getGlobalOptions() const { + return OptionsProvider->getGlobalOptions(); +} + +const ClangTidyOptions &ClangTidyContext::getOptions() const { + return CurrentOptions; +} + +ClangTidyOptions ClangTidyContext::getOptionsForFile(StringRef File) const { + // Merge options on top of getDefaults() as a safeguard against options with + // unset values. + return ClangTidyOptions::getDefaults().merge( + OptionsProvider->getOptions(File), 0); +} + +void ClangTidyContext::setEnableProfiling(bool P) { Profile = P; } + +void ClangTidyContext::setProfileStoragePrefix(StringRef Prefix) { + ProfilePrefix = std::string(Prefix); +} + +llvm::Optional +ClangTidyContext::getProfileStorageParams() const { + if (ProfilePrefix.empty()) + return llvm::None; + + return ClangTidyProfiling::StorageParams(ProfilePrefix, CurrentFile); +} + +bool ClangTidyContext::isCheckEnabled(StringRef CheckName) const { + assert(CheckFilter != nullptr); + return CheckFilter->contains(CheckName); +} + +bool ClangTidyContext::treatAsError(StringRef CheckName) const { + assert(WarningAsErrorFilter != nullptr); + return WarningAsErrorFilter->contains(CheckName); +} + +std::string ClangTidyContext::getCheckName(unsigned DiagnosticID) const { + std::string ClangWarningOption = std::string( + DiagEngine->getDiagnosticIDs()->getWarningOptionForDiag(DiagnosticID)); + if (!ClangWarningOption.empty()) + return "clang-diagnostic-" + ClangWarningOption; + llvm::DenseMap::const_iterator I = + CheckNamesByDiagnosticID.find(DiagnosticID); + if (I != CheckNamesByDiagnosticID.end()) + return I->second; + return ""; +} + +} // namespace tidy +} // namespace clang Index: clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h =================================================================== --- clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h +++ clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h @@ -9,11 +9,8 @@ #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/Tooling/Core/Diagnostic.h" -#include "llvm/ADT/DenseMap.h" #include "llvm/Support/Regex.h" namespace clang { @@ -29,185 +26,8 @@ } // namespace tooling namespace tidy { - -/// 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; - std::vector EnabledDiagnosticAliases; -}; - -/// Contains displayed and ignored diagnostic counters for a ClangTidy run. -struct ClangTidyStats { - unsigned ErrorsDisplayed = 0; - unsigned ErrorsIgnoredCheckFilter = 0; - unsigned ErrorsIgnoredNOLINT = 0; - unsigned ErrorsIgnoredNonUserCode = 0; - unsigned ErrorsIgnoredLineFilter = 0; - - unsigned errorsIgnored() const { - return ErrorsIgnoredNOLINT + ErrorsIgnoredCheckFilter + - ErrorsIgnoredNonUserCode + ErrorsIgnoredLineFilter; - } -}; - -/// 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: - /// Initializes \c ClangTidyContext instance. - ClangTidyContext(std::unique_ptr OptionsProvider, - bool AllowEnablingAnalyzerAlphaCheckers = false); - /// Sets the DiagnosticsEngine that diag() will emit diagnostics to. - // FIXME: this is required initialization, and should be a constructor param. - // Fix the context -> diag engine -> consumer -> context initialization cycle. - void setDiagnosticsEngine(DiagnosticsEngine *DiagEngine) { - this->DiagEngine = DiagEngine; - } - - ~ClangTidyContext(); - - /// 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); - - DiagnosticBuilder diag(StringRef CheckName, StringRef Message, - DiagnosticIDs::Level Level = DiagnosticIDs::Warning); - - DiagnosticBuilder diag(const ClangTidyError &Error); - - /// Report any errors to do with reading the configuration using this method. - DiagnosticBuilder - configurationDiag(StringRef Message, - DiagnosticIDs::Level Level = DiagnosticIDs::Warning); - - /// Sets the \c SourceManager of the used \c DiagnosticsEngine. - /// - /// This is called from the \c ClangTidyCheck base class. - void setSourceManager(SourceManager *SourceMgr); - - /// Should be called when starting to process new translation unit. - void setCurrentFile(StringRef File); - - /// Returns the main file name of the current translation unit. - StringRef getCurrentFile() const { return CurrentFile; } - - /// Sets ASTContext for the current translation unit. - void setASTContext(ASTContext *Context); - - /// Gets the language options from the AST context. - const LangOptions &getLangOpts() const { return LangOpts; } - - /// Returns the name of the clang-tidy check which produced this - /// diagnostic ID. - std::string getCheckName(unsigned DiagnosticID) const; - - /// 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; - - /// Returns \c true if the check should be upgraded to error for the - /// \c CurrentFile. - bool treatAsError(StringRef CheckName) const; - - /// Returns global options. - const ClangTidyGlobalOptions &getGlobalOptions() const; - - /// Returns options for \c CurrentFile. - /// - /// The \c CurrentFile can be changed using \c setCurrentFile. - const ClangTidyOptions &getOptions() const; - - /// Returns options for \c File. Does not change or depend on - /// \c CurrentFile. - ClangTidyOptions getOptionsForFile(StringRef File) const; - - /// Returns \c ClangTidyStats containing issued and ignored diagnostic - /// counters. - const ClangTidyStats &getStats() const { return Stats; } - - /// Control profile collection in clang-tidy. - void setEnableProfiling(bool Profile); - bool getEnableProfiling() const { return Profile; } - - /// Control storage of profile date. - void setProfileStoragePrefix(StringRef ProfilePrefix); - llvm::Optional - getProfileStorageParams() const; - - /// Should be called when starting to process new translation unit. - void setCurrentBuildDirectory(StringRef BuildDirectory) { - CurrentBuildDirectory = std::string(BuildDirectory); - } - - /// Returns build directory of the current translation unit. - const std::string &getCurrentBuildDirectory() const { - return CurrentBuildDirectory; - } - - /// If the experimental alpha checkers from the static analyzer can be - /// enabled. - bool canEnableAnalyzerAlphaCheckers() const { - return AllowEnablingAnalyzerAlphaCheckers; - } - - using DiagLevelAndFormatString = std::pair; - DiagLevelAndFormatString getDiagLevelAndFormatString(unsigned DiagnosticID, - SourceLocation Loc) { - return DiagLevelAndFormatString( - static_cast( - DiagEngine->getDiagnosticLevel(DiagnosticID, Loc)), - std::string( - DiagEngine->getDiagnosticIDs()->getDescription(DiagnosticID))); - } - -private: - // Writes to Stats. - friend class ClangTidyDiagnosticConsumer; - - DiagnosticsEngine *DiagEngine; - std::unique_ptr OptionsProvider; - - std::string CurrentFile; - ClangTidyOptions CurrentOptions; - class CachedGlobList; - std::unique_ptr CheckFilter; - std::unique_ptr WarningAsErrorFilter; - - LangOptions LangOpts; - - ClangTidyStats Stats; - - std::string CurrentBuildDirectory; - - llvm::DenseMap CheckNamesByDiagnosticID; - - bool Profile; - std::string ProfilePrefix; - - bool AllowEnablingAnalyzerAlphaCheckers; -}; +class ClangTidyContext; +struct ClangTidyError; /// Check whether a given diagnostic should be suppressed due to the presence /// of a "NOLINT" suppression comment. Index: clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp =================================================================== --- clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp +++ clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp @@ -6,8 +6,7 @@ // //===----------------------------------------------------------------------===// /// -/// \file This file implements ClangTidyDiagnosticConsumer, ClangTidyContext -/// and ClangTidyError classes. +/// \file This file implements the ClangTidyDiagnosticConsumer class. /// /// This tool uses the Clang Tooling infrastructure, see /// http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html @@ -16,6 +15,8 @@ //===----------------------------------------------------------------------===// #include "ClangTidyDiagnosticConsumer.h" +#include "ClangTidyContext.h" +#include "ClangTidyError.h" #include "ClangTidyOptions.h" #include "GlobList.h" #include "clang/AST/ASTContext.h" @@ -143,152 +144,6 @@ }; } // end anonymous namespace -ClangTidyError::ClangTidyError(StringRef CheckName, - ClangTidyError::Level DiagLevel, - StringRef BuildDirectory, bool IsWarningAsError) - : tooling::Diagnostic(CheckName, DiagLevel, BuildDirectory), - IsWarningAsError(IsWarningAsError) {} - -class ClangTidyContext::CachedGlobList { -public: - CachedGlobList(StringRef Globs) : Globs(Globs) {} - - bool contains(StringRef S) { - switch (auto &Result = Cache[S]) { - case Yes: - return true; - case No: - return false; - case None: - Result = Globs.contains(S) ? Yes : No; - return Result == Yes; - } - llvm_unreachable("invalid enum"); - } - -private: - GlobList Globs; - enum Tristate { None, Yes, No }; - llvm::StringMap Cache; -}; - -ClangTidyContext::ClangTidyContext( - std::unique_ptr OptionsProvider, - bool AllowEnablingAnalyzerAlphaCheckers) - : DiagEngine(nullptr), OptionsProvider(std::move(OptionsProvider)), - Profile(false), - AllowEnablingAnalyzerAlphaCheckers(AllowEnablingAnalyzerAlphaCheckers) { - // Before the first translation unit we can get errors related to command-line - // parsing, use empty string for the file name in this case. - setCurrentFile(""); -} - -ClangTidyContext::~ClangTidyContext() = default; - -DiagnosticBuilder ClangTidyContext::diag( - StringRef CheckName, SourceLocation Loc, StringRef Description, - DiagnosticIDs::Level Level /* = DiagnosticIDs::Warning*/) { - assert(Loc.isValid()); - unsigned ID = DiagEngine->getDiagnosticIDs()->getCustomDiagID( - Level, (Description + " [" + CheckName + "]").str()); - CheckNamesByDiagnosticID.try_emplace(ID, CheckName); - return DiagEngine->Report(Loc, ID); -} - -DiagnosticBuilder ClangTidyContext::diag( - StringRef CheckName, StringRef Description, - DiagnosticIDs::Level Level /* = DiagnosticIDs::Warning*/) { - unsigned ID = DiagEngine->getDiagnosticIDs()->getCustomDiagID( - Level, (Description + " [" + CheckName + "]").str()); - CheckNamesByDiagnosticID.try_emplace(ID, CheckName); - return DiagEngine->Report(ID); -} - -DiagnosticBuilder ClangTidyContext::diag(const ClangTidyError &Error) { - SourceManager &SM = DiagEngine->getSourceManager(); - llvm::ErrorOr File = - SM.getFileManager().getFile(Error.Message.FilePath); - FileID ID = SM.getOrCreateFileID(*File, SrcMgr::C_User); - SourceLocation FileStartLoc = SM.getLocForStartOfFile(ID); - SourceLocation Loc = FileStartLoc.getLocWithOffset(Error.Message.FileOffset); - return diag(Error.DiagnosticName, Loc, Error.Message.Message, - static_cast(Error.DiagLevel)); -} - -DiagnosticBuilder ClangTidyContext::configurationDiag( - StringRef Message, - DiagnosticIDs::Level Level /* = DiagnosticIDs::Warning*/) { - return diag("clang-tidy-config", Message, Level); -} - -void ClangTidyContext::setSourceManager(SourceManager *SourceMgr) { - DiagEngine->setSourceManager(SourceMgr); -} - -void ClangTidyContext::setCurrentFile(StringRef File) { - CurrentFile = std::string(File); - CurrentOptions = getOptionsForFile(CurrentFile); - CheckFilter = std::make_unique(*getOptions().Checks); - WarningAsErrorFilter = - std::make_unique(*getOptions().WarningsAsErrors); -} - -void ClangTidyContext::setASTContext(ASTContext *Context) { - DiagEngine->SetArgToStringFn(&FormatASTNodeDiagnosticArgument, Context); - LangOpts = Context->getLangOpts(); -} - -const ClangTidyGlobalOptions &ClangTidyContext::getGlobalOptions() const { - return OptionsProvider->getGlobalOptions(); -} - -const ClangTidyOptions &ClangTidyContext::getOptions() const { - return CurrentOptions; -} - -ClangTidyOptions ClangTidyContext::getOptionsForFile(StringRef File) const { - // Merge options on top of getDefaults() as a safeguard against options with - // unset values. - return ClangTidyOptions::getDefaults().merge( - OptionsProvider->getOptions(File), 0); -} - -void ClangTidyContext::setEnableProfiling(bool P) { Profile = P; } - -void ClangTidyContext::setProfileStoragePrefix(StringRef Prefix) { - ProfilePrefix = std::string(Prefix); -} - -llvm::Optional -ClangTidyContext::getProfileStorageParams() const { - if (ProfilePrefix.empty()) - return llvm::None; - - return ClangTidyProfiling::StorageParams(ProfilePrefix, CurrentFile); -} - -bool ClangTidyContext::isCheckEnabled(StringRef CheckName) const { - assert(CheckFilter != nullptr); - return CheckFilter->contains(CheckName); -} - -bool ClangTidyContext::treatAsError(StringRef CheckName) const { - assert(WarningAsErrorFilter != nullptr); - return WarningAsErrorFilter->contains(CheckName); -} - -std::string ClangTidyContext::getCheckName(unsigned DiagnosticID) const { - std::string ClangWarningOption = std::string( - DiagEngine->getDiagnosticIDs()->getWarningOptionForDiag(DiagnosticID)); - if (!ClangWarningOption.empty()) - return "clang-diagnostic-" + ClangWarningOption; - llvm::DenseMap::const_iterator I = - CheckNamesByDiagnosticID.find(DiagnosticID); - if (I != CheckNamesByDiagnosticID.end()) - return I->second; - return ""; -} - ClangTidyDiagnosticConsumer::ClangTidyDiagnosticConsumer( ClangTidyContext &Ctx, DiagnosticsEngine *ExternalDiagEngine, bool RemoveIncompatibleErrors, bool GetFixesFromNotes) Index: clang-tools-extra/clang-tidy/ClangTidyError.h =================================================================== --- /dev/null +++ clang-tools-extra/clang-tidy/ClangTidyError.h @@ -0,0 +1,38 @@ +//===--- ClangTidyError.h - clang-tidy --------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYERROR_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYERROR_H + +#include "clang/Tooling/Core/Diagnostic.h" +#include "llvm/ADT/StringRef.h" +#include +#include + +namespace clang { +namespace tidy { + +/// 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; + std::vector EnabledDiagnosticAliases; +}; + +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYDIAGNOSTICCONSUMER_H Index: clang-tools-extra/clang-tidy/ClangTidyError.cpp =================================================================== --- /dev/null +++ clang-tools-extra/clang-tidy/ClangTidyError.cpp @@ -0,0 +1,29 @@ +//===--- tools/extra/clang-tidy/ClangTidyError.cpp -----------------------=== // +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file This file implements the ClangTidyErrorDiagnosticConsumer class. +/// +/// This tool uses the Clang Tooling infrastructure, see +/// http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html +/// for details on setting it up with LLVM source tree. +/// +//===----------------------------------------------------------------------===// + +#include "ClangTidyError.h" + +namespace clang { +namespace tidy { + +ClangTidyError::ClangTidyError(StringRef CheckName, + ClangTidyError::Level DiagLevel, + StringRef BuildDirectory, bool IsWarningAsError) + : tooling::Diagnostic(CheckName, DiagLevel, BuildDirectory), + IsWarningAsError(IsWarningAsError) {} + +} // namespace tidy +} // namespace clang Index: clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp =================================================================== --- clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp +++ clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp @@ -16,6 +16,8 @@ #include "ClangTidyMain.h" #include "../ClangTidy.h" +#include "../ClangTidyContext.h" +#include "../ClangTidyError.h" #include "../ClangTidyForceLinker.h" #include "../GlobList.h" #include "clang/Tooling/CommonOptionsParser.h" @@ -128,10 +130,10 @@ cl::init(false), cl::cat(ClangTidyCategory)); static cl::opt FixNotes("fix-notes", cl::desc(R"( -If a warning has no fix, but a single fix can -be found through an associated diagnostic note, -apply the fix. -Specifying this flag will implicitly enable the +If a warning has no fix, but a single fix can +be found through an associated diagnostic note, +apply the fix. +Specifying this flag will implicitly enable the '--fix' flag. )"), cl::init(false), cl::cat(ClangTidyCategory)); Index: clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp =================================================================== --- clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp +++ clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp @@ -1,6 +1,7 @@ #include "ClangTidyOptions.h" #include "ClangTidyCheck.h" #include "ClangTidyDiagnosticConsumer.h" +#include "ClangTidyError.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/Testing/Support/Annotations.h" Index: clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h =================================================================== --- clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h +++ clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h @@ -12,6 +12,7 @@ #include "ClangTidy.h" #include "ClangTidyCheck.h" #include "ClangTidyDiagnosticConsumer.h" +#include "ClangTidyError.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendActions.h"