From e0b2c8e478bea77088f8c1d2fdc2cbfa61ac59b1 Mon Sep 17 00:00:00 2001 From: Samuel Benzaquen Date: Mon, 22 Jul 2013 16:13:57 +0000 Subject: [PATCH] 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 llvm-svn: 186836 --- clang/include/clang/ASTMatchers/ASTMatchers.h | 67 ++++++++++--------- .../include/clang/ASTMatchers/ASTMatchersMacros.h | 68 +++++++++---------- .../clang/ASTMatchers/Dynamic/Diagnostics.h | 27 +++++++- clang/lib/ASTMatchers/Dynamic/Diagnostics.cpp | 48 ++++++++++++-- clang/lib/ASTMatchers/Dynamic/Registry.cpp | 76 +++++++++++++++++++--- clang/unittests/ASTMatchers/Dynamic/ParserTest.cpp | 9 +++ .../unittests/ASTMatchers/Dynamic/RegistryTest.cpp | 24 +++++++ 7 files changed, 237 insertions(+), 82 deletions(-) diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h index 2085133..b151985 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -1536,24 +1536,25 @@ AST_MATCHER_P(CXXRecordDecl, isDerivedFrom, } /// \brief Overloaded method as shortcut for \c isDerivedFrom(hasName(...)). -inline internal::Matcher 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 isSameOrDerivedFrom( - internal::Matcher Base) { - return anyOf(Base, isDerivedFrom(Base)); +AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isSameOrDerivedFrom, + internal::Matcher, Base, 0) { + return Matcher(anyOf(Base, isDerivedFrom(Base))) + .matches(Node, Finder, Builder); } /// \brief Overloaded method as shortcut for /// \c isSameOrDerivedFrom(hasName(...)). -inline internal::Matcher 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::Matcher, /// class Y { public: void x(); }; /// void z() { Y y; y.x(); /// \endcode -inline internal::Matcher callee( - const internal::Matcher &InnerMatcher) { - return callExpr(hasDeclaration(InnerMatcher)); +AST_MATCHER_P_OVERLOAD(CallExpr, callee, internal::Matcher, 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 callee( /// class X {}; /// void y(X &x) { x; X z; } /// \endcode -AST_POLYMORPHIC_MATCHER_P(hasType, - AST_POLYMORPHIC_SUPPORTED_TYPES_2(Expr, ValueDecl), - internal::Matcher, InnerMatcher) { +AST_POLYMORPHIC_MATCHER_P_OVERLOAD( + hasType, AST_POLYMORPHIC_SUPPORTED_TYPES_2(Expr, ValueDecl), + internal::Matcher, InnerMatcher, 0) { return InnerMatcher.matches(Node.getType(), Finder, Builder); } @@ -1859,11 +1860,11 @@ AST_POLYMORPHIC_MATCHER_P(hasType, /// \endcode /// /// Usable as: Matcher, Matcher -inline internal::PolymorphicMatcherWithParam1< - internal::matcher_hasType0Matcher, internal::Matcher, - AST_POLYMORPHIC_SUPPORTED_TYPES_2(Expr, ValueDecl)> -hasType(const internal::Matcher &InnerMatcher) { - return hasType(qualType(hasDeclaration(InnerMatcher))); +AST_POLYMORPHIC_MATCHER_P_OVERLOAD( + hasType, AST_POLYMORPHIC_SUPPORTED_TYPES_2(Expr, ValueDecl), + internal::Matcher, 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 pointsTo( - const internal::Matcher &InnerMatcher) { - return pointsTo(qualType(hasDeclaration(InnerMatcher))); +AST_MATCHER_P_OVERLOAD(QualType, pointsTo, internal::Matcher, + 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, internal::Matcher, } /// \brief Overloaded to match the referenced type's declaration. -inline internal::Matcher references( - const internal::Matcher &InnerMatcher) { - return references(qualType(hasDeclaration(InnerMatcher))); +AST_MATCHER_P_OVERLOAD(QualType, references, internal::Matcher, + InnerMatcher, 1) { + return references(qualType(hasDeclaration(InnerMatcher))) + .matches(Node, Finder, Builder); } AST_MATCHER_P(CXXMemberCallExpr, onImplicitObjectArgument, @@ -1969,17 +1972,19 @@ AST_MATCHER_P(CXXMemberCallExpr, onImplicitObjectArgument, /// \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 thisPointerType( - const internal::Matcher &InnerMatcher) { +AST_MATCHER_P_OVERLOAD(CXXMemberCallExpr, thisPointerType, + internal::Matcher, 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 thisPointerType( - const internal::Matcher &InnerMatcher) { +AST_MATCHER_P_OVERLOAD(CXXMemberCallExpr, thisPointerType, + internal::Matcher, 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 diff --git a/clang/include/clang/ASTMatchers/ASTMatchersMacros.h b/clang/include/clang/ASTMatchers/ASTMatchersMacros.h index 79e9daa..0a22f45 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchersMacros.h +++ b/clang/include/clang/ASTMatchers/ASTMatchersMacros.h @@ -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 { \ + class matcher_##DefineMatcher##Matcher : public MatcherInterface { \ public: \ - explicit matcher_##DefineMatcher##OverloadId##Matcher() {} \ + explicit matcher_##DefineMatcher##Matcher() {} \ virtual bool matches(const Type &Node, ASTMatchFinder *Finder, \ BoundNodesTreeBuilder *Builder) const; \ }; \ } \ inline internal::Matcher 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(&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 \ - DefineMatcher(const ParamType1 &Param1, const ParamType2 &Param2) { \ + inline internal::Matcher DefineMatcher(const ParamType1 &Param1, \ + const ParamType2 &Param2) { \ return internal::makeMatcher( \ new internal::matcher_##DefineMatcher##OverloadId##Matcher(Param1, \ Param2)); \ } \ + typedef internal::Matcher(&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 \ - class matcher_##DefineMatcher##OverloadId##Matcher \ - : public MatcherInterface { \ + class matcher_##DefineMatcher##Matcher : public MatcherInterface { \ 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 \ - bool internal::matcher_##DefineMatcher##OverloadId##Matcher< \ - NodeType>::matches(const NodeType &Node, ASTMatchFinder *Finder, \ - BoundNodesTreeBuilder *Builder) const + bool internal::matcher_##DefineMatcher##Matcher::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 \ 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 \ bool internal::matcher_##DefineMatcher##OverloadId##Matcher< \ NodeType, ParamT1, ParamT2>::matches( \ diff --git a/clang/include/clang/ASTMatchers/Dynamic/Diagnostics.h b/clang/include/clang/ASTMatchers/Dynamic/Diagnostics.h index 21292af..aec0c0e 100644 --- a/clang/include/clang/ASTMatchers/Dynamic/Diagnostics.h +++ b/clang/include/clang/ASTMatchers/Dynamic/Diagnostics.h @@ -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 ContextStack; - SourceRange Range; - ErrorType Type; - std::vector Args; + struct Message { + SourceRange Range; + ErrorType Type; + std::vector Args; + }; + std::vector Messages; }; ArrayRef errors() const { return Errors; } diff --git a/clang/lib/ASTMatchers/Dynamic/Diagnostics.cpp b/clang/lib/ASTMatchers/Dynamic/Diagnostics.cpp index b72910e..da2ed9a 100644 --- a/clang/lib/ASTMatchers/Dynamic/Diagnostics.cpp +++ b/clang/lib/ASTMatchers/Dynamic/Diagnostics.cpp @@ -40,6 +40,25 @@ Diagnostics::Context::Context(MatcherArgEnum, Diagnostics *Error, 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::addError(const SourceRange &Range, 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(Diagnostics::ErrorType Type) { 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(const Diagnostics::ContextFrame &Frame, 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 { diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp index 6cab407..2daaa88 100644 --- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -48,10 +48,67 @@ void RegistryMaps::registerMatcher(StringRef MatcherName, 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 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 Args, + Diagnostics *Error) const { + std::vector 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 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); diff --git a/clang/unittests/ASTMatchers/Dynamic/ParserTest.cpp b/clang/unittests/ASTMatchers/Dynamic/ParserTest.cpp index 9ccd3dc..d9b2d3c8 100644 --- a/clang/unittests/ASTMatchers/Dynamic/ParserTest.cpp +++ b/clang/unittests/ASTMatchers/Dynamic/ParserTest.cpp @@ -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) != (Actual = String)\n" + "1:8: Candidate 2: Incorrect type for arg 1. " + "(Expected = Matcher) != (Actual = String)", + ParseWithError("callee(\"A\")")); +} + } // end anonymous namespace } // end namespace dynamic } // end namespace ast_matchers diff --git a/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp b/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp index 178a64a..e69017e 100644 --- a/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp +++ b/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp @@ -124,6 +124,30 @@ TEST_F(RegistryTest, ConstructWithMatcherArgs) { EXPECT_FALSE(matches("void f(int x, int a);", HasParameter)); } +TEST_F(RegistryTest, OverloadedMatchers) { + Matcher CallExpr0 = constructMatcher( + "callExpr", + constructMatcher("callee", constructMatcher("memberExpr", + constructMatcher("isArrow")))) + .getTypedMatcher(); + + Matcher CallExpr1 = constructMatcher( + "callExpr", + constructMatcher( + "callee", + constructMatcher("methodDecl", + constructMatcher("hasName", std::string("x"))))) + .getTypedMatcher(); + + 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 Var = -- 2.7.4