Index: clang-tidy/ClangTidyDiagnosticConsumer.h =================================================================== --- clang-tidy/ClangTidyDiagnosticConsumer.h +++ 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 @@ 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 @@ 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 @@ SmallVectorImpl *Errors; DiagnosticsEngine *DiagEngine; + ClangTidyOptions Options; ChecksFilter Filter; llvm::DenseMap CheckNamesByDiagnosticID; @@ -142,8 +143,10 @@ private: void finalizeLastError(); + bool relatesToUserCode(SourceLocation Location); ClangTidyContext &Context; + llvm::Regex HeaderFilter; std::unique_ptr Diags; SmallVector Errors; bool LastErrorRelatesToUserCode; Index: clang-tidy/ClangTidyDiagnosticConsumer.cpp =================================================================== --- clang-tidy/ClangTidyDiagnosticConsumer.cpp +++ clang-tidy/ClangTidyDiagnosticConsumer.cpp @@ -124,7 +124,7 @@ 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 @@ } 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 @@ 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; Index: clang-tidy/ClangTidyOptions.h =================================================================== --- clang-tidy/ClangTidyOptions.h +++ 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 @@ 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; }; Index: clang-tidy/tool/ClangTidyMain.cpp =================================================================== --- clang-tidy/tool/ClangTidyMain.cpp +++ clang-tidy/tool/ClangTidyMain.cpp @@ -39,6 +39,12 @@ "|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 @@ clang::tidy::ClangTidyOptions Options; Options.EnableChecksRegex = Checks; Options.DisableChecksRegex = DisableChecks; + Options.HeaderFilterRegex = HeaderFilter; Options.AnalyzeTemporaryDtors = AnalyzeTemporaryDtors; // FIXME: Allow using --list-checks without positional arguments. Index: test/clang-tidy/Inputs/file-filter/header1.h =================================================================== --- /dev/null +++ test/clang-tidy/Inputs/file-filter/header1.h @@ -0,0 +1 @@ +class A1 { A1(int); }; @@ -0,0 +1 @@ +class A1 { A1(int); }; @@ -0,0 +1 @@ +class A1 { A1(int); }; Index: test/clang-tidy/Inputs/file-filter/header2.h =================================================================== --- /dev/null +++ test/clang-tidy/Inputs/file-filter/header2.h @@ -0,0 +1 @@ +class A2 { A2(int); }; @@ -0,0 +1 @@ +class A2 { A2(int); }; @@ -0,0 +1 @@ +class A2 { A2(int); }; Index: test/clang-tidy/file-filter.cpp =================================================================== --- /dev/null +++ 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: