summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitri Gribenko <gribozavr@gmail.com>2019-05-03 12:50:00 +0000
committerDmitri Gribenko <gribozavr@gmail.com>2019-05-03 12:50:00 +0000
commit54eb12a115eb4fbdc59b1335d721d0415ca1f7a8 (patch)
tree6c6d7a7e8db17eb2fd40a6cd4d15abe8e4d3cece
parent6ef4cf339ce48cf922534c163eaec4bcbf85604f (diff)
Added an AST matcher for declarations that are in the `std` namespace
Reviewers: alexfh Subscribers: cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D61480 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@359876 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--docs/LibASTMatchersReference.html23
-rw-r--r--include/clang/ASTMatchers/ASTMatchers.h23
-rw-r--r--lib/AST/DeclBase.cpp3
-rw-r--r--lib/ASTMatchers/Dynamic/Registry.cpp1
-rw-r--r--unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp51
5 files changed, 100 insertions, 1 deletions
diff --git a/docs/LibASTMatchersReference.html b/docs/LibASTMatchersReference.html
index f0e965568d..a053bd1bb5 100644
--- a/docs/LibASTMatchersReference.html
+++ b/docs/LibASTMatchersReference.html
@@ -2827,6 +2827,29 @@ by the compiler (eg. implicit default/copy constructors).
</pre></td></tr>
+<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('isInStdNamespace0')"><a name="isInStdNamespace0Anchor">isInStdNamespace</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isInStdNamespace0"><pre>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.
+</pre></td></tr>
+
+
<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('isPrivate0')"><a name="isPrivate0Anchor">isPrivate</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isPrivate0"><pre>Matches private C++ declarations.
diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h
index 661dcbc767..8bd4429f0b 100644
--- a/include/clang/ASTMatchers/ASTMatchers.h
+++ b/include/clang/ASTMatchers/ASTMatchers.h
@@ -6212,6 +6212,29 @@ AST_MATCHER(NamespaceDecl, isAnonymous) {
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/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 5a6d85cd00..f40896da48 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -354,7 +354,8 @@ bool Decl::isInAnonymousNamespace() const {
}
bool Decl::isInStdNamespace() const {
- return getDeclContext()->isStdNamespace();
+ const DeclContext *DC = getDeclContext();
+ return DC && DC->isStdNamespace();
}
TranslationUnitDecl *Decl::getTranslationUnitDecl() {
diff --git a/lib/ASTMatchers/Dynamic/Registry.cpp b/lib/ASTMatchers/Dynamic/Registry.cpp
index 37f1a0077a..fedb9dd2ab 100644
--- a/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -366,6 +366,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(isExternC);
REGISTER_MATCHER(isFinal);
REGISTER_MATCHER(isImplicit);
+ REGISTER_MATCHER(isInStdNamespace);
REGISTER_MATCHER(isInTemplateInstantiation);
REGISTER_MATCHER(isInline);
REGISTER_MATCHER(isInstanceMessage);
diff --git a/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
index 012ca117c2..01b168da2b 100644
--- a/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ b/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -2031,6 +2031,57 @@ TEST(NS, Anonymous) {
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")),