jcking1034 created this revision. jcking1034 added reviewers: ymandel, tdl-g, aaron.ballman. jcking1034 requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
This contains changes to the AST Matcher infrastructure in order to provide contextual information about each matcher. This information can be useful for tasks such as performing introspection on matchers. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D113917 Files: clang/include/clang/ASTMatchers/ASTMatchersInternal.h clang/include/clang/ASTMatchers/ASTMatchersMacros.h clang/lib/ASTMatchers/ASTMatchersInternal.cpp
Index: clang/lib/ASTMatchers/ASTMatchersInternal.cpp =================================================================== --- clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -115,15 +115,19 @@ template <VariadicOperatorFunction Func> class VariadicMatcher : public DynMatcherInterface { public: - VariadicMatcher(std::vector<DynTypedMatcher> InnerMatchers) - : InnerMatchers(std::move(InnerMatchers)) {} + VariadicMatcher(std::string MatcherName, + std::vector<DynTypedMatcher> InnerMatchers) + : MatcherName(MatcherName), InnerMatchers(std::move(InnerMatchers)) {} bool dynMatches(const DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const override { return Func(DynNode, Finder, Builder, InnerMatchers); } + std::string getName() const override { return MatcherName; } + private: + const std::string MatcherName; std::vector<DynTypedMatcher> InnerMatchers; }; @@ -144,11 +148,39 @@ return InnerMatcher->TraversalKind(); } + std::string getName() const override { return InnerMatcher->getName(); } + private: const std::string ID; const IntrusiveRefCntPtr<DynMatcherInterface> InnerMatcher; }; +/// A matcher that specifies a particular name. +/// +/// The name provided to the constructor overrides any name that may be +/// specified by the `InnerMatcher`. +class NameMatcherImpl : public DynMatcherInterface { +public: + NameMatcherImpl(std::string _MatcherName, + IntrusiveRefCntPtr<DynMatcherInterface> InnerMatcher) + : MatcherName(_MatcherName), InnerMatcher(std::move(InnerMatcher)) {} + + bool dynMatches(const DynTypedNode &DynNode, ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const override { + return InnerMatcher->dynMatches(DynNode, Finder, Builder); + } + + std::string getName() const override { return MatcherName; } + + llvm::Optional<clang::TraversalKind> TraversalKind() const override { + return InnerMatcher->TraversalKind(); + } + +private: + const std::string MatcherName; + const IntrusiveRefCntPtr<DynMatcherInterface> InnerMatcher; +}; + /// A matcher that always returns true. class TrueMatcherImpl : public DynMatcherInterface { public: @@ -158,6 +190,8 @@ BoundNodesTreeBuilder *) const override { return true; } + + std::string getName() const override { return "TrueMatcher"; } }; /// A matcher that specifies a particular \c TraversalKind. @@ -180,6 +214,8 @@ return TK; } + std::string getName() const override { return InnerMatcher->getName(); } + private: clang::TraversalKind TK; IntrusiveRefCntPtr<DynMatcherInterface> InnerMatcher; @@ -219,31 +255,31 @@ RestrictKind = ASTNodeKind::getMostDerivedType(RestrictKind, IM.RestrictKind); } - return DynTypedMatcher( - SupportedKind, RestrictKind, - new VariadicMatcher<allOfVariadicOperator>(std::move(InnerMatchers))); + return DynTypedMatcher(SupportedKind, RestrictKind, + new VariadicMatcher<allOfVariadicOperator>( + "allOf", std::move(InnerMatchers))); case VO_AnyOf: - return DynTypedMatcher( - SupportedKind, RestrictKind, - new VariadicMatcher<anyOfVariadicOperator>(std::move(InnerMatchers))); + return DynTypedMatcher(SupportedKind, RestrictKind, + new VariadicMatcher<anyOfVariadicOperator>( + "anyOf", std::move(InnerMatchers))); case VO_EachOf: - return DynTypedMatcher( - SupportedKind, RestrictKind, - new VariadicMatcher<eachOfVariadicOperator>(std::move(InnerMatchers))); + return DynTypedMatcher(SupportedKind, RestrictKind, + new VariadicMatcher<eachOfVariadicOperator>( + "eachOf", std::move(InnerMatchers))); case VO_Optionally: return DynTypedMatcher(SupportedKind, RestrictKind, new VariadicMatcher<optionallyVariadicOperator>( - std::move(InnerMatchers))); + "optionally", std::move(InnerMatchers))); case VO_UnaryNot: // FIXME: Implement the Not operator to take a single matcher instead of a // vector. return DynTypedMatcher( SupportedKind, RestrictKind, - new VariadicMatcher<notUnaryOperator>(std::move(InnerMatchers))); + new VariadicMatcher<notUnaryOperator>("not", std::move(InnerMatchers))); } llvm_unreachable("Invalid Op value."); } @@ -263,6 +299,14 @@ return Copy; } +DynTypedMatcher +DynTypedMatcher::withMatcherName(std::string MatcherName) const { + auto Copy = *this; + Copy.Implementation = + new NameMatcherImpl(MatcherName, std::move(Copy.Implementation)); + return Copy; +} + DynTypedMatcher DynTypedMatcher::trueMatcher(ASTNodeKind NodeKind) { // We only ever need one instance of TrueMatcherImpl, so we create a static // instance and reuse it to reduce the overhead of the matcher and increase Index: clang/include/clang/ASTMatchers/ASTMatchersMacros.h =================================================================== --- clang/include/clang/ASTMatchers/ASTMatchersMacros.h +++ clang/include/clang/ASTMatchers/ASTMatchersMacros.h @@ -101,6 +101,7 @@ ::clang::ast_matchers::internal::ASTMatchFinder *Finder, \ ::clang::ast_matchers::internal::BoundNodesTreeBuilder \ *Builder) const override; \ + std::string getName() const override { return #DefineMatcher; } \ }; \ } \ inline ::clang::ast_matchers::internal::Matcher<Type> DefineMatcher() { \ @@ -141,6 +142,7 @@ ::clang::ast_matchers::internal::ASTMatchFinder *Finder, \ ::clang::ast_matchers::internal::BoundNodesTreeBuilder \ *Builder) const override; \ + std::string getName() const override { return #DefineMatcher; } \ \ private: \ ParamType Param; \ @@ -190,6 +192,7 @@ ::clang::ast_matchers::internal::ASTMatchFinder *Finder, \ ::clang::ast_matchers::internal::BoundNodesTreeBuilder \ *Builder) const override; \ + std::string getName() const override { return #DefineMatcher; } \ \ private: \ ParamType1 Param1; \ @@ -237,6 +240,7 @@ ::clang::ast_matchers::internal::ASTMatchFinder *Finder, \ ::clang::ast_matchers::internal::BoundNodesTreeBuilder \ *Builder) const override; \ + std::string getName() const override { return #DefineMatcher; } \ }; \ } \ inline ::clang::ast_matchers::internal::PolymorphicMatcher< \ @@ -279,6 +283,7 @@ ::clang::ast_matchers::internal::ASTMatchFinder *Finder, \ ::clang::ast_matchers::internal::BoundNodesTreeBuilder \ *Builder) const override; \ + std::string getName() const override { return #DefineMatcher; } \ \ private: \ ParamType Param; \ @@ -331,6 +336,7 @@ ::clang::ast_matchers::internal::ASTMatchFinder *Finder, \ ::clang::ast_matchers::internal::BoundNodesTreeBuilder \ *Builder) const override; \ + std::string getName() const override { return #DefineMatcher; } \ \ private: \ ParamType1 Param1; \ Index: clang/include/clang/ASTMatchers/ASTMatchersInternal.h =================================================================== --- clang/include/clang/ASTMatchers/ASTMatchersInternal.h +++ clang/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -83,6 +83,81 @@ namespace internal { +/// Helper function that obtains a name for a matcher based on its type, which +/// can be useful for cases like debugging matchers. +template <typename T> std::string makeMatcherNameFromType() { + return "Matcher<T>"; +} + +#define TYPELOC(CLASS, PARENT) \ + template <> inline std::string makeMatcherNameFromType<CLASS##TypeLoc>() { \ + return "`" #CLASS "TypeLoc` Node"; \ + } +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#include "clang/AST/TypeLocNodes.def" + +template <> inline std::string makeMatcherNameFromType<TypeLoc>() { + return "`TypeLoc` Node"; +} + +#define DECL(CLASS, PARENT) \ + template <> inline std::string makeMatcherNameFromType<CLASS##Decl>() { \ + return "`" #CLASS "Decl` Node"; \ + } +#define ABSTRACT_DECL(CLASS) +#include "clang/AST/DeclNodes.inc" + +template <> inline std::string makeMatcherNameFromType<Decl>() { + return "`Decl` Node"; +} + +#define STMT(CLASS, PARENT) \ + template <> inline std::string makeMatcherNameFromType<CLASS>() { \ + return "`" #CLASS "` Node"; \ + } +#define ABSTRACT_STMT(CLASS) +#include "clang/AST/StmtNodes.inc" + +template <> inline std::string makeMatcherNameFromType<Stmt>() { + return "`Stmt` Node"; +} + +#define TYPE(CLASS, PARENT) \ + template <> inline std::string makeMatcherNameFromType<CLASS##Type>() { \ + return "`" #CLASS "Type` Node"; \ + } +#define ABSTRACT_TYPE(CLASS, PARENT) +#include "clang/AST/TypeNodes.inc" + +template <> inline std::string makeMatcherNameFromType<Type>() { + return "`Type` Node"; +} + +#define ATTR(A) \ + template <> inline std::string makeMatcherNameFromType<A##Attr>() { \ + return "`" #A "Attr` Node"; \ + } +#include "clang/Basic/AttrList.inc" + +template <> inline std::string makeMatcherNameFromType<Attr>() { + return "`Attr` Node"; +} + +#define MAKE_MATCHER_NAME_FROM_TYPE(CLASS) \ + template <> inline std::string makeMatcherNameFromType<CLASS>() { \ + return "`" #CLASS "` Node"; \ + } +MAKE_MATCHER_NAME_FROM_TYPE(TemplateArgument) +MAKE_MATCHER_NAME_FROM_TYPE(TemplateArgumentLoc) +MAKE_MATCHER_NAME_FROM_TYPE(TemplateName) +MAKE_MATCHER_NAME_FROM_TYPE(NestedNameSpecifier) +MAKE_MATCHER_NAME_FROM_TYPE(NestedNameSpecifierLoc) +MAKE_MATCHER_NAME_FROM_TYPE(QualType) +MAKE_MATCHER_NAME_FROM_TYPE(CXXBaseSpecifier) +MAKE_MATCHER_NAME_FROM_TYPE(CXXCtorInitializer) +MAKE_MATCHER_NAME_FROM_TYPE(LambdaCapture) +#undef MAKE_MATCHER_NAME_FROM_TYPE + /// A type-list implementation. /// /// A "linked list" of types, accessible by using the ::head and ::tail @@ -357,6 +432,8 @@ virtual llvm::Optional<clang::TraversalKind> TraversalKind() const { return llvm::None; } + + virtual std::string getName() const = 0; }; /// Generic interface for matchers on an AST node of type T. @@ -381,6 +458,10 @@ BoundNodesTreeBuilder *Builder) const override { return matches(DynNode.getUnchecked<T>(), Finder, Builder); } + + std::string getName() const override { + return ::clang::ast_matchers::internal::makeMatcherNameFromType<T>(); + } }; /// Interface for matchers that only evaluate properties on a single @@ -467,12 +548,18 @@ /// restricts the node types for \p Kind. DynTypedMatcher dynCastTo(const ASTNodeKind Kind) const; - /// Return a matcher that that points to the same implementation, but sets the + /// Return a matcher that points to the same implementation, but sets the /// traversal kind. /// /// If the traversal kind is already set, then \c TK overrides it. DynTypedMatcher withTraversalKind(TraversalKind TK); + /// Return a matcher that points to the same implementation, but sets the + /// name. + /// + /// If the name is already set, then \c MatcherName overrides it. + DynTypedMatcher withMatcherName(std::string MatcherName) const; + /// Returns true if the matcher matches the given \c DynNode. bool matches(const DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const; @@ -544,6 +631,8 @@ return Implementation->TraversalKind(); } + std::string getMatcherName() const { return Implementation->getName(); } + private: DynTypedMatcher(ASTNodeKind SupportedKind, ASTNodeKind RestrictKind, IntrusiveRefCntPtr<DynMatcherInterface> Implementation) @@ -663,6 +752,8 @@ } }; + std::string getMatcherName() const { return Implementation.getMatcherName(); } + private: // For Matcher<T> <=> Matcher<U> conversions. template <typename U> friend class Matcher; @@ -927,6 +1018,10 @@ return matchesSpecialized(Node); } + std::string getName() const override { + return "HasOverloadedOperatorNameMatcher"; + } + private: /// CXXOperatorCallExpr exist only for calls to overloaded operators @@ -956,6 +1051,8 @@ bool matchesNode(const NamedDecl &Node) const override; + std::string getName() const override { return "HasNameMatcher"; } + private: /// Unqualified match routine. /// @@ -1011,6 +1108,8 @@ return matchesSpecialized(Node, Finder, Builder); } + std::string getName() const override { return "HasDeclarationMatcher"; } + private: /// Forwards to matching on the underlying type of the QualType. bool matchesSpecialized(const QualType &Node, ASTMatchFinder *Finder, @@ -1232,6 +1331,10 @@ template <typename T> class BindableMatcher : public Matcher<T> { public: explicit BindableMatcher(const Matcher<T> &M) : Matcher<T>(M) {} + explicit BindableMatcher(const Matcher<T> &M, std::string MatcherName) + : Matcher<T>(DynTypedMatcher(M) + .withMatcherName(MatcherName) + .unconditionalConvertTo<T>()) {} explicit BindableMatcher(MatcherInterface<T> *Implementation) : Matcher<T>(Implementation) {} @@ -1303,7 +1406,8 @@ BindableMatcher<T> makeDynCastAllOfComposite(ArrayRef<const Matcher<InnerT> *> InnerMatchers) { return BindableMatcher<T>( - makeAllOfComposite(InnerMatchers).template dynCastTo<T>()); + makeAllOfComposite(InnerMatchers).template dynCastTo<T>(), + makeMatcherNameFromType<InnerT>()); } /// A VariadicDynCastAllOfMatcher<SourceT, TargetT> object is a @@ -1773,6 +1877,8 @@ return Node.getValue() == ExpectedValue; } + std::string getName() const override { return "ValueEqualsMatcher"; } + private: ValueT ExpectedValue; }; @@ -2251,6 +2357,8 @@ return OptOpName && llvm::is_contained(Names, *OptOpName); } + std::string getName() const override { return "HasAnyOperatorNameMatcher"; } + private: static Optional<StringRef> getOpName(const UnaryOperator &Node) { return Node.getOpcodeStr(Node.getOpcode());
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits