blob: 9d77cb65767f75b1b9ffb103c1bfca2b70d5aae7 [file] [log] [blame]
Manuel Klimek04616e42012-07-06 05:48:52 +00001//===--- 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"
Samuel Benzaquen96039d72014-10-09 19:28:18 +000016#include "llvm/Support/ManagedStatic.h"
Manuel Klimek04616e42012-07-06 05:48:52 +000017
18namespace clang {
19namespace ast_matchers {
20namespace internal {
21
Manuel Klimeka0c025f2013-06-19 15:42:45 +000022void BoundNodesTreeBuilder::visitMatches(Visitor *ResultVisitor) {
23 if (Bindings.empty())
24 Bindings.push_back(BoundNodesMap());
25 for (unsigned i = 0, e = Bindings.size(); i != e; ++i) {
26 ResultVisitor->visitMatch(BoundNodes(Bindings[i]));
Manuel Klimek021d56f2012-08-28 23:26:39 +000027 }
28}
29
Samuel Benzaquenf28d9972014-10-01 15:08:07 +000030namespace {
31
32class VariadicMatcher : public DynMatcherInterface {
33 public:
34 VariadicMatcher(VariadicOperatorFunction Func,
35 std::vector<DynTypedMatcher> InnerMatchers)
36 : Func(Func), InnerMatchers(std::move(InnerMatchers)) {}
37
38 bool dynMatches(const ast_type_traits::DynTypedNode &DynNode,
39 ASTMatchFinder *Finder,
40 BoundNodesTreeBuilder *Builder) const override {
41 return Func(DynNode, Finder, Builder, InnerMatchers);
42 }
43
44 private:
45 VariadicOperatorFunction Func;
46 std::vector<DynTypedMatcher> InnerMatchers;
47};
48
49class IdDynMatcher : public DynMatcherInterface {
50 public:
51 IdDynMatcher(StringRef ID,
52 const IntrusiveRefCntPtr<DynMatcherInterface> &InnerMatcher)
53 : ID(ID), InnerMatcher(InnerMatcher) {}
54
55 bool dynMatches(const ast_type_traits::DynTypedNode &DynNode,
56 ASTMatchFinder *Finder,
57 BoundNodesTreeBuilder *Builder) const override {
58 bool Result = InnerMatcher->dynMatches(DynNode, Finder, Builder);
59 if (Result) Builder->setBinding(ID, DynNode);
60 return Result;
61 }
62
63 private:
64 const std::string ID;
65 const IntrusiveRefCntPtr<DynMatcherInterface> InnerMatcher;
66};
67
Samuel Benzaquen96039d72014-10-09 19:28:18 +000068/// \brief A matcher that always returns true.
69///
70/// We only ever need one instance of this matcher, so we create a global one
71/// and reuse it to reduce the overhead of the matcher and increase the chance
72/// of cache hits.
73struct TrueMatcherImpl {
74 TrueMatcherImpl() : Instance(new Impl) {}
75 const IntrusiveRefCntPtr<DynMatcherInterface> Instance;
76
77 class Impl : public DynMatcherInterface {
78 public:
79 bool dynMatches(const ast_type_traits::DynTypedNode &, ASTMatchFinder *,
80 BoundNodesTreeBuilder *) const override {
81 return true;
82 }
83 };
84};
85static llvm::ManagedStatic<TrueMatcherImpl> TrueMatcherInstance;
86
Samuel Benzaquenf28d9972014-10-01 15:08:07 +000087} // namespace
88
89DynTypedMatcher DynTypedMatcher::constructVariadic(
90 VariadicOperatorFunction Func, std::vector<DynTypedMatcher> InnerMatchers) {
91 assert(InnerMatchers.size() > 0 && "Array must not be empty.");
Samuel Benzaquen20099602014-10-13 17:38:12 +000092 assert(std::all_of(InnerMatchers.begin(), InnerMatchers.end(),
93 [&InnerMatchers](const DynTypedMatcher &M) {
94 return InnerMatchers[0].SupportedKind.isSame(M.SupportedKind);
95 }) &&
96 "SupportedKind must match!");
97
98 // We must relax the restrict kind here.
99 // The different operators might deal differently with a mismatch.
100 // Make it the same as SupportedKind, since that is the broadest type we are
101 // allowed to accept.
Samuel Benzaquen193d87f2014-10-13 18:17:11 +0000102 auto SupportedKind = InnerMatchers[0].SupportedKind;
103 return DynTypedMatcher(SupportedKind, SupportedKind,
Samuel Benzaquen20099602014-10-13 17:38:12 +0000104 new VariadicMatcher(Func, std::move(InnerMatchers)));
Samuel Benzaquenf28d9972014-10-01 15:08:07 +0000105}
106
Samuel Benzaquen96039d72014-10-09 19:28:18 +0000107DynTypedMatcher DynTypedMatcher::trueMatcher(
108 ast_type_traits::ASTNodeKind NodeKind) {
109 return DynTypedMatcher(NodeKind, NodeKind, TrueMatcherInstance->Instance);
110}
111
Samuel Benzaquenf28d9972014-10-01 15:08:07 +0000112DynTypedMatcher DynTypedMatcher::dynCastTo(
113 const ast_type_traits::ASTNodeKind Kind) const {
114 auto Copy = *this;
115 Copy.SupportedKind = Kind;
Samuel Benzaquena1170022014-10-06 13:14:30 +0000116 Copy.RestrictKind =
117 ast_type_traits::ASTNodeKind::getMostDerivedType(Kind, RestrictKind);
Samuel Benzaquenf28d9972014-10-01 15:08:07 +0000118 return Copy;
119}
120
121bool DynTypedMatcher::matches(const ast_type_traits::DynTypedNode &DynNode,
122 ASTMatchFinder *Finder,
123 BoundNodesTreeBuilder *Builder) const {
124 if (RestrictKind.isBaseOf(DynNode.getNodeKind()) &&
125 Implementation->dynMatches(DynNode, Finder, Builder)) {
126 return true;
127 }
128 // Delete all bindings when a matcher does not match.
129 // This prevents unexpected exposure of bound nodes in unmatches
130 // branches of the match tree.
131 Builder->removeBindings([](const BoundNodesMap &) { return true; });
132 return false;
133}
134
135llvm::Optional<DynTypedMatcher> DynTypedMatcher::tryBind(StringRef ID) const {
136 if (!AllowBind) return llvm::None;
137 auto Result = *this;
138 Result.Implementation = new IdDynMatcher(ID, Result.Implementation);
139 return Result;
140}
141
Samuel Benzaquenab005ed2014-09-04 14:13:58 +0000142bool DynTypedMatcher::canConvertTo(ast_type_traits::ASTNodeKind To) const {
143 const auto From = getSupportedKind();
144 auto QualKind = ast_type_traits::ASTNodeKind::getFromNodeKind<QualType>();
145 auto TypeKind = ast_type_traits::ASTNodeKind::getFromNodeKind<Type>();
146 /// Mimic the implicit conversions of Matcher<>.
147 /// - From Matcher<Type> to Matcher<QualType>
148 if (From.isSame(TypeKind) && To.isSame(QualKind)) return true;
149 /// - From Matcher<Base> to Matcher<Derived>
150 return From.isBaseOf(To);
151}
152
Manuel Klimeka0c025f2013-06-19 15:42:45 +0000153void BoundNodesTreeBuilder::addMatch(const BoundNodesTreeBuilder &Other) {
154 for (unsigned i = 0, e = Other.Bindings.size(); i != e; ++i) {
155 Bindings.push_back(Other.Bindings[i]);
Daniel Jasper94a56852012-11-16 18:39:22 +0000156 }
Manuel Klimek021d56f2012-08-28 23:26:39 +0000157}
158
Samuel Benzaquen4d058742013-11-22 14:41:48 +0000159bool NotUnaryOperator(const ast_type_traits::DynTypedNode DynNode,
160 ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder,
161 ArrayRef<DynTypedMatcher> InnerMatchers) {
162 if (InnerMatchers.size() != 1)
163 return false;
164
165 // The 'unless' matcher will always discard the result:
166 // If the inner matcher doesn't match, unless returns true,
167 // but the inner matcher cannot have bound anything.
168 // If the inner matcher matches, the result is false, and
169 // any possible binding will be discarded.
170 // We still need to hand in all the bound nodes up to this
171 // point so the inner matcher can depend on bound nodes,
172 // and we need to actively discard the bound nodes, otherwise
173 // the inner matcher will reset the bound nodes if it doesn't
174 // match, but this would be inversed by 'unless'.
175 BoundNodesTreeBuilder Discard(*Builder);
176 return !InnerMatchers[0].matches(DynNode, Finder, &Discard);
177}
178
Samuel Benzaquen85ec25d2013-08-27 15:11:16 +0000179bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
180 ASTMatchFinder *Finder,
181 BoundNodesTreeBuilder *Builder,
Samuel Benzaquenf34ac3e2013-10-29 14:37:15 +0000182 ArrayRef<DynTypedMatcher> InnerMatchers) {
Samuel Benzaquen85ec25d2013-08-27 15:11:16 +0000183 // allOf leads to one matcher for each alternative in the first
184 // matcher combined with each alternative in the second matcher.
185 // Thus, we can reuse the same Builder.
186 for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) {
Samuel Benzaquenf34ac3e2013-10-29 14:37:15 +0000187 if (!InnerMatchers[i].matches(DynNode, Finder, Builder))
Samuel Benzaquen85ec25d2013-08-27 15:11:16 +0000188 return false;
189 }
190 return true;
191}
192
193bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
194 ASTMatchFinder *Finder,
195 BoundNodesTreeBuilder *Builder,
Samuel Benzaquenf34ac3e2013-10-29 14:37:15 +0000196 ArrayRef<DynTypedMatcher> InnerMatchers) {
Samuel Benzaquen85ec25d2013-08-27 15:11:16 +0000197 BoundNodesTreeBuilder Result;
198 bool Matched = false;
199 for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) {
200 BoundNodesTreeBuilder BuilderInner(*Builder);
Samuel Benzaquenf34ac3e2013-10-29 14:37:15 +0000201 if (InnerMatchers[i].matches(DynNode, Finder, &BuilderInner)) {
Samuel Benzaquen85ec25d2013-08-27 15:11:16 +0000202 Matched = true;
203 Result.addMatch(BuilderInner);
204 }
205 }
Benjamin Kramerd9c91622014-08-29 11:22:47 +0000206 *Builder = std::move(Result);
Samuel Benzaquen85ec25d2013-08-27 15:11:16 +0000207 return Matched;
208}
209
210bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
211 ASTMatchFinder *Finder,
212 BoundNodesTreeBuilder *Builder,
Samuel Benzaquenf34ac3e2013-10-29 14:37:15 +0000213 ArrayRef<DynTypedMatcher> InnerMatchers) {
Samuel Benzaquen85ec25d2013-08-27 15:11:16 +0000214 for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) {
215 BoundNodesTreeBuilder Result = *Builder;
Samuel Benzaquenf34ac3e2013-10-29 14:37:15 +0000216 if (InnerMatchers[i].matches(DynNode, Finder, &Result)) {
Benjamin Kramerd9c91622014-08-29 11:22:47 +0000217 *Builder = std::move(Result);
Samuel Benzaquen85ec25d2013-08-27 15:11:16 +0000218 return true;
219 }
220 }
221 return false;
222}
223
Manuel Klimek04616e42012-07-06 05:48:52 +0000224} // end namespace internal
225} // end namespace ast_matchers
226} // end namespace clang