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. +/// For extension-less header files, using an empty string or leaving an +/// empty string between "," if there are other filename extensions. 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,6 +61,22 @@ 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) @@ -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/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,9 @@ +#pragma once + +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,7 @@ -// RUN: %check_clang_tidy %s modernize-concat-nested-namespaces %t -- -- -std=c++17 +// RUN: cp %S/modernize-concat-nested-namespaces.h %T/modernize-concat-nested-namespaces.h +// RUN: %check_clang_tidy %s modernize-concat-nested-namespaces %t -- -header-filter="concat" -- -std=c++17 -I %T + +#include "modernize-concat-nested-namespaces.h" namespace n1 {} @@ -159,3 +162,7 @@ return 0; } + +// Checks for header file: + +// CHECK-MESSAGES: modernize-concat-nested-namespaces.h:{{.*}} warning: nested namespaces can be concatenated [modernize-concat-nested-namespaces]