r186836 - Add support for overloaded matchers. ie different matcher function signatures with the same name.
Samuel Benzaquen
sbenza at google.com
Mon Jul 22 09:13:58 PDT 2013
Author: sbenza
Date: Mon Jul 22 11:13:57 2013
New Revision: 186836
URL: http://llvm.org/viewvc/llvm-project?rev=186836&view=rev
Log:
Add support for overloaded matchers. ie different matcher function signatures with the same name.
Summary:
Add support for overloaded matchers.
This composes with other features, like supporting polymorphic matchers.
Reviewers: klimek
CC: cfe-commits, revane
Differential Revision: http://llvm-reviews.chandlerc.com/D1188
Modified:
cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h
cfe/trunk/include/clang/ASTMatchers/ASTMatchersMacros.h
cfe/trunk/include/clang/ASTMatchers/Dynamic/Diagnostics.h
cfe/trunk/lib/ASTMatchers/Dynamic/Diagnostics.cpp
cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp
cfe/trunk/unittests/ASTMatchers/Dynamic/ParserTest.cpp
cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h?rev=186836&r1=186835&r2=186836&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h Mon Jul 22 11:13:57 2013
@@ -1536,24 +1536,25 @@ AST_MATCHER_P(CXXRecordDecl, isDerivedFr
}
/// \brief Overloaded method as shortcut for \c isDerivedFrom(hasName(...)).
-inline internal::Matcher<CXXRecordDecl> isDerivedFrom(StringRef BaseName) {
+AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isDerivedFrom, StringRef, BaseName, 1) {
assert(!BaseName.empty());
- return isDerivedFrom(hasName(BaseName));
+ return isDerivedFrom(hasName(BaseName)).matches(Node, Finder, Builder);
}
/// \brief Similar to \c isDerivedFrom(), but also matches classes that directly
/// match \c Base.
-inline internal::Matcher<CXXRecordDecl> isSameOrDerivedFrom(
- internal::Matcher<NamedDecl> Base) {
- return anyOf(Base, isDerivedFrom(Base));
+AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isSameOrDerivedFrom,
+ internal::Matcher<NamedDecl>, Base, 0) {
+ return Matcher<CXXRecordDecl>(anyOf(Base, isDerivedFrom(Base)))
+ .matches(Node, Finder, Builder);
}
/// \brief Overloaded method as shortcut for
/// \c isSameOrDerivedFrom(hasName(...)).
-inline internal::Matcher<CXXRecordDecl> isSameOrDerivedFrom(
- StringRef BaseName) {
+AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isSameOrDerivedFrom, StringRef, BaseName,
+ 1) {
assert(!BaseName.empty());
- return isSameOrDerivedFrom(hasName(BaseName));
+ return isSameOrDerivedFrom(hasName(BaseName)).matches(Node, Finder, Builder);
}
/// \brief Matches the first method of a class or struct that satisfies \c
@@ -1822,9 +1823,9 @@ AST_MATCHER_P(CallExpr, callee, internal
/// class Y { public: void x(); };
/// void z() { Y y; y.x();
/// \endcode
-inline internal::Matcher<CallExpr> callee(
- const internal::Matcher<Decl> &InnerMatcher) {
- return callExpr(hasDeclaration(InnerMatcher));
+AST_MATCHER_P_OVERLOAD(CallExpr, callee, internal::Matcher<Decl>, InnerMatcher,
+ 1) {
+ return callExpr(hasDeclaration(InnerMatcher)).matches(Node, Finder, Builder);
}
/// \brief Matches if the expression's or declaration's type matches a type
@@ -1836,9 +1837,9 @@ inline internal::Matcher<CallExpr> calle
/// class X {};
/// void y(X &x) { x; X z; }
/// \endcode
-AST_POLYMORPHIC_MATCHER_P(hasType,
- AST_POLYMORPHIC_SUPPORTED_TYPES_2(Expr, ValueDecl),
- internal::Matcher<QualType>, InnerMatcher) {
+AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
+ hasType, AST_POLYMORPHIC_SUPPORTED_TYPES_2(Expr, ValueDecl),
+ internal::Matcher<QualType>, InnerMatcher, 0) {
return InnerMatcher.matches(Node.getType(), Finder, Builder);
}
@@ -1859,11 +1860,11 @@ AST_POLYMORPHIC_MATCHER_P(hasType,
/// \endcode
///
/// Usable as: Matcher<Expr>, Matcher<ValueDecl>
-inline internal::PolymorphicMatcherWithParam1<
- internal::matcher_hasType0Matcher, internal::Matcher<QualType>,
- AST_POLYMORPHIC_SUPPORTED_TYPES_2(Expr, ValueDecl)>
-hasType(const internal::Matcher<Decl> &InnerMatcher) {
- return hasType(qualType(hasDeclaration(InnerMatcher)));
+AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
+ hasType, AST_POLYMORPHIC_SUPPORTED_TYPES_2(Expr, ValueDecl),
+ internal::Matcher<Decl>, InnerMatcher, 1) {
+ return qualType(hasDeclaration(InnerMatcher))
+ .matches(Node.getType(), Finder, Builder);
}
/// \brief Matches if the type location of the declarator decl's type matches
@@ -1912,9 +1913,10 @@ AST_MATCHER_P(
}
/// \brief Overloaded to match the pointee type's declaration.
-inline internal::Matcher<QualType> pointsTo(
- const internal::Matcher<Decl> &InnerMatcher) {
- return pointsTo(qualType(hasDeclaration(InnerMatcher)));
+AST_MATCHER_P_OVERLOAD(QualType, pointsTo, internal::Matcher<Decl>,
+ InnerMatcher, 1) {
+ return pointsTo(qualType(hasDeclaration(InnerMatcher)))
+ .matches(Node, Finder, Builder);
}
/// \brief Matches if the matched type is a reference type and the referenced
@@ -1955,9 +1957,10 @@ AST_MATCHER_P(QualType, hasCanonicalType
}
/// \brief Overloaded to match the referenced type's declaration.
-inline internal::Matcher<QualType> references(
- const internal::Matcher<Decl> &InnerMatcher) {
- return references(qualType(hasDeclaration(InnerMatcher)));
+AST_MATCHER_P_OVERLOAD(QualType, references, internal::Matcher<Decl>,
+ InnerMatcher, 1) {
+ return references(qualType(hasDeclaration(InnerMatcher)))
+ .matches(Node, Finder, Builder);
}
AST_MATCHER_P(CXXMemberCallExpr, onImplicitObjectArgument,
@@ -1969,17 +1972,19 @@ AST_MATCHER_P(CXXMemberCallExpr, onImpli
/// \brief Matches if the expression's type either matches the specified
/// matcher, or is a pointer to a type that matches the InnerMatcher.
-inline internal::Matcher<CXXMemberCallExpr> thisPointerType(
- const internal::Matcher<QualType> &InnerMatcher) {
+AST_MATCHER_P_OVERLOAD(CXXMemberCallExpr, thisPointerType,
+ internal::Matcher<QualType>, InnerMatcher, 0) {
return onImplicitObjectArgument(
- anyOf(hasType(InnerMatcher), hasType(pointsTo(InnerMatcher))));
+ anyOf(hasType(InnerMatcher), hasType(pointsTo(InnerMatcher))))
+ .matches(Node, Finder, Builder);
}
/// \brief Overloaded to match the type's declaration.
-inline internal::Matcher<CXXMemberCallExpr> thisPointerType(
- const internal::Matcher<Decl> &InnerMatcher) {
+AST_MATCHER_P_OVERLOAD(CXXMemberCallExpr, thisPointerType,
+ internal::Matcher<Decl>, InnerMatcher, 1) {
return onImplicitObjectArgument(
- anyOf(hasType(InnerMatcher), hasType(pointsTo(InnerMatcher))));
+ anyOf(hasType(InnerMatcher), hasType(pointsTo(InnerMatcher))))
+ .matches(Node, Finder, Builder);
}
/// \brief Matches a DeclRefExpr that refers to a declaration that matches the
Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchersMacros.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchersMacros.h?rev=186836&r1=186835&r2=186836&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchersMacros.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchersMacros.h Mon Jul 22 11:13:57 2013
@@ -49,23 +49,19 @@
///
/// The code should return true if 'Node' matches.
#define AST_MATCHER(Type, DefineMatcher) \
- AST_MATCHER_OVERLOAD(Type, DefineMatcher, 0)
-
-#define AST_MATCHER_OVERLOAD(Type, DefineMatcher, OverloadId) \
namespace internal { \
- class matcher_##DefineMatcher##OverloadId##Matcher \
- : public MatcherInterface<Type> { \
+ class matcher_##DefineMatcher##Matcher : public MatcherInterface<Type> { \
public: \
- explicit matcher_##DefineMatcher##OverloadId##Matcher() {} \
+ explicit matcher_##DefineMatcher##Matcher() {} \
virtual bool matches(const Type &Node, ASTMatchFinder *Finder, \
BoundNodesTreeBuilder *Builder) const; \
}; \
} \
inline internal::Matcher<Type> DefineMatcher() { \
return internal::makeMatcher( \
- new internal::matcher_##DefineMatcher##OverloadId##Matcher()); \
+ new internal::matcher_##DefineMatcher##Matcher()); \
} \
- inline bool internal::matcher_##DefineMatcher##OverloadId##Matcher::matches( \
+ inline bool internal::matcher_##DefineMatcher##Matcher::matches( \
const Type &Node, ASTMatchFinder *Finder, \
BoundNodesTreeBuilder *Builder) const
@@ -93,10 +89,10 @@
public: \
explicit matcher_##DefineMatcher##OverloadId##Matcher( \
const ParamType &A##Param) \
- : Param(A##Param) { \
- } \
+ : Param(A##Param) {} \
virtual bool matches(const Type &Node, ASTMatchFinder *Finder, \
BoundNodesTreeBuilder *Builder) const; \
+ \
private: \
const ParamType Param; \
}; \
@@ -105,6 +101,8 @@
return internal::makeMatcher( \
new internal::matcher_##DefineMatcher##OverloadId##Matcher(Param)); \
} \
+ typedef internal::Matcher<Type>(&DefineMatcher##_Type##OverloadId)( \
+ const ParamType &Param); \
inline bool internal::matcher_##DefineMatcher##OverloadId##Matcher::matches( \
const Type &Node, ASTMatchFinder *Finder, \
BoundNodesTreeBuilder *Builder) const
@@ -136,21 +134,23 @@
public: \
matcher_##DefineMatcher##OverloadId##Matcher(const ParamType1 &A##Param1, \
const ParamType2 &A##Param2) \
- : Param1(A##Param1), Param2(A##Param2) { \
- } \
+ : Param1(A##Param1), Param2(A##Param2) {} \
virtual bool matches(const Type &Node, ASTMatchFinder *Finder, \
BoundNodesTreeBuilder *Builder) const; \
+ \
private: \
const ParamType1 Param1; \
const ParamType2 Param2; \
}; \
} \
- inline internal::Matcher<Type> \
- DefineMatcher(const ParamType1 &Param1, const ParamType2 &Param2) { \
+ inline internal::Matcher<Type> DefineMatcher(const ParamType1 &Param1, \
+ const ParamType2 &Param2) { \
return internal::makeMatcher( \
new internal::matcher_##DefineMatcher##OverloadId##Matcher(Param1, \
Param2)); \
} \
+ typedef internal::Matcher<Type>(&DefineMatcher##_Type##OverloadId)( \
+ const ParamType1 &Param1, const ParamType2 &Param2); \
inline bool internal::matcher_##DefineMatcher##OverloadId##Matcher::matches( \
const Type &Node, ASTMatchFinder *Finder, \
BoundNodesTreeBuilder *Builder) const
@@ -180,30 +180,24 @@
/// The variables are the same as for AST_MATCHER, but NodeType will be deduced
/// from the calling context.
#define AST_POLYMORPHIC_MATCHER(DefineMatcher, ReturnTypesF) \
- AST_POLYMORPHIC_MATCHER_OVERLOAD(DefineMatcher, ReturnTypesF, 0)
-
-#define AST_POLYMORPHIC_MATCHER_OVERLOAD(DefineMatcher, ReturnTypesF, \
- OverloadId) \
namespace internal { \
template <typename NodeType> \
- class matcher_##DefineMatcher##OverloadId##Matcher \
- : public MatcherInterface<NodeType> { \
+ class matcher_##DefineMatcher##Matcher : public MatcherInterface<NodeType> { \
public: \
virtual bool matches(const NodeType &Node, ASTMatchFinder *Finder, \
BoundNodesTreeBuilder *Builder) const; \
}; \
} \
inline internal::PolymorphicMatcherWithParam0< \
- internal::matcher_##DefineMatcher##OverloadId##Matcher, ReturnTypesF> \
+ internal::matcher_##DefineMatcher##Matcher, ReturnTypesF> \
DefineMatcher() { \
return internal::PolymorphicMatcherWithParam0< \
- internal::matcher_##DefineMatcher##OverloadId##Matcher, \
- ReturnTypesF>(); \
+ internal::matcher_##DefineMatcher##Matcher, ReturnTypesF>(); \
} \
template <typename NodeType> \
- bool internal::matcher_##DefineMatcher##OverloadId##Matcher< \
- NodeType>::matches(const NodeType &Node, ASTMatchFinder *Finder, \
- BoundNodesTreeBuilder *Builder) const
+ bool internal::matcher_##DefineMatcher##Matcher<NodeType>::matches( \
+ const NodeType &Node, ASTMatchFinder *Finder, \
+ BoundNodesTreeBuilder *Builder) const
/// \brief AST_POLYMORPHIC_MATCHER_P(DefineMatcher, ParamType, Param) { ... }
/// defines a single-parameter function named DefineMatcher() that is
@@ -228,21 +222,25 @@
public: \
explicit matcher_##DefineMatcher##OverloadId##Matcher( \
const ParamType &A##Param) \
- : Param(A##Param) { \
- } \
+ : Param(A##Param) {} \
virtual bool matches(const NodeType &Node, ASTMatchFinder *Finder, \
BoundNodesTreeBuilder *Builder) const; \
+ \
private: \
const ParamType Param; \
}; \
} \
inline internal::PolymorphicMatcherWithParam1< \
internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType, \
- ReturnTypesF> DefineMatcher(const ParamType & Param) { \
+ ReturnTypesF> DefineMatcher(const ParamType &Param) { \
return internal::PolymorphicMatcherWithParam1< \
internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType, \
ReturnTypesF>(Param); \
} \
+ typedef internal::PolymorphicMatcherWithParam1< \
+ internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType, \
+ ReturnTypesF>(&DefineMatcher##_Type##OverloadId)( \
+ const ParamType &Param); \
template <typename NodeType, typename ParamT> \
bool internal::matcher_##DefineMatcher##OverloadId##Matcher< \
NodeType, ParamT>::matches(const NodeType &Node, ASTMatchFinder *Finder, \
@@ -271,10 +269,10 @@
public: \
matcher_##DefineMatcher##OverloadId##Matcher(const ParamType1 &A##Param1, \
const ParamType2 &A##Param2) \
- : Param1(A##Param1), Param2(A##Param2) { \
- } \
+ : Param1(A##Param1), Param2(A##Param2) {} \
virtual bool matches(const NodeType &Node, ASTMatchFinder *Finder, \
BoundNodesTreeBuilder *Builder) const; \
+ \
private: \
const ParamType1 Param1; \
const ParamType2 Param2; \
@@ -282,12 +280,16 @@
} \
inline internal::PolymorphicMatcherWithParam2< \
internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType1, \
- ParamType2, ReturnTypesF> DefineMatcher(const ParamType1 & Param1, \
- const ParamType2 & Param2) { \
+ ParamType2, ReturnTypesF> DefineMatcher(const ParamType1 &Param1, \
+ const ParamType2 &Param2) { \
return internal::PolymorphicMatcherWithParam2< \
internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType1, \
ParamType2, ReturnTypesF>(Param1, Param2); \
} \
+ typedef internal::PolymorphicMatcherWithParam2< \
+ internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType1, \
+ ParamType2, ReturnTypesF>(&DefineMatcher##_Type##OverloadId)( \
+ const ParamType1 &Param1, const ParamType2 &Param2); \
template <typename NodeType, typename ParamT1, typename ParamT2> \
bool internal::matcher_##DefineMatcher##OverloadId##Matcher< \
NodeType, ParamT1, ParamT2>::matches( \
Modified: cfe/trunk/include/clang/ASTMatchers/Dynamic/Diagnostics.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/Dynamic/Diagnostics.h?rev=186836&r1=186835&r2=186836&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/Dynamic/Diagnostics.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/Dynamic/Diagnostics.h Mon Jul 22 11:13:57 2013
@@ -65,6 +65,7 @@ public:
ET_RegistryWrongArgCount = 2,
ET_RegistryWrongArgType = 3,
ET_RegistryNotBindable = 4,
+ ET_RegistryAmbiguousOverload = 5,
ET_ParserStringError = 100,
ET_ParserNoOpenParen = 101,
@@ -114,6 +115,23 @@ public:
Diagnostics *const Error;
};
+ /// \brief Context for overloaded matcher construction.
+ ///
+ /// This context will take care of merging all errors that happen within it
+ /// as "candidate" overloads for the same matcher.
+ struct OverloadContext {
+ public:
+ OverloadContext(Diagnostics* Error);
+ ~OverloadContext();
+
+ /// \brief Revert all errors that happened within this context.
+ void revertErrors();
+
+ private:
+ Diagnostics *const Error;
+ unsigned BeginIndex;
+ };
+
/// \brief Add an error to the diagnostics.
///
/// All the context information will be kept on the error message.
@@ -131,9 +149,12 @@ public:
/// \brief Information stored for each error found.
struct ErrorContent {
std::vector<ContextFrame> ContextStack;
- SourceRange Range;
- ErrorType Type;
- std::vector<std::string> Args;
+ struct Message {
+ SourceRange Range;
+ ErrorType Type;
+ std::vector<std::string> Args;
+ };
+ std::vector<Message> Messages;
};
ArrayRef<ErrorContent> errors() const { return Errors; }
Modified: cfe/trunk/lib/ASTMatchers/Dynamic/Diagnostics.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/Diagnostics.cpp?rev=186836&r1=186835&r2=186836&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/Dynamic/Diagnostics.cpp (original)
+++ cfe/trunk/lib/ASTMatchers/Dynamic/Diagnostics.cpp Mon Jul 22 11:13:57 2013
@@ -40,6 +40,25 @@ Diagnostics::Context::Context(MatcherArg
Diagnostics::Context::~Context() { Error->ContextStack.pop_back(); }
+Diagnostics::OverloadContext::OverloadContext(Diagnostics *Error)
+ : Error(Error), BeginIndex(Error->Errors.size()) {}
+
+Diagnostics::OverloadContext::~OverloadContext() {
+ // Merge all errors that happened while in this context.
+ if (BeginIndex < Error->Errors.size()) {
+ Diagnostics::ErrorContent &Dest = Error->Errors[BeginIndex];
+ for (size_t i = BeginIndex + 1, e = Error->Errors.size(); i < e; ++i) {
+ Dest.Messages.push_back(Error->Errors[i].Messages[0]);
+ }
+ Error->Errors.resize(BeginIndex + 1);
+ }
+}
+
+void Diagnostics::OverloadContext::revertErrors() {
+ // Revert the errors.
+ Error->Errors.resize(BeginIndex);
+}
+
Diagnostics::ArgStream &Diagnostics::ArgStream::operator<<(const Twine &Arg) {
Out->push_back(Arg.str());
return *this;
@@ -50,9 +69,10 @@ Diagnostics::ArgStream Diagnostics::addE
Errors.push_back(ErrorContent());
ErrorContent &Last = Errors.back();
Last.ContextStack = ContextStack;
- Last.Range = Range;
- Last.Type = Error;
- return ArgStream(&Last.Args);
+ Last.Messages.push_back(ErrorContent::Message());
+ Last.Messages.back().Range = Range;
+ Last.Messages.back().Type = Error;
+ return ArgStream(&Last.Messages.back().Args);
}
StringRef contextTypeToFormatString(Diagnostics::ContextType Type) {
@@ -75,6 +95,9 @@ StringRef errorTypeToFormatString(Diagno
return "Incorrect type for arg $0. (Expected = $1) != (Actual = $2)";
case Diagnostics::ET_RegistryNotBindable:
return "Matcher does not support binding.";
+ case Diagnostics::ET_RegistryAmbiguousOverload:
+ // TODO: Add type info about the overload error.
+ return "Ambiguous matcher overload.";
case Diagnostics::ET_ParserStringError:
return "Error parsing string token: <$0>";
@@ -138,10 +161,25 @@ static void printContextFrameToStream(co
formatErrorString(contextTypeToFormatString(Frame.Type), Frame.Args, OS);
}
+static void
+printMessageToStream(const Diagnostics::ErrorContent::Message &Message,
+ const Twine Prefix, llvm::raw_ostream &OS) {
+ maybeAddLineAndColumn(Message.Range, OS);
+ OS << Prefix;
+ formatErrorString(errorTypeToFormatString(Message.Type), Message.Args, OS);
+}
+
static void printErrorContentToStream(const Diagnostics::ErrorContent &Content,
llvm::raw_ostream &OS) {
- maybeAddLineAndColumn(Content.Range, OS);
- formatErrorString(errorTypeToFormatString(Content.Type), Content.Args, OS);
+ if (Content.Messages.size() == 1) {
+ printMessageToStream(Content.Messages[0], "", OS);
+ } else {
+ for (size_t i = 0, e = Content.Messages.size(); i != e; ++i) {
+ if (i != 0) OS << "\n";
+ printMessageToStream(Content.Messages[i],
+ "Candidate " + Twine(i + 1) + ": ", OS);
+ }
+ }
}
void Diagnostics::printToStream(llvm::raw_ostream &OS) const {
Modified: cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp?rev=186836&r1=186835&r2=186836&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp (original)
+++ cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp Mon Jul 22 11:13:57 2013
@@ -48,10 +48,67 @@ void RegistryMaps::registerMatcher(Strin
Constructors[MatcherName] = Callback;
}
+/// \brief MatcherCreateCallback that wraps multiple "overloads" of the same
+/// matcher.
+///
+/// It will try every overload and generate appropriate errors for when none or
+/// more than one overloads match the arguments.
+class OverloadedMatcherCreateCallback : public MatcherCreateCallback {
+ public:
+ OverloadedMatcherCreateCallback(ArrayRef<MatcherCreateCallback *> Callbacks)
+ : Overloads(Callbacks) {}
+
+ virtual ~OverloadedMatcherCreateCallback() {
+ for (size_t i = 0, e = Overloads.size(); i != e; ++i)
+ delete Overloads[i];
+ }
+
+ virtual MatcherList run(const SourceRange &NameRange,
+ ArrayRef<ParserValue> Args,
+ Diagnostics *Error) const {
+ std::vector<MatcherList> Constructed;
+ Diagnostics::OverloadContext Ctx(Error);
+ for (size_t i = 0, e = Overloads.size(); i != e; ++i) {
+ MatcherList SubMatcher = Overloads[i]->run(NameRange, Args, Error);
+ if (!SubMatcher.empty()) {
+ Constructed.push_back(SubMatcher);
+ }
+ }
+
+ if (Constructed.empty()) return MatcherList(); // No overload matched.
+ // We ignore the errors if any matcher succeeded.
+ Ctx.revertErrors();
+ if (Constructed.size() > 1) {
+ // More than one constructed. It is ambiguous.
+ Error->addError(NameRange, Error->ET_RegistryAmbiguousOverload);
+ return MatcherList();
+ }
+ return Constructed[0];
+ }
+
+ private:
+ std::vector<MatcherCreateCallback*> Overloads;
+};
+
#define REGISTER_MATCHER(name) \
registerMatcher(#name, internal::makeMatcherAutoMarshall( \
::clang::ast_matchers::name, #name));
+#define SPECIFIC_MATCHER_OVERLOAD(name, Id) \
+ static_cast< ::clang::ast_matchers::name##_Type##Id>( \
+ ::clang::ast_matchers::name)
+
+#define REGISTER_OVERLOADED_2(name) \
+ do { \
+ MatcherCreateCallback *Callbacks[] = { \
+ internal::makeMatcherAutoMarshall(SPECIFIC_MATCHER_OVERLOAD(name, 0), \
+ #name), \
+ internal::makeMatcherAutoMarshall(SPECIFIC_MATCHER_OVERLOAD(name, 1), \
+ #name) \
+ }; \
+ registerMatcher(#name, new OverloadedMatcherCreateCallback(Callbacks)); \
+ } while (0)
+
/// \brief Generate a registry map with all the known matchers.
RegistryMaps::RegistryMaps() {
// TODO: Here is the list of the missing matchers, grouped by reason.
@@ -59,16 +116,6 @@ RegistryMaps::RegistryMaps() {
// Need Variant/Parser fixes:
// ofKind
//
- // Function overloaded by args:
- // hasType
- // callee
- // hasPrefix
- // isDerivedFrom
- // isSameOrDerivedFrom
- // pointsTo
- // references
- // thisPointerType
- //
// Polymorphic + argument overload:
// unless
// eachOf
@@ -90,6 +137,15 @@ RegistryMaps::RegistryMaps() {
// equalsNode
// hasDeclaration
+ REGISTER_OVERLOADED_2(callee);
+ REGISTER_OVERLOADED_2(hasPrefix);
+ REGISTER_OVERLOADED_2(hasType);
+ REGISTER_OVERLOADED_2(isDerivedFrom);
+ REGISTER_OVERLOADED_2(isSameOrDerivedFrom);
+ REGISTER_OVERLOADED_2(pointsTo);
+ REGISTER_OVERLOADED_2(references);
+ REGISTER_OVERLOADED_2(thisPointerType);
+
REGISTER_MATCHER(accessSpecDecl);
REGISTER_MATCHER(alignOfExpr);
REGISTER_MATCHER(anything);
Modified: cfe/trunk/unittests/ASTMatchers/Dynamic/ParserTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/Dynamic/ParserTest.cpp?rev=186836&r1=186835&r2=186836&view=diff
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/Dynamic/ParserTest.cpp (original)
+++ cfe/trunk/unittests/ASTMatchers/Dynamic/ParserTest.cpp Mon Jul 22 11:13:57 2013
@@ -256,6 +256,15 @@ TEST(ParserTest, Errors) {
ParseMatcherWithError("hasBody(stmt())"));
}
+TEST(ParserTest, OverloadErrors) {
+ EXPECT_EQ("1:1: Error building matcher callee.\n"
+ "1:8: Candidate 1: Incorrect type for arg 1. "
+ "(Expected = Matcher<Stmt>) != (Actual = String)\n"
+ "1:8: Candidate 2: Incorrect type for arg 1. "
+ "(Expected = Matcher<Decl>) != (Actual = String)",
+ ParseWithError("callee(\"A\")"));
+}
+
} // end anonymous namespace
} // end namespace dynamic
} // end namespace ast_matchers
Modified: cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp?rev=186836&r1=186835&r2=186836&view=diff
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp (original)
+++ cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp Mon Jul 22 11:13:57 2013
@@ -124,6 +124,30 @@ TEST_F(RegistryTest, ConstructWithMatche
EXPECT_FALSE(matches("void f(int x, int a);", HasParameter));
}
+TEST_F(RegistryTest, OverloadedMatchers) {
+ Matcher<Stmt> CallExpr0 = constructMatcher(
+ "callExpr",
+ constructMatcher("callee", constructMatcher("memberExpr",
+ constructMatcher("isArrow"))))
+ .getTypedMatcher<Stmt>();
+
+ Matcher<Stmt> CallExpr1 = constructMatcher(
+ "callExpr",
+ constructMatcher(
+ "callee",
+ constructMatcher("methodDecl",
+ constructMatcher("hasName", std::string("x")))))
+ .getTypedMatcher<Stmt>();
+
+ std::string Code = "class Y { public: void x(); }; void z() { Y y; y.x(); }";
+ EXPECT_FALSE(matches(Code, CallExpr0));
+ EXPECT_TRUE(matches(Code, CallExpr1));
+
+ Code = "class Z { public: void z() { this->z(); } };";
+ EXPECT_TRUE(matches(Code, CallExpr0));
+ EXPECT_FALSE(matches(Code, CallExpr1));
+}
+
TEST_F(RegistryTest, PolymorphicMatchers) {
const MatcherList IsDefinition = constructMatcher("isDefinition");
Matcher<Decl> Var =
More information about the cfe-commits
mailing list