aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdwin Vane <edwin.vane@intel.com>2013-03-06 17:02:57 +0000
committerEdwin Vane <edwin.vane@intel.com>2013-03-06 17:02:57 +0000
commit6a19a97e57c8678adb0505a07c97d7ccadc8fe4e (patch)
tree2cd9322d7a522eeab9455a5ab8b0fe3d5e42241c
parent7e73f94c104070cf03c6f711a10f1928a550193f (diff)
New ASTMatchers and enhancement to hasOverloadedOperatorName
Added two new narrowing matchers: * hasMethod: aplies a matcher to a CXXRecordDecl's methods until a match is made or there are no more methods. * hasCanonicalType: applies a matcher to a QualType's canonicalType. Enhanced hasOverloadedOperatorName to work on CXXMethodDecl as well as CXXOperatorCallExpr. Updated tests and docs. Reviewers: klimek, gribozavr git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@176556 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--docs/LibASTMatchersReference.html65
-rw-r--r--include/clang/ASTMatchers/ASTMatchers.h64
-rw-r--r--include/clang/ASTMatchers/ASTMatchersInternal.h38
-rw-r--r--unittests/ASTMatchers/ASTMatchersTest.cpp25
4 files changed, 176 insertions, 16 deletions
diff --git a/docs/LibASTMatchersReference.html b/docs/LibASTMatchersReference.html
index 617d194e2c..a32f1a4afb 100644
--- a/docs/LibASTMatchersReference.html
+++ b/docs/LibASTMatchersReference.html
@@ -1393,17 +1393,43 @@ constructorDecl(hasAnyConstructorInitializer(isWritten()))
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>&gt;</td><td class="name" onclick="toggle('hasOverloadedOperatorName0')"><a name="hasOverloadedOperatorName0Anchor">hasOverloadedOperatorName</a></td><td>std::string Name</td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>&gt;</td><td class="name" onclick="toggle('hasOverloadedOperatorName0')"><a name="hasOverloadedOperatorName0Anchor">hasOverloadedOperatorName</a></td><td>StringRef Name</td></tr>
<tr><td colspan="4" class="doc" id="hasOverloadedOperatorName0"><pre>Matches overloaded operator names.
Matches overloaded operator names specified in strings without the
-"operator" prefix, such as "&lt;&lt;", for OverloadedOperatorCall's.
+"operator" prefix: e.g. "&lt;&lt;".
-Example matches a &lt;&lt; b
- (matcher == operatorCallExpr(hasOverloadedOperatorName("&lt;&lt;")))
- a &lt;&lt; b;
- c &amp;&amp; d; assuming both operator&lt;&lt;
- and operator&amp;&amp; are overloaded somewhere.
+Given:
+ class A { int operator*(); };
+ const A &amp;operator&lt;&lt;(const A &amp;a, const A &amp;b);
+ A a;
+ a &lt;&lt; a; &lt;-- This matches
+
+operatorCallExpr(hasOverloadedOperatorName("&lt;&lt;"))) matches the specified
+line and recordDecl(hasMethod(hasOverloadedOperatorName("*"))) matches
+the declaration of A.
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>&gt;</td><td class="name" onclick="toggle('hasOverloadedOperatorName1')"><a name="hasOverloadedOperatorName1Anchor">hasOverloadedOperatorName</a></td><td>StringRef Name</td></tr>
+<tr><td colspan="4" class="doc" id="hasOverloadedOperatorName1"><pre>Matches overloaded operator names.
+
+Matches overloaded operator names specified in strings without the
+"operator" prefix: e.g. "&lt;&lt;".
+
+Given:
+ class A { int operator*(); };
+ const A &amp;operator&lt;&lt;(const A &amp;a, const A &amp;b);
+ A a;
+ a &lt;&lt; a; &lt;-- This matches
+
+operatorCallExpr(hasOverloadedOperatorName("&lt;&lt;"))) matches the specified
+line and recordDecl(hasMethod(hasOverloadedOperatorName("*"))) matches
+the declaration of A.
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>&gt;
</pre></td></tr>
@@ -2230,6 +2256,18 @@ Example matches A() in the last line
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>&gt;</td><td class="name" onclick="toggle('hasMethod0')"><a name="hasMethod0Anchor">hasMethod</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasMethod0"><pre>Matches the first method of a class or struct that satisfies InnerMatcher.
+
+Given:
+ class A { void func(); };
+ class B { void member(); };
+
+recordDecl(hasMethod(hasName("func"))) matches the declaration of A
+but not B.
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>&gt;</td><td class="name" onclick="toggle('isDerivedFrom0')"><a name="isDerivedFrom0Anchor">isDerivedFrom</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>&gt; Base</td></tr>
<tr><td colspan="4" class="doc" id="isDerivedFrom0"><pre>Matches C++ classes that are directly or indirectly derived from
a class matching Base.
@@ -2909,6 +2947,19 @@ Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockP
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;</td><td class="name" onclick="toggle('hasCanonicalType0')"><a name="hasCanonicalType0Anchor">hasCanonicalType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasCanonicalType0"><pre>Matches QualTypes whose canonical type matches InnerMatcher.
+
+Given:
+ typedef int &amp;int_ref;
+ int a;
+ int_ref b = a;
+
+varDecl(hasType(qualType(referenceType()))))) will not match the
+declaration of b but varDecl(hasType(qualType(hasCanonicalType(referenceType())))))) does.
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;</td><td class="name" onclick="toggle('hasDeclaration5')"><a name="hasDeclaration5Anchor">hasDeclaration</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasDeclaration5"><pre>Matches a type if the declaration of the type matches the given
matcher.
diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h
index 4e369523e8..c5ebd3c450 100644
--- a/include/clang/ASTMatchers/ASTMatchers.h
+++ b/include/clang/ASTMatchers/ASTMatchers.h
@@ -1384,18 +1384,26 @@ AST_MATCHER_P(NamedDecl, matchesName, std::string, RegExp) {
/// \brief Matches overloaded operator names.
///
/// Matches overloaded operator names specified in strings without the
-/// "operator" prefix, such as "<<", for OverloadedOperatorCall's.
+/// "operator" prefix: e.g. "<<".
///
-/// Example matches a << b
-/// (matcher == operatorCallExpr(hasOverloadedOperatorName("<<")))
+/// Given:
/// \code
-/// a << b;
-/// c && d; // assuming both operator<<
-/// // and operator&& are overloaded somewhere.
+/// class A { int operator*(); };
+/// const A &operator<<(const A &a, const A &b);
+/// A a;
+/// a << a; // <-- This matches
/// \endcode
-AST_MATCHER_P(CXXOperatorCallExpr,
- hasOverloadedOperatorName, std::string, Name) {
- return getOperatorSpelling(Node.getOperator()) == Name;
+///
+/// \c operatorCallExpr(hasOverloadedOperatorName("<<"))) matches the specified
+/// line and \c recordDecl(hasMethod(hasOverloadedOperatorName("*"))) matches
+/// the declaration of \c A.
+///
+/// Usable as: Matcher<CXXOperatorCallExpr>, Matcher<CXXMethodDecl>
+inline internal::PolymorphicMatcherWithParam1<
+ internal::HasOverloadedOperatorNameMatcher, StringRef>
+hasOverloadedOperatorName(const StringRef Name) {
+ return internal::PolymorphicMatcherWithParam1<
+ internal::HasOverloadedOperatorNameMatcher, StringRef>(Name);
}
/// \brief Matches C++ classes that are directly or indirectly derived from
@@ -1445,6 +1453,27 @@ inline internal::Matcher<CXXRecordDecl> isSameOrDerivedFrom(
return isSameOrDerivedFrom(hasName(BaseName));
}
+/// \brief Matches the first method of a class or struct that satisfies \c
+/// InnerMatcher.
+///
+/// Given:
+/// \code
+/// class A { void func(); };
+/// class B { void member(); };
+/// \code
+///
+/// \c recordDecl(hasMethod(hasName("func"))) matches the declaration of \c A
+/// but not \c B.
+AST_MATCHER_P(CXXRecordDecl, hasMethod, internal::Matcher<CXXMethodDecl>,
+ InnerMatcher) {
+ for (CXXRecordDecl::method_iterator I = Node.method_begin(),
+ E = Node.method_end();
+ I != E; ++I)
+ if (InnerMatcher.matches(**I, Finder, Builder))
+ return true;
+ return false;
+}
+
/// \brief Matches AST nodes that have child AST nodes that match the
/// provided matcher.
///
@@ -1786,6 +1815,23 @@ AST_MATCHER_P(QualType, references, internal::Matcher<QualType>,
InnerMatcher.matches(Node->getPointeeType(), Finder, Builder));
}
+/// \brief Matches QualTypes whose canonical type matches InnerMatcher.
+///
+/// Given:
+/// \code
+/// typedef int &int_ref;
+/// int a;
+/// int_ref b = a;
+/// \code
+///
+/// \c varDecl(hasType(qualType(referenceType()))))) will not match the
+/// declaration of b but \c
+/// varDecl(hasType(qualType(hasCanonicalType(referenceType())))))) does.
+AST_MATCHER_P(QualType, hasCanonicalType, internal::Matcher<QualType>,
+ InnerMatcher) {
+ return InnerMatcher.matches(Node.getCanonicalType(), Finder, Builder);
+}
+
/// \brief Overloaded to match the referenced type's declaration.
inline internal::Matcher<QualType> references(
const internal::Matcher<Decl> &InnerMatcher) {
diff --git a/include/clang/ASTMatchers/ASTMatchersInternal.h b/include/clang/ASTMatchers/ASTMatchersInternal.h
index f309794034..30691ad8f9 100644
--- a/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -370,6 +370,44 @@ template <typename T> struct has_getDecl {
static bool const value = sizeof(f<Derived>(0)) == 2;
};
+/// \brief Matches overloaded operators with a specific name.
+///
+/// The type argument ArgT is not used by this matcher but is used by
+/// PolymorphicMatcherWithParam1 and should be StringRef.
+template <typename T, typename ArgT>
+class HasOverloadedOperatorNameMatcher : public SingleNodeMatcherInterface<T> {
+ TOOLING_COMPILE_ASSERT((llvm::is_same<T, CXXOperatorCallExpr>::value ||
+ llvm::is_same<T, CXXMethodDecl>::value),
+ unsupported_class_for_matcher);
+ TOOLING_COMPILE_ASSERT((llvm::is_same<ArgT, StringRef>::value),
+ argument_type_must_be_StringRef);
+public:
+ explicit HasOverloadedOperatorNameMatcher(const StringRef Name)
+ : SingleNodeMatcherInterface<T>(), Name(Name) {}
+
+ virtual bool matchesNode(const T &Node) const LLVM_OVERRIDE {
+ return matchesSpecialized(Node);
+ }
+
+private:
+
+ /// \brief CXXOperatorCallExpr exist only for calls to overloaded operators
+ /// so this function returns true if the call is to an operator of the given
+ /// name.
+ bool matchesSpecialized(const CXXOperatorCallExpr &Node) const {
+ return getOperatorSpelling(Node.getOperator()) == Name;
+ }
+
+ /// \brief Returns true only if CXXMethodDecl represents an overloaded
+ /// operator and has the given operator name.
+ bool matchesSpecialized(const CXXMethodDecl &Node) const {
+ return Node.isOverloadedOperator() &&
+ getOperatorSpelling(Node.getOverloadedOperator()) == Name;
+ }
+
+ std::string Name;
+};
+
/// \brief Matches declarations for QualType and CallExpr.
///
/// Type argument DeclMatcherT is required by PolymorphicMatcherWithParam1 but
diff --git a/unittests/ASTMatchers/ASTMatchersTest.cpp b/unittests/ASTMatchers/ASTMatchersTest.cpp
index 4d369e5585..318d09c9bf 100644
--- a/unittests/ASTMatchers/ASTMatchersTest.cpp
+++ b/unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -313,6 +313,13 @@ TEST(DeclarationMatcher, ClassIsDerived) {
recordDecl(isDerivedFrom(recordDecl(hasName("X")).bind("test")))));
}
+TEST(DeclarationMatcher, hasMethod) {
+ EXPECT_TRUE(matches("class A { void func(); };",
+ recordDecl(hasMethod(hasName("func")))));
+ EXPECT_TRUE(notMatches("class A { void func(); };",
+ recordDecl(hasMethod(isPublic()))));
+}
+
TEST(DeclarationMatcher, ClassDerivedFromDependentTemplateSpecialization) {
EXPECT_TRUE(matches(
"template <typename T> struct A {"
@@ -1022,6 +1029,12 @@ TEST(Matcher, HasOperatorNameForOverloadedOperatorCall) {
"bool operator&&(Y x, Y y) { return true; }; "
"Y a; Y b; bool c = a && b;",
OpCallLessLess));
+ DeclarationMatcher ClassWithOpStar =
+ recordDecl(hasMethod(hasOverloadedOperatorName("*")));
+ EXPECT_TRUE(matches("class Y { int operator*(); };",
+ ClassWithOpStar));
+ EXPECT_TRUE(notMatches("class Y { void myOperator(); };",
+ ClassWithOpStar)) ;
}
TEST(Matcher, NestedOverloadedOperatorCalls) {
@@ -1329,6 +1342,18 @@ TEST(Matcher, References) {
notMatches("class X {}; void y(X *y) { X *&x = y; }", ReferenceClassX));
}
+TEST(QualType, hasCanonicalType) {
+ EXPECT_TRUE(notMatches("typedef int &int_ref;"
+ "int a;"
+ "int_ref b = a;",
+ varDecl(hasType(qualType(referenceType())))));
+ EXPECT_TRUE(
+ matches("typedef int &int_ref;"
+ "int a;"
+ "int_ref b = a;",
+ varDecl(hasType(qualType(hasCanonicalType(referenceType()))))));
+}
+
TEST(HasParameter, CallsInnerMatcher) {
EXPECT_TRUE(matches("class X { void x(int) {} };",
methodDecl(hasParameter(0, varDecl()))));