diff --git a/clang-tools-extra/clang-tidy/modernize/ConcatNestedNamespacesCheck.h b/clang-tools-extra/clang-tidy/modernize/ConcatNestedNamespacesCheck.h --- a/clang-tools-extra/clang-tidy/modernize/ConcatNestedNamespacesCheck.h +++ b/clang-tools-extra/clang-tidy/modernize/ConcatNestedNamespacesCheck.h @@ -10,6 +10,7 @@ #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_CONCATNESTEDNAMESPACESCHECK_H #include "../ClangTidyCheck.h" +#include "../utils/HeaderFileExtensionsUtils.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" @@ -17,10 +18,16 @@ namespace tidy { namespace modernize { +/// The check supports these options: +/// - `HeaderFileExtensions`: a comma-separated list of filename extensions of +/// header files (The filename extensions should not contain "." prefix), +/// "h,hh,hpp,hxx" by default. +/// To enable extension-less header files, use an empty string or leave an +/// empty section between two commas like in "h,hxx,,hpp". class ConcatNestedNamespacesCheck : public ClangTidyCheck { public: - ConcatNestedNamespacesCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} + ConcatNestedNamespacesCheck(StringRef Name, ClangTidyContext *Context); + void storeOptions(ClangTidyOptions::OptionMap &Opts) override; void registerMatchers(ast_matchers::MatchFinder *Finder) override; void check(const ast_matchers::MatchFinder::MatchResult &Result) override; @@ -32,6 +39,8 @@ const SourceRange &BackReplacement); NamespaceString concatNamespaces(); NamespaceContextVec Namespaces; + const std::string RawStringHeaderFileExtensions; + utils::HeaderFileExtensionsSet HeaderFileExtensions; }; } // namespace modernize } // namespace tidy diff --git a/clang-tools-extra/clang-tidy/modernize/ConcatNestedNamespacesCheck.cpp b/clang-tools-extra/clang-tidy/modernize/ConcatNestedNamespacesCheck.cpp --- a/clang-tools-extra/clang-tidy/modernize/ConcatNestedNamespacesCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/ConcatNestedNamespacesCheck.cpp @@ -61,9 +61,25 @@ return Result; } +ConcatNestedNamespacesCheck::ConcatNestedNamespacesCheck( + StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + RawStringHeaderFileExtensions(Options.getLocalOrGlobal( + "HeaderFileExtensions", utils::defaultHeaderFileExtensions())) { + if (!utils::parseHeaderFileExtensions(RawStringHeaderFileExtensions, + HeaderFileExtensions, ',')) + llvm::errs() << "Invalid header file extension: " + << RawStringHeaderFileExtensions << "\n"; +} + +void ConcatNestedNamespacesCheck::storeOptions( + ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "HeaderFileExtensions", RawStringHeaderFileExtensions); +} + void ConcatNestedNamespacesCheck::registerMatchers( ast_matchers::MatchFinder *Finder) { - if (!getLangOpts().CPlusPlus17) + if (!getLangOpts().CPlusPlus17 && !getLangOpts().CPlusPlus2a) return; Finder->addMatcher(ast_matchers::namespaceDecl().bind("namespace"), this); @@ -85,7 +101,9 @@ if (!locationsInSameFile(Sources, ND.getBeginLoc(), ND.getRBraceLoc())) return; - if (!Sources.isInMainFile(ND.getBeginLoc())) + if (!Sources.isInMainFile(ND.getBeginLoc()) && + !utils::isSpellingLocInHeaderFile(ND.getBeginLoc(), *Result.SourceManager, + HeaderFileExtensions)) return; if (anonymousOrInlineNamespace(ND)) diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -195,6 +195,11 @@ :doc:`objc-property-declaration ` check have been removed. +- The :doc:`modernize-concat-nested-namespaces + ` now supports the + `HeaderFileExtensions` option and issues warnings for transitively included + header files that pass the header filter. + - The :doc:`modernize-use-override ` now supports `OverrideSpelling` and `FinalSpelling` options. diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize-concat-nested-namespaces.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize-concat-nested-namespaces.rst --- a/clang-tools-extra/docs/clang-tidy/checks/modernize-concat-nested-namespaces.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/modernize-concat-nested-namespaces.rst @@ -47,3 +47,13 @@ } } +Options +------- + +.. option:: HeaderFileExtensions + + A comma-separated list of filename extensions of header files (the filename + extensions should not contain "." prefix). Default is `h,hh,hpp,hxx`. + For header files without an extension, use an empty string (if there are no + other desired extensions) or leave an empty element in the list. e.g., + `h,hh,hpp,hxx,` (note the trailing comma). diff --git a/clang-tools-extra/test/clang-tidy/modernize-concat-nested-namespaces.h b/clang-tools-extra/test/clang-tidy/modernize-concat-nested-namespaces.h new file mode 100644 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/modernize-concat-nested-namespaces.h @@ -0,0 +1,11 @@ +#pragma once + +#include "modernize-concat-nested-namespaces2.h" + +namespace foo { +namespace bar { +namespace baz { +struct S {}; +} // namespace baz +} // namespace bar +} // namespace foo diff --git a/clang-tools-extra/test/clang-tidy/modernize-concat-nested-namespaces.cpp b/clang-tools-extra/test/clang-tidy/modernize-concat-nested-namespaces.cpp --- a/clang-tools-extra/test/clang-tidy/modernize-concat-nested-namespaces.cpp +++ b/clang-tools-extra/test/clang-tidy/modernize-concat-nested-namespaces.cpp @@ -1,4 +1,12 @@ -// RUN: %check_clang_tidy -std=c++17-or-later %s modernize-concat-nested-namespaces %t +// Note: since this check fixes instances in the headers, we need to copy the +// headers before each run (for a mode that supports this check). +// +// RUN: cp %S/modernize-concat-nested-namespaces*.h %T +// RUN: %check_clang_tidy -std=c++17 %s modernize-concat-nested-namespaces %t -- -header-filter="concat" -- -I %T +// RUN: cp %S/modernize-concat-nested-namespaces*.h %T +// RUN: %check_clang_tidy -std=c++2a %s modernize-concat-nested-namespaces %t -- -header-filter="concat" -- -I %T + +#include "modernize-concat-nested-namespaces.h" namespace n1 {} @@ -159,3 +167,8 @@ return 0; } + +// Checks for header file: + +// CHECK-MESSAGES: modernize-concat-nested-namespaces.h:{{.*}} warning: nested namespaces can be concatenated [modernize-concat-nested-namespaces] +// CHECK-MESSAGES: modernize-concat-nested-namespaces2.h:{{.*}} warning: nested namespaces can be concatenated [modernize-concat-nested-namespaces] diff --git a/clang-tools-extra/test/clang-tidy/modernize-concat-nested-namespaces2.h b/clang-tools-extra/test/clang-tidy/modernize-concat-nested-namespaces2.h new file mode 100644 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/modernize-concat-nested-namespaces2.h @@ -0,0 +1,9 @@ +#pragma once + +namespace foo { +namespace bar { +namespace baz { +struct S2 {}; +} // namespace baz +} // namespace bar +} // namespace foo