diff --git a/clang-tools-extra/clang-tidy/bugprone/InaccurateEraseCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/InaccurateEraseCheck.cpp --- a/clang-tools-extra/clang-tidy/bugprone/InaccurateEraseCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/InaccurateEraseCheck.cpp @@ -17,10 +17,6 @@ namespace tidy { namespace bugprone { -namespace { -AST_MATCHER(Decl, isInStdNamespace) { return Node.isInStdNamespace(); } -} - void InaccurateEraseCheck::registerMatchers(MatchFinder *Finder) { // Only register the matchers for C++; the functionality currently does not // provide any benefit to other languages, despite being benign. diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -2827,6 +2827,29 @@ +
Matches declarations in the namespace `std`, but not in nested namespaces. + +Given + class vector {}; + namespace foo { + class vector {}; + namespace std { + class vector {}; + } + } + namespace std { + inline namespace __1 { + class vector {}; // #1 + namespace experimental { + class vector {}; + } + } + } +cxxRecordDecl(hasName("vector"), isInStdNamespace()) will match only #1. +
Matches private C++ declarations. diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -6212,6 +6212,29 @@ return Node.isAnonymousNamespace(); } +/// Matches declarations in the namespace `std`, but not in nested namespaces. +/// +/// Given +/// \code +/// class vector {}; +/// namespace foo { +/// class vector {}; +/// namespace std { +/// class vector {}; +/// } +/// } +/// namespace std { +/// inline namespace __1 { +/// class vector {}; // #1 +/// namespace experimental { +/// class vector {}; +/// } +/// } +/// } +/// \endcode +/// cxxRecordDecl(hasName("vector"), isInStdNamespace()) will match only #1. +AST_MATCHER(Decl, isInStdNamespace) { return Node.isInStdNamespace(); } + /// If the given case statement does not use the GNU case range /// extension, matches the constant given in the statement. /// diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -354,7 +354,8 @@ } bool Decl::isInStdNamespace() const { - return getDeclContext()->isStdNamespace(); + const DeclContext *DC = getDeclContext(); + return DC && DC->isStdNamespace(); } TranslationUnitDecl *Decl::getTranslationUnitDecl() { diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp --- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -366,6 +366,7 @@ REGISTER_MATCHER(isExternC); REGISTER_MATCHER(isFinal); REGISTER_MATCHER(isImplicit); + REGISTER_MATCHER(isInStdNamespace); REGISTER_MATCHER(isInTemplateInstantiation); REGISTER_MATCHER(isInline); REGISTER_MATCHER(isInstanceMessage); diff --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp --- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp @@ -2031,6 +2031,57 @@ EXPECT_TRUE(matches("namespace {}", namespaceDecl(isAnonymous()))); } +TEST(DeclarationMatcher, InStdNamespace) { + EXPECT_TRUE(notMatches("class vector {};" + "namespace foo {" + " class vector {};" + "}" + "namespace foo {" + " namespace std {" + " class vector {};" + " }" + "}", + cxxRecordDecl(hasName("vector"), isInStdNamespace()))); + + EXPECT_TRUE(matches("namespace std {" + " class vector {};" + "}", + cxxRecordDecl(hasName("vector"), isInStdNamespace()))); + EXPECT_TRUE(matches("namespace std {" + " inline namespace __1 {" + " class vector {};" + " }" + "}", + cxxRecordDecl(hasName("vector"), isInStdNamespace()))); + EXPECT_TRUE(notMatches("namespace std {" + " inline namespace __1 {" + " inline namespace __fs {" + " namespace filesystem {" + " inline namespace v1 {" + " class path {};" + " }" + " }" + " }" + " }" + "}", + cxxRecordDecl(hasName("path"), isInStdNamespace()))); + EXPECT_TRUE( + matches("namespace std {" + " inline namespace __1 {" + " inline namespace __fs {" + " namespace filesystem {" + " inline namespace v1 {" + " class path {};" + " }" + " }" + " }" + " }" + "}", + cxxRecordDecl(hasName("path"), + hasAncestor(namespaceDecl(hasName("filesystem"), + isInStdNamespace()))))); +} + TEST(EqualsBoundNodeMatcher, QualType) { EXPECT_TRUE(matches( "int i = 1;", varDecl(hasType(qualType().bind("type")),