Index: clang-tools-extra/clang-tidy/ClangTidy.cpp =================================================================== --- clang-tools-extra/clang-tidy/ClangTidy.cpp +++ clang-tools-extra/clang-tidy/ClangTidy.cpp @@ -307,20 +307,26 @@ class ClangTidyASTConsumer : public MultiplexConsumer { public: - ClangTidyASTConsumer(std::vector> Consumers, - std::unique_ptr Profiling, - std::unique_ptr Finder, - std::vector> Checks) + ClangTidyASTConsumer( + std::vector> Consumers, + std::unique_ptr Profiling, + std::unique_ptr Finder, + std::unique_ptr AllFileFinder, + std::vector> Checks, + std::vector> AllFileChecks) : MultiplexConsumer(std::move(Consumers)), Profiling(std::move(Profiling)), Finder(std::move(Finder)), - Checks(std::move(Checks)) {} + AllFileFinder(std::move(AllFileFinder)), Checks(std::move(Checks)), + AllFileChecks(std::move(AllFileChecks)) {} private: // Destructor order matters! Profiling must be destructed last. // Or at least after Finder. std::unique_ptr Profiling; std::unique_ptr Finder; + std::unique_ptr AllFileFinder; std::vector> Checks; + std::vector> AllFileChecks; }; } // namespace @@ -403,22 +409,38 @@ std::vector> Checks = CheckFactories->createChecks(&Context); + std::vector> AllFileChecks = + CheckFactories->createAllFileChecks(&Context); - llvm::erase_if(Checks, [&](std::unique_ptr &Check) { + auto EraseFilter = [&](std::unique_ptr &Check) { return !Check->isLanguageVersionSupported(Context.getLangOpts()); - }); + }; + llvm::erase_if(Checks, EraseFilter); + llvm::erase_if(AllFileChecks, EraseFilter); ast_matchers::MatchFinder::MatchFinderOptions FinderOptions; + ast_matchers::MatchFinder::MatchFinderOptions AllFileFinderOptions; std::unique_ptr Profiling; if (Context.getEnableProfiling()) { Profiling = std::make_unique( Context.getProfileStorageParams()); + // Two Finders share the same Profiling->Records. FinderOptions.CheckProfiling.emplace(Profiling->Records); + AllFileFinderOptions.CheckProfiling.emplace(Profiling->Records); + } + + // LocationFilter is not for AllFileFinder. + if (*Context.getOptions().SkipHeaders) { + std::unique_ptr LocationFilter( + ClangTidyDiagnosticConsumer::newLocationFilter(&Context)); + FinderOptions.Filter = std::move(LocationFilter); } std::unique_ptr Finder( new ast_matchers::MatchFinder(std::move(FinderOptions))); + std::unique_ptr AllFileFinder( + new ast_matchers::MatchFinder(std::move(AllFileFinderOptions))); Preprocessor *PP = &Compiler.getPreprocessor(); Preprocessor *ModuleExpanderPP = PP; @@ -434,10 +456,16 @@ Check->registerMatchers(&*Finder); Check->registerPPCallbacks(*SM, PP, ModuleExpanderPP); } + for (auto &Check : AllFileChecks) { + Check->registerMatchers(&*AllFileFinder); + Check->registerPPCallbacks(*SM, PP, ModuleExpanderPP); + } std::vector> Consumers; if (!Checks.empty()) Consumers.push_back(Finder->newASTConsumer()); + if (!AllFileChecks.empty()) + Consumers.push_back(AllFileFinder->newASTConsumer()); #if CLANG_TIDY_ENABLE_STATIC_ANALYZER AnalyzerOptionsRef AnalyzerOptions = Compiler.getAnalyzerOpts(); @@ -458,7 +486,7 @@ #endif // CLANG_TIDY_ENABLE_STATIC_ANALYZER return std::make_unique( std::move(Consumers), std::move(Profiling), std::move(Finder), - std::move(Checks)); + std::move(AllFileFinder), std::move(Checks), std::move(AllFileChecks)); } std::vector ClangTidyASTConsumerFactory::getCheckNames() { @@ -484,6 +512,10 @@ CheckFactories->createChecks(&Context); for (const auto &Check : Checks) Check->storeOptions(Options); + std::vector> AllFileChecks = + CheckFactories->createAllFileChecks(&Context); + for (const auto &Check : AllFileChecks) + Check->storeOptions(Options); return Options; } Index: clang-tools-extra/clang-tidy/ClangTidyCheck.h =================================================================== --- clang-tools-extra/clang-tidy/ClangTidyCheck.h +++ clang-tools-extra/clang-tidy/ClangTidyCheck.h @@ -132,6 +132,11 @@ /// whether it has the default value or it has been overridden. virtual void storeOptions(ClangTidyOptions::OptionMap &Options) {} + /// Returns true if the Location should have warnings suppressed. + static bool skipLocation(SourceLocation Location) { + return ClangTidyDiagnosticConsumer::skipLocation(Location); + } + /// Provides access to the ``ClangTidyCheck`` options via check-local /// names. /// Index: clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h =================================================================== --- clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h +++ clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h @@ -11,7 +11,9 @@ #include "ClangTidyOptions.h" #include "ClangTidyProfiling.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceManager.h" #include "clang/Tooling/Core/Diagnostic.h" #include "llvm/ADT/DenseMap.h" #include "llvm/Support/Regex.h" @@ -20,10 +22,6 @@ class ASTContext; class CompilerInstance; -class SourceManager; -namespace ast_matchers { -class MatchFinder; -} namespace tooling { class CompilationDatabase; } @@ -104,6 +102,11 @@ configurationDiag(StringRef Message, DiagnosticIDs::Level Level = DiagnosticIDs::Warning); + /// Returns the \c SourceManager of the used \c DiagnosticsEngine. + SourceManager &getSourceManager() const { + return DiagEngine->getSourceManager(); + } + /// Sets the \c SourceManager of the used \c DiagnosticsEngine. /// /// This is called from the \c ClangTidyCheck base class. @@ -212,6 +215,11 @@ bool AllowEnablingAnalyzerAlphaCheckers; }; +typedef ast_matchers::MatchFinder::MatchFinderOptions::LocFilter + ClangTidyLocationFilter; + +class ClangTidyLocationFilterImpl; + /// Check whether a given diagnostic should be suppressed due to the presence /// of a "NOLINT" suppression comment. /// This is exposed so that other tools that present clang-tidy diagnostics @@ -244,6 +252,7 @@ DiagnosticsEngine *ExternalDiagEngine = nullptr, bool RemoveIncompatibleErrors = true, bool GetFixesFromNotes = false); + ~ClangTidyDiagnosticConsumer(); // FIXME: The concept of converting between FixItHints and Replacements is // more generic and should be pulled out into a more useful Diagnostics @@ -254,15 +263,21 @@ // Retrieve the diagnostics that were captured. std::vector take(); + /// Returns true if the Location should have warnings suppressed. + static bool skipLocation(SourceLocation Location) { + return LocationFilter && LocationFilter->skipLocation(Location); + } + + static ClangTidyLocationFilter *newLocationFilter(ClangTidyContext *Context); + + static ClangTidyLocationFilterImpl * + newLocationFilterImpl(ClangTidyContext *Context); + private: void finalizeLastError(); void removeIncompatibleErrors(); void removeDuplicatedDiagnosticsOfAliasCheckers(); - /// Returns the \c HeaderFilter constructed for the options set in the - /// context. - llvm::Regex *getHeaderFilter(); - /// Updates \c LastErrorRelatesToUserCode and LastErrorPassesLineFilter /// according to the diagnostic \p Location. void checkFilters(SourceLocation Location, const SourceManager &Sources); @@ -275,10 +290,12 @@ bool RemoveIncompatibleErrors; bool GetFixesFromNotes; std::vector Errors; - std::unique_ptr HeaderFilter; + std::unique_ptr LocationFilterImpl; bool LastErrorRelatesToUserCode; bool LastErrorPassesLineFilter; bool LastErrorWasIgnored; + + static std::unique_ptr LocationFilter; }; } // end namespace tidy Index: clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp =================================================================== --- clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp +++ clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp @@ -38,6 +38,91 @@ using namespace clang; using namespace tidy; +namespace clang { +namespace tidy { + +class ClangTidyLocationFilterImpl : ClangTidyLocationFilter { +public: + ClangTidyLocationFilterImpl(ClangTidyContext *Context); + ~ClangTidyLocationFilterImpl(); + virtual bool skipLocation(SourceLocation Location) const override; + +private: + friend class ClangTidyDiagnosticConsumer; + /// Returns true if the Location with FileID is in a skipped system header. + bool isSkippedSystemHeader(SourceLocation Location, FileID FileID, + const FileEntry *File, + const SourceManager &Sources) const; + + /// Returns true if the Location with FileID is in user code. + bool isUserCode(SourceLocation Location, FileID FileID, const FileEntry *File, + const SourceManager &Sources) const; + + ClangTidyContext *Context; + mutable FileID LastSkippedSystemFileID; + mutable FileID LastSkippedFileID; + mutable FileID LastAcceptedFileID; + std::unique_ptr HeaderFilterRegex; +}; + +} // end namespace tidy +} // end namespace clang + +ClangTidyLocationFilterImpl::~ClangTidyLocationFilterImpl() = default; + +ClangTidyLocationFilterImpl::ClangTidyLocationFilterImpl( + ClangTidyContext *Context) + : Context(Context), LastSkippedSystemFileID(FileID::getSentinel()), + LastSkippedFileID(FileID::getSentinel()), + LastAcceptedFileID(FileID::getSentinel()), + HeaderFilterRegex(std::make_unique( + *Context->getOptions().HeaderFilterRegex)) {} + +bool ClangTidyLocationFilterImpl::skipLocation(SourceLocation Location) const { + if (!Location.isValid()) + return false; + SourceManager &Sources = Context->getSourceManager(); + FileID FID = Sources.getDecomposedExpansionLoc(Location).first; + // Do not skip built-in and command line yet. + const FileEntry *File = Sources.getFileEntryForID(FID); + if (!File) + return false; + return isSkippedSystemHeader(Location, FID, File, Sources) || + !isUserCode(Location, FID, File, Sources); +} + +bool ClangTidyLocationFilterImpl::isSkippedSystemHeader( + SourceLocation Location, FileID FID, const FileEntry *File, + const SourceManager &Sources) const { + if (!File) + return false; + if (FID == LastSkippedSystemFileID) + return true; + if (!*Context->getOptions().SystemHeaders && + Sources.isInSystemHeader(Location)) { + LastSkippedSystemFileID = FID; + return true; + } + return false; +} + +bool ClangTidyLocationFilterImpl::isUserCode( + SourceLocation Location, FileID FID, const FileEntry *File, + const SourceManager &Sources) const { + assert(File); + if (FID == LastSkippedFileID) + return false; + if (FID == LastAcceptedFileID) + return true; + bool IsUserCode = Sources.isInMainFile(Location) || + HeaderFilterRegex->match(File->getName()); + if (IsUserCode) + LastAcceptedFileID = FID; + else + LastSkippedFileID = FID; + return IsUserCode; +} + namespace { class ClangTidyDiagnosticRenderer : public DiagnosticRenderer { public: @@ -276,13 +361,35 @@ return ""; } +// Global LocationFilter is non-null if --skip-header is enabled. +std::unique_ptr + ClangTidyDiagnosticConsumer::LocationFilter; + ClangTidyDiagnosticConsumer::ClangTidyDiagnosticConsumer( ClangTidyContext &Ctx, DiagnosticsEngine *ExternalDiagEngine, bool RemoveIncompatibleErrors, bool GetFixesFromNotes) : Context(Ctx), ExternalDiagEngine(ExternalDiagEngine), RemoveIncompatibleErrors(RemoveIncompatibleErrors), - GetFixesFromNotes(GetFixesFromNotes), LastErrorRelatesToUserCode(false), - LastErrorPassesLineFilter(false), LastErrorWasIgnored(false) {} + GetFixesFromNotes(GetFixesFromNotes), + LocationFilterImpl(newLocationFilterImpl(&Ctx)), + LastErrorRelatesToUserCode(false), LastErrorPassesLineFilter(false), + LastErrorWasIgnored(false) { + if (*Ctx.getOptions().SkipHeaders) + LocationFilter = + std::unique_ptr(newLocationFilter(&Ctx)); +} + +ClangTidyLocationFilterImpl * +ClangTidyDiagnosticConsumer::newLocationFilterImpl(ClangTidyContext *Context) { + return new ClangTidyLocationFilterImpl(Context); +} + +ClangTidyLocationFilter * +ClangTidyDiagnosticConsumer::newLocationFilter(ClangTidyContext *Context) { + return new ClangTidyLocationFilterImpl(Context); +} + +ClangTidyDiagnosticConsumer::~ClangTidyDiagnosticConsumer() = default; void ClangTidyDiagnosticConsumer::finalizeLastError() { if (!Errors.empty()) { @@ -580,21 +687,19 @@ void ClangTidyDiagnosticConsumer::checkFilters(SourceLocation Location, const SourceManager &Sources) { // Invalid location may mean a diagnostic in a command line, don't skip these. - if (!Location.isValid()) { + if (!Location.isValid() || *Context.getOptions().ShowAllWarnings) { LastErrorRelatesToUserCode = true; LastErrorPassesLineFilter = true; return; } - if (!*Context.getOptions().SystemHeaders && - Sources.isInSystemHeader(Location)) - return; - // 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; const FileEntry *File = Sources.getFileEntryForID(FID); + if (LocationFilterImpl->isSkippedSystemHeader(Location, FID, File, Sources)) + return; // -DMACRO definitions on the command line have locations in a virtual buffer // that doesn't have a FileEntry. Don't skip these as well. @@ -605,22 +710,15 @@ } StringRef FileName(File->getName()); - LastErrorRelatesToUserCode = LastErrorRelatesToUserCode || - Sources.isInMainFile(Location) || - getHeaderFilter()->match(FileName); + LastErrorRelatesToUserCode = + LastErrorRelatesToUserCode || + LocationFilterImpl->isUserCode(Location, FID, File, Sources); unsigned LineNumber = Sources.getExpansionLineNumber(Location); LastErrorPassesLineFilter = LastErrorPassesLineFilter || passesLineFilter(FileName, LineNumber); } -llvm::Regex *ClangTidyDiagnosticConsumer::getHeaderFilter() { - if (!HeaderFilter) - HeaderFilter = - std::make_unique(*Context.getOptions().HeaderFilterRegex); - return HeaderFilter.get(); -} - void ClangTidyDiagnosticConsumer::removeIncompatibleErrors() { // Each error is modelled as the set of intervals in which it applies // replacements. To detect overlapping replacements, we use a sweep line Index: clang-tools-extra/clang-tidy/ClangTidyModule.h =================================================================== --- clang-tools-extra/clang-tidy/ClangTidyModule.h +++ clang-tools-extra/clang-tidy/ClangTidyModule.h @@ -33,7 +33,8 @@ /// Registers check \p Factory with name \p Name. /// /// For all checks that have default constructors, use \c registerCheck. - void registerCheckFactory(llvm::StringRef Name, CheckFactory Factory); + void registerCheckFactory(llvm::StringRef Name, CheckFactory Factory, + bool IsAllFileCheck = false); /// Registers the \c CheckType with the name \p Name. /// @@ -53,27 +54,37 @@ /// class MyModule : public ClangTidyModule { /// void addCheckFactories(ClangTidyCheckFactories &Factories) override { /// Factories.registerCheck("myproject-my-check"); + /// // or Factories.registerCheck("my-check", true); + /// // for a check that needs to match all Decls in header files. /// } /// }; /// \endcode - template void registerCheck(llvm::StringRef CheckName) { - registerCheckFactory(CheckName, - [](llvm::StringRef Name, ClangTidyContext *Context) { - return std::make_unique(Name, Context); - }); + template + void registerCheck(llvm::StringRef CheckName, bool IsAllFileCheck = false) { + registerCheckFactory( + CheckName, + [](llvm::StringRef Name, ClangTidyContext *Context) { + return std::make_unique(Name, Context); + }, + IsAllFileCheck); } /// Create instances of checks that are enabled. std::vector> createChecks(ClangTidyContext *Context); + /// Create instances of all-file checks that are enabled. + std::vector> + createAllFileChecks(ClangTidyContext *Context); + typedef llvm::StringMap FactoryMap; FactoryMap::const_iterator begin() const { return Factories.begin(); } FactoryMap::const_iterator end() const { return Factories.end(); } bool empty() const { return Factories.empty(); } private: - FactoryMap Factories; + FactoryMap Factories; // has both normal checks and all-file checks + llvm::StringMap IsAllFileChecks; // check name -> is all-file check }; /// A clang-tidy module groups a number of \c ClangTidyChecks and gives Index: clang-tools-extra/clang-tidy/ClangTidyModule.cpp =================================================================== --- clang-tools-extra/clang-tidy/ClangTidyModule.cpp +++ clang-tools-extra/clang-tidy/ClangTidyModule.cpp @@ -17,20 +17,34 @@ namespace tidy { void ClangTidyCheckFactories::registerCheckFactory(StringRef Name, - CheckFactory Factory) { + CheckFactory Factory, + bool IsAllFileCheck) { Factories.insert_or_assign(Name, std::move(Factory)); + IsAllFileChecks.insert_or_assign(Name, IsAllFileCheck); } std::vector> ClangTidyCheckFactories::createChecks(ClangTidyContext *Context) { std::vector> Checks; for (const auto &Factory : Factories) { - if (Context->isCheckEnabled(Factory.getKey())) + if (Context->isCheckEnabled(Factory.getKey()) && + !IsAllFileChecks[Factory.getKey()]) Checks.emplace_back(Factory.getValue()(Factory.getKey(), Context)); } return Checks; } +std::vector> +ClangTidyCheckFactories::createAllFileChecks(ClangTidyContext *Context) { + std::vector> AllFileChecks; + for (const auto &Factory : Factories) { + if (Context->isCheckEnabled(Factory.getKey()) && + IsAllFileChecks[Factory.getKey()]) + AllFileChecks.emplace_back(Factory.getValue()(Factory.getKey(), Context)); + } + return AllFileChecks; +} + ClangTidyOptions ClangTidyModule::getModuleOptions() { return ClangTidyOptions(); } Index: clang-tools-extra/clang-tidy/ClangTidyOptions.h =================================================================== --- clang-tools-extra/clang-tidy/ClangTidyOptions.h +++ clang-tools-extra/clang-tidy/ClangTidyOptions.h @@ -79,6 +79,15 @@ /// Output warnings from system headers matching \c HeaderFilterRegex. llvm::Optional SystemHeaders; + /// Show all warnings, including warnings from all header files. + /// This overrides HeaderFilterRegex and SystemHeaders. + /// This is an option intended for testing/debugging clang-tidy. + llvm::Optional ShowAllWarnings; + + /// Do not check included files, except files matching the --header-filter + /// and system files when --system-headers is used. + llvm::Optional SkipHeaders; + /// Format code around applied fixes with clang-format using this /// style. /// Index: clang-tools-extra/clang-tidy/ClangTidyOptions.cpp =================================================================== --- clang-tools-extra/clang-tidy/ClangTidyOptions.cpp +++ clang-tools-extra/clang-tidy/ClangTidyOptions.cpp @@ -89,6 +89,9 @@ IO.mapOptional("Checks", Options.Checks); IO.mapOptional("WarningsAsErrors", Options.WarningsAsErrors); IO.mapOptional("HeaderFilterRegex", Options.HeaderFilterRegex); + // SystemHeaders not mapped? + // ShowAllWarnings is hidden debug only option. + IO.mapOptional("SkipHeaders", Options.SkipHeaders); IO.mapOptional("AnalyzeTemporaryDtors", Ignored); // legacy compatibility IO.mapOptional("FormatStyle", Options.FormatStyle); IO.mapOptional("User", Options.User); @@ -111,6 +114,8 @@ Options.Checks = ""; Options.WarningsAsErrors = ""; Options.HeaderFilterRegex = ""; + Options.ShowAllWarnings = false; + Options.SkipHeaders = false; Options.SystemHeaders = false; Options.FormatStyle = "none"; Options.User = llvm::None; @@ -147,6 +152,8 @@ mergeCommaSeparatedLists(Checks, Other.Checks); mergeCommaSeparatedLists(WarningsAsErrors, Other.WarningsAsErrors); overrideValue(HeaderFilterRegex, Other.HeaderFilterRegex); + overrideValue(ShowAllWarnings, Other.ShowAllWarnings); + overrideValue(SkipHeaders, Other.SkipHeaders); overrideValue(SystemHeaders, Other.SystemHeaders); overrideValue(FormatStyle, Other.FormatStyle); overrideValue(User, Other.User); Index: clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp =================================================================== --- clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp +++ clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp @@ -99,7 +99,7 @@ CheckFactories.registerCheck( "bugprone-fold-init-type"); CheckFactories.registerCheck( - "bugprone-forward-declaration-namespace"); + "bugprone-forward-declaration-namespace", true); CheckFactories.registerCheck( "bugprone-forwarding-reference-overload"); CheckFactories.registerCheck( Index: clang-tools-extra/clang-tidy/bugprone/ForwardDeclarationNamespaceCheck.cpp =================================================================== --- clang-tools-extra/clang-tidy/bugprone/ForwardDeclarationNamespaceCheck.cpp +++ clang-tools-extra/clang-tidy/bugprone/ForwardDeclarationNamespaceCheck.cpp @@ -130,6 +130,9 @@ CurDecl->getLocation().isInvalid()) { continue; } + if (skipLocation(CurDecl->getLocation())) { + continue; // Skip if --skip-headers and CurDecl's file is skipped. + } // Compare with all other declarations with the same name. for (const auto *Decl : Declarations) { if (Decl == CurDecl) { Index: clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp =================================================================== --- clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp +++ clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp @@ -55,7 +55,7 @@ CheckFactories.registerCheck( "misc-unused-parameters"); CheckFactories.registerCheck( - "misc-unused-using-decls"); + "misc-unused-using-decls", true); } }; Index: clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp =================================================================== --- clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp +++ clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp @@ -179,7 +179,8 @@ void UnusedUsingDeclsCheck::onEndOfTranslationUnit() { for (const auto &Context : Contexts) { - if (!Context.IsUsed) { + if (!Context.IsUsed && + !skipLocation(Context.FoundUsingDecl->getLocation())) { diag(Context.FoundUsingDecl->getLocation(), "using decl %0 is unused") << Context.FoundUsingDecl; // Emit a fix and a fix description of the check; Index: clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp =================================================================== --- clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp +++ clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp @@ -217,6 +217,12 @@ return true; } + // When Stmt S does not have a "valid" location, + // skipLocation won't skip it. + // So we need to check here if C should be skipped. + if (Check.skipLocation(C->getBeginLoc())) + return true; + auto* CastSubExpr = C->getSubExpr()->IgnoreParens(); // Ignore cast expressions which cast nullptr literal. if (isa(CastSubExpr)) { Index: clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp =================================================================== --- clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp +++ clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp @@ -95,10 +95,23 @@ cl::init(""), cl::cat(ClangTidyCategory)); +static cl::opt ShowAllWarnings("show-all-warnings", + cl::desc("Display all warning messages."), + cl::init(false), cl::Hidden, + cl::cat(ClangTidyCategory)); + +static cl::opt SkipHeaders("skip-headers", cl::desc(R"( +Do not check included header files, but +files matching the --header-filter pattern are still checked. +System headers are still checked if --system-headers is true. +)"), + cl::init(false), cl::cat(ClangTidyCategory)); + static cl::opt SystemHeaders("system-headers", cl::desc("Display the errors from system headers."), cl::init(false), cl::cat(ClangTidyCategory)); + static cl::opt LineFilter("line-filter", cl::desc(R"( List of files with line ranges to filter the warnings. Can be used together with @@ -300,6 +313,8 @@ DefaultOptions.Checks = DefaultChecks; DefaultOptions.WarningsAsErrors = ""; DefaultOptions.HeaderFilterRegex = HeaderFilter; + DefaultOptions.ShowAllWarnings = ShowAllWarnings; + DefaultOptions.SkipHeaders = SkipHeaders; DefaultOptions.SystemHeaders = SystemHeaders; DefaultOptions.FormatStyle = FormatStyle; DefaultOptions.User = llvm::sys::Process::GetEnv("USER"); @@ -314,6 +329,10 @@ OverrideOptions.WarningsAsErrors = WarningsAsErrors; if (HeaderFilter.getNumOccurrences() > 0) OverrideOptions.HeaderFilterRegex = HeaderFilter; + if (ShowAllWarnings.getNumOccurrences() > 0) + OverrideOptions.ShowAllWarnings = ShowAllWarnings; + if (SkipHeaders.getNumOccurrences() > 0) + OverrideOptions.SkipHeaders = SkipHeaders; if (SystemHeaders.getNumOccurrences() > 0) OverrideOptions.SystemHeaders = SystemHeaders; if (FormatStyle.getNumOccurrences() > 0) Index: clang-tools-extra/test/clang-tidy/checkers/Inputs/bugprone-forward-declaration-namespace/a.h =================================================================== --- /dev/null +++ clang-tools-extra/test/clang-tidy/checkers/Inputs/bugprone-forward-declaration-namespace/a.h @@ -0,0 +1,9 @@ +namespace { +// This is a declaration in a wrong namespace. +class T_A; +} // namespace + +namespace na { +// This is a declaration in a wrong namespace. +class T_A; +} // namespace na Index: clang-tools-extra/test/clang-tidy/checkers/Inputs/bugprone-forward-declaration-namespace/b.h =================================================================== --- /dev/null +++ clang-tools-extra/test/clang-tidy/checkers/Inputs/bugprone-forward-declaration-namespace/b.h @@ -0,0 +1,9 @@ +namespace nb { +class T_B; +} + +namespace nb { +class T_B { + int x; +}; +} // namespace nb Index: clang-tools-extra/test/clang-tidy/checkers/Inputs/modernize-pass-by-value/header.h =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/Inputs/modernize-pass-by-value/header.h +++ clang-tools-extra/test/clang-tidy/checkers/Inputs/modernize-pass-by-value/header.h @@ -8,3 +8,10 @@ A(const ThreadId &tid) : threadid(tid) {} ThreadId threadid; }; + +struct Movable { + int a, b, c; + Movable() = default; + Movable(const Movable &) {} + Movable(Movable &&) {} +}; Index: clang-tools-extra/test/clang-tidy/checkers/Inputs/skip-headers/a.h =================================================================== --- /dev/null +++ clang-tools-extra/test/clang-tidy/checkers/Inputs/skip-headers/a.h @@ -0,0 +1,4 @@ +class A { +#include "b.h" + void fooA(int x) { x = 1; }; +}; Index: clang-tools-extra/test/clang-tidy/checkers/Inputs/skip-headers/b.h =================================================================== --- /dev/null +++ clang-tools-extra/test/clang-tidy/checkers/Inputs/skip-headers/b.h @@ -0,0 +1,4 @@ +class B { + // expect a warning on fooB + void fooB(int x) { x = 2; }; +}; Index: clang-tools-extra/test/clang-tidy/checkers/Inputs/skip-headers/c.h =================================================================== --- /dev/null +++ clang-tools-extra/test/clang-tidy/checkers/Inputs/skip-headers/c.h @@ -0,0 +1,9 @@ +template +class C { +public: + template + explicit C(const R r, int *x = 0) : p(x) {} + +private: + int *p; +}; Index: clang-tools-extra/test/clang-tidy/checkers/Inputs/skip-headers/c1.h =================================================================== --- /dev/null +++ clang-tools-extra/test/clang-tidy/checkers/Inputs/skip-headers/c1.h @@ -0,0 +1,10 @@ +#ifndef C1_H_ +#define C1_H_ + +struct C1 { + static int foo1(int n = 1ll); + int foo2(int n = 2ll); + int foo3(int n); +}; + +#endif // C1_H_ Index: clang-tools-extra/test/clang-tidy/checkers/Inputs/skip-headers/my_header1.h =================================================================== --- /dev/null +++ clang-tools-extra/test/clang-tidy/checkers/Inputs/skip-headers/my_header1.h @@ -0,0 +1,3 @@ +// no header guard + +#include "my_header2.h" Index: clang-tools-extra/test/clang-tidy/checkers/Inputs/skip-headers/my_header2.h =================================================================== --- /dev/null +++ clang-tools-extra/test/clang-tidy/checkers/Inputs/skip-headers/my_header2.h @@ -0,0 +1,6 @@ +// bad header guard +#ifndef SOME_MACRO + +int abc = 123; // bad definition in .h file + +#endif Index: clang-tools-extra/test/clang-tidy/checkers/Inputs/unused-using-decls.h =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/Inputs/unused-using-decls.h +++ clang-tools-extra/test/clang-tidy/checkers/Inputs/unused-using-decls.h @@ -9,3 +9,11 @@ S(); } }; + +QC1 *foo(); + +namespace Q2 { +class QC2 {}; +} // namespace Q2 +using Q2::QC2; +// not used QC2 should have warning only when .h file is selected with --header-filter Index: clang-tools-extra/test/clang-tidy/checkers/abseil-no-internal-dependencies.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/abseil-no-internal-dependencies.cpp +++ clang-tools-extra/test/clang-tidy/checkers/abseil-no-internal-dependencies.cpp @@ -1,5 +1,5 @@ -// RUN: %check_clang_tidy %s abseil-no-internal-dependencies %t, -- -- -I %S/Inputs -// RUN: clang-tidy -checks='-*, abseil-no-internal-dependencies' -header-filter='.*' %s -- -I %S/Inputs 2>&1 | FileCheck %s +// RUN: %check_clang_tidy %s abseil-no-internal-dependencies %t, -- --skip-headers=0 -- -I %S/Inputs +// RUN: clang-tidy --skip-headers=0 -checks='-*, abseil-no-internal-dependencies' -header-filter='.*' %s -- -I %S/Inputs 2>&1 | FileCheck %s #include "absl/strings/internal-file.h" #include "absl/flags/internal-file.h" Index: clang-tools-extra/test/clang-tidy/checkers/abseil-upgrade-duration-conversions.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/abseil-upgrade-duration-conversions.cpp +++ clang-tools-extra/test/clang-tidy/checkers/abseil-upgrade-duration-conversions.cpp @@ -1,4 +1,5 @@ -// RUN: %check_clang_tidy -std=c++11-or-later %s abseil-upgrade-duration-conversions %t -- -- -I%S/Inputs +// RUN: %check_clang_tidy -std=c++11-or-later %s abseil-upgrade-duration-conversions %t -- --skip-headers=0 -- -I%S/Inputs +// RUN: %check_clang_tidy -std=c++11-or-later %s abseil-upgrade-duration-conversions %t -- --skip-headers -- -I%S/Inputs using int64_t = long long; Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-forward-declaration-namespace-header.cpp =================================================================== --- /dev/null +++ clang-tools-extra/test/clang-tidy/checkers/bugprone-forward-declaration-namespace-header.cpp @@ -0,0 +1,174 @@ +// Same output with skip-headers=0, skip-headers=1, or skip-headers +// +// With --skip-headers=0 and no --header-filter, there should be no warning +// shown for a.h or b.h. But there seems to be a bug and we are seeing the A1 warnings. +// RUN: %check_clang_tidy -check-suffixes=ALL,A1 %s bugprone-forward-declaration-namespace %t -- --skip-headers=0 \ +// RUN: -- -I%S/Inputs/bugprone-forward-declaration-namespace +// RUN: %check_clang_tidy -check-suffixes=ALL %s bugprone-forward-declaration-namespace %t -- --skip-headers=1 \ +// RUN: -- -I%S/Inputs/bugprone-forward-declaration-namespace +// RUN: %check_clang_tidy -check-suffixes=ALL %s bugprone-forward-declaration-namespace %t -- --skip-headers \ +// RUN: -- -I%S/Inputs/bugprone-forward-declaration-namespace +// +// Same output with header-filter=b.h because there is no warning on b.h +// RUN: %check_clang_tidy -check-suffixes=ALL %s bugprone-forward-declaration-namespace %t -- --skip-headers \ +// RUN: --header-filter=b.h -- -I%S/Inputs/bugprone-forward-declaration-namespace +// +// With --header-filter, we should see all warnings from a.h. +// RUN: %check_clang_tidy -check-suffixes=ALL,A,A1 %s bugprone-forward-declaration-namespace %t -- --skip-headers=0 \ +// RUN: --header-filter=.* -- -I%S/Inputs/bugprone-forward-declaration-namespace +// RUN: %check_clang_tidy -check-suffixes=ALL,A,A1 %s bugprone-forward-declaration-namespace %t -- --skip-headers \ +// RUN: --header-filter=.* -- -I%S/Inputs/bugprone-forward-declaration-namespace +// RUN: %check_clang_tidy -check-suffixes=ALL,A,A1 %s bugprone-forward-declaration-namespace %t -- --skip-headers=0 \ +// RUN: --header-filter=a.h -- -I%S/Inputs/bugprone-forward-declaration-namespace +// RUN: %check_clang_tidy -check-suffixes=ALL,A,A1 %s bugprone-forward-declaration-namespace %t -- --skip-headers \ +// RUN: --header-filter=a.h -- -I%S/Inputs/bugprone-forward-declaration-namespace + +#include "a.h" + +class T_A; + +class T_A { + int x; +}; + +class NESTED; +// CHECK-NOTES-ALL: :[[@LINE-1]]:7: warning: no definition found for 'NESTED', but a definition with the same name 'NESTED' found in another namespace '(anonymous namespace)::nq::(anonymous)' +// CHECK-NOTES-ALL: note: a definition of 'NESTED' is found here + +namespace { +namespace nq { +namespace { +class NESTED {}; +} // namespace +} // namespace nq +} // namespace + +namespace na { +class T_B; +// CHECK-NOTES-ALL: :[[@LINE-1]]:7: warning: declaration 'T_B' is never referenced, but a declaration with the same name found in another namespace 'nb' +// CHECK-NOTES-ALL: note: a declaration of 'T_B' is found here +// CHECK-NOTES-ALL: :[[@LINE-3]]:7: warning: no definition found for 'T_B', but a definition with the same name 'T_B' found in another namespace 'nb' +// CHECK-NOTES-ALL: note: a definition of 'T_B' is found here +} // namespace na + +#include "b.h" + +namespace na { +class T_B; +// CHECK-NOTES-ALL: :[[@LINE-1]]:7: warning: declaration 'T_B' is never referenced, but a declaration with the same name found in another namespace 'nb' +// CHECK-NOTES-ALL: note: a declaration of 'T_B' is found here +// CHECK-NOTES-ALL: :[[@LINE-3]]:7: warning: no definition found for 'T_B', but a definition with the same name 'T_B' found in another namespace 'nb' +// CHECK-NOTES-ALL: note: a definition of 'T_B' is found here +} // namespace na + +// A simple forward declaration. Although it is never used, but no declaration +// with the same name is found in other namespace. +class OUTSIDER; + +namespace na { +// This class is referenced declaration, we don't generate warning. +class OUTSIDER_1; +} // namespace na + +void f(na::OUTSIDER_1); + +namespace nc { +// This class is referenced as friend in OOP. +class OUTSIDER_1; + +class OOP { + friend struct OUTSIDER_1; +}; +} // namespace nc + +namespace nd { +class OUTSIDER_1; +void f(OUTSIDER_1 *); +} // namespace nd + +namespace nb { +class OUTSIDER_1; +// CHECK-NOTES-ALL: :[[@LINE-1]]:7: warning: declaration 'OUTSIDER_1' is never referenced, but a declaration with the same name found in another namespace 'na' +// CHECK-NOTES-ALL: note: a declaration of 'OUTSIDER_1' is found here +} // namespace nb + +namespace na { +template +class T_C; +} + +namespace nb { +// FIXME: this is an error, but we don't consider template class declaration +// now. +template +class T_C; +} // namespace nb + +namespace na { +template +class T_C { + int x; +}; +} // namespace na + +namespace na { + +template +class T_TEMP { + template + struct rebind { typedef T_TEMP<_Tp1> other; }; +}; + +// We ignore class template specialization. +template class T_TEMP; +} // namespace na + +namespace nb { + +template +class T_TEMP_1 { + template + struct rebind { typedef T_TEMP_1<_Tp1> other; }; +}; + +// We ignore class template specialization. +extern template class T_TEMP_1; +} // namespace nb + +namespace nd { +class D; +// CHECK-NOTES-ALL: :[[@LINE-1]]:7: warning: declaration 'D' is never referenced, but a declaration with the same name found in another namespace 'nd::ne' +// CHECK-NOTES-ALL: note: a declaration of 'D' is found here +} // namespace nd + +namespace nd { +namespace ne { +class D; +} +} // namespace nd + +int f(nd::ne::D &d); + +// This should be ignored by the check. +template +class Observer { + class Impl; +}; + +template +class Observer::Impl { +}; + +// Work around limit of FileCheck, the expected warnings in a.h files are listed here. +// +// Warnings on namespace { class T_A; } +// CHECK-NOTES-A: warning: declaration 'T_A' is never referenced, but a declaration with the same name found in another namespace 'na' [bugprone-forward-declaration-namespace] +// CHECK-NOTES-A: note: a declaration of 'T_A' is found here +// CHECK-NOTES-A1: warning: no definition found for 'T_A', but a definition with the same name 'T_A' found in another namespace '(global)' [bugprone-forward-declaration-namespace] +// CHECK-NOTES-A1: note: a definition of 'T_A' is found here +// +// Warnings on namespace na { class T_A; } +// CHECK-NOTES-A: warning: declaration 'T_A' is never referenced, but a declaration with the same name found in another namespace '(anonymous)' +// CHECK-NOTES-A: note: a declaration of 'T_A' is found here +// CHECK-NOTES-A1: warning: no definition found for 'T_A', but a definition with the same name 'T_A' found in another namespace '(global)' +// CHECK-NOTES-A1: note: a definition of 'T_A' is found here Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-forward-declaration-namespace.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/bugprone-forward-declaration-namespace.cpp +++ clang-tools-extra/test/clang-tidy/checkers/bugprone-forward-declaration-namespace.cpp @@ -1,4 +1,5 @@ -// RUN: %check_clang_tidy %s bugprone-forward-declaration-namespace %t +// RUN: %check_clang_tidy %s bugprone-forward-declaration-namespace %t -- --skip-headers=0 +// RUN: %check_clang_tidy %s bugprone-forward-declaration-namespace %t -- --skip-headers namespace { // This is a declaration in a wrong namespace. Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-reserved-identifier.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/bugprone-reserved-identifier.cpp +++ clang-tools-extra/test/clang-tidy/checkers/bugprone-reserved-identifier.cpp @@ -1,4 +1,7 @@ -// RUN: %check_clang_tidy %s bugprone-reserved-identifier %t -- -- \ +// RUN: %check_clang_tidy %s bugprone-reserved-identifier %t -- --skip-headers=0 -- \ +// RUN: -I%S/Inputs/bugprone-reserved-identifier \ +// RUN: -isystem %S/Inputs/bugprone-reserved-identifier/system +// RUN: %check_clang_tidy %s bugprone-reserved-identifier %t -- --skip-headers -- \ // RUN: -I%S/Inputs/bugprone-reserved-identifier \ // RUN: -isystem %S/Inputs/bugprone-reserved-identifier/system Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-suspicious-include.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/bugprone-suspicious-include.cpp +++ clang-tools-extra/test/clang-tidy/checkers/bugprone-suspicious-include.cpp @@ -1,4 +1,5 @@ -// RUN: %check_clang_tidy %s bugprone-suspicious-include %t -- -- -isystem %S/Inputs/Headers -fmodules +// RUN: %check_clang_tidy %s bugprone-suspicious-include %t -- --skip-headers=0 -- -isystem %S/Inputs/Headers -fmodules +// RUN: %check_clang_tidy %s bugprone-suspicious-include %t -- --skip-headers -- -isystem %S/Inputs/Headers -fmodules // clang-format off Index: clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-interfaces-global-init.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-interfaces-global-init.cpp +++ clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-interfaces-global-init.cpp @@ -1,4 +1,5 @@ -// RUN: %check_clang_tidy %s cppcoreguidelines-interfaces-global-init %t +// RUN: %check_clang_tidy %s cppcoreguidelines-interfaces-global-init %t -- --skip-headers=0 +// RUN: %check_clang_tidy %s cppcoreguidelines-interfaces-global-init %t -- --skip-headers constexpr int makesInt() { return 3; } constexpr int takesInt(int i) { return i + 1; } Index: clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-macro-usage-command-line-macros.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-macro-usage-command-line-macros.cpp +++ clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-macro-usage-command-line-macros.cpp @@ -1,6 +1,11 @@ -// RUN: %check_clang_tidy -check-suffixes=NORMAL %s cppcoreguidelines-macro-usage %t -- -- -D_ZZZ_IM_A_MACRO -// RUN: %check_clang_tidy -check-suffixes=NORMAL %s cppcoreguidelines-macro-usage %t -- -config='{CheckOptions: [{key: cppcoreguidelines-macro-usage.IgnoreCommandLineMacros, value: true}]}' -- -D_ZZZ_IM_A_MACRO -// RUN: %check_clang_tidy -check-suffixes=NORMAL,CL %s cppcoreguidelines-macro-usage %t -- -config='{CheckOptions: [{key: cppcoreguidelines-macro-usage.IgnoreCommandLineMacros, value: false}]}' -- -D_ZZZ_IM_A_MACRO +// RUN: %check_clang_tidy -check-suffixes=NORMAL %s cppcoreguidelines-macro-usage %t -- --skip-headers=0 -- -D_ZZZ_IM_A_MACRO +// RUN: %check_clang_tidy -check-suffixes=NORMAL %s cppcoreguidelines-macro-usage %t -- --skip-headers=0 -config='{CheckOptions: [{key: cppcoreguidelines-macro-usage.IgnoreCommandLineMacros, value: true}]}' -- -D_ZZZ_IM_A_MACRO +// RUN: %check_clang_tidy -check-suffixes=NORMAL,CL %s cppcoreguidelines-macro-usage %t -- --skip-headers=0 -config='{CheckOptions: [{key: cppcoreguidelines-macro-usage.IgnoreCommandLineMacros, value: false}]}' -- -D_ZZZ_IM_A_MACRO +// +// Should work with --skip-header too. +// RUN: %check_clang_tidy -check-suffixes=NORMAL %s cppcoreguidelines-macro-usage %t -- --skip-headers -- -D_ZZZ_IM_A_MACRO +// RUN: %check_clang_tidy -check-suffixes=NORMAL %s cppcoreguidelines-macro-usage %t -- --skip-headers -config='{CheckOptions: [{key: cppcoreguidelines-macro-usage.IgnoreCommandLineMacros, value: true}]}' -- -D_ZZZ_IM_A_MACRO +// RUN: %check_clang_tidy -check-suffixes=NORMAL,CL %s cppcoreguidelines-macro-usage %t -- --skip-headers -config='{CheckOptions: [{key: cppcoreguidelines-macro-usage.IgnoreCommandLineMacros, value: false}]}' -- -D_ZZZ_IM_A_MACRO // CHECK-MESSAGES-CL: warning: macro '_ZZZ_IM_A_MACRO' used to declare a constant; consider using a 'constexpr' constant Index: clang-tools-extra/test/clang-tidy/checkers/google-namespaces.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/google-namespaces.cpp +++ clang-tools-extra/test/clang-tidy/checkers/google-namespaces.cpp @@ -1,6 +1,32 @@ -// RUN: clang-tidy %s -checks='-*,google-build-namespaces,google-build-using-namespace' -header-filter='.*' -- | FileCheck %s -implicit-check-not="{{warning|error}}:" +// RUN: clang-tidy %s --skip-headers=0 -checks='-*,google-build-namespaces,google-build-using-namespace' -header-filter='.*' -- \ +// RUN: 2>&1 | FileCheck %s -check-prefixes CHECK,CHECK1 -implicit-check-not="{{warning|error}}:" + +// RUN: clang-tidy %s --skip-headers=0 -checks='-*,google-build-namespaces,google-build-using-namespace' -- \ +// RUN: 2>&1 | FileCheck %s -check-prefixes CHECK,CHECK0 -implicit-check-not="{{warning|error}}:" +// +// RUN: clang-tidy %s --skip-headers -checks='-*,google-build-namespaces,google-build-using-namespace' -- \ +// RUN: 2>&1 | FileCheck %s -check-prefixes CHECK,CHECK2 -implicit-check-not="{{warning|error}}:" +// +// -header-filter overrides --skip-header +// RUN: clang-tidy %s --skip-headers -header-filter='.*' -checks='-*,google-build-namespaces,google-build-using-namespace' -- \ +// RUN: 2>&1 | FileCheck %s -check-prefixes CHECK,CHECK1 -implicit-check-not="{{warning|error}}:" +// +// --show-all-warnings is like -header-filter=.* + -system-headers +// RUN: clang-tidy %s --skip-headers=0 --show-all-warnings -checks='-*,google-build-namespaces,google-build-using-namespace' -- \ +// RUN: 2>&1 | FileCheck %s -check-prefixes CHECK,CHECK1 -implicit-check-not="{{warning|error}}:" + +// --skip-header skips 1 warning in the header file. +// CHECK0: 7 warnings generated +// CHECK1: 7 warnings generated +// CHECK2: 6 warnings generated + #include "Inputs/google-namespaces.h" -// CHECK: warning: do not use unnamed namespaces in header files [google-build-namespaces] +// with -header-filter, warning in .h file is shown +// CHECK1: warning: do not use unnamed namespaces in header files [google-build-namespaces] +// without -header-filter, warning in .h files are not shown +// CHECK0-NOT: warning: do not use unnamed namespaces in header files [google-build-namespaces] +// with --skip-header, no warning in .h file is detected at all +// CHECK2-NOT: warning: do not use unnamed namespaces in header files [google-build-namespaces] using namespace spaaaace; // CHECK: :[[@LINE-1]]:1: warning: do not use namespace using-directives; use using-declarations instead [google-build-using-namespace] @@ -50,3 +76,14 @@ using namespace foo_literals; // CHECK: :[[@LINE-1]]:1: warning: do not use namespace using-directives; use using-declarations instead [google-build-using-namespace] + +// If -header-filter= is not used and there is some warning in .h file, +// give a reminder to use -header-filter. +// CHECK0: Use -header-filter={{.*}} to display errors{{.*}} +// +// If -header-filter= is used, no summary of this message. +// CHECK1-NOT: Use -header-filter={{.*}} to display errors{{.*}} +// +// With --skip-header, no warning in .h file is detected or hidden, +// no need to give a reminder to use -header-filter. +// CHECK2-NOT: Use -header-filter={{.*}} to display errors{{.*}} Index: clang-tools-extra/test/clang-tidy/checkers/google-objc-function-naming.m =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/google-objc-function-naming.m +++ clang-tools-extra/test/clang-tidy/checkers/google-objc-function-naming.m @@ -1,4 +1,5 @@ -// RUN: %check_clang_tidy %s google-objc-function-naming %t -- -- -isystem %S/Inputs/Headers +// RUN: %check_clang_tidy %s google-objc-function-naming %t -- --skip-headers=0 -- -isystem %S/Inputs/Headers +// RUN: %check_clang_tidy %s google-objc-function-naming %t -- --skip-headers -- -isystem %S/Inputs/Headers #include Index: clang-tools-extra/test/clang-tidy/checkers/google-upgrade-googletest-case.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/google-upgrade-googletest-case.cpp +++ clang-tools-extra/test/clang-tidy/checkers/google-upgrade-googletest-case.cpp @@ -1,5 +1,7 @@ -// RUN: %check_clang_tidy %s google-upgrade-googletest-case %t -- -- -I%S/Inputs -// RUN: %check_clang_tidy -check-suffix=NOSUITE %s google-upgrade-googletest-case %t -- -- -DNOSUITE -I%S/Inputs/gtest/nosuite +// RUN: %check_clang_tidy %s google-upgrade-googletest-case %t -- --skip-headers=0 -- -I%S/Inputs +// RUN: %check_clang_tidy -check-suffix=NOSUITE %s google-upgrade-googletest-case %t -- --skip-headers=0 -- -DNOSUITE -I%S/Inputs/gtest/nosuite +// RUN: %check_clang_tidy %s google-upgrade-googletest-case %t -- --skip-headers -- -I%S/Inputs +// RUN: %check_clang_tidy -check-suffix=NOSUITE %s google-upgrade-googletest-case %t -- --skip-headers -- -DNOSUITE -I%S/Inputs/gtest/nosuite #include "gtest/gtest.h" Index: clang-tools-extra/test/clang-tidy/checkers/llvm-include-order.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/llvm-include-order.cpp +++ clang-tools-extra/test/clang-tidy/checkers/llvm-include-order.cpp @@ -1,4 +1,5 @@ -// RUN: %check_clang_tidy %s llvm-include-order %t -- -- -isystem %S/Inputs/Headers +// RUN: %check_clang_tidy %s llvm-include-order %t -- --skip-headers=0 -- -isystem %S/Inputs/Headers +// RUN: %check_clang_tidy %s llvm-include-order %t -- --skip-headers -- -isystem %S/Inputs/Headers // CHECK-MESSAGES: [[@LINE+2]]:1: warning: #includes are not sorted properly #include "j.h" Index: clang-tools-extra/test/clang-tidy/checkers/llvm-prefer-register-over-unsigned.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/llvm-prefer-register-over-unsigned.cpp +++ clang-tools-extra/test/clang-tidy/checkers/llvm-prefer-register-over-unsigned.cpp @@ -1,4 +1,5 @@ -// RUN: %check_clang_tidy %s llvm-prefer-register-over-unsigned %t +// RUN: %check_clang_tidy %s llvm-prefer-register-over-unsigned %t -- --skip-headers=0 +// RUN: %check_clang_tidy %s llvm-prefer-register-over-unsigned %t -- --skip-headers namespace llvm { class Register { Index: clang-tools-extra/test/clang-tidy/checkers/llvmlibc-implementation-in-namespace.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/llvmlibc-implementation-in-namespace.cpp +++ clang-tools-extra/test/clang-tidy/checkers/llvmlibc-implementation-in-namespace.cpp @@ -1,4 +1,5 @@ -// RUN: %check_clang_tidy %s llvmlibc-implementation-in-namespace %t +// RUN: %check_clang_tidy %s llvmlibc-implementation-in-namespace %t -- --skip-headers=0 +// RUN: %check_clang_tidy %s llvmlibc-implementation-in-namespace %t -- --skip-headers #define MACRO_A "defining macros outside namespace is valid" Index: clang-tools-extra/test/clang-tidy/checkers/llvmlibc-restrict-system-libc-headers.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/llvmlibc-restrict-system-libc-headers.cpp +++ clang-tools-extra/test/clang-tidy/checkers/llvmlibc-restrict-system-libc-headers.cpp @@ -1,5 +1,9 @@ // RUN: %check_clang_tidy %s llvmlibc-restrict-system-libc-headers %t \ -// RUN: -- -- -isystem %S/Inputs/llvmlibc/system \ +// RUN: -- --skip-headers=0 -- -isystem %S/Inputs/llvmlibc/system \ +// RUN: -resource-dir %S/Inputs/llvmlibc/resource +// +// RUN: %check_clang_tidy %s llvmlibc-restrict-system-libc-headers %t \ +// RUN: -- --skip-headers -- -isystem %S/Inputs/llvmlibc/system \ // RUN: -resource-dir %S/Inputs/llvmlibc/resource #include Index: clang-tools-extra/test/clang-tidy/checkers/misc-no-recursion.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/misc-no-recursion.cpp +++ clang-tools-extra/test/clang-tidy/checkers/misc-no-recursion.cpp @@ -1,4 +1,5 @@ -// RUN: %check_clang_tidy %s misc-no-recursion %t +// RUN: %check_clang_tidy %s misc-no-recursion %t -- --skip-headers=0 +// RUN: %check_clang_tidy %s misc-no-recursion %t -- --skip-headers // We don't have the definition of this function, // so we can't tell anything about it.. Index: clang-tools-extra/test/clang-tidy/checkers/misc-unused-using-decls.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/misc-unused-using-decls.cpp +++ clang-tools-extra/test/clang-tidy/checkers/misc-unused-using-decls.cpp @@ -1,4 +1,13 @@ -// RUN: %check_clang_tidy %s misc-unused-using-decls %t -- --fix-notes -- -fno-delayed-template-parsing -isystem %S/Inputs/ +// Setup header directory +// RUN: rm -rf %theaders +// RUN: mkdir %theaders +// RUN: cp -R %S/Inputs/unused-using-decls.h %theaders + +// RUN: %check_clang_tidy %s misc-unused-using-decls %t -- --skip-headers=0 \ +// RUN: --fix-notes -- -fno-delayed-template-parsing -I%theaders +// +// RUN: %check_clang_tidy %s misc-unused-using-decls %t -- --skip-headers \ +// RUN: --fix-notes -- -fno-delayed-template-parsing -I%theaders // ----- Definitions ----- template class vector {}; @@ -66,7 +75,24 @@ } // namespace n +namespace Q1 { +class QC1; +} +using Q1::QC1; +// Do not give warning about unused QC1! It is used in .h file. +// CHECK-MESSAGES-NOT: warning: using decl 'QC1' is unused + #include "unused-using-decls.h" +// FIXME: here we should have a warning on unused using decl 'QC2' + +namespace Q3 { +class QC3; +} +using Q3::QC3; // QC3 should be removed +// CHECK-MESSAGES: warning: using decl 'QC3' is unused +// CHECK-MESSAGES: note: remove the using +// CHECK-FIXES: {{^}}// QC3 should be removed + namespace ns { template class AA { Index: clang-tools-extra/test/clang-tidy/checkers/modernize-deprecated-headers-cxx03.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/modernize-deprecated-headers-cxx03.cpp +++ clang-tools-extra/test/clang-tidy/checkers/modernize-deprecated-headers-cxx03.cpp @@ -1,4 +1,5 @@ -// RUN: %check_clang_tidy -std=c++98 %s modernize-deprecated-headers %t -- -extra-arg-before=-isystem%S/Inputs/modernize-deprecated-headers +// RUN: %check_clang_tidy -std=c++98 %s modernize-deprecated-headers %t -- --skip-headers=0 -extra-arg-before=-isystem%S/Inputs/modernize-deprecated-headers +// RUN: %check_clang_tidy -std=c++98 %s modernize-deprecated-headers %t -- --skip-headers -extra-arg-before=-isystem%S/Inputs/modernize-deprecated-headers #include // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'assert.h'; consider using 'cassert' instead [modernize-deprecated-headers] Index: clang-tools-extra/test/clang-tidy/checkers/modernize-deprecated-headers-cxx11.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/modernize-deprecated-headers-cxx11.cpp +++ clang-tools-extra/test/clang-tidy/checkers/modernize-deprecated-headers-cxx11.cpp @@ -1,4 +1,5 @@ -// RUN: %check_clang_tidy -std=c++11-or-later %s modernize-deprecated-headers %t -- -extra-arg-before=-isystem%S/Inputs/modernize-deprecated-headers +// RUN: %check_clang_tidy -std=c++11-or-later %s modernize-deprecated-headers %t -- --skip-headers=0 -extra-arg-before=-isystem%S/Inputs/modernize-deprecated-headers +// RUN: %check_clang_tidy -std=c++11-or-later %s modernize-deprecated-headers %t -- --skip-headers -extra-arg-before=-isystem%S/Inputs/modernize-deprecated-headers #include // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'assert.h'; consider using 'cassert' instead [modernize-deprecated-headers] Index: clang-tools-extra/test/clang-tidy/checkers/modernize-pass-by-value-header.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/modernize-pass-by-value-header.cpp +++ clang-tools-extra/test/clang-tidy/checkers/modernize-pass-by-value-header.cpp @@ -1,9 +1,83 @@ +// Reuse some tests from modernize-pass-by-value.cpp, +// to show that header file warnings can be skipped by skip-headers, +// but fix to header files is already suppressed by -header-filter. +// +// (1) -fix --skip-headers=0, suppress warning and fix in .h file +// showmain,noheader fixmain, nofixheader +// (2) -fix --skip-headers=1, skip warning and fix in .h file +// showmain,skipheader fixmain, nofixheader +// (3) -fix --skip-headers=0 -header-filter=.* , show and fix warnings in .h file +// showmain,showheader fixmain, fixheader +// (4) -fix --skip-headers=1 -header-filter=.* , show and fix warnings in .h file +// showmain,showheader fixmain, fixheader +// +// (1) // RUN: cp %S/Inputs/modernize-pass-by-value/header.h %T/pass-by-value-header.h -// RUN: clang-tidy %s -checks='-*,modernize-pass-by-value' -header-filter='.*' -fix -- -std=c++11 -I %T | FileCheck %s -check-prefix=CHECK-MESSAGES -implicit-check-not="{{warning|error}}:" -// RUN: FileCheck -input-file=%T/pass-by-value-header.h %s -check-prefix=CHECK-FIXES -// FIXME: Make the test work in all language modes. +// RUN: cp %S/modernize-pass-by-value-header.cpp %T/pass-by-value-header.cpp +// RUN: clang-tidy %T/pass-by-value-header.cpp -checks='-*,modernize-pass-by-value' \ +// RUN: --skip-headers=0 -fix -- -std=c++11 2>&1 \ +// RUN: | FileCheck %s -check-prefixes=SHOWMAIN,NOHEADER +// RUN: FileCheck -input-file=%T/pass-by-value-header.h %s -check-prefix=NOFIXHEADER +// RUN: FileCheck -input-file=%T/pass-by-value-header.cpp %s -check-prefix=FIXMAIN +// +// (2) +// RUN: cp %S/Inputs/modernize-pass-by-value/header.h %T/pass-by-value-header.h +// RUN: cp %S/modernize-pass-by-value-header.cpp %T/pass-by-value-header.cpp +// RUN: clang-tidy %T/pass-by-value-header.cpp -checks='-*,modernize-pass-by-value' \ +// RUN: --skip-headers -fix -- -std=c++11 2>&1 \ +// RUN: | FileCheck %s -check-prefixes=SHOWMAIN,SKIPHEADER +// RUN: FileCheck -input-file=%T/pass-by-value-header.h %s -check-prefix=NOFIXHEADER +// RUN: FileCheck -input-file=%T/pass-by-value-header.cpp %s -check-prefix=FIXMAIN +// +// (3) +// RUN: cp %S/Inputs/modernize-pass-by-value/header.h %T/pass-by-value-header.h +// RUN: cp %S/modernize-pass-by-value-header.cpp %T/pass-by-value-header.cpp +// RUN: clang-tidy %T/pass-by-value-header.cpp -checks='-*,modernize-pass-by-value' \ +// RUN: --header-filter=.* --skip-headers=0 -fix -- -std=c++11 2>&1 \ +// RUN: | FileCheck %s -check-prefixes=SHOWMAIN,SHOWHEADER +// RUN: FileCheck -input-file=%T/pass-by-value-header.h %s -check-prefix=FIXHEADER +// RUN: FileCheck -input-file=%T/pass-by-value-header.cpp %s -check-prefix=FIXMAIN +// +// (4) +// RUN: cp %S/Inputs/modernize-pass-by-value/header.h %T/pass-by-value-header.h +// RUN: cp %S/modernize-pass-by-value-header.cpp %T/pass-by-value-header.cpp +// RUN: clang-tidy %T/pass-by-value-header.cpp -checks='-*,modernize-pass-by-value' \ +// RUN: --header-filter=.* --skip-headers -fix -- -std=c++11 2>&1 \ +// RUN: | FileCheck %s -check-prefixes=SHOWMAIN,SHOWHEADER +// RUN: FileCheck -input-file=%T/pass-by-value-header.h %s -check-prefix=FIXHEADER +// RUN: FileCheck -input-file=%T/pass-by-value-header.cpp %s -check-prefix=FIXMAIN #include "pass-by-value-header.h" -// CHECK-MESSAGES: :8:5: warning: pass by value and use std::move [modernize-pass-by-value] -// CHECK-FIXES: #include -// CHECK-FIXES: A(ThreadId tid) : threadid(std::move(tid)) {} +// FIXHEADER: #include +// FIXHEADER: struct A +// FIXHEADER: A(ThreadId tid) : threadid(std::move(tid)) {} +// NOFIXHEADER-NOT: #include +// NOFIXHEADER: struct A +// NOFIXHEADER: A(const ThreadId &tid) : threadid(tid) {} +// NOFIXHEADER-NOT: A(ThreadId tid) : threadid(std::move(tid)) {} + +// Test that both declaration and definition are updated. +struct D { + D(const Movable &M); + // FIXMAIN: D(Movable M); + Movable M; +}; +// NOTE! Use DAG tage because header file warnings may shown after +// main file warnings on Linux, but before main file warnings on Windows. +// SHOWHEADER-DAG: :8:5: warning: pass by value and use std::move [modernize-pass-by-value] +// NOHEADER-NOT: :8:5: warning: pass by value and use std::move [modernize-pass-by-value] +// SKIPHEADER-NOT: :8:5: warning: pass by value and use std::move [modernize-pass-by-value] + +D::D(const Movable &M) : M(M) {} +// SHOWMAIN-DAG: :[[@LINE-1]]:6: warning: pass by value and use std::move +// FIXMAIN: D::D(Movable M) : M(std::move(M)) {} + +// no more warning or error +// SHOWMAIN-NOT: {{warning|error}}: +// SHOWHEADER-NOT: {{warning|error}}: +// NOHEADER-NOT: {{warning|error}}: +// SKIPHEADER-NOT: {{warning|error}}: +// +// NOHEADER: Suppressed {{.*}} warnings +// SKIPHEADER-NOT: Suppressed {{.*}} warnings +// SHOWHEADER-NOT: Suppressed {{.*}} warnings Index: clang-tools-extra/test/clang-tidy/checkers/portability-restrict-system-includes-allow.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/portability-restrict-system-includes-allow.cpp +++ clang-tools-extra/test/clang-tidy/checkers/portability-restrict-system-includes-allow.cpp @@ -1,5 +1,9 @@ // RUN: %check_clang_tidy %s portability-restrict-system-includes %t \ -// RUN: -- -config="{CheckOptions: [{key: portability-restrict-system-includes.Includes, value: '*,-stddef.h'}]}" \ +// RUN: -- -config="{CheckOptions: [{key: portability-restrict-system-includes.Includes, value: '*,-stddef.h'}]}" --skip-headers=0 \ +// RUN: -- -isystem %S/Inputs/portability-restrict-system-includes/system +// +// RUN: %check_clang_tidy %s portability-restrict-system-includes %t \ +// RUN: -- -config="{CheckOptions: [{key: portability-restrict-system-includes.Includes, value: '*,-stddef.h'}]}" --skip-headers \ // RUN: -- -isystem %S/Inputs/portability-restrict-system-includes/system // Test block-list functionality: allow all but stddef.h. Index: clang-tools-extra/test/clang-tidy/checkers/portability-restrict-system-includes-disallow.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/portability-restrict-system-includes-disallow.cpp +++ clang-tools-extra/test/clang-tidy/checkers/portability-restrict-system-includes-disallow.cpp @@ -1,5 +1,9 @@ // RUN: %check_clang_tidy %s portability-restrict-system-includes %t \ -// RUN: -- -config="{CheckOptions: [{key: portability-restrict-system-includes.Includes, value: '-*,stddef.h'}]}" \ +// RUN: -- -config="{CheckOptions: [{key: portability-restrict-system-includes.Includes, value: '-*,stddef.h'}]}" --skip-headers=0 \ +// RUN: -- -isystem %S/Inputs/portability-restrict-system-includes/system +// +// RUN: %check_clang_tidy %s portability-restrict-system-includes %t \ +// RUN: -- -config="{CheckOptions: [{key: portability-restrict-system-includes.Includes, value: '-*,stddef.h'}]}" --skip-headers \ // RUN: -- -isystem %S/Inputs/portability-restrict-system-includes/system // Test allow-list functionality: disallow all but stddef.h. Index: clang-tools-extra/test/clang-tidy/checkers/readability-simplify-bool-expr-chained-conditional-assignment.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/readability-simplify-bool-expr-chained-conditional-assignment.cpp +++ clang-tools-extra/test/clang-tidy/checkers/readability-simplify-bool-expr-chained-conditional-assignment.cpp @@ -1,4 +1,7 @@ -// RUN: %check_clang_tidy %s readability-simplify-boolean-expr %t -- -config="{CheckOptions: [{key: "readability-simplify-boolean-expr.ChainedConditionalAssignment", value: true}]}" -- +// RUN: %check_clang_tidy %s readability-simplify-boolean-expr %t -- --skip-headers=0 \ +// RUN: -config="{CheckOptions: [{key: "readability-simplify-boolean-expr.ChainedConditionalAssignment", value: true}]}" -- +// RUN: %check_clang_tidy %s readability-simplify-boolean-expr %t -- --skip-headers \ +// RUN: -config="{CheckOptions: [{key: "readability-simplify-boolean-expr.ChainedConditionalAssignment", value: true}]}" -- void chained_conditional_compound_assignment(int i) { bool b; Index: clang-tools-extra/test/clang-tidy/checkers/readability-simplify-bool-expr-chained-conditional-return.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/readability-simplify-bool-expr-chained-conditional-return.cpp +++ clang-tools-extra/test/clang-tidy/checkers/readability-simplify-bool-expr-chained-conditional-return.cpp @@ -1,4 +1,7 @@ -// RUN: %check_clang_tidy %s readability-simplify-boolean-expr %t -- -config="{CheckOptions: [{key: "readability-simplify-boolean-expr.ChainedConditionalReturn", value: true}]}" -- +// RUN: %check_clang_tidy %s readability-simplify-boolean-expr %t -- --skip-headers=0 \ +// RUN: -config="{CheckOptions: [{key: "readability-simplify-boolean-expr.ChainedConditionalReturn", value: true}]}" -- +// RUN: %check_clang_tidy %s readability-simplify-boolean-expr %t -- --skip-headers \ +// RUN: -config="{CheckOptions: [{key: "readability-simplify-boolean-expr.ChainedConditionalReturn", value: true}]}" -- bool chained_conditional_compound_return(int i) { if (i < 0) { Index: clang-tools-extra/test/clang-tidy/checkers/readability-simplify-bool-expr-members.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/readability-simplify-bool-expr-members.cpp +++ clang-tools-extra/test/clang-tidy/checkers/readability-simplify-bool-expr-members.cpp @@ -1,4 +1,5 @@ -// RUN: %check_clang_tidy %s readability-simplify-boolean-expr %t +// RUN: %check_clang_tidy %s readability-simplify-boolean-expr %t -- --skip-headers=0 +// RUN: %check_clang_tidy %s readability-simplify-boolean-expr %t -- --skip-headers class A { public: Index: clang-tools-extra/test/clang-tidy/checkers/readability-simplify-bool-expr.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/readability-simplify-bool-expr.cpp +++ clang-tools-extra/test/clang-tidy/checkers/readability-simplify-bool-expr.cpp @@ -1,4 +1,5 @@ -// RUN: %check_clang_tidy %s readability-simplify-boolean-expr %t +// RUN: %check_clang_tidy %s readability-simplify-boolean-expr %t -- --skip-headers=0 +// RUN: %check_clang_tidy %s readability-simplify-boolean-expr %t -- --skip-headers bool a1 = false; Index: clang-tools-extra/test/clang-tidy/checkers/skip-headers-1.cpp =================================================================== --- /dev/null +++ clang-tools-extra/test/clang-tidy/checkers/skip-headers-1.cpp @@ -0,0 +1,60 @@ +// Test --skip-headers, --show-all-warnings, and --header-filter. +// +// Default shows no warning in .h files, with hint to use --header-filter +// RUN: clang-tidy %s -checks='*' --skip-headers=0 -- \ +// RUN: 2>&1 | FileCheck %s -check-prefixes COUNTER,NOHEADER,MAIN,HINT +// +// --skip-headers skips all included files warnings; without hint +// RUN: clang-tidy %s -checks='*' --skip-headers -- \ +// RUN: 2>&1 | FileCheck %s -check-prefixes COUNTER,NOHEADER,MAIN,NOHINT +// +// --show-all-warnings reports all warnings, even without --header-filters +// RUN: clang-tidy %s -checks='*' --show-all-warnings --skip-headers=0 -- \ +// RUN: 2>&1 | FileCheck %s -check-prefixes COUNTER,HEADER,MAIN,NOHINT +// +// --header-filter='.*' is like --show-all-warnings +// RUN: clang-tidy %s -checks='*' --header-filter='.*' --skip-headers=0 -- \ +// RUN: 2>&1 | FileCheck %s -check-prefixes COUNTER,HEADER,MAIN,NOHINT +// +// With --show-all-warnings and --skip-headers, +// no warnings should be reported from header files. +// RUN: clang-tidy %s -checks='*' --skip-headers --show-all-warnings -- \ +// RUN: 2>&1 | FileCheck %s -check-prefixes COUNTER,NOHEADER,MAIN,NOHINT +// +// --header-filter='header1.h' shows only warnings in header1.h +// RUN: clang-tidy %s -checks='*' --header-filter='header1.h' --skip-headers=0 -- \ +// RUN: 2>&1 | FileCheck %s -check-prefixes COUNTER,H1,MAIN,HINT +// +// RUN: clang-tidy %s -checks='*' --header-filter='header1.h' --skip-headers -- \ +// RUN: 2>&1 | FileCheck %s -check-prefixes COUNTER,H1,MAIN,NOHINT +// +// --header-filter='header2.h' shows only warnings in header2.h +// RUN: clang-tidy %s -checks='*' --header-filter='header2.h' --skip-headers=0 -- \ +// RUN: 2>&1 | FileCheck %s -check-prefixes COUNTER,H2,MAIN,HINT +// +// RUN: clang-tidy %s -checks='*' --header-filter='header2.h' --skip-headers -- \ +// RUN: 2>&1 | FileCheck %s -check-prefixes COUNTER,H2,MAIN,NOHINT + +// All options have warning count reported: +// COUNTER: {{[0-9]+}} warnings generated. + +// Not all PPCallback checks have supported skip-header yet. +// So, some headers still have warnings. +#include "Inputs/skip-headers/my_header1.h" +// H1: my_header1.h:1:1: warning: header is missing header guard +// HEADER: my_header1.h:1:1: warning: header is missing header guard +// H2-NOT: my_header1.h +// NOHEADER-NOT: my_header1.h FIXME + +// H2: my_header2.h:1:1: warning: header is missing header guard +// HEADER: my_header2.h:1:1: warning: header is missing header guard +// H1-NOT: my_header2.h +// NOHEADER-NOT: my_header2.h FIXME + +int xyz = 135; +// MAIN: skip-headers-1.cpp:{{[0-9]+}}:{{[0-9]+}}: warning: + +// HINT: Use -header-filter={{.*}} to display errors{{.*}} +// NOHINT-NOT: Use -header-filter= FIXME +// Not all PPCallback checks have supported skip-header yet. +// So there are still "hint" at the end of these tests. Index: clang-tools-extra/test/clang-tidy/checkers/skip-headers-2.cpp =================================================================== --- /dev/null +++ clang-tools-extra/test/clang-tidy/checkers/skip-headers-2.cpp @@ -0,0 +1,39 @@ +// Test --skip-headers, --show-all-warnings, and --header-filter +// with nested Decls. Users should be able to select exactly +// which .h file to check for warnings. +// Here a.h includes/uses b.h. Maintainers of a.h wants to check/see +// warnings in a.h but not b.h. So they use --header-filer=a.h --skip-headers. +// +// RUN: clang-tidy %s --skip-headers=0 --show-all-warnings \ +// RUN: -checks='-*,readability-convert-member-functions-to-static' -- \ +// RUN: | FileCheck %s -check-prefixes WARNA,WARNB,WARNMAIN +// +// RUN: clang-tidy %s --skip-headers=1 --show-all-warnings \ +// RUN: -checks='-*,readability-convert-member-functions-to-static' -- \ +// RUN: | FileCheck %s -check-prefixes WARNMAIN,NOWARNA,NOWARNB +// +// RUN: clang-tidy %s --skip-headers=1 --show-all-warnings --header-filter=a.h \ +// RUN: -checks='-*,readability-convert-member-functions-to-static' -- \ +// RUN: | FileCheck %s -check-prefixes WARNMAIN,WARNA,NOWARNB +// +// RUN: clang-tidy %s --skip-headers=1 --show-all-warnings --header-filter=.* \ +// RUN: -checks='-*,readability-convert-member-functions-to-static' -- \ +// RUN: | FileCheck %s -check-prefixes WARNMAIN,WARNA,WARNB +// +// Current limitation of --skip-haders: b.h is skipped if a.h is skipped. +// RUN: clang-tidy %s --skip-headers=1 --show-all-warnings --header-filter=b.h \ +// RUN: -checks='-*,readability-convert-member-functions-to-static' -- \ +// RUN: | FileCheck %s -check-prefixes WARNMAIN,NOWARNA,NOWARNB + +#include "Inputs/skip-headers/a.h" + +// WARNA: warning: method 'fooA' can be made static +// NOWARNA-NOT: warning: method 'fooA' can be made static + +// WARNB: warning: method 'fooB' can be made static +// NOWARNB-NOT: warning: method 'fooB' can be made static + +class C { + void foo(int x) { x = 3; }; + // WARNMAIN: warning: method 'foo' can be made static +}; Index: clang-tools-extra/test/clang-tidy/checkers/skip-headers-3.cpp =================================================================== --- /dev/null +++ clang-tools-extra/test/clang-tidy/checkers/skip-headers-3.cpp @@ -0,0 +1,30 @@ +// Test --skip-headers, which should skip statements and expressions +// in a called function of header files even if the calling function +// is in the main file. +// +// RUN: clang-tidy %s --skip-headers=0 --show-all-warnings \ +// RUN: -checks='-*,cert-dcl16-c' \ +// RUN: | FileCheck %s -check-prefixes WARNC,MAIN +// +// RUN: clang-tidy %s --skip-headers --show-all-warnings \ +// RUN: -checks='-*,cert-dcl16-c' --header-filter=c1.h \ +// RUN: | FileCheck %s -check-prefixes MAIN,WARNC +// +// RUN: clang-tidy %s --skip-headers --show-all-warnings \ +// RUN: -checks='-*,cert-dcl16-c' \ +// RUN: | FileCheck %s -check-prefixes MAIN,NOWARNC + +#include "Inputs/skip-headers/c1.h" +// WARNC: c1.h:5:27: warning: integer literal has suffix 'll', which is not uppercase [cert-dcl16-c] +// WARNC: c1.h:6:20: warning: integer literal has suffix 'll', which is not uppercase [cert-dcl16-c] +// NOWARNC-NOT: c1.h:5:27: warning: integer literal has suffix 'll', which is not uppercase [cert-dcl16-c] +// NOWARNC-NOT: c1.h:6:20: warning: integer literal has suffix 'll', which is not uppercase [cert-dcl16-c] + +void foo(int x = 3ll, C1 *p = nullptr) { + // MAIN: skip-headers-3.cpp:[[@LINE-1]]:18: warning: integer literal has suffix 'll', which is not uppercase [cert-dcl16-c] + C1::foo1(); + p->foo2(); + p->foo3(x); +} + +// MAIN-NOT: warning: integer literal has suffix 'll', which is not uppercase [cert-dcl16-c] Index: clang-tools-extra/test/clang-tidy/checkers/skip-headers-4.cpp =================================================================== --- /dev/null +++ clang-tools-extra/test/clang-tidy/checkers/skip-headers-4.cpp @@ -0,0 +1,40 @@ +// When the statement of a template function call does not have a +// "valid" source location and its default argument value cast expression +// is in an included header file, the warning on the expression should +// be suppressed by --skip-headers. +// +// RUN: clang-tidy %s --skip-headers=0 \ +// RUN: -checks='-*,modernize-use-nullptr' -- \ +// RUN: | FileCheck %s -check-prefixes MAIN,NOWARNC +// +// RUN: clang-tidy %s --skip-headers --show-all-warnings \ +// RUN: -checks='-*,modernize-use-nullptr' -- \ +// RUN: | FileCheck %s -check-prefixes MAIN,NOWARNC +// +// RUN: clang-tidy %s --skip-headers=0 \ +// RUN: -checks='-*,modernize-use-nullptr' -header-filter=c.h -- \ +// RUN: | FileCheck %s -check-prefixes MAIN,WARNC +// +// RUN: clang-tidy %s --skip-headers --show-all-warnings \ +// RUN: -checks='-*,modernize-use-nullptr' -header-filter=c.h -- \ +// RUN: | FileCheck %s -check-prefixes MAIN,WARNC + +#include "Inputs/skip-headers/c.h" +// WARNC: c.h:5:34: warning: use nullptr [modernize-use-nullptr] +// NOWARNC-NOT: c.h:5:34: warning: use nullptr [modernize-use-nullptr] +// NOWARNC-NOT: c.h: + +template +class D { +public: + template + explicit D(const R r, int *x = 0) : p(x) {} + // MAIN: :[[@LINE-1]]:34: warning: use nullptr [modernize-use-nullptr] +private: + int *p; +}; + +C x = C(2); +D y = D(4); + +// MAIN-NOT: warning: Index: clang-tools-extra/test/clang-tidy/infrastructure/file-filter-symlinks.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/infrastructure/file-filter-symlinks.cpp +++ clang-tools-extra/test/clang-tidy/infrastructure/file-filter-symlinks.cpp @@ -5,12 +5,12 @@ // RUN: echo 'class A { A(int); };' > %t/dir1/header.h // RUN: ln -s %t/dir1/header.h %t/dir1/header_alias.h // -// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='dir1/dir2/\.\./header_alias\.h' %s -- -I %t 2>&1 | FileCheck --check-prefix=CHECK_HEADER_ALIAS %s -// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='dir1/dir2/\.\./header_alias\.h' -quiet %s -- -I %t 2>&1 | FileCheck --check-prefix=CHECK_HEADER_ALIAS %s -// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='header_alias\.h' %s -- -I %t 2>&1 | FileCheck --check-prefix=CHECK_HEADER_ALIAS %s -// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='header_alias\.h' -quiet %s -- -I %t 2>&1 | FileCheck --check-prefix=CHECK_HEADER_ALIAS %s -// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='header\.h' %s -- -I %t 2>&1 | FileCheck --check-prefix=CHECK_HEADER %s -// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='header\.h' -quiet %s -- -I %t 2>&1 | FileCheck --check-prefix=CHECK_HEADER %s +// RUN: clang-tidy --skip-headers=0 -checks='-*,google-explicit-constructor' -header-filter='dir1/dir2/\.\./header_alias\.h' %s -- -I %t 2>&1 | FileCheck --check-prefix=CHECK_HEADER_ALIAS %s +// RUN: clang-tidy --skip-headers=0 -checks='-*,google-explicit-constructor' -header-filter='dir1/dir2/\.\./header_alias\.h' -quiet %s -- -I %t 2>&1 | FileCheck --check-prefix=CHECK_HEADER_ALIAS %s +// RUN: clang-tidy --skip-headers=0 -checks='-*,google-explicit-constructor' -header-filter='header_alias\.h' %s -- -I %t 2>&1 | FileCheck --check-prefix=CHECK_HEADER_ALIAS %s +// RUN: clang-tidy --skip-headers=0 -checks='-*,google-explicit-constructor' -header-filter='header_alias\.h' -quiet %s -- -I %t 2>&1 | FileCheck --check-prefix=CHECK_HEADER_ALIAS %s +// RUN: clang-tidy --skip-headers=0 -checks='-*,google-explicit-constructor' -header-filter='header\.h' %s -- -I %t 2>&1 | FileCheck --check-prefix=CHECK_HEADER %s +// RUN: clang-tidy --skip-headers=0 -checks='-*,google-explicit-constructor' -header-filter='header\.h' -quiet %s -- -I %t 2>&1 | FileCheck --check-prefix=CHECK_HEADER %s // Check that `-header-filter` operates on the same file paths as paths in // diagnostics printed by ClangTidy. Index: clang-tools-extra/test/clang-tidy/infrastructure/file-filter.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/infrastructure/file-filter.cpp +++ clang-tools-extra/test/clang-tidy/infrastructure/file-filter.cpp @@ -1,14 +1,14 @@ -// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='' %s -- -I %S/Inputs/file-filter -isystem %S/Inputs/file-filter/system 2>&1 | FileCheck %s -// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='' -quiet %s -- -I %S/Inputs/file-filter -isystem %S/Inputs/file-filter/system 2>&1 | FileCheck --check-prefix=CHECK-QUIET %s -// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='.*' %s -- -I %S/Inputs/file-filter -isystem %S/Inputs/file-filter/system 2>&1 | FileCheck --check-prefix=CHECK2 %s -// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='.*' -quiet %s -- -I %S/Inputs/file-filter -isystem %S/Inputs/file-filter/system 2>&1 | FileCheck --check-prefix=CHECK2-QUIET %s -// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='header2\.h' %s -- -I %S/Inputs/file-filter -isystem %S/Inputs/file-filter/system 2>&1 | FileCheck --check-prefix=CHECK3 %s -// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='header2\.h' -quiet %s -- -I %S/Inputs/file-filter -isystem %S/Inputs/file-filter/system 2>&1 | FileCheck --check-prefix=CHECK3-QUIET %s +// RUN: clang-tidy --skip-headers=0 -checks='-*,google-explicit-constructor' -header-filter='' %s -- -I %S/Inputs/file-filter -isystem %S/Inputs/file-filter/system 2>&1 | FileCheck %s +// RUN: clang-tidy --skip-headers=0 -checks='-*,google-explicit-constructor' -header-filter='' -quiet %s -- -I %S/Inputs/file-filter -isystem %S/Inputs/file-filter/system 2>&1 | FileCheck --check-prefix=CHECK-QUIET %s +// RUN: clang-tidy --skip-headers=0 -checks='-*,google-explicit-constructor' -header-filter='.*' %s -- -I %S/Inputs/file-filter -isystem %S/Inputs/file-filter/system 2>&1 | FileCheck --check-prefix=CHECK2 %s +// RUN: clang-tidy --skip-headers=0 -checks='-*,google-explicit-constructor' -header-filter='.*' -quiet %s -- -I %S/Inputs/file-filter -isystem %S/Inputs/file-filter/system 2>&1 | FileCheck --check-prefix=CHECK2-QUIET %s +// RUN: clang-tidy --skip-headers=0 -checks='-*,google-explicit-constructor' -header-filter='header2\.h' %s -- -I %S/Inputs/file-filter -isystem %S/Inputs/file-filter/system 2>&1 | FileCheck --check-prefix=CHECK3 %s +// RUN: clang-tidy --skip-headers=0 -checks='-*,google-explicit-constructor' -header-filter='header2\.h' -quiet %s -- -I %S/Inputs/file-filter -isystem %S/Inputs/file-filter/system 2>&1 | FileCheck --check-prefix=CHECK3-QUIET %s // FIXME: "-I %S/Inputs/file-filter/system/.." must be redundant. // On Win32, file-filter/system\system-header1.h precedes // file-filter\header*.h due to code order between '/' and '\\'. -// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='.*' -system-headers %s -- -I %S/Inputs/file-filter/system/.. -isystem %S/Inputs/file-filter/system 2>&1 | FileCheck --check-prefix=CHECK4 %s -// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='.*' -system-headers -quiet %s -- -I %S/Inputs/file-filter/system/.. -isystem %S/Inputs/file-filter/system 2>&1 | FileCheck --check-prefix=CHECK4-QUIET %s +// RUN: clang-tidy --skip-headers=0 -checks='-*,google-explicit-constructor' -header-filter='.*' -system-headers %s -- -I %S/Inputs/file-filter/system/.. -isystem %S/Inputs/file-filter/system 2>&1 | FileCheck --check-prefix=CHECK4 %s +// RUN: clang-tidy --skip-headers=0 -checks='-*,google-explicit-constructor' -header-filter='.*' -system-headers -quiet %s -- -I %S/Inputs/file-filter/system/.. -isystem %S/Inputs/file-filter/system 2>&1 | FileCheck --check-prefix=CHECK4-QUIET %s #include "header1.h" // CHECK-NOT: warning: Index: clang-tools-extra/test/clang-tidy/infrastructure/line-filter.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/infrastructure/line-filter.cpp +++ clang-tools-extra/test/clang-tidy/infrastructure/line-filter.cpp @@ -1,4 +1,4 @@ -// RUN: clang-tidy -checks='-*,google-explicit-constructor' -line-filter='[{"name":"line-filter.cpp","lines":[[18,18],[22,22]]},{"name":"header1.h","lines":[[1,2]]},{"name":"header2.h"},{"name":"header3.h"}]' -header-filter='header[12]\.h$' %s -- -I %S/Inputs/line-filter 2>&1 | FileCheck %s +// RUN: clang-tidy --skip-headers=0 -checks='-*,google-explicit-constructor' -line-filter='[{"name":"line-filter.cpp","lines":[[18,18],[22,22]]},{"name":"header1.h","lines":[[1,2]]},{"name":"header2.h"},{"name":"header3.h"}]' -header-filter='header[12]\.h$' %s -- -I %S/Inputs/line-filter 2>&1 | FileCheck %s #include "header1.h" // CHECK-NOT: header1.h:{{.*}} warning Index: clang/include/clang/ASTMatchers/ASTMatchFinder.h =================================================================== --- clang/include/clang/ASTMatchers/ASTMatchFinder.h +++ clang/include/clang/ASTMatchers/ASTMatchFinder.h @@ -133,11 +133,18 @@ /// Per bucket timing information. llvm::StringMap &Records; }; + struct LocFilter { + virtual bool skipLocation(SourceLocation) const = 0; + virtual ~LocFilter(); + }; /// Enables per-check timers. /// /// It prints a report after match. llvm::Optional CheckProfiling; + + /// Check if MatchASTVisitor should skip node at a location. + std::unique_ptr Filter; }; MatchFinder(MatchFinderOptions Options = MatchFinderOptions()); Index: clang/lib/ASTMatchers/ASTMatchFinder.cpp =================================================================== --- clang/lib/ASTMatchers/ASTMatchFinder.cpp +++ clang/lib/ASTMatchers/ASTMatchFinder.cpp @@ -1202,6 +1202,8 @@ if (!DeclNode) { return true; } + if (Options.Filter && Options.Filter->skipLocation(DeclNode->getLocation())) + return true; bool ScopedTraversal = TraversingASTNodeNotSpelledInSource || DeclNode->isImplicit(); @@ -1232,6 +1234,13 @@ if (!StmtNode) { return true; } + // When a function call is in the main file or wanted header files, + // the call site maybe in the Decl that is not to be skipped. + // But the statements of the called function or parameter default expressions + // should be skipped. So here we need to call skipLocation here. + if (Options.Filter && Options.Filter->skipLocation(StmtNode->getBeginLoc())) + return true; + bool ScopedTraversal = TraversingASTNodeNotSpelledInSource || TraversingASTChildrenNotSpelledInSource; @@ -1454,5 +1463,7 @@ return llvm::None; } +MatchFinder::MatchFinderOptions::LocFilter::~LocFilter() = default; + } // end namespace ast_matchers } // end namespace clang