1 //===--- ASTMatchersInternal.cpp - Structural query framework -------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 //  Implements the base layer of the matcher framework.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "clang/ASTMatchers/ASTMatchers.h"
15 #include "clang/ASTMatchers/ASTMatchersInternal.h"
16 
17 namespace clang {
18 namespace ast_matchers {
19 namespace internal {
20 
21 void BoundNodesTreeBuilder::visitMatches(Visitor *ResultVisitor) {
22   if (Bindings.empty())
23     Bindings.push_back(BoundNodesMap());
24   for (unsigned i = 0, e = Bindings.size(); i != e; ++i) {
25     ResultVisitor->visitMatch(BoundNodes(Bindings[i]));
26   }
27 }
28 
29 bool DynTypedMatcher::canConvertTo(ast_type_traits::ASTNodeKind To) const {
30   const auto From = getSupportedKind();
31   auto QualKind = ast_type_traits::ASTNodeKind::getFromNodeKind<QualType>();
32   auto TypeKind = ast_type_traits::ASTNodeKind::getFromNodeKind<Type>();
33   /// Mimic the implicit conversions of Matcher<>.
34   /// - From Matcher<Type> to Matcher<QualType>
35   if (From.isSame(TypeKind) && To.isSame(QualKind)) return true;
36   /// - From Matcher<Base> to Matcher<Derived>
37   return From.isBaseOf(To);
38 }
39 
40 DynTypedMatcher::MatcherStorage::~MatcherStorage() {}
41 
42 void BoundNodesTreeBuilder::addMatch(const BoundNodesTreeBuilder &Other) {
43   for (unsigned i = 0, e = Other.Bindings.size(); i != e; ++i) {
44     Bindings.push_back(Other.Bindings[i]);
45   }
46 }
47 
48 bool NotUnaryOperator(const ast_type_traits::DynTypedNode DynNode,
49                       ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder,
50                       ArrayRef<DynTypedMatcher> InnerMatchers) {
51   if (InnerMatchers.size() != 1)
52     return false;
53 
54   // The 'unless' matcher will always discard the result:
55   // If the inner matcher doesn't match, unless returns true,
56   // but the inner matcher cannot have bound anything.
57   // If the inner matcher matches, the result is false, and
58   // any possible binding will be discarded.
59   // We still need to hand in all the bound nodes up to this
60   // point so the inner matcher can depend on bound nodes,
61   // and we need to actively discard the bound nodes, otherwise
62   // the inner matcher will reset the bound nodes if it doesn't
63   // match, but this would be inversed by 'unless'.
64   BoundNodesTreeBuilder Discard(*Builder);
65   return !InnerMatchers[0].matches(DynNode, Finder, &Discard);
66 }
67 
68 bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
69                            ASTMatchFinder *Finder,
70                            BoundNodesTreeBuilder *Builder,
71                            ArrayRef<DynTypedMatcher> InnerMatchers) {
72   // allOf leads to one matcher for each alternative in the first
73   // matcher combined with each alternative in the second matcher.
74   // Thus, we can reuse the same Builder.
75   for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) {
76     if (!InnerMatchers[i].matches(DynNode, Finder, Builder))
77       return false;
78   }
79   return true;
80 }
81 
82 bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
83                             ASTMatchFinder *Finder,
84                             BoundNodesTreeBuilder *Builder,
85                             ArrayRef<DynTypedMatcher> InnerMatchers) {
86   BoundNodesTreeBuilder Result;
87   bool Matched = false;
88   for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) {
89     BoundNodesTreeBuilder BuilderInner(*Builder);
90     if (InnerMatchers[i].matches(DynNode, Finder, &BuilderInner)) {
91       Matched = true;
92       Result.addMatch(BuilderInner);
93     }
94   }
95   *Builder = std::move(Result);
96   return Matched;
97 }
98 
99 bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
100                            ASTMatchFinder *Finder,
101                            BoundNodesTreeBuilder *Builder,
102                            ArrayRef<DynTypedMatcher> InnerMatchers) {
103   for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) {
104     BoundNodesTreeBuilder Result = *Builder;
105     if (InnerMatchers[i].matches(DynNode, Finder, &Result)) {
106       *Builder = std::move(Result);
107       return true;
108     }
109   }
110   return false;
111 }
112 
113 } // end namespace internal
114 } // end namespace ast_matchers
115 } // end namespace clang
116