Print stats on displayed and ignored warnings.
Summary:
Also displays a hint to use -header-filter='.*' in case any warnings
are in non-user code. This will help discoverability of this option.
Reviewers: klimek
Reviewed By: klimek
Subscribers: cfe-commits
Differential Revision: http://reviews.llvm.org/D3621
llvm-svn: 208174
diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp b/clang-tools-extra/clang-tidy/ClangTidy.cpp
index 0445710..e44dab3 100644
--- a/clang-tools-extra/clang-tidy/ClangTidy.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp
@@ -298,10 +298,10 @@
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 @@
};
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 8d71eeb..1bc3e29 100644
--- a/clang-tools-extra/clang-tidy/ClangTidy.h
+++ b/clang-tools-extra/clang-tidy/ClangTidy.h
@@ -121,10 +121,10 @@
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 fdf1f0c..ad30898 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
@@ -41,8 +41,6 @@
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 @@
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 @@
++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 @@
}
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 @@
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 d944836..c030a67 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
+++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
@@ -68,6 +68,17 @@
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 @@
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 @@
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 17d1c78..624e6c0 100644
--- a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
+++ b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
@@ -59,6 +59,31 @@
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 @@
}
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;
}