From 9d02807c3ea9782442b98201df68294cd7cd7313 Mon Sep 17 00:00:00 2001 From: Samuel Benzaquen Date: Tue, 13 Aug 2013 14:54:51 +0000 Subject: [PATCH] Refactor "MatcherList" into "VariantMatcher" and abstract the notion of a list of matchers for the polymorphic case. Summary: Refactor "MatcherList" into "VariantMatcher" and abstract the notion of a list of matchers for the polymorphic case. This work is to support future changes needed for eachOf/allOf/anyOf matchers. We will add a new type on VariantMatcher. Reviewers: klimek CC: cfe-commits, revane Differential Revision: http://llvm-reviews.chandlerc.com/D1365 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@188272 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/ASTMatchers/Dynamic/Parser.h | 14 +-- include/clang/ASTMatchers/Dynamic/Registry.h | 24 ++-- .../clang/ASTMatchers/Dynamic/VariantValue.h | 98 +++++++++------ lib/ASTMatchers/Dynamic/Marshallers.h | 115 +++++++++--------- lib/ASTMatchers/Dynamic/Parser.cpp | 21 ++-- lib/ASTMatchers/Dynamic/Registry.cpp | 52 ++++---- lib/ASTMatchers/Dynamic/VariantValue.cpp | 88 ++++++++------ unittests/ASTMatchers/Dynamic/ParserTest.cpp | 28 +++-- .../ASTMatchers/Dynamic/RegistryTest.cpp | 59 +++++---- .../ASTMatchers/Dynamic/VariantValueTest.cpp | 53 ++++---- 10 files changed, 309 insertions(+), 243 deletions(-) diff --git a/include/clang/ASTMatchers/Dynamic/Parser.h b/include/clang/ASTMatchers/Dynamic/Parser.h index b3fd7d607f..3759f631b3 100644 --- a/include/clang/ASTMatchers/Dynamic/Parser.h +++ b/include/clang/ASTMatchers/Dynamic/Parser.h @@ -74,14 +74,14 @@ public: /// /// \param Args The argument list for the matcher. /// - /// \return The matcher objects constructed by the processor, or an empty - /// list if an error occurred. In that case, \c Error will contain a + /// \return The matcher objects constructed by the processor, or a null + /// matcher if an error occurred. In that case, \c Error will contain a /// description of the error. - virtual MatcherList actOnMatcherExpression(StringRef MatcherName, - const SourceRange &NameRange, - StringRef BindID, - ArrayRef Args, - Diagnostics *Error) = 0; + virtual VariantMatcher actOnMatcherExpression(StringRef MatcherName, + const SourceRange &NameRange, + StringRef BindID, + ArrayRef Args, + Diagnostics *Error) = 0; }; /// \brief Parse a matcher expression, creating matchers from the registry. diff --git a/include/clang/ASTMatchers/Dynamic/Registry.h b/include/clang/ASTMatchers/Dynamic/Registry.h index a75f29641a..c113c1404e 100644 --- a/include/clang/ASTMatchers/Dynamic/Registry.h +++ b/include/clang/ASTMatchers/Dynamic/Registry.h @@ -43,26 +43,26 @@ public: /// values must be valid for the matcher requested. Otherwise, the function /// will return an error. /// - /// \return The matcher objects constructed if no error was found. - /// An empty list if the matcher is not found, or if the number of + /// \return The matcher object constructed if no error was found. + /// A null matcher if the matcher is not found, or if the number of /// arguments or argument types do not match the signature. /// In that case \c Error will contain the description of the error. - static MatcherList constructMatcher(StringRef MatcherName, - const SourceRange &NameRange, - ArrayRef Args, - Diagnostics *Error); + static VariantMatcher constructMatcher(StringRef MatcherName, + const SourceRange &NameRange, + ArrayRef Args, + Diagnostics *Error); /// \brief Construct a matcher from the registry and bind it. /// /// Similar the \c constructMatcher() above, but it then tries to bind the /// matcher to the specified \c BindID. /// If the matcher is not bindable, it sets an error in \c Error and returns - /// an empty list. - static MatcherList constructBoundMatcher(StringRef MatcherName, - const SourceRange &NameRange, - StringRef BindID, - ArrayRef Args, - Diagnostics *Error); + /// a null matcher. + static VariantMatcher constructBoundMatcher(StringRef MatcherName, + const SourceRange &NameRange, + StringRef BindID, + ArrayRef Args, + Diagnostics *Error); private: Registry() LLVM_DELETED_FUNCTION; diff --git a/include/clang/ASTMatchers/Dynamic/VariantValue.h b/include/clang/ASTMatchers/Dynamic/VariantValue.h index 44f497248a..abfce078b3 100644 --- a/include/clang/ASTMatchers/Dynamic/VariantValue.h +++ b/include/clang/ASTMatchers/Dynamic/VariantValue.h @@ -30,32 +30,53 @@ namespace dynamic { using ast_matchers::internal::DynTypedMatcher; -/// \brief A list of \c DynTypedMatcher objects. +/// \brief A variant matcher object. /// -/// The purpose of this list is to wrap multiple different matchers and -/// provide the right one when calling \c hasTypedMatcher/getTypedMatcher. -class MatcherList { +/// The purpose of this object is to abstract simple and polymorphic matchers +/// into a single object type. +/// Polymorphic matchers might be implemented as a list of all the possible +/// overloads of the matcher. \c VariantMatcher knows how to select the +/// appropriate overload when needed. +/// To get a real matcher object out of a \c VariantMatcher you can do: +/// - getSingleMatcher() which returns a matcher, only if it is not ambiguous +/// to decide which matcher to return. Eg. it contains only a single +/// matcher, or a polymorphic one with only one overload. +/// - hasTypedMatcher()/getTypedMatcher(): These calls will determine if +/// the underlying matcher(s) can unambiguously return a Matcher. +class VariantMatcher { public: - /// \brief An empty list. - MatcherList(); + /// \brief A null matcher. + VariantMatcher(); + /// \brief Clones the matcher objects. - MatcherList(const MatcherList &Other); + VariantMatcher(const VariantMatcher &Other); + /// \brief Clones the provided matcher. - MatcherList(const DynTypedMatcher &Matcher); - ~MatcherList(); + static VariantMatcher SingleMatcher(const DynTypedMatcher &Matcher); + + /// \brief Clones the provided matchers. + /// + /// They should be the result of a polymorphic matcher. + static VariantMatcher + PolymorphicMatcher(ArrayRef Matchers); - MatcherList &operator=(const MatcherList &Other); + ~VariantMatcher(); - /// \brief Add a matcher to this list. The matcher is cloned. - void add(const DynTypedMatcher &Matcher); + /// \brief Copy the \c VariantMatcher, by making a copy of its representation. + VariantMatcher &operator=(const VariantMatcher &Other); - /// \brief Empties the list. + /// \brief Makes the matcher the "null" matcher. void reset(); - /// \brief Whether the list is empty. - bool empty() const { return List.empty(); } + /// \brief Whether the matcher is null. + bool isNull() const { return List.empty(); } - ArrayRef matchers() const { return List; } + /// \brief Return a single matcher, if there is no ambiguity. + /// + /// \returns True, and set Out to the matcher, if there is only one matcher. + /// False, if the underlying matcher is a polymorphic matcher with + /// more than one representation. + bool getSingleMatcher(const DynTypedMatcher *&Out) const; /// \brief Determines if any of the contained matchers can be converted /// to \c Matcher. @@ -65,35 +86,35 @@ public: /// result would be ambigous and false is returned. template bool hasTypedMatcher() const { - size_t Matches = 0; - for (size_t I = 0, E = List.size(); I != E; ++I) { - Matches += ast_matchers::internal::Matcher::canConstructFrom(*List[I]); - } - return Matches == 1; + return getTypedMatcher( + &ast_matchers::internal::Matcher::canConstructFrom) != NULL; } /// \brief Wrap the correct matcher as a \c Matcher. /// - /// Selects the appropriate matcher from the list and returns it as a - /// \c Matcher. + /// Selects the appropriate matcher from the wrapped matchers and returns it + /// as a \c Matcher. /// Asserts that \c hasTypedMatcher() is true. template ast_matchers::internal::Matcher getTypedMatcher() const { assert(hasTypedMatcher()); - for (size_t I = 0, E = List.size(); I != E; ++I) { - if (ast_matchers::internal::Matcher::canConstructFrom(*List[I])) - return ast_matchers::internal::Matcher::constructFrom(*List[I]); - } - llvm_unreachable("!hasTypedMatcher()"); + return ast_matchers::internal::Matcher::constructFrom(*getTypedMatcher( + &ast_matchers::internal::Matcher::canConstructFrom)); } /// \brief String representation of the type of the value. /// - /// If there are more than one matcher on the list, the string will show all + /// If the underlying matcher is a polymorphic one, the string will show all /// the types. std::string getTypeAsString() const; private: + /// \brief Returns the matcher that passes the callback. + /// + /// Returns NULL if no matcher passes the test, or if more than one do. + const DynTypedMatcher * + getTypedMatcher(bool (*CanConstructCallback)(const DynTypedMatcher &)) const; + std::vector List; }; @@ -108,7 +129,7 @@ private: /// Supported types: /// - \c unsigned /// - \c std::string -/// - \c MatcherList (\c DynTypedMatcher / \c Matcher) +/// - \c VariantMatcher (\c DynTypedMatcher / \c Matcher) class VariantValue { public: VariantValue() : Type(VT_Nothing) {} @@ -120,8 +141,7 @@ public: /// \brief Specific constructors for each supported type. VariantValue(unsigned Unsigned); VariantValue(const std::string &String); - VariantValue(const DynTypedMatcher &Matcher); - VariantValue(const MatcherList &Matchers); + VariantValue(const VariantMatcher &Matchers); /// \brief Unsigned value functions. bool isUnsigned() const; @@ -134,19 +154,19 @@ public: void setString(const std::string &String); /// \brief Matcher value functions. - bool isMatchers() const; - const MatcherList &getMatchers() const; - void setMatchers(const MatcherList &Matchers); + bool isMatcher() const; + const VariantMatcher &getMatcher() const; + void setMatcher(const VariantMatcher &Matcher); /// \brief Shortcut functions. template bool hasTypedMatcher() const { - return isMatchers() && getMatchers().hasTypedMatcher(); + return isMatcher() && getMatcher().hasTypedMatcher(); } template ast_matchers::internal::Matcher getTypedMatcher() const { - return getMatchers().getTypedMatcher(); + return getMatcher().getTypedMatcher(); } /// \brief String representation of the type of the value. @@ -160,14 +180,14 @@ private: VT_Nothing, VT_Unsigned, VT_String, - VT_Matchers + VT_Matcher }; /// \brief All supported value types. union AllValues { unsigned Unsigned; std::string *String; - MatcherList *Matchers; + VariantMatcher *Matcher; }; ValueType Type; diff --git a/lib/ASTMatchers/Dynamic/Marshallers.h b/lib/ASTMatchers/Dynamic/Marshallers.h index 9f1cfe3443..abd5d402f1 100644 --- a/lib/ASTMatchers/Dynamic/Marshallers.h +++ b/lib/ASTMatchers/Dynamic/Marshallers.h @@ -26,6 +26,7 @@ #include "clang/ASTMatchers/Dynamic/Diagnostics.h" #include "clang/ASTMatchers/Dynamic/VariantValue.h" #include "clang/Basic/LLVM.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/type_traits.h" namespace clang { @@ -82,9 +83,9 @@ template <> struct ArgTypeTraits { class MatcherCreateCallback { public: virtual ~MatcherCreateCallback() {} - virtual MatcherList run(const SourceRange &NameRange, - ArrayRef Args, - Diagnostics *Error) const = 0; + virtual VariantMatcher run(const SourceRange &NameRange, + ArrayRef Args, + Diagnostics *Error) const = 0; }; /// \brief Simple callback implementation. Marshaller and function are provided. @@ -99,10 +100,10 @@ public: /// FIXME: Use void(*)() as FuncType on this interface to remove the template /// argument of this class. The marshaller can cast the function pointer back /// to the original type. - typedef MatcherList (*MarshallerType)(FuncType, StringRef, - const SourceRange &, - ArrayRef, - Diagnostics *); + typedef VariantMatcher (*MarshallerType)(FuncType, StringRef, + const SourceRange &, + ArrayRef, + Diagnostics *); /// \param Marshaller Function to unpack the arguments and call \c Func /// \param Func Matcher construct function. This is the function that @@ -111,8 +112,8 @@ public: StringRef MatcherName) : Marshaller(Marshaller), Func(Func), MatcherName(MatcherName.str()) {} - MatcherList run(const SourceRange &NameRange, ArrayRef Args, - Diagnostics *Error) const { + VariantMatcher run(const SourceRange &NameRange, ArrayRef Args, + Diagnostics *Error) const { return Marshaller(Func, MatcherName, NameRange, Args, Error); } @@ -131,16 +132,16 @@ private: /// object file. class FreeFuncMatcherCreateCallback : public MatcherCreateCallback { public: - typedef MatcherList (*RunFunc)(StringRef MatcherName, - const SourceRange &NameRange, - ArrayRef Args, - Diagnostics *Error); + typedef VariantMatcher (*RunFunc)(StringRef MatcherName, + const SourceRange &NameRange, + ArrayRef Args, + Diagnostics *Error); FreeFuncMatcherCreateCallback(RunFunc Func, StringRef MatcherName) : Func(Func), MatcherName(MatcherName.str()) {} - MatcherList run(const SourceRange &NameRange, ArrayRef Args, - Diagnostics *Error) const { + VariantMatcher run(const SourceRange &NameRange, ArrayRef Args, + Diagnostics *Error) const { return Func(MatcherName, NameRange, Args, Error); } @@ -154,7 +155,7 @@ private: if (Args.size() != count) { \ Error->addError(NameRange, Error->ET_RegistryWrongArgCount) \ << count << Args.size(); \ - return MatcherList(); \ + return VariantMatcher(); \ } #define CHECK_ARG_TYPE(index, type) \ @@ -162,76 +163,80 @@ private: Error->addError(Args[index].Range, Error->ET_RegistryWrongArgType) \ << (index + 1) << ArgTypeTraits::asString() \ << Args[index].Value.getTypeAsString(); \ - return MatcherList(); \ + return VariantMatcher(); \ } /// \brief Helper methods to extract and merge all possible typed matchers /// out of the polymorphic object. template -static void mergePolyMatchers(const PolyMatcher &Poly, MatcherList *Out, +static void mergePolyMatchers(const PolyMatcher &Poly, + std::vector &Out, ast_matchers::internal::EmptyTypeList) {} template -static void mergePolyMatchers(const PolyMatcher &Poly, MatcherList *Out, +static void mergePolyMatchers(const PolyMatcher &Poly, + std::vector &Out, TypeList) { - Out->add(ast_matchers::internal::Matcher(Poly)); + Out.push_back(ast_matchers::internal::Matcher(Poly) + .clone()); mergePolyMatchers(Poly, Out, typename TypeList::tail()); } -/// \brief Convert the return values of the functions into a MatcherList. +/// \brief Convert the return values of the functions into a VariantMatcher. /// /// There are 2 cases right now: The return value is a Matcher or is a -/// polymorphic matcher. For the former, we just construct the MatcherList. For -/// the latter, we instantiate all the possible Matcher of the poly matcher. +/// polymorphic matcher. For the former, we just construct the VariantMatcher. +/// For the latter, we instantiate all the possible Matcher of the poly +/// matcher. template -static MatcherList -outvalueToMatcherList(const ast_matchers::internal::Matcher &Matcher) { - return MatcherList(Matcher); +static VariantMatcher +outvalueToVariantMatcher(const ast_matchers::internal::Matcher &Matcher) { + return VariantMatcher::SingleMatcher(Matcher); } template -static MatcherList -outvalueToMatcherList(const T& PolyMatcher, typename T::ReturnTypes* = NULL) { - MatcherList Matchers; - mergePolyMatchers(PolyMatcher, &Matchers, typename T::ReturnTypes()); - return Matchers; +static VariantMatcher outvalueToVariantMatcher(const T &PolyMatcher, + typename T::ReturnTypes * = + NULL) { + std::vector Matchers; + mergePolyMatchers(PolyMatcher, Matchers, typename T::ReturnTypes()); + VariantMatcher Out = VariantMatcher::PolymorphicMatcher(Matchers); + llvm::DeleteContainerPointers(Matchers); + return Out; } /// \brief 0-arg marshaller function. template -static MatcherList matcherMarshall0(ReturnType (*Func)(), - StringRef MatcherName, - const SourceRange &NameRange, - ArrayRef Args, - Diagnostics *Error) { +static VariantMatcher +matcherMarshall0(ReturnType (*Func)(), StringRef MatcherName, + const SourceRange &NameRange, ArrayRef Args, + Diagnostics *Error) { CHECK_ARG_COUNT(0); - return outvalueToMatcherList(Func()); + return outvalueToVariantMatcher(Func()); } /// \brief 1-arg marshaller function. template -static MatcherList matcherMarshall1(ReturnType (*Func)(ArgType1), - StringRef MatcherName, - const SourceRange &NameRange, - ArrayRef Args, - Diagnostics *Error) { +static VariantMatcher +matcherMarshall1(ReturnType (*Func)(ArgType1), StringRef MatcherName, + const SourceRange &NameRange, ArrayRef Args, + Diagnostics *Error) { CHECK_ARG_COUNT(1); CHECK_ARG_TYPE(0, ArgType1); - return outvalueToMatcherList( + return outvalueToVariantMatcher( Func(ArgTypeTraits::get(Args[0].Value))); } /// \brief 2-arg marshaller function. template -static MatcherList matcherMarshall2(ReturnType (*Func)(ArgType1, ArgType2), - StringRef MatcherName, - const SourceRange &NameRange, - ArrayRef Args, - Diagnostics *Error) { +static VariantMatcher +matcherMarshall2(ReturnType (*Func)(ArgType1, ArgType2), StringRef MatcherName, + const SourceRange &NameRange, ArrayRef Args, + Diagnostics *Error) { CHECK_ARG_COUNT(2); CHECK_ARG_TYPE(0, ArgType1); CHECK_ARG_TYPE(1, ArgType2); - return outvalueToMatcherList( + return outvalueToVariantMatcher( Func(ArgTypeTraits::get(Args[0].Value), ArgTypeTraits::get(Args[1].Value))); } @@ -242,10 +247,10 @@ static MatcherList matcherMarshall2(ReturnType (*Func)(ArgType1, ArgType2), /// \brief Variadic marshaller function. template )> -MatcherList variadicMatcherCreateCallback(StringRef MatcherName, - const SourceRange &NameRange, - ArrayRef Args, - Diagnostics *Error) { +VariantMatcher +variadicMatcherCreateCallback(StringRef MatcherName, + const SourceRange &NameRange, + ArrayRef Args, Diagnostics *Error) { ArgT **InnerArgs = new ArgT *[Args.size()](); bool HasError = false; @@ -262,9 +267,9 @@ MatcherList variadicMatcherCreateCallback(StringRef MatcherName, InnerArgs[i] = new ArgT(ArgTraits::get(Value)); } - MatcherList Out; + VariantMatcher Out; if (!HasError) { - Out = outvalueToMatcherList( + Out = outvalueToVariantMatcher( Func(ArrayRef(InnerArgs, Args.size()))); } diff --git a/lib/ASTMatchers/Dynamic/Parser.cpp b/lib/ASTMatchers/Dynamic/Parser.cpp index 54424cea7e..37e6c10478 100644 --- a/lib/ASTMatchers/Dynamic/Parser.cpp +++ b/lib/ASTMatchers/Dynamic/Parser.cpp @@ -311,9 +311,9 @@ bool Parser::parseMatcherExpressionImpl(VariantValue *Value) { NameToken.Text, NameToken.Range); SourceRange MatcherRange = NameToken.Range; MatcherRange.End = EndToken.Range.End; - MatcherList Result = S->actOnMatcherExpression( + VariantMatcher Result = S->actOnMatcherExpression( NameToken.Text, MatcherRange, BindID, Args, Error); - if (Result.empty()) return false; + if (Result.isNull()) return false; *Value = Result; return true; @@ -358,11 +358,11 @@ Parser::Parser(CodeTokenizer *Tokenizer, Sema *S, class RegistrySema : public Parser::Sema { public: virtual ~RegistrySema() {} - MatcherList actOnMatcherExpression(StringRef MatcherName, - const SourceRange &NameRange, - StringRef BindID, - ArrayRef Args, - Diagnostics *Error) { + VariantMatcher actOnMatcherExpression(StringRef MatcherName, + const SourceRange &NameRange, + StringRef BindID, + ArrayRef Args, + Diagnostics *Error) { if (BindID.empty()) { return Registry::constructMatcher(MatcherName, NameRange, Args, Error); } else { @@ -402,16 +402,17 @@ DynTypedMatcher *Parser::parseMatcherExpression(StringRef Code, VariantValue Value; if (!parseExpression(Code, S, &Value, Error)) return NULL; - if (!Value.isMatchers()) { + if (!Value.isMatcher()) { Error->addError(SourceRange(), Error->ET_ParserNotAMatcher); return NULL; } - if (Value.getMatchers().matchers().size() != 1) { + const DynTypedMatcher *Result; + if (!Value.getMatcher().getSingleMatcher(Result)) { Error->addError(SourceRange(), Error->ET_ParserOverloadedType) << Value.getTypeAsString(); return NULL; } - return Value.getMatchers().matchers()[0]->clone(); + return Result->clone(); } } // namespace dynamic diff --git a/lib/ASTMatchers/Dynamic/Registry.cpp b/lib/ASTMatchers/Dynamic/Registry.cpp index e0c72806d9..47957c760b 100644 --- a/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/lib/ASTMatchers/Dynamic/Registry.cpp @@ -63,25 +63,25 @@ class OverloadedMatcherCreateCallback : public MatcherCreateCallback { delete Overloads[i]; } - virtual MatcherList run(const SourceRange &NameRange, - ArrayRef Args, - Diagnostics *Error) const { - std::vector Constructed; + virtual VariantMatcher 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()) { + VariantMatcher SubMatcher = Overloads[i]->run(NameRange, Args, Error); + if (!SubMatcher.isNull()) { Constructed.push_back(SubMatcher); } } - if (Constructed.empty()) return MatcherList(); // No overload matched. + if (Constructed.empty()) return VariantMatcher(); // 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 VariantMatcher(); } return Constructed[0]; } @@ -405,38 +405,38 @@ static llvm::ManagedStatic RegistryData; } // anonymous namespace // static -MatcherList Registry::constructMatcher(StringRef MatcherName, - const SourceRange &NameRange, - ArrayRef Args, - Diagnostics *Error) { +VariantMatcher Registry::constructMatcher(StringRef MatcherName, + const SourceRange &NameRange, + ArrayRef Args, + Diagnostics *Error) { ConstructorMap::const_iterator it = RegistryData->constructors().find(MatcherName); if (it == RegistryData->constructors().end()) { Error->addError(NameRange, Error->ET_RegistryNotFound) << MatcherName; - return MatcherList(); + return VariantMatcher(); } return it->second->run(NameRange, Args, Error); } // static -MatcherList Registry::constructBoundMatcher(StringRef MatcherName, - const SourceRange &NameRange, - StringRef BindID, - ArrayRef Args, - Diagnostics *Error) { - MatcherList Out = constructMatcher(MatcherName, NameRange, Args, Error); - if (Out.empty()) return Out; - - ArrayRef Matchers = Out.matchers(); - if (Matchers.size() == 1) { - OwningPtr Bound(Matchers[0]->tryBind(BindID)); +VariantMatcher Registry::constructBoundMatcher(StringRef MatcherName, + const SourceRange &NameRange, + StringRef BindID, + ArrayRef Args, + Diagnostics *Error) { + VariantMatcher Out = constructMatcher(MatcherName, NameRange, Args, Error); + if (Out.isNull()) return Out; + + const DynTypedMatcher *Result; + if (Out.getSingleMatcher(Result)) { + OwningPtr Bound(Result->tryBind(BindID)); if (Bound) { - return *Bound; + return VariantMatcher::SingleMatcher(*Bound); } } Error->addError(NameRange, Error->ET_RegistryNotBindable); - return MatcherList(); + return VariantMatcher(); } } // namespace dynamic diff --git a/lib/ASTMatchers/Dynamic/VariantValue.cpp b/lib/ASTMatchers/Dynamic/VariantValue.cpp index 79c5c8e23a..a8fd7c6bbb 100644 --- a/lib/ASTMatchers/Dynamic/VariantValue.cpp +++ b/lib/ASTMatchers/Dynamic/VariantValue.cpp @@ -15,25 +15,38 @@ #include "clang/ASTMatchers/Dynamic/VariantValue.h" #include "clang/Basic/LLVM.h" +#include "llvm/ADT/STLExtras.h" namespace clang { namespace ast_matchers { namespace dynamic { -MatcherList::MatcherList() : List() {} +VariantMatcher::VariantMatcher() : List() {} -MatcherList::MatcherList(const DynTypedMatcher &Matcher) - : List(1, Matcher.clone()) {} - -MatcherList::MatcherList(const MatcherList& Other) { +VariantMatcher::VariantMatcher(const VariantMatcher& Other) { *this = Other; } -MatcherList::~MatcherList() { +VariantMatcher VariantMatcher::SingleMatcher(const DynTypedMatcher &Matcher) { + VariantMatcher Out; + Out.List.push_back(Matcher.clone()); + return Out; +} + +VariantMatcher +VariantMatcher::PolymorphicMatcher(ArrayRef Matchers) { + VariantMatcher Out; + for (size_t i = 0, e = Matchers.size(); i != e; ++i) { + Out.List.push_back(Matchers[i]->clone()); + } + return Out; +} + +VariantMatcher::~VariantMatcher() { reset(); } -MatcherList &MatcherList::operator=(const MatcherList &Other) { +VariantMatcher &VariantMatcher::operator=(const VariantMatcher &Other) { if (this == &Other) return *this; reset(); for (size_t i = 0, e = Other.List.size(); i != e; ++i) { @@ -42,18 +55,17 @@ MatcherList &MatcherList::operator=(const MatcherList &Other) { return *this; } -void MatcherList::add(const DynTypedMatcher &Matcher) { - List.push_back(Matcher.clone()); +bool VariantMatcher::getSingleMatcher(const DynTypedMatcher *&Out) const { + if (List.size() != 1) return false; + Out = List[0]; + return true; } -void MatcherList::reset() { - for (size_t i = 0, e = List.size(); i != e; ++i) { - delete List[i]; - } - List.resize(0); +void VariantMatcher::reset() { + llvm::DeleteContainerPointers(List); } -std::string MatcherList::getTypeAsString() const { +std::string VariantMatcher::getTypeAsString() const { std::string Inner; for (size_t I = 0, E = List.size(); I != E; ++I) { if (I != 0) Inner += "|"; @@ -62,6 +74,18 @@ std::string MatcherList::getTypeAsString() const { return (Twine("Matcher<") + Inner + ">").str(); } +const DynTypedMatcher *VariantMatcher::getTypedMatcher( + bool (*CanConstructCallback)(const DynTypedMatcher &)) const { + const DynTypedMatcher *Out = NULL; + for (size_t i = 0, e = List.size(); i != e; ++i) { + if (CanConstructCallback(*List[i])) { + if (Out) return NULL; + Out = List[i]; + } + } + return Out; +} + VariantValue::VariantValue(const VariantValue &Other) : Type(VT_Nothing) { *this = Other; } @@ -74,12 +98,8 @@ VariantValue::VariantValue(const std::string &String) : Type(VT_Nothing) { setString(String); } -VariantValue::VariantValue(const DynTypedMatcher &Matcher) : Type(VT_Nothing) { - setMatchers(MatcherList(Matcher)); -} - -VariantValue::VariantValue(const MatcherList &Matchers) : Type(VT_Nothing) { - setMatchers(Matchers); +VariantValue::VariantValue(const VariantMatcher &Matcher) : Type(VT_Nothing) { + setMatcher(Matcher); } VariantValue::~VariantValue() { reset(); } @@ -94,8 +114,8 @@ VariantValue &VariantValue::operator=(const VariantValue &Other) { case VT_String: setString(Other.getString()); break; - case VT_Matchers: - setMatchers(Other.getMatchers()); + case VT_Matcher: + setMatcher(Other.getMatcher()); break; case VT_Nothing: Type = VT_Nothing; @@ -109,8 +129,8 @@ void VariantValue::reset() { case VT_String: delete Value.String; break; - case VT_Matchers: - delete Value.Matchers; + case VT_Matcher: + delete Value.Matcher; break; // Cases that do nothing. case VT_Unsigned: @@ -150,25 +170,25 @@ void VariantValue::setString(const std::string &NewValue) { Value.String = new std::string(NewValue); } -bool VariantValue::isMatchers() const { - return Type == VT_Matchers; +bool VariantValue::isMatcher() const { + return Type == VT_Matcher; } -const MatcherList &VariantValue::getMatchers() const { - assert(isMatchers()); - return *Value.Matchers; +const VariantMatcher &VariantValue::getMatcher() const { + assert(isMatcher()); + return *Value.Matcher; } -void VariantValue::setMatchers(const MatcherList &NewValue) { +void VariantValue::setMatcher(const VariantMatcher &NewValue) { reset(); - Type = VT_Matchers; - Value.Matchers = new MatcherList(NewValue); + Type = VT_Matcher; + Value.Matcher = new VariantMatcher(NewValue); } std::string VariantValue::getTypeAsString() const { switch (Type) { case VT_String: return "String"; - case VT_Matchers: return getMatchers().getTypeAsString(); + case VT_Matcher: return getMatcher().getTypeAsString(); case VT_Unsigned: return "Unsigned"; case VT_Nothing: return "Nothing"; } diff --git a/unittests/ASTMatchers/Dynamic/ParserTest.cpp b/unittests/ASTMatchers/Dynamic/ParserTest.cpp index d9b2d3c87f..71b0f87e02 100644 --- a/unittests/ASTMatchers/Dynamic/ParserTest.cpp +++ b/unittests/ASTMatchers/Dynamic/ParserTest.cpp @@ -76,16 +76,16 @@ public: Errors.push_back(Error.toStringFull()); } - MatcherList actOnMatcherExpression(StringRef MatcherName, - const SourceRange &NameRange, - StringRef BindID, - ArrayRef Args, - Diagnostics *Error) { + VariantMatcher actOnMatcherExpression(StringRef MatcherName, + const SourceRange &NameRange, + StringRef BindID, + ArrayRef Args, + Diagnostics *Error) { MatcherInfo ToStore = { MatcherName, NameRange, Args, BindID }; Matchers.push_back(ToStore); DummyDynTypedMatcher Matcher(ExpectedMatchers[MatcherName]); OwningPtr Out(Matcher.tryBind(BindID)); - return *Out; + return VariantMatcher::SingleMatcher(*Out); } struct MatcherInfo { @@ -137,6 +137,12 @@ bool matchesRange(const SourceRange &Range, unsigned StartLine, Range.Start.Column == StartColumn && Range.End.Column == EndColumn; } +const DynTypedMatcher *getSingleMatcher(const VariantValue &value) { + const DynTypedMatcher *Out; + EXPECT_TRUE(value.getMatcher().getSingleMatcher(Out)); + return Out; +} + TEST(ParserTest, ParseMatcher) { MockSema Sema; const uint64_t ExpectedFoo = Sema.expectMatcher("Foo"); @@ -148,9 +154,9 @@ TEST(ParserTest, ParseMatcher) { } EXPECT_EQ(1ULL, Sema.Values.size()); - EXPECT_EQ(ExpectedFoo, Sema.Values[0].getMatchers().matchers()[0]->getID()); + EXPECT_EQ(ExpectedFoo, getSingleMatcher(Sema.Values[0])->getID()); EXPECT_EQ("Yo!", static_cast( - Sema.Values[0].getMatchers().matchers()[0])->boundID()); + getSingleMatcher(Sema.Values[0]))->boundID()); EXPECT_EQ(3ULL, Sema.Matchers.size()); const MockSema::MatcherInfo Bar = Sema.Matchers[0]; @@ -169,10 +175,8 @@ TEST(ParserTest, ParseMatcher) { EXPECT_EQ("Foo", Foo.MatcherName); EXPECT_TRUE(matchesRange(Foo.NameRange, 1, 2, 2, 12)); EXPECT_EQ(2ULL, Foo.Args.size()); - EXPECT_EQ(ExpectedBar, - Foo.Args[0].Value.getMatchers().matchers()[0]->getID()); - EXPECT_EQ(ExpectedBaz, - Foo.Args[1].Value.getMatchers().matchers()[0]->getID()); + EXPECT_EQ(ExpectedBar, getSingleMatcher(Foo.Args[0].Value)->getID()); + EXPECT_EQ(ExpectedBaz, getSingleMatcher(Foo.Args[1].Value)->getID()); EXPECT_EQ("Yo!", Foo.BoundID); } diff --git a/unittests/ASTMatchers/Dynamic/RegistryTest.cpp b/unittests/ASTMatchers/Dynamic/RegistryTest.cpp index 7f49b6a4ac..55490a5bab 100644 --- a/unittests/ASTMatchers/Dynamic/RegistryTest.cpp +++ b/unittests/ASTMatchers/Dynamic/RegistryTest.cpp @@ -36,32 +36,34 @@ public: return Out; } - MatcherList constructMatcher(StringRef MatcherName, - Diagnostics *Error = NULL) { + VariantMatcher constructMatcher(StringRef MatcherName, + Diagnostics *Error = NULL) { Diagnostics DummyError; if (!Error) Error = &DummyError; - const MatcherList Out = + const VariantMatcher Out = Registry::constructMatcher(MatcherName, SourceRange(), Args(), Error); EXPECT_EQ("", DummyError.toStringFull()); return Out; } - MatcherList constructMatcher(StringRef MatcherName, const VariantValue &Arg1, - Diagnostics *Error = NULL) { + VariantMatcher constructMatcher(StringRef MatcherName, + const VariantValue &Arg1, + Diagnostics *Error = NULL) { Diagnostics DummyError; if (!Error) Error = &DummyError; - const MatcherList Out = Registry::constructMatcher( + const VariantMatcher Out = Registry::constructMatcher( MatcherName, SourceRange(), Args(Arg1), Error); EXPECT_EQ("", DummyError.toStringFull()); return Out; } - MatcherList constructMatcher(StringRef MatcherName, const VariantValue &Arg1, - const VariantValue &Arg2, - Diagnostics *Error = NULL) { + VariantMatcher constructMatcher(StringRef MatcherName, + const VariantValue &Arg1, + const VariantValue &Arg2, + Diagnostics *Error = NULL) { Diagnostics DummyError; if (!Error) Error = &DummyError; - const MatcherList Out = Registry::constructMatcher( + const VariantMatcher Out = Registry::constructMatcher( MatcherName, SourceRange(), Args(Arg1, Arg2), Error); EXPECT_EQ("", DummyError.toStringFull()); return Out; @@ -99,11 +101,12 @@ TEST_F(RegistryTest, ConstructWithSimpleArgs) { } TEST_F(RegistryTest, ConstructWithMatcherArgs) { - Matcher HasInitializerSimple = - constructMatcher("varDecl", constructMatcher("hasInitializer", stmt())) - .getTypedMatcher(); + Matcher HasInitializerSimple = constructMatcher( + "varDecl", constructMatcher("hasInitializer", constructMatcher("stmt"))) + .getTypedMatcher(); Matcher HasInitializerComplex = constructMatcher( - "varDecl", constructMatcher("hasInitializer", callExpr())) + "varDecl", + constructMatcher("hasInitializer", constructMatcher("callExpr"))) .getTypedMatcher(); std::string code = "int i;"; @@ -118,8 +121,10 @@ TEST_F(RegistryTest, ConstructWithMatcherArgs) { EXPECT_TRUE(matches(code, HasInitializerSimple)); EXPECT_TRUE(matches(code, HasInitializerComplex)); - Matcher HasParameter = functionDecl(constructMatcher( - "hasParameter", 1, hasName("x")).getTypedMatcher()); + Matcher HasParameter = + functionDecl(constructMatcher( + "hasParameter", 1, constructMatcher("hasName", std::string("x"))) + .getTypedMatcher()); EXPECT_TRUE(matches("void f(int a, int x);", HasParameter)); EXPECT_FALSE(matches("void f(int x, int a);", HasParameter)); } @@ -149,7 +154,7 @@ TEST_F(RegistryTest, OverloadedMatchers) { } TEST_F(RegistryTest, PolymorphicMatchers) { - const MatcherList IsDefinition = constructMatcher("isDefinition"); + const VariantMatcher IsDefinition = constructMatcher("isDefinition"); Matcher Var = constructMatcher("varDecl", IsDefinition).getTypedMatcher(); Matcher Class = @@ -165,7 +170,8 @@ TEST_F(RegistryTest, PolymorphicMatchers) { Matcher Anything = constructMatcher("anything").getTypedMatcher(); Matcher RecordDecl = - constructMatcher("recordDecl", Anything).getTypedMatcher(); + constructMatcher("recordDecl", VariantMatcher::SingleMatcher(Anything)) + .getTypedMatcher(); EXPECT_TRUE(matches("int a;", Anything)); EXPECT_TRUE(matches("class A {};", Anything)); @@ -214,8 +220,10 @@ TEST_F(RegistryTest, TypeTraversal) { TEST_F(RegistryTest, CXXCtorInitializer) { Matcher CtorDecl = constructMatcher( "constructorDecl", - constructMatcher("hasAnyConstructorInitializer", - constructMatcher("forField", hasName("foo")))) + constructMatcher( + "hasAnyConstructorInitializer", + constructMatcher("forField", + constructMatcher("hasName", std::string("foo"))))) .getTypedMatcher(); EXPECT_TRUE(matches("struct Foo { Foo() : foo(1) {} int foo; };", CtorDecl)); EXPECT_FALSE(matches("struct Foo { Foo() {} int foo; };", CtorDecl)); @@ -256,23 +264,24 @@ TEST_F(RegistryTest, Adaptative) { TEST_F(RegistryTest, Errors) { // Incorrect argument count. OwningPtr Error(new Diagnostics()); - EXPECT_TRUE(constructMatcher("hasInitializer", Error.get()).empty()); + EXPECT_TRUE(constructMatcher("hasInitializer", Error.get()).isNull()); EXPECT_EQ("Incorrect argument count. (Expected = 1) != (Actual = 0)", Error->toString()); Error.reset(new Diagnostics()); - EXPECT_TRUE(constructMatcher("isArrow", std::string(), Error.get()).empty()); + EXPECT_TRUE(constructMatcher("isArrow", std::string(), Error.get()).isNull()); EXPECT_EQ("Incorrect argument count. (Expected = 0) != (Actual = 1)", Error->toString()); // Bad argument type Error.reset(new Diagnostics()); - EXPECT_TRUE(constructMatcher("ofClass", std::string(), Error.get()).empty()); + EXPECT_TRUE(constructMatcher("ofClass", std::string(), Error.get()).isNull()); EXPECT_EQ("Incorrect type for arg 1. (Expected = Matcher) != " "(Actual = String)", Error->toString()); Error.reset(new Diagnostics()); - EXPECT_TRUE(constructMatcher("recordDecl", recordDecl(), parameterCountIs(3), - Error.get()).empty()); + EXPECT_TRUE(constructMatcher("recordDecl", constructMatcher("recordDecl"), + constructMatcher("parameterCountIs", 3), + Error.get()).isNull()); EXPECT_EQ("Incorrect type for arg 2. (Expected = Matcher) != " "(Actual = Matcher)", Error->toString()); diff --git a/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp b/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp index 625f70bd46..168741ca4d 100644 --- a/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp +++ b/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp @@ -27,7 +27,7 @@ TEST(VariantValueTest, Unsigned) { EXPECT_EQ(kUnsigned, Value.getUnsigned()); EXPECT_FALSE(Value.isString()); - EXPECT_FALSE(Value.isMatchers()); + EXPECT_FALSE(Value.isMatcher()); EXPECT_FALSE(Value.hasTypedMatcher()); EXPECT_FALSE(Value.hasTypedMatcher()); } @@ -41,29 +41,29 @@ TEST(VariantValueTest, String) { EXPECT_EQ("String", Value.getTypeAsString()); EXPECT_FALSE(Value.isUnsigned()); - EXPECT_FALSE(Value.isMatchers()); + EXPECT_FALSE(Value.isMatcher()); } TEST(VariantValueTest, DynTypedMatcher) { - VariantValue Value = stmt(); + VariantValue Value = VariantMatcher::SingleMatcher(stmt()); EXPECT_FALSE(Value.isUnsigned()); EXPECT_FALSE(Value.isString()); - EXPECT_TRUE(Value.isMatchers()); + EXPECT_TRUE(Value.isMatcher()); EXPECT_FALSE(Value.hasTypedMatcher()); EXPECT_TRUE(Value.hasTypedMatcher()); EXPECT_EQ("Matcher", Value.getTypeAsString()); // Can only convert to compatible matchers. - Value = recordDecl(); - EXPECT_TRUE(Value.isMatchers()); + Value = VariantMatcher::SingleMatcher(recordDecl()); + EXPECT_TRUE(Value.isMatcher()); EXPECT_TRUE(Value.hasTypedMatcher()); EXPECT_FALSE(Value.hasTypedMatcher()); EXPECT_EQ("Matcher", Value.getTypeAsString()); - Value = ignoringImpCasts(expr()); - EXPECT_TRUE(Value.isMatchers()); + Value = VariantMatcher::SingleMatcher(ignoringImpCasts(expr())); + EXPECT_TRUE(Value.isMatcher()); EXPECT_FALSE(Value.hasTypedMatcher()); EXPECT_FALSE(Value.hasTypedMatcher()); EXPECT_TRUE(Value.hasTypedMatcher()); @@ -77,13 +77,13 @@ TEST(VariantValueTest, Assignment) { EXPECT_TRUE(Value.isString()); EXPECT_EQ("A", Value.getString()); EXPECT_FALSE(Value.isUnsigned()); - EXPECT_FALSE(Value.isMatchers()); + EXPECT_FALSE(Value.isMatcher()); EXPECT_EQ("String", Value.getTypeAsString()); - Value = recordDecl(); + Value = VariantMatcher::SingleMatcher(recordDecl()); EXPECT_FALSE(Value.isUnsigned()); EXPECT_FALSE(Value.isString()); - EXPECT_TRUE(Value.isMatchers()); + EXPECT_TRUE(Value.isMatcher()); EXPECT_TRUE(Value.hasTypedMatcher()); EXPECT_FALSE(Value.hasTypedMatcher()); EXPECT_EQ("Matcher", Value.getTypeAsString()); @@ -91,39 +91,46 @@ TEST(VariantValueTest, Assignment) { Value = 17; EXPECT_TRUE(Value.isUnsigned()); EXPECT_EQ(17U, Value.getUnsigned()); - EXPECT_FALSE(Value.isMatchers()); + EXPECT_FALSE(Value.isMatcher()); EXPECT_FALSE(Value.isString()); Value = VariantValue(); EXPECT_FALSE(Value.isUnsigned()); EXPECT_FALSE(Value.isString()); - EXPECT_FALSE(Value.isMatchers()); + EXPECT_FALSE(Value.isMatcher()); EXPECT_EQ("Nothing", Value.getTypeAsString()); } TEST(VariantValueTest, Matcher) { - EXPECT_TRUE(matches("class X {};", VariantValue(recordDecl(hasName("X"))) + EXPECT_TRUE(matches("class X {};", VariantValue(VariantMatcher::SingleMatcher( + recordDecl(hasName("X")))) .getTypedMatcher())); + EXPECT_TRUE(matches("int x;", + VariantValue(VariantMatcher::SingleMatcher(varDecl())) + .getTypedMatcher())); EXPECT_TRUE( - matches("int x;", VariantValue(varDecl()).getTypedMatcher())); - EXPECT_TRUE(matches("int foo() { return 1 + 1; }", - VariantValue(functionDecl()).getTypedMatcher())); + matches("int foo() { return 1 + 1; }", + VariantValue(VariantMatcher::SingleMatcher(functionDecl())) + .getTypedMatcher())); // Can't get the wrong matcher. - EXPECT_FALSE(VariantValue(varDecl()).hasTypedMatcher()); + EXPECT_FALSE(VariantValue(VariantMatcher::SingleMatcher(varDecl())) + .hasTypedMatcher()); #if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST && !defined(_MSC_VER) // Trying to get the wrong matcher fails an assertion in Matcher. We don't // do this test when building with MSVC because its debug C runtime prints the // assertion failure message as a wide string, which gtest doesn't understand. - EXPECT_DEATH(VariantValue(varDecl()).getTypedMatcher(), + EXPECT_DEATH(VariantValue(VariantMatcher::SingleMatcher(varDecl())) + .getTypedMatcher(), "hasTypedMatcher"); #endif - EXPECT_FALSE( - matches("int x;", VariantValue(functionDecl()).getTypedMatcher())); + EXPECT_FALSE(matches( + "int x;", VariantValue(VariantMatcher::SingleMatcher(functionDecl())) + .getTypedMatcher())); EXPECT_FALSE( matches("int foo() { return 1 + 1; }", - - VariantValue(declRefExpr()).getTypedMatcher())); + VariantValue(VariantMatcher::SingleMatcher(declRefExpr())) + .getTypedMatcher())); } } // end anonymous namespace -- 2.40.0