diff options
8 files changed, 83 insertions, 26 deletions
diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp b/clang-tools-extra/clang-tidy/ClangTidy.cpp index 0445710eaa2..e44dab3faef 100644 --- a/clang-tools-extra/clang-tidy/ClangTidy.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp @@ -298,10 +298,10 @@ std::vector<std::string> getCheckNames(const ClangTidyOptions &Options) { return Factory.getCheckNames(); } -void runClangTidy(const ClangTidyOptions &Options, - const tooling::CompilationDatabase &Compilations, - ArrayRef<std::string> Ranges, - SmallVectorImpl<ClangTidyError> *Errors) { +ClangTidyStats runClangTidy(const ClangTidyOptions &Options, + const tooling::CompilationDatabase &Compilations, + ArrayRef<std::string> Ranges, + SmallVectorImpl<ClangTidyError> *Errors) { // FIXME: Ranges are currently full files. Support selecting specific // (line-)ranges. ClangTool Tool(Compilations, Ranges); @@ -333,6 +333,7 @@ void runClangTidy(const ClangTidyOptions &Options, }; Tool.run(new ActionFactory(new ClangTidyASTConsumerFactory(Context, Options))); + return Context.getStats(); } void handleErrors(SmallVectorImpl<ClangTidyError> &Errors, bool Fix) { diff --git a/clang-tools-extra/clang-tidy/ClangTidy.h b/clang-tools-extra/clang-tidy/ClangTidy.h index 8d71eeb37ad..1bc3e29592d 100644 --- a/clang-tools-extra/clang-tidy/ClangTidy.h +++ b/clang-tools-extra/clang-tidy/ClangTidy.h @@ -121,10 +121,10 @@ private: std::vector<std::string> getCheckNames(const ClangTidyOptions &Options); /// \brief Run a set of clang-tidy checks on a set of files. -void runClangTidy(const ClangTidyOptions &Options, - const tooling::CompilationDatabase &Compilations, - ArrayRef<std::string> Ranges, - SmallVectorImpl<ClangTidyError> *Errors); +ClangTidyStats runClangTidy(const ClangTidyOptions &Options, + const tooling::CompilationDatabase &Compilations, + ArrayRef<std::string> Ranges, + SmallVectorImpl<ClangTidyError> *Errors); // FIXME: This interface will need to be significantly extended to be useful. // FIXME: Implement confidence levels for displaying/fixing errors. diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp index fdf1f0c2e6c..ad30898e489 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp @@ -41,8 +41,6 @@ protected: ArrayRef<CharSourceRange> Ranges, const SourceManager *SM, DiagOrStoredDiag Info) override { - if (Level == DiagnosticsEngine::Ignored) - return; ClangTidyMessage TidyMessage = Loc.isValid() ? ClangTidyMessage(Message, *SM, Loc) : ClangTidyMessage(Message); @@ -111,8 +109,7 @@ ClangTidyMessage::ClangTidyMessage(StringRef Message, FileOffset = Sources.getFileOffset(Loc); } -ClangTidyError::ClangTidyError(StringRef CheckName) - : CheckName(CheckName) {} +ClangTidyError::ClangTidyError(StringRef CheckName) : CheckName(CheckName) {} ChecksFilter::ChecksFilter(const ClangTidyOptions &Options) : EnableChecks(Options.EnableChecksRegex), @@ -139,8 +136,10 @@ DiagnosticBuilder ClangTidyContext::diag( ++P; StringRef RestOfLine(CharacterData, P - CharacterData + 1); // FIXME: Handle /\bNOLINT\b(\([^)]*\))?/ as cpplint.py does. - if (RestOfLine.find("NOLINT") != StringRef::npos) + if (RestOfLine.find("NOLINT") != StringRef::npos) { Level = DiagnosticIDs::Ignored; + ++Stats.ErrorsIgnoredNOLINT; + } } unsigned ID = DiagEngine->getDiagnosticIDs()->getCustomDiagID( Level, (Description + " [" + CheckName + "]").str()); @@ -181,8 +180,18 @@ ClangTidyDiagnosticConsumer::ClangTidyDiagnosticConsumer(ClangTidyContext &Ctx) } void ClangTidyDiagnosticConsumer::finalizeLastError() { - if (!LastErrorRelatesToUserCode && !Errors.empty()) - Errors.pop_back(); + if (!Errors.empty()) { + ClangTidyError &Error = Errors.back(); + if (!Context.getChecksFilter().isCheckEnabled(Error.CheckName)) { + ++Context.Stats.ErrorsIgnoredCheckFilter; + Errors.pop_back(); + } else if (!LastErrorRelatesToUserCode) { + ++Context.Stats.ErrorsIgnoredNonUserCode; + Errors.pop_back(); + } else { + ++Context.Stats.ErrorsDisplayed; + } + } LastErrorRelatesToUserCode = false; } @@ -259,10 +268,9 @@ struct LessClangTidyError { void ClangTidyDiagnosticConsumer::finish() { finalizeLastError(); std::set<const ClangTidyError*, LessClangTidyError> UniqueErrors; - for (const ClangTidyError &Error : Errors) { - if (Context.getChecksFilter().isCheckEnabled(Error.CheckName)) - UniqueErrors.insert(&Error); - } + for (const ClangTidyError &Error : Errors) + UniqueErrors.insert(&Error); + for (const ClangTidyError *Error : UniqueErrors) Context.storeError(*Error); Errors.clear(); diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h index d944836c1b1..c030a67013a 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h +++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h @@ -68,6 +68,17 @@ private: llvm::Regex DisableChecks; }; +struct ClangTidyStats { + ClangTidyStats() + : ErrorsDisplayed(0), ErrorsIgnoredCheckFilter(0), ErrorsIgnoredNOLINT(0), + ErrorsIgnoredNonUserCode(0) {} + + unsigned ErrorsDisplayed; + unsigned ErrorsIgnoredCheckFilter; + unsigned ErrorsIgnoredNOLINT; + unsigned ErrorsIgnoredNonUserCode; +}; + /// \brief Every \c ClangTidyCheck reports errors through a \c DiagnosticEngine /// provided by this context. /// @@ -108,6 +119,7 @@ public: ChecksFilter &getChecksFilter() { return Filter; } const ClangTidyOptions &getOptions() const { return Options; } + const ClangTidyStats &getStats() const { return Stats; } private: friend class ClangTidyDiagnosticConsumer; // Calls storeError(). @@ -119,6 +131,7 @@ private: DiagnosticsEngine *DiagEngine; ClangTidyOptions Options; ChecksFilter Filter; + ClangTidyStats Stats; llvm::DenseMap<unsigned, std::string> CheckNamesByDiagnosticID; }; diff --git a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp index 17d1c786079..624e6c05f9b 100644 --- a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp +++ b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp @@ -59,6 +59,31 @@ static cl::opt<bool> AnalyzeTemporaryDtors( cl::init(false), cl::cat(ClangTidyCategory)); +static void printStats(const clang::tidy::ClangTidyStats &Stats) { + unsigned ErrorsIgnored = Stats.ErrorsIgnoredNOLINT + + Stats.ErrorsIgnoredCheckFilter + + Stats.ErrorsIgnoredNonUserCode; + if (ErrorsIgnored) { + llvm::errs() << "Suppressed " << ErrorsIgnored << " warnings ("; + StringRef Separator = ""; + if (Stats.ErrorsIgnoredNonUserCode) { + llvm::errs() << Stats.ErrorsIgnoredNonUserCode << " in non-user code"; + Separator = ", "; + } + if (Stats.ErrorsIgnoredNOLINT) { + llvm::errs() << Separator << Stats.ErrorsIgnoredNOLINT << " NOLINT"; + Separator = ", "; + } + if (Stats.ErrorsIgnoredCheckFilter) + llvm::errs() << Separator << Stats.ErrorsIgnoredCheckFilter + << " with check filters"; + llvm::errs() << ").\n"; + if (Stats.ErrorsIgnoredNonUserCode) + llvm::errs() << "Use -header-filter='.*' to display errors from all " + "non-system headers.\n"; + } +} + int main(int argc, const char **argv) { CommonOptionsParser OptionsParser(argc, argv, ClangTidyCategory); @@ -78,10 +103,12 @@ int main(int argc, const char **argv) { } SmallVector<clang::tidy::ClangTidyError, 16> Errors; - clang::tidy::runClangTidy(Options, OptionsParser.getCompilations(), - OptionsParser.getSourcePathList(), &Errors); + clang::tidy::ClangTidyStats Stats = + clang::tidy::runClangTidy(Options, OptionsParser.getCompilations(), + OptionsParser.getSourcePathList(), &Errors); clang::tidy::handleErrors(Errors, Fix); + printStats(Stats); return 0; } diff --git a/clang-tools-extra/test/clang-tidy/file-filter.cpp b/clang-tools-extra/test/clang-tidy/file-filter.cpp index f9e029b2692..fa740f34d35 100644 --- a/clang-tools-extra/test/clang-tidy/file-filter.cpp +++ b/clang-tools-extra/test/clang-tidy/file-filter.cpp @@ -1,6 +1,6 @@ -// RUN: clang-tidy -checks=google-explicit-constructor -disable-checks='' -header-filter='' %s -- -I %S/Inputs/file-filter | FileCheck %s -// RUN: clang-tidy -checks=google-explicit-constructor -disable-checks='' -header-filter='.*' %s -- -I %S/Inputs/file-filter | FileCheck --check-prefix=CHECK2 %s -// RUN: clang-tidy -checks=google-explicit-constructor -disable-checks='' -header-filter='header2\.h' %s -- -I %S/Inputs/file-filter | FileCheck --check-prefix=CHECK3 %s +// RUN: clang-tidy -checks=google-explicit-constructor -disable-checks='' -header-filter='' %s -- -I %S/Inputs/file-filter 2>&1 | FileCheck %s +// RUN: clang-tidy -checks=google-explicit-constructor -disable-checks='' -header-filter='.*' %s -- -I %S/Inputs/file-filter 2>&1 | FileCheck --check-prefix=CHECK2 %s +// RUN: clang-tidy -checks=google-explicit-constructor -disable-checks='' -header-filter='header2\.h' %s -- -I %S/Inputs/file-filter 2>&1 | FileCheck --check-prefix=CHECK3 %s #include "header1.h" // CHECK-NOT: warning: @@ -20,3 +20,10 @@ class A { A(int); }; // CHECK-NOT: warning: // CHECK2-NOT: warning: // CHECK3-NOT: warning: + +// CHECK: Suppressed 2 warnings (2 in non-user code) +// CHECK: Use -header-filter='.*' to display errors from all non-system headers. +// CHECK2-NOT: Suppressed {{.*}} warnings +// CHECK2-NOT: Use -header-filter='.*' {{.*}} +// CHECK3: Suppressed 1 warnings (1 in non-user code) +// CHECK3: Use -header-filter='.*' {{.*}} diff --git a/clang-tools-extra/test/clang-tidy/nolint.cpp b/clang-tools-extra/test/clang-tidy/nolint.cpp index f192930c2b7..d4a5c4cd623 100644 --- a/clang-tools-extra/test/clang-tidy/nolint.cpp +++ b/clang-tools-extra/test/clang-tidy/nolint.cpp @@ -1,4 +1,4 @@ -// RUN: clang-tidy -checks=google-explicit-constructor -disable-checks='' %s -- | FileCheck %s +// RUN: clang-tidy -checks=google-explicit-constructor -disable-checks='' %s -- 2>&1 | FileCheck %s class A { A(int i); }; // CHECK: :[[@LINE-1]]:11: warning: Single-argument constructors must be explicit [google-explicit-constructor] @@ -8,3 +8,4 @@ class B { B(int i); }; // NOLINT class C { C(int i); }; // NOLINT(we-dont-care-about-categories-yet) // CHECK-NOT: :[[@LINE-1]]:11: warning: Single-argument constructors must be explicit [google-explicit-constructor] +// CHECK: Suppressed 2 warnings (2 NOLINT) diff --git a/clang-tools-extra/test/clang-tidy/redundant-smartptr-get.cpp b/clang-tools-extra/test/clang-tidy/redundant-smartptr-get.cpp index 091e9d4dc68..22decca04af 100644 --- a/clang-tools-extra/test/clang-tidy/redundant-smartptr-get.cpp +++ b/clang-tools-extra/test/clang-tidy/redundant-smartptr-get.cpp @@ -78,7 +78,7 @@ void Positive() { // CHECK: nullptr != sp->get(); } -// CHECK-NOT: warning +// CHECK-NOT: warning: void Negative() { struct NegPtr { |

