diff options
author | Edwin Vane <edwin.vane@intel.com> | 2013-02-25 20:43:32 +0000 |
---|---|---|
committer | Edwin Vane <edwin.vane@intel.com> | 2013-02-25 20:43:32 +0000 |
commit | 742d9e77e32f014194679575c97c6bb4fd0998c4 (patch) | |
tree | 9e2daa162742d5c9d211730eb7724a358a848b39 | |
parent | c2833111020d7a672bb4b547799fcd87ea4f8fb5 (diff) |
Various additions to ASTMatcher library:
New type matchers:
* recordType
* elaboratedType
New narrowing matchers:
* hasQualifier
* namesType
* hasDeclContext
Added tests and updated LibASTMatchersReference.
Reviewers: klimek
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@176047 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | docs/LibASTMatchersReference.html | 120 | ||||
-rw-r--r-- | include/clang/ASTMatchers/ASTMatchers.h | 94 | ||||
-rw-r--r-- | unittests/ASTMatchers/ASTMatchersTest.cpp | 72 |
3 files changed, 285 insertions, 1 deletions
diff --git a/docs/LibASTMatchersReference.html b/docs/LibASTMatchersReference.html index 8afb1639e5..31799008bc 100644 --- a/docs/LibASTMatchersReference.html +++ b/docs/LibASTMatchersReference.html @@ -930,6 +930,26 @@ dependentSizedArrayType </pre></td></tr> +<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td><td class="name" onclick="toggle('elaboratedTypeLoc0')"><a name="elaboratedTypeLoc0Anchor">elaboratedTypeLoc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ElaboratedTypeLoc.html">ElaboratedTypeLoc</a>>...</td></tr> +<tr><td colspan="4" class="doc" id="elaboratedTypeLoc0"><pre>Matches types specified with an elaborated type keyword or with a +qualified name. + +Given + namespace N { + namespace M { + class D {}; + } + } + class C {}; + + class C c; + N::M::D d; + +elaboratedType() matches the type of the variable declarations of both +c and d. +</pre></td></tr> + + <tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td><td class="name" onclick="toggle('functionTypeLoc0')"><a name="functionTypeLoc0Anchor">functionTypeLoc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionTypeLoc.html">FunctionTypeLoc</a>>...</td></tr> <tr><td colspan="4" class="doc" id="functionTypeLoc0"><pre>Matches FunctionType nodes. @@ -975,6 +995,21 @@ pointerType() </pre></td></tr> +<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td><td class="name" onclick="toggle('recordTypeLoc0')"><a name="recordTypeLoc0Anchor">recordTypeLoc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordTypeLoc.html">RecordTypeLoc</a>>...</td></tr> +<tr><td colspan="4" class="doc" id="recordTypeLoc0"><pre>Matches record types (e.g. structs, classes). + +Given + class C {}; + struct S {}; + + C c; + S s; + +recordType() matches the type of the variable declarations of both c +and s. +</pre></td></tr> + + <tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td><td class="name" onclick="toggle('referenceTypeLoc0')"><a name="referenceTypeLoc0Anchor">referenceTypeLoc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceTypeLoc.html">ReferenceTypeLoc</a>>...</td></tr> <tr><td colspan="4" class="doc" id="referenceTypeLoc0"><pre>Matches reference types. @@ -1124,6 +1159,26 @@ dependentSizedArrayType </pre></td></tr> +<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('elaboratedType0')"><a name="elaboratedType0Anchor">elaboratedType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ElaboratedType.html">ElaboratedType</a>>...</td></tr> +<tr><td colspan="4" class="doc" id="elaboratedType0"><pre>Matches types specified with an elaborated type keyword or with a +qualified name. + +Given + namespace N { + namespace M { + class D {}; + } + } + class C {}; + + class C c; + N::M::D d; + +elaboratedType() matches the type of the variable declarations of both +c and d. +</pre></td></tr> + + <tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('functionType0')"><a name="functionType0Anchor">functionType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionType.html">FunctionType</a>>...</td></tr> <tr><td colspan="4" class="doc" id="functionType0"><pre>Matches FunctionType nodes. @@ -1169,6 +1224,21 @@ pointerType() </pre></td></tr> +<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('recordType0')"><a name="recordType0Anchor">recordType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>>...</td></tr> +<tr><td colspan="4" class="doc" id="recordType0"><pre>Matches record types (e.g. structs, classes). + +Given + class C {}; + struct S {}; + + C c; + S s; + +recordType() matches the type of the variable declarations of both c +and s. +</pre></td></tr> + + <tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('referenceType0')"><a name="referenceType0Anchor">referenceType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceType.html">ReferenceType</a>>...</td></tr> <tr><td colspan="4" class="doc" id="referenceType0"><pre>Matches reference types. @@ -2399,6 +2469,22 @@ declStmt(hasSingleDecl(anything())) </pre></td></tr> +<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('hasDeclContext0')"><a name="hasDeclContext0Anchor">hasDeclContext</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr> +<tr><td colspan="4" class="doc" id="hasDeclContext0"><pre>Matches declarations whose declaration context, interpreted as a +Decl, matches InnerMatcher. + +Given + namespace N { + namespace M { + class D {}; + } + } + +recordDecl(hasDeclContext(namedDecl(hasName("M")))) matches the +declaration of class D. +</pre></td></tr> + + <tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1DoStmt.html">DoStmt</a>></td><td class="name" onclick="toggle('hasBody0')"><a name="hasBody0Anchor">hasBody</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>> InnerMatcher</td></tr> <tr><td colspan="4" class="doc" id="hasBody0"><pre>Matches a 'for', 'while', or 'do while' statement that has a given body. @@ -2421,6 +2507,40 @@ Example matches true (matcher = hasCondition(boolLiteral(equals(true)))) </pre></td></tr> +<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ElaboratedType.html">ElaboratedType</a>></td><td class="name" onclick="toggle('hasQualifier0')"><a name="hasQualifier0Anchor">hasQualifier</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifier.html">NestedNameSpecifier</a>> InnerMatcher</td></tr> +<tr><td colspan="4" class="doc" id="hasQualifier0"><pre>Matches ElaboratedTypes whose qualifier, a NestedNameSpecifier, +matches InnerMatcher. + +Given + namespace N { + namespace M { + class D {}; + } + } + N::M::D d; + +elaboratedType(hasQualifier(hasPrefix(specifiesNamespace(hasName("N")))) +matches the type of the variable declaration of d. +</pre></td></tr> + + +<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ElaboratedType.html">ElaboratedType</a>></td><td class="name" onclick="toggle('namesType0')"><a name="namesType0Anchor">namesType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr> +<tr><td colspan="4" class="doc" id="namesType0"><pre>Matches ElaboratedTypes whose named type matches InnerMatcher. + +Given + namespace N { + namespace M { + class D {}; + } + } + N::M::D d; + +elaboratedType(namesType(recordType( +hasDeclaration(namedDecl(hasName("D")))))) matches the type of the variable +declaration of d. +</pre></td></tr> + + <tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ExplicitCastExpr.html">ExplicitCastExpr</a>></td><td class="name" onclick="toggle('hasDestinationType0')"><a name="hasDestinationType0Anchor">hasDestinationType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr> <tr><td colspan="4" class="doc" id="hasDestinationType0"><pre>Matches casts whose destination type matches a given matcher. diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h index bee7c21435..b663770460 100644 --- a/include/clang/ASTMatchers/ASTMatchers.h +++ b/include/clang/ASTMatchers/ASTMatchers.h @@ -2929,6 +2929,100 @@ AST_TYPE_MATCHER(TypedefType, typedefType); /// instantiation in \c A and the type of the variable declaration in \c B. AST_TYPE_MATCHER(TemplateSpecializationType, templateSpecializationType); +/// \brief Matches record types (e.g. structs, classes). +/// +/// Given +/// \code +/// class C {}; +/// struct S {}; +/// +/// C c; +/// S s; +/// \code +/// +/// \c recordType() matches the type of the variable declarations of both \c c +/// and \c s. +AST_TYPE_MATCHER(RecordType, recordType); + +/// \brief Matches types specified with an elaborated type keyword or with a +/// qualified name. +/// +/// Given +/// \code +/// namespace N { +/// namespace M { +/// class D {}; +/// } +/// } +/// class C {}; +/// +/// class C c; +/// N::M::D d; +/// \code +/// +/// \c elaboratedType() matches the type of the variable declarations of both +/// \c c and \c d. +AST_TYPE_MATCHER(ElaboratedType, elaboratedType); + +/// \brief Matches ElaboratedTypes whose qualifier, a NestedNameSpecifier, +/// matches \c InnerMatcher. +/// +/// Given +/// \code +/// namespace N { +/// namespace M { +/// class D {}; +/// } +/// } +/// N::M::D d; +/// \code +/// +/// \c elaboratedType(hasQualifier(hasPrefix(specifiesNamespace(hasName("N")))) +/// matches the type of the variable declaration of \c d. +AST_MATCHER_P(ElaboratedType, hasQualifier, + internal::Matcher<NestedNameSpecifier>, InnerMatcher) { + return InnerMatcher.matches(*Node.getQualifier(), Finder, Builder); +} + +/// \brief Matches ElaboratedTypes whose named type matches \c InnerMatcher. +/// +/// Given +/// \code +/// namespace N { +/// namespace M { +/// class D {}; +/// } +/// } +/// N::M::D d; +/// \code +/// +/// \c elaboratedType(namesType(recordType( +/// hasDeclaration(namedDecl(hasName("D")))))) matches the type of the variable +/// declaration of \c d. +AST_MATCHER_P(ElaboratedType, namesType, internal::Matcher<QualType>, + InnerMatcher) { + return InnerMatcher.matches(Node.getNamedType(), Finder, Builder); +} + +/// \brief Matches declarations whose declaration context, interpreted as a +/// Decl, matches \c InnerMatcher. +/// +/// Given +/// \code +/// namespace N { +/// namespace M { +/// class D {}; +/// } +/// } +/// \code +/// +/// \c recordDecl(hasDeclContext(namedDecl(hasName("M")))) matches the +/// declaration of \c class \c D. +AST_MATCHER_P(Decl, hasDeclContext, internal::Matcher<Decl>, InnerMatcher) { + return InnerMatcher.matches(*Decl::castFromDeclContext(Node.getDeclContext()), + Finder, Builder); +} + /// \brief Matches nested name specifiers. /// /// Given diff --git a/unittests/ASTMatchers/ASTMatchersTest.cpp b/unittests/ASTMatchers/ASTMatchersTest.cpp index 6eb552aa56..565c356235 100644 --- a/unittests/ASTMatchers/ASTMatchersTest.cpp +++ b/unittests/ASTMatchers/ASTMatchersTest.cpp @@ -323,6 +323,23 @@ TEST(DeclarationMatcher, ClassDerivedFromDependentTemplateSpecialization) { recordDecl(hasName("B"), isDerivedFrom(recordDecl())))); } +TEST(DeclarationMatcher, hasDeclContext) { + EXPECT_TRUE(matches( + "namespace N {" + " namespace M {" + " class D {};" + " }" + "}", + recordDecl(hasDeclContext(namedDecl(hasName("M")))))); + EXPECT_TRUE(notMatches( + "namespace N {" + " namespace M {" + " class D {};" + " }" + "}", + recordDecl(hasDeclContext(namedDecl(hasName("N")))))); +} + TEST(ClassTemplate, DoesNotMatchClass) { DeclarationMatcher ClassX = classTemplateDecl(hasName("X")); EXPECT_TRUE(notMatches("class X;", ClassX)); @@ -3413,10 +3430,63 @@ TEST(TypeMatching, MatchesTypedefTypes) { } TEST(TypeMatching, MatchesTemplateSpecializationType) { - EXPECT_TRUE(matches("template <typename T> class A{}; A<int>a;", + EXPECT_TRUE(matches("template <typename T> class A{}; A<int> a;", templateSpecializationType())); } +TEST(TypeMatching, MatchesRecordType) { + EXPECT_TRUE(matches("class C{}; C c;", recordType())); + EXPECT_TRUE(matches("struct S{}; S s;", recordType())); + EXPECT_TRUE(notMatches("int i;", recordType())); +} + +TEST(TypeMatching, MatchesElaboratedType) { + EXPECT_TRUE(matches( + "namespace N {" + " namespace M {" + " class D {};" + " }" + "}" + "N::M::D d;", elaboratedType())); + EXPECT_TRUE(matches("class C {} c;", elaboratedType())); + EXPECT_TRUE(notMatches("class C {}; C c;", elaboratedType())); +} + +TEST(ElaboratedTypeNarrowing, hasQualifier) { + EXPECT_TRUE(matches( + "namespace N {" + " namespace M {" + " class D {};" + " }" + "}" + "N::M::D d;", + elaboratedType(hasQualifier(hasPrefix(specifiesNamespace(hasName("N"))))))); + EXPECT_TRUE(notMatches( + "namespace M {" + " class D {};" + "}" + "M::D d;", + elaboratedType(hasQualifier(hasPrefix(specifiesNamespace(hasName("N"))))))); +} + +TEST(ElaboratedTypeNarrowing, namesType) { + EXPECT_TRUE(matches( + "namespace N {" + " namespace M {" + " class D {};" + " }" + "}" + "N::M::D d;", + elaboratedType(elaboratedType(namesType(recordType( + hasDeclaration(namedDecl(hasName("D"))))))))); + EXPECT_TRUE(notMatches( + "namespace M {" + " class D {};" + "}" + "M::D d;", + elaboratedType(elaboratedType(namesType(typedefType()))))); +} + TEST(NNS, MatchesNestedNameSpecifiers) { EXPECT_TRUE(matches("namespace ns { struct A {}; } ns::A a;", nestedNameSpecifier())); |