//===--- ASTMatchersInternal.cpp - Structural query framework -------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Implements the base layer of the matcher framework. // //===----------------------------------------------------------------------===// #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/ASTMatchers/ASTMatchersInternal.h" namespace clang { namespace ast_matchers { namespace internal { void BoundNodesTreeBuilder::visitMatches(Visitor *ResultVisitor) { if (Bindings.empty()) Bindings.push_back(BoundNodesMap()); for (unsigned i = 0, e = Bindings.size(); i != e; ++i) { ResultVisitor->visitMatch(BoundNodes(Bindings[i])); } } namespace { class VariadicMatcher : public DynMatcherInterface { public: VariadicMatcher(VariadicOperatorFunction Func, std::vector InnerMatchers) : Func(Func), InnerMatchers(std::move(InnerMatchers)) {} bool dynMatches(const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const override { return Func(DynNode, Finder, Builder, InnerMatchers); } private: VariadicOperatorFunction Func; std::vector InnerMatchers; }; class IdDynMatcher : public DynMatcherInterface { public: IdDynMatcher(StringRef ID, const IntrusiveRefCntPtr &InnerMatcher) : ID(ID), InnerMatcher(InnerMatcher) {} bool dynMatches(const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const override { bool Result = InnerMatcher->dynMatches(DynNode, Finder, Builder); if (Result) Builder->setBinding(ID, DynNode); return Result; } private: const std::string ID; const IntrusiveRefCntPtr InnerMatcher; }; } // namespace DynTypedMatcher DynTypedMatcher::constructVariadic( VariadicOperatorFunction Func, std::vector InnerMatchers) { assert(InnerMatchers.size() > 0 && "Array must not be empty."); DynTypedMatcher Result = InnerMatchers[0]; // Use the least derived type as the restriction for the wrapper. // This allows mismatches to be resolved on the inner matchers. for (const DynTypedMatcher &M : InnerMatchers) { assert(Result.SupportedKind.isSame(M.SupportedKind) && "SupportedKind must match!"); Result.RestrictKind = ast_type_traits::ASTNodeKind::getMostDerivedCommonAncestor( Result.RestrictKind, M.RestrictKind); } Result.Implementation = new VariadicMatcher(Func, std::move(InnerMatchers)); return Result; } DynTypedMatcher DynTypedMatcher::dynCastTo( const ast_type_traits::ASTNodeKind Kind) const { auto Copy = *this; Copy.SupportedKind = Kind; Copy.RestrictKind = ast_type_traits::ASTNodeKind::getMostDerivedType(Kind, RestrictKind); return Copy; } bool DynTypedMatcher::matches(const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const { if (RestrictKind.isBaseOf(DynNode.getNodeKind()) && Implementation->dynMatches(DynNode, Finder, Builder)) { return true; } // Delete all bindings when a matcher does not match. // This prevents unexpected exposure of bound nodes in unmatches // branches of the match tree. Builder->removeBindings([](const BoundNodesMap &) { return true; }); return false; } llvm::Optional DynTypedMatcher::tryBind(StringRef ID) const { if (!AllowBind) return llvm::None; auto Result = *this; Result.Implementation = new IdDynMatcher(ID, Result.Implementation); return Result; } bool DynTypedMatcher::canConvertTo(ast_type_traits::ASTNodeKind To) const { const auto From = getSupportedKind(); auto QualKind = ast_type_traits::ASTNodeKind::getFromNodeKind(); auto TypeKind = ast_type_traits::ASTNodeKind::getFromNodeKind(); /// Mimic the implicit conversions of Matcher<>. /// - From Matcher to Matcher if (From.isSame(TypeKind) && To.isSame(QualKind)) return true; /// - From Matcher to Matcher return From.isBaseOf(To); } void BoundNodesTreeBuilder::addMatch(const BoundNodesTreeBuilder &Other) { for (unsigned i = 0, e = Other.Bindings.size(); i != e; ++i) { Bindings.push_back(Other.Bindings[i]); } } bool NotUnaryOperator(const ast_type_traits::DynTypedNode DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef InnerMatchers) { if (InnerMatchers.size() != 1) return false; // The 'unless' matcher will always discard the result: // If the inner matcher doesn't match, unless returns true, // but the inner matcher cannot have bound anything. // If the inner matcher matches, the result is false, and // any possible binding will be discarded. // We still need to hand in all the bound nodes up to this // point so the inner matcher can depend on bound nodes, // and we need to actively discard the bound nodes, otherwise // the inner matcher will reset the bound nodes if it doesn't // match, but this would be inversed by 'unless'. BoundNodesTreeBuilder Discard(*Builder); return !InnerMatchers[0].matches(DynNode, Finder, &Discard); } bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef InnerMatchers) { // allOf leads to one matcher for each alternative in the first // matcher combined with each alternative in the second matcher. // Thus, we can reuse the same Builder. for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) { if (!InnerMatchers[i].matches(DynNode, Finder, Builder)) return false; } return true; } bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef InnerMatchers) { BoundNodesTreeBuilder Result; bool Matched = false; for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) { BoundNodesTreeBuilder BuilderInner(*Builder); if (InnerMatchers[i].matches(DynNode, Finder, &BuilderInner)) { Matched = true; Result.addMatch(BuilderInner); } } *Builder = std::move(Result); return Matched; } bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef InnerMatchers) { for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) { BoundNodesTreeBuilder Result = *Builder; if (InnerMatchers[i].matches(DynNode, Finder, &Result)) { *Builder = std::move(Result); return true; } } return false; } } // end namespace internal } // end namespace ast_matchers } // end namespace clang