forked from OSchip/llvm-project
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 llvm-svn: 176556
This commit is contained in:
parent
063dfe3244
commit
0a4836ed0e
|
@ -1393,17 +1393,43 @@ constructorDecl(hasAnyConstructorInitializer(isWritten()))
|
|||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>></td><td class="name" onclick="toggle('hasOverloadedOperatorName0')"><a name="hasOverloadedOperatorName0Anchor">hasOverloadedOperatorName</a></td><td>std::string Name</td></tr>
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>></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 "<<", for OverloadedOperatorCall's.
|
||||
"operator" prefix: e.g. "<<".
|
||||
|
||||
Example matches a << b
|
||||
(matcher == operatorCallExpr(hasOverloadedOperatorName("<<")))
|
||||
a << b;
|
||||
c && d; assuming both operator<<
|
||||
and operator&& are overloaded somewhere.
|
||||
Given:
|
||||
class A { int operator*(); };
|
||||
const A &operator<<(const A &a, const A &b);
|
||||
A a;
|
||||
a << a; <-- This matches
|
||||
|
||||
operatorCallExpr(hasOverloadedOperatorName("<<"))) matches the specified
|
||||
line and recordDecl(hasMethod(hasOverloadedOperatorName("*"))) matches
|
||||
the declaration of A.
|
||||
|
||||
Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>>
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>></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. "<<".
|
||||
|
||||
Given:
|
||||
class A { int operator*(); };
|
||||
const A &operator<<(const A &a, const A &b);
|
||||
A a;
|
||||
a << a; <-- This matches
|
||||
|
||||
operatorCallExpr(hasOverloadedOperatorName("<<"))) matches the specified
|
||||
line and recordDecl(hasMethod(hasOverloadedOperatorName("*"))) matches
|
||||
the declaration of A.
|
||||
|
||||
Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>>
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
|
@ -2230,6 +2256,18 @@ Example matches A() in the last line
|
|||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('hasMethod0')"><a name="hasMethod0Anchor">hasMethod</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>> 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<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('isDerivedFrom0')"><a name="isDerivedFrom0Anchor">isDerivedFrom</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>> 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<<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockP
|
|||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>></td><td class="name" onclick="toggle('hasCanonicalType0')"><a name="hasCanonicalType0Anchor">hasCanonicalType</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="hasCanonicalType0"><pre>Matches QualTypes whose canonical type matches InnerMatcher.
|
||||
|
||||
Given:
|
||||
typedef int &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<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>></td><td class="name" onclick="toggle('hasDeclaration5')"><a name="hasDeclaration5Anchor">hasDeclaration</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="hasDeclaration5"><pre>Matches a type if the declaration of the type matches the given
|
||||
matcher.
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()))));
|
||||
|
|
Loading…
Reference in New Issue