#pragma once #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" #endif //===- ASTMatchersInternal.h - Structural query framework -------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // Implements the base layer of the matcher framework. // // Matchers are methods that return a Matcher which provides a method // Matches(...) which is a predicate on an AST node. The Matches method's // parameters define the context of the match, which allows matchers to recurse // or store the current node as bound to a specific string, so that it can be // retrieved later. // // In general, matchers have two parts: // 1. A function Matcher MatcherName() which returns a Matcher // based on the arguments and optionally on template type deduction based // on the arguments. Matchers form an implicit reverse hierarchy // to clang's AST class hierarchy, meaning that you can use a Matcher // everywhere a Matcher is required. // 2. An implementation of a class derived from MatcherInterface. // // The matcher functions are defined in ASTMatchers.h. To make it possible // to implement both the matcher function and the implementation of the matcher // interface in one place, ASTMatcherMacros.h defines macros that allow // implementing a matcher in a single place. // // This file contains the base classes needed to construct the actual matchers. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_ASTMATCHERS_ASTMATCHERSINTERNAL_H #define LLVM_CLANG_ASTMATCHERS_ASTMATCHERSINTERNAL_H #include "clang/AST/ASTTypeTraits.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclFriend.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/Stmt.h" #include "clang/AST/TemplateName.h" #include "clang/AST/Type.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/OperatorKinds.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Regex.h" #include #include #include #include #include #include #include #include #include #include #include #include namespace clang { class ASTContext; namespace ast_matchers { class BoundNodes; namespace internal { /// A type-list implementation. /// /// A "linked list" of types, accessible by using the ::head and ::tail /// typedefs. template struct TypeList {}; // Empty sentinel type list. template struct TypeList { /// The first type on the list. using head = T1; /// A sublist with the tail. ie everything but the head. /// /// This type is used to do recursion. TypeList<>/EmptyTypeList indicates the /// end of the list. using tail = TypeList; }; /// The empty type list. using EmptyTypeList = TypeList<>; /// Helper meta-function to determine if some type \c T is present or /// a parent type in the list. template struct TypeListContainsSuperOf { static const bool value = std::is_base_of::value || TypeListContainsSuperOf::value; }; template struct TypeListContainsSuperOf { static const bool value = false; }; /// Variadic function object. /// /// Most of the functions below that use VariadicFunction could be implemented /// using plain C++11 variadic functions, but the function object allows us to /// capture it on the dynamic matcher registry. template )> struct VariadicFunction { ResultT operator()() const { return Func(std::nullopt); } template ResultT operator()(const ArgT &Arg1, const ArgsT &... Args) const { return Execute(Arg1, static_cast(Args)...); } // We also allow calls with an already created array, in case the caller // already had it. ResultT operator()(ArrayRef Args) const { return Func(llvm::to_vector<8>(llvm::make_pointer_range(Args))); } private: // Trampoline function to allow for implicit conversions to take place // before we make the array. template ResultT Execute(const ArgsT &... Args) const { const ArgT *const ArgsArray[] = {&Args...}; return Func(ArrayRef(ArgsArray, sizeof...(ArgsT))); } }; /// Unifies obtaining the underlying type of a regular node through /// `getType` and a TypedefNameDecl node through `getUnderlyingType`. inline QualType getUnderlyingType(const Expr &Node) { return Node.getType(); } inline QualType getUnderlyingType(const ValueDecl &Node) { return Node.getType(); } inline QualType getUnderlyingType(const TypedefNameDecl &Node) { return Node.getUnderlyingType(); } inline QualType getUnderlyingType(const FriendDecl &Node) { if (const TypeSourceInfo *TSI = Node.getFriendType()) return TSI->getType(); return QualType(); } inline QualType getUnderlyingType(const CXXBaseSpecifier &Node) { return Node.getType(); } /// Unifies obtaining a `TypeSourceInfo` from different node types. template , T>::value> * = nullptr> inline TypeSourceInfo *GetTypeSourceInfo(const T &Node) { return Node.getTypeSourceInfo(); } template , T>::value> * = nullptr> inline TypeSourceInfo *GetTypeSourceInfo(const T &Node) { return Node.getTypeInfoAsWritten(); } inline TypeSourceInfo *GetTypeSourceInfo(const BlockDecl &Node) { return Node.getSignatureAsWritten(); } inline TypeSourceInfo *GetTypeSourceInfo(const CXXNewExpr &Node) { return Node.getAllocatedTypeSourceInfo(); } inline TypeSourceInfo * GetTypeSourceInfo(const ClassTemplateSpecializationDecl &Node) { return Node.getTypeAsWritten(); } /// Unifies obtaining the FunctionProtoType pointer from both /// FunctionProtoType and FunctionDecl nodes.. inline const FunctionProtoType * getFunctionProtoType(const FunctionProtoType &Node) { return &Node; } inline const FunctionProtoType *getFunctionProtoType(const FunctionDecl &Node) { return Node.getType()->getAs(); } /// Unifies obtaining the access specifier from Decl and CXXBaseSpecifier nodes. inline clang::AccessSpecifier getAccessSpecifier(const Decl &Node) { return Node.getAccess(); } inline clang::AccessSpecifier getAccessSpecifier(const CXXBaseSpecifier &Node) { return Node.getAccessSpecifier(); } /// Internal version of BoundNodes. Holds all the bound nodes. class BoundNodesMap { public: /// Adds \c Node to the map with key \c ID. /// /// The node's base type should be in NodeBaseType or it will be unaccessible. void addNode(StringRef ID, const DynTypedNode &DynNode) { NodeMap[std::string(ID)] = DynNode; } /// Returns the AST node bound to \c ID. /// /// Returns NULL if there was no node bound to \c ID or if there is a node but /// it cannot be converted to the specified type. template const T *getNodeAs(StringRef ID) const { IDToNodeMap::const_iterator It = NodeMap.find(ID); if (It == NodeMap.end()) { return nullptr; } return It->second.get(); } DynTypedNode getNode(StringRef ID) const { IDToNodeMap::const_iterator It = NodeMap.find(ID); if (It == NodeMap.end()) { return DynTypedNode(); } return It->second; } /// Imposes an order on BoundNodesMaps. bool operator<(const BoundNodesMap &Other) const { return NodeMap < Other.NodeMap; } /// A map from IDs to the bound nodes. /// /// Note that we're using std::map here, as for memoization: /// - we need a comparison operator /// - we need an assignment operator using IDToNodeMap = std::map>; const IDToNodeMap &getMap() const { return NodeMap; } /// Returns \c true if this \c BoundNodesMap can be compared, i.e. all /// stored nodes have memoization data. bool isComparable() const { for (const auto &IDAndNode : NodeMap) { if (!IDAndNode.second.getMemoizationData()) return false; } return true; } private: IDToNodeMap NodeMap; }; /// Creates BoundNodesTree objects. /// /// The tree builder is used during the matching process to insert the bound /// nodes from the Id matcher. class BoundNodesTreeBuilder { public: /// A visitor interface to visit all BoundNodes results for a /// BoundNodesTree. class Visitor { public: virtual ~Visitor() = default; /// Called multiple times during a single call to VisitMatches(...). /// /// 'BoundNodesView' contains the bound nodes for a single match. virtual void visitMatch(const BoundNodes& BoundNodesView) = 0; }; /// Add a binding from an id to a node. void setBinding(StringRef Id, const DynTypedNode &DynNode) { if (Bindings.empty()) Bindings.emplace_back(); for (BoundNodesMap &Binding : Bindings) Binding.addNode(Id, DynNode); } /// Adds a branch in the tree. void addMatch(const BoundNodesTreeBuilder &Bindings); /// Visits all matches that this BoundNodesTree represents. /// /// The ownership of 'ResultVisitor' remains at the caller. void visitMatches(Visitor* ResultVisitor); template bool removeBindings(const ExcludePredicate &Predicate) { llvm::erase_if(Bindings, Predicate); return !Bindings.empty(); } /// Imposes an order on BoundNodesTreeBuilders. bool operator<(const BoundNodesTreeBuilder &Other) const { return Bindings < Other.Bindings; } /// Returns \c true if this \c BoundNodesTreeBuilder can be compared, /// i.e. all stored node maps have memoization data. bool isComparable() const { for (const BoundNodesMap &NodesMap : Bindings) { if (!NodesMap.isComparable()) return false; } return true; } private: SmallVector Bindings; }; class ASTMatchFinder; /// Generic interface for all matchers. /// /// Used by the implementation of Matcher and DynTypedMatcher. /// In general, implement MatcherInterface or SingleNodeMatcherInterface /// instead. class DynMatcherInterface : public llvm::ThreadSafeRefCountedBase { public: virtual ~DynMatcherInterface() = default; /// Returns true if \p DynNode can be matched. /// /// May bind \p DynNode to an ID via \p Builder, or recurse into /// the AST via \p Finder. virtual bool dynMatches(const DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const = 0; virtual std::optional TraversalKind() const { return std::nullopt; } }; /// Generic interface for matchers on an AST node of type T. /// /// Implement this if your matcher may need to inspect the children or /// descendants of the node or bind matched nodes to names. If you are /// writing a simple matcher that only inspects properties of the /// current node and doesn't care about its children or descendants, /// implement SingleNodeMatcherInterface instead. template class MatcherInterface : public DynMatcherInterface { public: /// Returns true if 'Node' can be matched. /// /// May bind 'Node' to an ID via 'Builder', or recurse into /// the AST via 'Finder'. virtual bool matches(const T &Node, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const = 0; bool dynMatches(const DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const override { return matches(DynNode.getUnchecked(), Finder, Builder); } }; /// Interface for matchers that only evaluate properties on a single /// node. template class SingleNodeMatcherInterface : public MatcherInterface { public: /// Returns true if the matcher matches the provided node. /// /// A subclass must implement this instead of Matches(). virtual bool matchesNode(const T &Node) const = 0; private: /// Implements MatcherInterface::Matches. bool matches(const T &Node, ASTMatchFinder * /* Finder */, BoundNodesTreeBuilder * /* Builder */) const override { return matchesNode(Node); } }; template class Matcher; /// Matcher that works on a \c DynTypedNode. /// /// It is constructed from a \c Matcher object and redirects most calls to /// underlying matcher. /// It checks whether the \c DynTypedNode is convertible into the type of the /// underlying matcher and then do the actual match on the actual node, or /// return false if it is not convertible. class DynTypedMatcher { public: /// Takes ownership of the provided implementation pointer. template DynTypedMatcher(MatcherInterface *Implementation) : SupportedKind(ASTNodeKind::getFromNodeKind()), RestrictKind(SupportedKind), Implementation(Implementation) {} /// Construct from a variadic function. enum VariadicOperator { /// Matches nodes for which all provided matchers match. VO_AllOf, /// Matches nodes for which at least one of the provided matchers /// matches. VO_AnyOf, /// Matches nodes for which at least one of the provided matchers /// matches, but doesn't stop at the first match. VO_EachOf, /// Matches any node but executes all inner matchers to find result /// bindings. VO_Optionally, /// Matches nodes that do not match the provided matcher. /// /// Uses the variadic matcher interface, but fails if /// InnerMatchers.size() != 1. VO_UnaryNot }; static DynTypedMatcher constructVariadic(VariadicOperator Op, ASTNodeKind SupportedKind, std::vector InnerMatchers); static DynTypedMatcher constructRestrictedWrapper(const DynTypedMatcher &InnerMatcher, ASTNodeKind RestrictKind); /// Get a "true" matcher for \p NodeKind. /// /// It only checks that the node is of the right kind. static DynTypedMatcher trueMatcher(ASTNodeKind NodeKind); void setAllowBind(bool AB) { AllowBind = AB; } /// Check whether this matcher could ever match a node of kind \p Kind. /// \return \c false if this matcher will never match such a node. Otherwise, /// return \c true. bool canMatchNodesOfKind(ASTNodeKind Kind) const; /// Return a matcher that points to the same implementation, but /// restricts the node types for \p Kind. DynTypedMatcher dynCastTo(const ASTNodeKind Kind) const; /// 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); /// Returns true if the matcher matches the given \c DynNode. bool matches(const DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const; /// Same as matches(), but skips the kind check. /// /// It is faster, but the caller must ensure the node is valid for the /// kind of this matcher. bool matchesNoKindCheck(const DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const; /// Bind the specified \p ID to the matcher. /// \return A new matcher with the \p ID bound to it if this matcher supports /// binding. Otherwise, returns an empty \c std::optional<>. std::optional tryBind(StringRef ID) const; /// Returns a unique \p ID for the matcher. /// /// Casting a Matcher to Matcher creates a matcher that has the /// same \c Implementation pointer, but different \c RestrictKind. We need to /// include both in the ID to make it unique. /// /// \c MatcherIDType supports operator< and provides strict weak ordering. using MatcherIDType = std::pair; MatcherIDType getID() const { /// FIXME: Document the requirements this imposes on matcher /// implementations (no new() implementation_ during a Matches()). return std::make_pair(RestrictKind, reinterpret_cast(Implementation.get())); } /// Returns the type this matcher works on. /// /// \c matches() will always return false unless the node passed is of this /// or a derived type. ASTNodeKind getSupportedKind() const { return SupportedKind; } /// Returns \c true if the passed \c DynTypedMatcher can be converted /// to a \c Matcher. /// /// This method verifies that the underlying matcher in \c Other can process /// nodes of types T. template bool canConvertTo() const { return canConvertTo(ASTNodeKind::getFromNodeKind()); } bool canConvertTo(ASTNodeKind To) const; /// Construct a \c Matcher interface around the dynamic matcher. /// /// This method asserts that \c canConvertTo() is \c true. Callers /// should call \c canConvertTo() first to make sure that \c this is /// compatible with T. template Matcher convertTo() const { assert(canConvertTo()); return unconditionalConvertTo(); } /// Same as \c convertTo(), but does not check that the underlying /// matcher can handle a value of T. /// /// If it is not compatible, then this matcher will never match anything. template Matcher unconditionalConvertTo() const; /// Returns the \c TraversalKind respected by calls to `match()`, if any. /// /// Most matchers will not have a traversal kind set, instead relying on the /// surrounding context. For those, \c std::nullopt is returned. std::optional getTraversalKind() const { return Implementation->TraversalKind(); } private: DynTypedMatcher(ASTNodeKind SupportedKind, ASTNodeKind RestrictKind, IntrusiveRefCntPtr Implementation) : SupportedKind(SupportedKind), RestrictKind(RestrictKind), Implementation(std::move(Implementation)) {} bool AllowBind = false; ASTNodeKind SupportedKind; /// A potentially stricter node kind. /// /// It allows to perform implicit and dynamic cast of matchers without /// needing to change \c Implementation. ASTNodeKind RestrictKind; IntrusiveRefCntPtr Implementation; }; /// Wrapper of a MatcherInterface *that allows copying. /// /// A Matcher can be used anywhere a Matcher is /// required. This establishes an is-a relationship which is reverse /// to the AST hierarchy. In other words, Matcher is contravariant /// with respect to T. The relationship is built via a type conversion /// operator rather than a type hierarchy to be able to templatize the /// type hierarchy instead of spelling it out. template class Matcher { public: /// Takes ownership of the provided implementation pointer. explicit Matcher(MatcherInterface *Implementation) : Implementation(Implementation) {} /// Implicitly converts \c Other to a Matcher. /// /// Requires \c T to be derived from \c From. template Matcher(const Matcher &Other, std::enable_if_t::value && !std::is_same::value> * = nullptr) : Implementation(restrictMatcher(Other.Implementation)) { assert(Implementation.getSupportedKind().isSame( ASTNodeKind::getFromNodeKind())); } /// Implicitly converts \c Matcher to \c Matcher. /// /// The resulting matcher is not strict, i.e. ignores qualifiers. template Matcher(const Matcher &Other, std::enable_if_t::value && std::is_same::value> * = nullptr) : Implementation(new TypeToQualType(Other)) {} /// Convert \c this into a \c Matcher by applying dyn_cast<> to the /// argument. /// \c To must be a base class of \c T. template Matcher dynCastTo() const & { static_assert(std::is_base_of::value, "Invalid dynCast call."); return Matcher(Implementation); } template Matcher dynCastTo() && { static_assert(std::is_base_of::value, "Invalid dynCast call."); return Matcher(std::move(Implementation)); } /// Forwards the call to the underlying MatcherInterface pointer. bool matches(const T &Node, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const { return Implementation.matches(DynTypedNode::create(Node), Finder, Builder); } /// Returns an ID that uniquely identifies the matcher. DynTypedMatcher::MatcherIDType getID() const { return Implementation.getID(); } /// Extract the dynamic matcher. /// /// The returned matcher keeps the same restrictions as \c this and remembers /// that it is meant to support nodes of type \c T. operator DynTypedMatcher() const & { return Implementation; } operator DynTypedMatcher() && { return std::move(Implementation); } /// Allows the conversion of a \c Matcher to a \c /// Matcher. /// /// Depending on the constructor argument, the matcher is either strict, i.e. /// does only matches in the absence of qualifiers, or not, i.e. simply /// ignores any qualifiers. template class TypeToQualType : public MatcherInterface { const DynTypedMatcher InnerMatcher; public: TypeToQualType(const Matcher &InnerMatcher) : InnerMatcher(InnerMatcher) {} bool matches(const QualType &Node, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const override { if (Node.isNull()) return false; return this->InnerMatcher.matches(DynTypedNode::create(*Node), Finder, Builder); } std::optional TraversalKind() const override { return this->InnerMatcher.getTraversalKind(); } }; private: // For Matcher <=> Matcher conversions. template friend class Matcher; // For DynTypedMatcher::unconditionalConvertTo. friend class DynTypedMatcher; static DynTypedMatcher restrictMatcher(const DynTypedMatcher &Other) { return Other.dynCastTo(ASTNodeKind::getFromNodeKind()); } explicit Matcher(const DynTypedMatcher &Implementation) : Implementation(restrictMatcher(Implementation)) { assert(this->Implementation.getSupportedKind().isSame( ASTNodeKind::getFromNodeKind())); } DynTypedMatcher Implementation; }; // class Matcher /// A convenient helper for creating a Matcher without specifying /// the template type argument. template inline Matcher makeMatcher(MatcherInterface *Implementation) { return Matcher(Implementation); } /// Interface that allows matchers to traverse the AST. /// FIXME: Find a better name. /// /// This provides three entry methods for each base node type in the AST: /// - \c matchesChildOf: /// Matches a matcher on every child node of the given node. Returns true /// if at least one child node could be matched. /// - \c matchesDescendantOf: /// Matches a matcher on all descendant nodes of the given node. Returns true /// if at least one descendant matched. /// - \c matchesAncestorOf: /// Matches a matcher on all ancestors of the given node. Returns true if /// at least one ancestor matched. /// /// FIXME: Currently we only allow Stmt and Decl nodes to start a traversal. /// In the future, we want to implement this for all nodes for which it makes /// sense. In the case of matchesAncestorOf, we'll want to implement it for /// all nodes, as all nodes have ancestors. class ASTMatchFinder { public: /// Defines how bindings are processed on recursive matches. enum BindKind { /// Stop at the first match and only bind the first match. BK_First, /// Create results for all combinations of bindings that match. BK_All }; /// Defines which ancestors are considered for a match. enum AncestorMatchMode { /// All ancestors. AMM_All, /// Direct parent only. AMM_ParentOnly }; virtual ~ASTMatchFinder() = default; /// Returns true if the given C++ class is directly or indirectly derived /// from a base type matching \c base. /// /// A class is not considered to be derived from itself. virtual bool classIsDerivedFrom(const CXXRecordDecl *Declaration, const Matcher &Base, BoundNodesTreeBuilder *Builder, bool Directly) = 0; /// Returns true if the given Objective-C class is directly or indirectly /// derived from a base class matching \c base. /// /// A class is not considered to be derived from itself. virtual bool objcClassIsDerivedFrom(const ObjCInterfaceDecl *Declaration, const Matcher &Base, BoundNodesTreeBuilder *Builder, bool Directly) = 0; template bool matchesChildOf(const T &Node, const DynTypedMatcher &Matcher, BoundNodesTreeBuilder *Builder, BindKind Bind) { static_assert(std::is_base_of::value || std::is_base_of::value || std::is_base_of::value || std::is_base_of::value || std::is_base_of::value || std::is_base_of::value || std::is_base_of::value, "unsupported type for recursive matching"); return matchesChildOf(DynTypedNode::create(Node), getASTContext(), Matcher, Builder, Bind); } template bool matchesDescendantOf(const T &Node, const DynTypedMatcher &Matcher, BoundNodesTreeBuilder *Builder, BindKind Bind) { static_assert(std::is_base_of::value || std::is_base_of::value || std::is_base_of::value || std::is_base_of::value || std::is_base_of::value || std::is_base_of::value || std::is_base_of::value, "unsupported type for recursive matching"); return matchesDescendantOf(DynTypedNode::create(Node), getASTContext(), Matcher, Builder, Bind); } // FIXME: Implement support for BindKind. template bool matchesAncestorOf(const T &Node, const DynTypedMatcher &Matcher, BoundNodesTreeBuilder *Builder, AncestorMatchMode MatchMode) { static_assert(std::is_base_of::value || std::is_base_of::value || std::is_base_of::value || std::is_base_of::value || std::is_base_of::value, "type not allowed for recursive matching"); return matchesAncestorOf(DynTypedNode::create(Node), getASTContext(), Matcher, Builder, MatchMode); } virtual ASTContext &getASTContext() const = 0; virtual bool IsMatchingInASTNodeNotSpelledInSource() const = 0; virtual bool IsMatchingInASTNodeNotAsIs() const = 0; bool isTraversalIgnoringImplicitNodes() const; protected: virtual bool matchesChildOf(const DynTypedNode &Node, ASTContext &Ctx, const DynTypedMatcher &Matcher, BoundNodesTreeBuilder *Builder, BindKind Bind) = 0; virtual bool matchesDescendantOf(const DynTypedNode &Node, ASTContext &Ctx, const DynTypedMatcher &Matcher, BoundNodesTreeBuilder *Builder, BindKind Bind) = 0; virtual bool matchesAncestorOf(const DynTypedNode &Node, ASTContext &Ctx, const DynTypedMatcher &Matcher, BoundNodesTreeBuilder *Builder, AncestorMatchMode MatchMode) = 0; private: friend struct ASTChildrenNotSpelledInSourceScope; virtual bool isMatchingChildrenNotSpelledInSource() const = 0; virtual void setMatchingChildrenNotSpelledInSource(bool Set) = 0; }; struct ASTChildrenNotSpelledInSourceScope { ASTChildrenNotSpelledInSourceScope(ASTMatchFinder *V, bool B) : MV(V), MB(V->isMatchingChildrenNotSpelledInSource()) { V->setMatchingChildrenNotSpelledInSource(B); } ~ASTChildrenNotSpelledInSourceScope() { MV->setMatchingChildrenNotSpelledInSource(MB); } private: ASTMatchFinder *MV; bool MB; }; /// Specialization of the conversion functions for QualType. /// /// This specialization provides the Matcher->Matcher /// conversion that the static API does. template <> inline Matcher DynTypedMatcher::convertTo() const { assert(canConvertTo()); const ASTNodeKind SourceKind = getSupportedKind(); if (SourceKind.isSame(ASTNodeKind::getFromNodeKind())) { // We support implicit conversion from Matcher to Matcher return unconditionalConvertTo(); } return unconditionalConvertTo(); } /// Finds the first node in a range that matches the given matcher. template IteratorT matchesFirstInRange(const MatcherT &Matcher, IteratorT Start, IteratorT End, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) { for (IteratorT I = Start; I != End; ++I) { BoundNodesTreeBuilder Result(*Builder); if (Matcher.matches(*I, Finder, &Result)) { *Builder = std::move(Result); return I; } } return End; } /// Finds the first node in a pointer range that matches the given /// matcher. template IteratorT matchesFirstInPointerRange(const MatcherT &Matcher, IteratorT Start, IteratorT End, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) { for (IteratorT I = Start; I != End; ++I) { BoundNodesTreeBuilder Result(*Builder); if (Matcher.matches(**I, Finder, &Result)) { *Builder = std::move(Result); return I; } } return End; } template ::value> * = nullptr> inline bool isDefaultedHelper(const T *) { return false; } inline bool isDefaultedHelper(const FunctionDecl *FD) { return FD->isDefaulted(); } // Metafunction to determine if type T has a member called getDecl. template class has_getDecl { using yes = char[1]; using no = char[2]; template static yes& test(Inner *I, decltype(I->getDecl()) * = nullptr); template static no& test(...); public: static const bool value = sizeof(test(nullptr)) == sizeof(yes); }; /// Matches overloaded operators with a specific name. /// /// The type argument ArgT is not used by this matcher but is used by /// PolymorphicMatcher and should be StringRef. template class HasOverloadedOperatorNameMatcher : public SingleNodeMatcherInterface { static_assert(std::is_same::value || std::is_base_of::value, "unsupported class for matcher"); static_assert(std::is_same>::value, "argument type must be std::vector"); public: explicit HasOverloadedOperatorNameMatcher(std::vector Names) : SingleNodeMatcherInterface(), Names(std::move(Names)) {} bool matchesNode(const T &Node) const override { return matchesSpecialized(Node); } private: /// CXXOperatorCallExpr exist only for calls to overloaded operators /// so this function returns true if the call is to an operator of the given /// name. bool matchesSpecialized(const CXXOperatorCallExpr &Node) const { return llvm::is_contained(Names, getOperatorSpelling(Node.getOperator())); } /// Returns true only if CXXMethodDecl represents an overloaded /// operator and has the given operator name. bool matchesSpecialized(const FunctionDecl &Node) const { return Node.isOverloadedOperator() && llvm::is_contained( Names, getOperatorSpelling(Node.getOverloadedOperator())); } std::vector Names; }; /// Matches named declarations with a specific name. /// /// See \c hasName() and \c hasAnyName() in ASTMatchers.h for details. class HasNameMatcher : public SingleNodeMatcherInterface { public: explicit HasNameMatcher(std::vector Names); bool matchesNode(const NamedDecl &Node) const override; private: /// Unqualified match routine. /// /// It is much faster than the full match, but it only works for unqualified /// matches. bool matchesNodeUnqualified(const NamedDecl &Node) const; /// Full match routine /// /// Fast implementation for the simple case of a named declaration at /// namespace or RecordDecl scope. /// It is slower than matchesNodeUnqualified, but faster than /// matchesNodeFullSlow. bool matchesNodeFullFast(const NamedDecl &Node) const; /// Full match routine /// /// It generates the fully qualified name of the declaration (which is /// expensive) before trying to match. /// It is slower but simple and works on all cases. bool matchesNodeFullSlow(const NamedDecl &Node) const; bool UseUnqualifiedMatch; std::vector Names; }; /// Trampoline function to use VariadicFunction<> to construct a /// HasNameMatcher. Matcher hasAnyNameFunc(ArrayRef NameRefs); /// Trampoline function to use VariadicFunction<> to construct a /// hasAnySelector matcher. Matcher hasAnySelectorFunc( ArrayRef NameRefs); /// Matches declarations for QualType and CallExpr. /// /// Type argument DeclMatcherT is required by PolymorphicMatcher but /// not actually used. template class HasDeclarationMatcher : public MatcherInterface { static_assert(std::is_same>::value, "instantiated with wrong types"); DynTypedMatcher InnerMatcher; public: explicit HasDeclarationMatcher(const Matcher &InnerMatcher) : InnerMatcher(InnerMatcher) {} bool matches(const T &Node, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const override { return matchesSpecialized(Node, Finder, Builder); } private: /// Forwards to matching on the underlying type of the QualType. bool matchesSpecialized(const QualType &Node, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const { if (Node.isNull()) return false; return matchesSpecialized(*Node, Finder, Builder); } /// Finds the best declaration for a type and returns whether the inner /// matcher matches on it. bool matchesSpecialized(const Type &Node, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const { // DeducedType does not have declarations of its own, so // match the deduced type instead. if (const auto *S = dyn_cast(&Node)) { QualType DT = S->getDeducedType(); return !DT.isNull() ? matchesSpecialized(*DT, Finder, Builder) : false; } // First, for any types that have a declaration, extract the declaration and // match on it. if (const auto *S = dyn_cast(&Node)) { return matchesDecl(S->getDecl(), Finder, Builder); } if (const auto *S = dyn_cast(&Node)) { return matchesDecl(S->getDecl(), Finder, Builder); } if (const auto *S = dyn_cast(&Node)) { return matchesDecl(S->getDecl(), Finder, Builder); } if (const auto *S = dyn_cast(&Node)) { return matchesDecl(S->getDecl(), Finder, Builder); } if (const auto *S = dyn_cast(&Node)) { return matchesDecl(S->getDecl(), Finder, Builder); } if (const auto *S = dyn_cast(&Node)) { return matchesDecl(S->getInterface(), Finder, Builder); } // A SubstTemplateTypeParmType exists solely to mark a type substitution // on the instantiated template. As users usually want to match the // template parameter on the uninitialized template, we can always desugar // one level without loss of expressivness. // For example, given: // template struct X { T t; } class A {}; X a; // The following matcher will match, which otherwise would not: // fieldDecl(hasType(pointerType())). if (const auto *S = dyn_cast(&Node)) { return matchesSpecialized(S->getReplacementType(), Finder, Builder); } // For template specialization types, we want to match the template // declaration, as long as the type is still dependent, and otherwise the // declaration of the instantiated tag type. if (const auto *S = dyn_cast(&Node)) { if (!S->isTypeAlias() && S->isSugared()) { // If the template is non-dependent, we want to match the instantiated // tag type. // For example, given: // template struct X {}; X a; // The following matcher will match, which otherwise would not: // templateSpecializationType(hasDeclaration(cxxRecordDecl())). return matchesSpecialized(*S->desugar(), Finder, Builder); } // If the template is dependent or an alias, match the template // declaration. return matchesDecl(S->getTemplateName().getAsTemplateDecl(), Finder, Builder); } // FIXME: We desugar elaborated types. This makes the assumption that users // do never want to match on whether a type is elaborated - there are // arguments for both sides; for now, continue desugaring. if (const auto *S = dyn_cast(&Node)) { return matchesSpecialized(S->desugar(), Finder, Builder); } // Similarly types found via using declarations. // These are *usually* meaningless sugar, and this matches the historical // behavior prior to the introduction of UsingType. if (const auto *S = dyn_cast(&Node)) { return matchesSpecialized(S->desugar(), Finder, Builder); } return false; } /// Extracts the Decl the DeclRefExpr references and returns whether /// the inner matcher matches on it. bool matchesSpecialized(const DeclRefExpr &Node, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const { return matchesDecl(Node.getDecl(), Finder, Builder); } /// Extracts the Decl of the callee of a CallExpr and returns whether /// the inner matcher matches on it. bool matchesSpecialized(const CallExpr &Node, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const { return matchesDecl(Node.getCalleeDecl(), Finder, Builder); } /// Extracts the Decl of the constructor call and returns whether the /// inner matcher matches on it. bool matchesSpecialized(const CXXConstructExpr &Node, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const { return matchesDecl(Node.getConstructor(), Finder, Builder); } bool matchesSpecialized(const ObjCIvarRefExpr &Node, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const { return matchesDecl(Node.getDecl(), Finder, Builder); } /// Extracts the operator new of the new call and returns whether the /// inner matcher matches on it. bool matchesSpecialized(const CXXNewExpr &Node, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const { return matchesDecl(Node.getOperatorNew(), Finder, Builder); } /// Extracts the \c ValueDecl a \c MemberExpr refers to and returns /// whether the inner matcher matches on it. bool matchesSpecialized(const MemberExpr &Node, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const { return matchesDecl(Node.getMemberDecl(), Finder, Builder); } /// Extracts the \c LabelDecl a \c AddrLabelExpr refers to and returns /// whether the inner matcher matches on it. bool matchesSpecialized(const AddrLabelExpr &Node, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const { return matchesDecl(Node.getLabel(), Finder, Builder); } /// Extracts the declaration of a LabelStmt and returns whether the /// inner matcher matches on it. bool matchesSpecialized(const LabelStmt &Node, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const { return matchesDecl(Node.getDecl(), Finder, Builder); } /// Returns whether the inner matcher \c Node. Returns false if \c Node /// is \c NULL. bool matchesDecl(const Decl *Node, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const { return Node != nullptr && !(Finder->isTraversalIgnoringImplicitNodes() && Node->isImplicit()) && this->InnerMatcher.matches(DynTypedNode::create(*Node), Finder, Builder); } }; /// IsBaseType::value is true if T is a "base" type in the AST /// node class hierarchies. template struct IsBaseType { static const bool value = std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value; }; template const bool IsBaseType::value; /// A "type list" that contains all types. /// /// Useful for matchers like \c anything and \c unless. using AllNodeBaseTypes = TypeList; /// Helper meta-function to extract the argument out of a function of /// type void(Arg). /// /// See AST_POLYMORPHIC_SUPPORTED_TYPES for details. template struct ExtractFunctionArgMeta; template struct ExtractFunctionArgMeta { using type = T; }; template constexpr T *new_from_tuple_impl(Tuple &&t, std::index_sequence) { return new T(std::get(std::forward(t))...); } template constexpr T *new_from_tuple(Tuple &&t) { return new_from_tuple_impl( std::forward(t), std::make_index_sequence< std::tuple_size>::value>{}); } /// Default type lists for ArgumentAdaptingMatcher matchers. using AdaptativeDefaultFromTypes = AllNodeBaseTypes; using AdaptativeDefaultToTypes = TypeList; /// All types that are supported by HasDeclarationMatcher above. using HasDeclarationSupportedTypes = TypeList; /// A Matcher that allows binding the node it matches to an id. /// /// BindableMatcher provides a \a bind() method that allows binding the /// matched node to an id if the match was successful. template class BindableMatcher : public Matcher { public: explicit BindableMatcher(const Matcher &M) : Matcher(M) {} explicit BindableMatcher(MatcherInterface *Implementation) : Matcher(Implementation) {} /// Returns a matcher that will bind the matched node on a match. /// /// The returned matcher is equivalent to this matcher, but will /// bind the matched node on a match. Matcher bind(StringRef ID) const { return DynTypedMatcher(*this) .tryBind(ID) ->template unconditionalConvertTo(); } /// Same as Matcher's conversion operator, but enables binding on /// the returned matcher. operator DynTypedMatcher() const { DynTypedMatcher Result = static_cast &>(*this); Result.setAllowBind(true); return Result; } }; /// Matches any instance of the given NodeType. /// /// This is useful when a matcher syntactically requires a child matcher, /// but the context doesn't care. See for example: anything(). class TrueMatcher { public: using ReturnTypes = AllNodeBaseTypes; template operator Matcher() const { return DynTypedMatcher::trueMatcher(ASTNodeKind::getFromNodeKind()) .template unconditionalConvertTo(); } }; /// Creates a Matcher that matches if all inner matchers match. template BindableMatcher makeAllOfComposite(ArrayRef *> InnerMatchers) { // For the size() == 0 case, we return a "true" matcher. if (InnerMatchers.empty()) { return BindableMatcher(TrueMatcher()); } // For the size() == 1 case, we simply return that one matcher. // No need to wrap it in a variadic operation. if (InnerMatchers.size() == 1) { return BindableMatcher(*InnerMatchers[0]); } using PI = llvm::pointee_iterator *const *>; std::vector DynMatchers(PI(InnerMatchers.begin()), PI(InnerMatchers.end())); return BindableMatcher( DynTypedMatcher::constructVariadic(DynTypedMatcher::VO_AllOf, ASTNodeKind::getFromNodeKind(), std::move(DynMatchers)) .template unconditionalConvertTo()); } /// Creates a Matcher that matches if /// T is dyn_cast'able into InnerT and all inner matchers match. /// /// Returns BindableMatcher, as matchers that use dyn_cast have /// the same object both to match on and to run submatchers on, /// so there is no ambiguity with what gets bound. template BindableMatcher makeDynCastAllOfComposite(ArrayRef *> InnerMatchers) { return BindableMatcher( makeAllOfComposite(InnerMatchers).template dynCastTo()); } /// A VariadicDynCastAllOfMatcher object is a /// variadic functor that takes a number of Matcher and returns a /// Matcher that matches TargetT nodes that are matched by all of the /// given matchers, if SourceT can be dynamically casted into TargetT. /// /// For example: /// const VariadicDynCastAllOfMatcher record; /// Creates a functor record(...) that creates a Matcher given /// a variable number of arguments of type Matcher. /// The returned matcher matches if the given Decl can by dynamically /// casted to CXXRecordDecl and all given matchers match. template class VariadicDynCastAllOfMatcher : public VariadicFunction, Matcher, makeDynCastAllOfComposite> { public: VariadicDynCastAllOfMatcher() {} }; /// A \c VariadicAllOfMatcher object is a variadic functor that takes /// a number of \c Matcher and returns a \c Matcher that matches \c T /// nodes that are matched by all of the given matchers. /// /// For example: /// const VariadicAllOfMatcher nestedNameSpecifier; /// Creates a functor nestedNameSpecifier(...) that creates a /// \c Matcher given a variable number of arguments of type /// \c Matcher. /// The returned matcher matches if all given matchers match. template class VariadicAllOfMatcher : public VariadicFunction, Matcher, makeAllOfComposite> { public: VariadicAllOfMatcher() {} }; /// VariadicOperatorMatcher related types. /// @{ /// Polymorphic matcher object that uses a \c /// DynTypedMatcher::VariadicOperator operator. /// /// Input matchers can have any type (including other polymorphic matcher /// types), and the actual Matcher is generated on demand with an implicit /// conversion operator. template class VariadicOperatorMatcher { public: VariadicOperatorMatcher(DynTypedMatcher::VariadicOperator Op, Ps &&... Params) : Op(Op), Params(std::forward(Params)...) {} template operator Matcher() const & { return DynTypedMatcher::constructVariadic( Op, ASTNodeKind::getFromNodeKind(), getMatchers(std::index_sequence_for())) .template unconditionalConvertTo(); } template operator Matcher() && { return DynTypedMatcher::constructVariadic( Op, ASTNodeKind::getFromNodeKind(), getMatchers(std::index_sequence_for())) .template unconditionalConvertTo(); } private: // Helper method to unpack the tuple into a vector. template std::vector getMatchers(std::index_sequence) const & { return {Matcher(std::get(Params))...}; } template std::vector getMatchers(std::index_sequence) && { return {Matcher(std::get(std::move(Params)))...}; } const DynTypedMatcher::VariadicOperator Op; std::tuple Params; }; /// Overloaded function object to generate VariadicOperatorMatcher /// objects from arbitrary matchers. template struct VariadicOperatorMatcherFunc { DynTypedMatcher::VariadicOperator Op; template VariadicOperatorMatcher operator()(Ms &&... Ps) const { static_assert(MinCount <= sizeof...(Ms) && sizeof...(Ms) <= MaxCount, "invalid number of parameters for variadic matcher"); return VariadicOperatorMatcher(Op, std::forward(Ps)...); } }; template struct GetCladeImpl { using Type = Head; }; template struct GetCladeImpl : GetCladeImpl::value, typename Tail::head, typename Tail::tail> {}; template struct GetClade : GetCladeImpl {}; template struct MapAnyOfMatcherImpl { template BindableMatcher operator()(InnerMatchers &&... InnerMatcher) const { return VariadicAllOfMatcher()(std::apply( internal::VariadicOperatorMatcherFunc< 0, std::numeric_limits::max()>{ internal::DynTypedMatcher::VO_AnyOf}, std::apply( [&](auto... Matcher) { return std::make_tuple(Matcher(InnerMatcher...)...); }, std::tuple< VariadicDynCastAllOfMatcher...>()))); } }; template using MapAnyOfMatcher = MapAnyOfMatcherImpl::Type, MatcherTypes...>; template struct MapAnyOfHelper { using CladeType = typename GetClade::Type; MapAnyOfMatcher with; operator BindableMatcher() const { return with(); } Matcher bind(StringRef ID) const { return with().bind(ID); } }; template