forked from OSchip/llvm-project
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
This commit is contained in:
parent
d103130ee0
commit
5d174547a9
|
@ -298,7 +298,7 @@ std::vector<std::string> getCheckNames(const ClangTidyOptions &Options) {
|
|||
return Factory.getCheckNames();
|
||||
}
|
||||
|
||||
void runClangTidy(const ClangTidyOptions &Options,
|
||||
ClangTidyStats runClangTidy(const ClangTidyOptions &Options,
|
||||
const tooling::CompilationDatabase &Compilations,
|
||||
ArrayRef<std::string> Ranges,
|
||||
SmallVectorImpl<ClangTidyError> *Errors) {
|
||||
|
@ -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) {
|
||||
|
|
|
@ -121,7 +121,7 @@ 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,
|
||||
ClangTidyStats runClangTidy(const ClangTidyOptions &Options,
|
||||
const tooling::CompilationDatabase &Compilations,
|
||||
ArrayRef<std::string> Ranges,
|
||||
SmallVectorImpl<ClangTidyError> *Errors);
|
||||
|
|
|
@ -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())
|
||||
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))
|
||||
for (const ClangTidyError &Error : Errors)
|
||||
UniqueErrors.insert(&Error);
|
||||
}
|
||||
|
||||
for (const ClangTidyError *Error : UniqueErrors)
|
||||
Context.storeError(*Error);
|
||||
Errors.clear();
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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::ClangTidyStats Stats =
|
||||
clang::tidy::runClangTidy(Options, OptionsParser.getCompilations(),
|
||||
OptionsParser.getSourcePathList(), &Errors);
|
||||
clang::tidy::handleErrors(Errors, Fix);
|
||||
|
||||
printStats(Stats);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -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='.*' {{.*}}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -78,7 +78,7 @@ void Positive() {
|
|||
// CHECK: nullptr != sp->get();
|
||||
}
|
||||
|
||||
// CHECK-NOT: warning
|
||||
// CHECK-NOT: warning:
|
||||
|
||||
void Negative() {
|
||||
struct NegPtr {
|
||||
|
|
Loading…
Reference in New Issue