From 9ff5b6f3ca4898c860b1d4c666250e22e020a80a Mon Sep 17 00:00:00 2001 From: Alexander Kornienko Date: Mon, 5 May 2014 14:54:47 +0000 Subject: [PATCH] Add clang-tidy -header-filter option Summary: Add clang-tidy -header-filter option to specify from which headers we want diagnostics to be printed. By default we don't print diagnostics from headers. We always print diagnostics from the main file of each translation unit. Reviewers: djasper, klimek Reviewed By: klimek Subscribers: klimek, cfe-commits Differential Revision: http://reviews.llvm.org/D3590 llvm-svn: 207970 --- .../ClangTidyDiagnosticConsumer.cpp | 27 ++++++++++++++++--- .../clang-tidy/ClangTidyDiagnosticConsumer.h | 7 +++-- .../clang-tidy/ClangTidyOptions.h | 5 ++++ .../clang-tidy/tool/ClangTidyMain.cpp | 7 +++++ .../clang-tidy/Inputs/file-filter/header1.h | 1 + .../clang-tidy/Inputs/file-filter/header2.h | 1 + .../test/clang-tidy/file-filter.cpp | 22 +++++++++++++++ 7 files changed, 64 insertions(+), 6 deletions(-) create mode 100644 clang-tools-extra/test/clang-tidy/Inputs/file-filter/header1.h create mode 100644 clang-tools-extra/test/clang-tidy/Inputs/file-filter/header2.h create mode 100644 clang-tools-extra/test/clang-tidy/file-filter.cpp diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp index 2a680cdcad156..f32470407abc5 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp @@ -124,7 +124,7 @@ bool ChecksFilter::isCheckEnabled(StringRef Name) { ClangTidyContext::ClangTidyContext(SmallVectorImpl *Errors, const ClangTidyOptions &Options) - : Errors(Errors), DiagEngine(nullptr), Filter(Options) {} + : Errors(Errors), DiagEngine(nullptr), Options(Options), Filter(Options) {} DiagnosticBuilder ClangTidyContext::diag( StringRef CheckName, SourceLocation Loc, StringRef Description, @@ -171,7 +171,8 @@ StringRef ClangTidyContext::getCheckName(unsigned DiagnosticID) const { } ClangTidyDiagnosticConsumer::ClangTidyDiagnosticConsumer(ClangTidyContext &Ctx) - : Context(Ctx), LastErrorRelatesToUserCode(false) { + : Context(Ctx), HeaderFilter(Ctx.getOptions().HeaderFilterRegex), + LastErrorRelatesToUserCode(false) { IntrusiveRefCntPtr DiagOpts = new DiagnosticOptions(); Diags.reset(new DiagnosticsEngine( IntrusiveRefCntPtr(new DiagnosticIDs), &*DiagOpts, this, @@ -217,12 +218,30 @@ void ClangTidyDiagnosticConsumer::HandleDiagnostic( Sources); // Let argument parsing-related warnings through. - if (!Info.getLocation().isValid() || - !Diags->getSourceManager().isInSystemHeader(Info.getLocation())) { + if (relatesToUserCode(Info.getLocation())) { LastErrorRelatesToUserCode = true; } } +bool ClangTidyDiagnosticConsumer::relatesToUserCode(SourceLocation Location) { + // Invalid location may mean a diagnostic in a command line, don't skip these. + if (!Location.isValid()) + return true; + + const SourceManager &Sources = Diags->getSourceManager(); + if (Sources.isInSystemHeader(Location)) + return false; + + // FIXME: We start with a conservative approach here, but the actual type of + // location needed depends on the check (in particular, where this check wants + // to apply fixes). + FileID FID = Sources.getDecomposedExpansionLoc(Location).first; + if (FID == Sources.getMainFileID()) + return true; + + return HeaderFilter.match(Sources.getFileEntryForID(FID)->getName()); +} + struct LessClangTidyError { bool operator()(const ClangTidyError *LHS, const ClangTidyError *RHS) const { const ClangTidyMessage &M1 = LHS->Message; diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h index 6ba690ef245c5..d944836c1b1d9 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h +++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h @@ -10,6 +10,7 @@ #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANG_TIDY_DIAGNOSTIC_CONSUMER_H #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANG_TIDY_DIAGNOSTIC_CONSUMER_H +#include "ClangTidyOptions.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/SourceManager.h" #include "clang/Tooling/Refactoring.h" @@ -28,8 +29,6 @@ class CompilationDatabase; namespace tidy { -struct ClangTidyOptions; - /// \brief A message from a clang-tidy check. /// /// Note that this is independent of a \c SourceManager. @@ -108,6 +107,7 @@ class ClangTidyContext { StringRef getCheckName(unsigned DiagnosticID) const; ChecksFilter &getChecksFilter() { return Filter; } + const ClangTidyOptions &getOptions() const { return Options; } private: friend class ClangTidyDiagnosticConsumer; // Calls storeError(). @@ -117,6 +117,7 @@ class ClangTidyContext { SmallVectorImpl *Errors; DiagnosticsEngine *DiagEngine; + ClangTidyOptions Options; ChecksFilter Filter; llvm::DenseMap CheckNamesByDiagnosticID; @@ -142,8 +143,10 @@ class ClangTidyDiagnosticConsumer : public DiagnosticConsumer { private: void finalizeLastError(); + bool relatesToUserCode(SourceLocation Location); ClangTidyContext &Context; + llvm::Regex HeaderFilter; std::unique_ptr Diags; SmallVector Errors; bool LastErrorRelatesToUserCode; diff --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.h b/clang-tools-extra/clang-tidy/ClangTidyOptions.h index 582dc78563669..f3e5fd22df93c 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyOptions.h +++ b/clang-tools-extra/clang-tidy/ClangTidyOptions.h @@ -10,6 +10,8 @@ #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANG_TIDY_OPTIONS_H #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANG_TIDY_OPTIONS_H +#include + namespace clang { namespace tidy { @@ -18,6 +20,9 @@ struct ClangTidyOptions { ClangTidyOptions() : EnableChecksRegex(".*"), AnalyzeTemporaryDtors(false) {} std::string EnableChecksRegex; std::string DisableChecksRegex; + // Output warnings from headers matching this filter. Warnings from main files + // will always be displayed. + std::string HeaderFilterRegex; bool AnalyzeTemporaryDtors; }; diff --git a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp index 3d5c312fe7d56..17d1c78607929 100644 --- a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp +++ b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp @@ -39,6 +39,12 @@ static cl::opt DisableChecks( "|llvm-namespace-comment" // Not complete. "|google-.*)"), // Doesn't apply to LLVM. cl::cat(ClangTidyCategory)); +static cl::opt HeaderFilter( + "header-filter", + cl::desc("Regular expression matching the names of the headers to output\n" + "diagnostics from. Diagnostics from the main file of each\n" + "translation unit are always displayed."), + cl::init(""), cl::cat(ClangTidyCategory)); static cl::opt Fix("fix", cl::desc("Fix detected errors if possible."), cl::init(false), cl::cat(ClangTidyCategory)); @@ -59,6 +65,7 @@ int main(int argc, const char **argv) { clang::tidy::ClangTidyOptions Options; Options.EnableChecksRegex = Checks; Options.DisableChecksRegex = DisableChecks; + Options.HeaderFilterRegex = HeaderFilter; Options.AnalyzeTemporaryDtors = AnalyzeTemporaryDtors; // FIXME: Allow using --list-checks without positional arguments. diff --git a/clang-tools-extra/test/clang-tidy/Inputs/file-filter/header1.h b/clang-tools-extra/test/clang-tidy/Inputs/file-filter/header1.h new file mode 100644 index 0000000000000..ba9e3d153ee63 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/Inputs/file-filter/header1.h @@ -0,0 +1 @@ +class A1 { A1(int); }; diff --git a/clang-tools-extra/test/clang-tidy/Inputs/file-filter/header2.h b/clang-tools-extra/test/clang-tidy/Inputs/file-filter/header2.h new file mode 100644 index 0000000000000..09bfeabc8723b --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/Inputs/file-filter/header2.h @@ -0,0 +1 @@ +class A2 { A2(int); }; diff --git a/clang-tools-extra/test/clang-tidy/file-filter.cpp b/clang-tools-extra/test/clang-tidy/file-filter.cpp new file mode 100644 index 0000000000000..f9e029b2692de --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/file-filter.cpp @@ -0,0 +1,22 @@ +// 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 + +#include "header1.h" +// CHECK-NOT: warning: +// CHECK2: header1.h:1:12: warning: Single-argument constructors must be explicit [google-explicit-constructor] +// CHECK3-NOT: warning: + +#include "header2.h" +// CHECK-NOT: warning: +// CHECK2: header2.h:1:12: warning: Single-argument constructors {{.*}} +// CHECK3: header2.h:1:12: warning: Single-argument constructors {{.*}} + +class A { A(int); }; +// CHECK: :[[@LINE-1]]:11: warning: Single-argument constructors {{.*}} +// CHECK2: :[[@LINE-2]]:11: warning: Single-argument constructors {{.*}} +// CHECK3: :[[@LINE-3]]:11: warning: Single-argument constructors {{.*}} + +// CHECK-NOT: warning: +// CHECK2-NOT: warning: +// CHECK3-NOT: warning: