blob: ed48d7718a215ac3651ea41ee97b6f4aa6b56d64 [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 Benzaquen8513d622014-10-15 14:58:46 +000016#include "llvm/ADT/SmallString.h"
Samuel Benzaquen922bef42016-02-22 21:13:02 +000017#include "llvm/ADT/SmallVector.h"
Samuel Benzaquen96039d72014-10-09 19:28:18 +000018#include "llvm/Support/ManagedStatic.h"
Manuel Klimek04616e42012-07-06 05:48:52 +000019
20namespace clang {
21namespace ast_matchers {
22namespace internal {
23
Hans Wennborgb27f2492015-07-14 16:50:14 +000024bool NotUnaryOperator(const ast_type_traits::DynTypedNode &DynNode,
Samuel Benzaquen2c15e8c2014-11-20 15:45:53 +000025 ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder,
26 ArrayRef<DynTypedMatcher> InnerMatchers);
27
Hans Wennborgb27f2492015-07-14 16:50:14 +000028bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode,
Samuel Benzaquen2c15e8c2014-11-20 15:45:53 +000029 ASTMatchFinder *Finder,
30 BoundNodesTreeBuilder *Builder,
31 ArrayRef<DynTypedMatcher> InnerMatchers);
32
Hans Wennborgb27f2492015-07-14 16:50:14 +000033bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode,
Samuel Benzaquen2c15e8c2014-11-20 15:45:53 +000034 ASTMatchFinder *Finder,
35 BoundNodesTreeBuilder *Builder,
36 ArrayRef<DynTypedMatcher> InnerMatchers);
37
Hans Wennborgb27f2492015-07-14 16:50:14 +000038bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode,
Samuel Benzaquen2c15e8c2014-11-20 15:45:53 +000039 ASTMatchFinder *Finder,
40 BoundNodesTreeBuilder *Builder,
41 ArrayRef<DynTypedMatcher> InnerMatchers);
42
43
Manuel Klimeka0c025f2013-06-19 15:42:45 +000044void BoundNodesTreeBuilder::visitMatches(Visitor *ResultVisitor) {
45 if (Bindings.empty())
46 Bindings.push_back(BoundNodesMap());
Benjamin Kramer79f15902014-10-24 13:29:15 +000047 for (BoundNodesMap &Binding : Bindings) {
48 ResultVisitor->visitMatch(BoundNodes(Binding));
Manuel Klimek021d56f2012-08-28 23:26:39 +000049 }
50}
51
Samuel Benzaquenf28d9972014-10-01 15:08:07 +000052namespace {
53
Samuel Benzaquen95636e52014-12-01 14:46:14 +000054typedef bool (*VariadicOperatorFunction)(
Hans Wennborgb27f2492015-07-14 16:50:14 +000055 const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder,
Samuel Benzaquen95636e52014-12-01 14:46:14 +000056 BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers);
57
58template <VariadicOperatorFunction Func>
Samuel Benzaquenf28d9972014-10-01 15:08:07 +000059class VariadicMatcher : public DynMatcherInterface {
Samuel Benzaquen2c15e8c2014-11-20 15:45:53 +000060public:
Samuel Benzaquen95636e52014-12-01 14:46:14 +000061 VariadicMatcher(std::vector<DynTypedMatcher> InnerMatchers)
62 : InnerMatchers(std::move(InnerMatchers)) {}
Samuel Benzaquenf28d9972014-10-01 15:08:07 +000063
64 bool dynMatches(const ast_type_traits::DynTypedNode &DynNode,
65 ASTMatchFinder *Finder,
66 BoundNodesTreeBuilder *Builder) const override {
67 return Func(DynNode, Finder, Builder, InnerMatchers);
68 }
69
Samuel Benzaquen2c15e8c2014-11-20 15:45:53 +000070private:
Samuel Benzaquenf28d9972014-10-01 15:08:07 +000071 std::vector<DynTypedMatcher> InnerMatchers;
72};
73
74class IdDynMatcher : public DynMatcherInterface {
75 public:
76 IdDynMatcher(StringRef ID,
77 const IntrusiveRefCntPtr<DynMatcherInterface> &InnerMatcher)
78 : ID(ID), InnerMatcher(InnerMatcher) {}
79
80 bool dynMatches(const ast_type_traits::DynTypedNode &DynNode,
81 ASTMatchFinder *Finder,
82 BoundNodesTreeBuilder *Builder) const override {
83 bool Result = InnerMatcher->dynMatches(DynNode, Finder, Builder);
84 if (Result) Builder->setBinding(ID, DynNode);
85 return Result;
86 }
87
88 private:
89 const std::string ID;
90 const IntrusiveRefCntPtr<DynMatcherInterface> InnerMatcher;
91};
92
Samuel Benzaquen96039d72014-10-09 19:28:18 +000093/// \brief A matcher that always returns true.
94///
95/// We only ever need one instance of this matcher, so we create a global one
96/// and reuse it to reduce the overhead of the matcher and increase the chance
97/// of cache hits.
Benjamin Kramer967c0792014-10-24 13:29:21 +000098class TrueMatcherImpl : public DynMatcherInterface {
99public:
100 TrueMatcherImpl() {
101 Retain(); // Reference count will never become zero.
102 }
103 bool dynMatches(const ast_type_traits::DynTypedNode &, ASTMatchFinder *,
104 BoundNodesTreeBuilder *) const override {
105 return true;
106 }
Samuel Benzaquen96039d72014-10-09 19:28:18 +0000107};
108static llvm::ManagedStatic<TrueMatcherImpl> TrueMatcherInstance;
109
Samuel Benzaquenf28d9972014-10-01 15:08:07 +0000110} // namespace
111
112DynTypedMatcher DynTypedMatcher::constructVariadic(
Samuel Benzaquen2c15e8c2014-11-20 15:45:53 +0000113 DynTypedMatcher::VariadicOperator Op,
Samuel Benzaquenb063f5c2015-07-17 16:05:27 +0000114 ast_type_traits::ASTNodeKind SupportedKind,
Samuel Benzaquen9743c9d2014-11-17 14:55:49 +0000115 std::vector<DynTypedMatcher> InnerMatchers) {
Samuel Benzaquenf28d9972014-10-01 15:08:07 +0000116 assert(InnerMatchers.size() > 0 && "Array must not be empty.");
Samuel Benzaquen20099602014-10-13 17:38:12 +0000117 assert(std::all_of(InnerMatchers.begin(), InnerMatchers.end(),
Samuel Benzaquenb063f5c2015-07-17 16:05:27 +0000118 [SupportedKind](const DynTypedMatcher &M) {
119 return M.canConvertTo(SupportedKind);
120 }) &&
121 "InnerMatchers must be convertible to SupportedKind!");
Samuel Benzaquen20099602014-10-13 17:38:12 +0000122
123 // We must relax the restrict kind here.
124 // The different operators might deal differently with a mismatch.
125 // Make it the same as SupportedKind, since that is the broadest type we are
126 // allowed to accept.
Samuel Benzaquen95636e52014-12-01 14:46:14 +0000127 auto RestrictKind = SupportedKind;
128
Samuel Benzaquen2c15e8c2014-11-20 15:45:53 +0000129 switch (Op) {
130 case VO_AllOf:
Samuel Benzaquen95636e52014-12-01 14:46:14 +0000131 // In the case of allOf() we must pass all the checks, so making
132 // RestrictKind the most restrictive can save us time. This way we reject
133 // invalid types earlier and we can elide the kind checks inside the
134 // matcher.
135 for (auto &IM : InnerMatchers) {
136 RestrictKind = ast_type_traits::ASTNodeKind::getMostDerivedType(
137 RestrictKind, IM.RestrictKind);
138 }
139 return DynTypedMatcher(
140 SupportedKind, RestrictKind,
141 new VariadicMatcher<AllOfVariadicOperator>(std::move(InnerMatchers)));
Samuel Benzaquen2c15e8c2014-11-20 15:45:53 +0000142
Samuel Benzaquen95636e52014-12-01 14:46:14 +0000143 case VO_AnyOf:
144 return DynTypedMatcher(
145 SupportedKind, RestrictKind,
146 new VariadicMatcher<AnyOfVariadicOperator>(std::move(InnerMatchers)));
147
148 case VO_EachOf:
149 return DynTypedMatcher(
150 SupportedKind, RestrictKind,
151 new VariadicMatcher<EachOfVariadicOperator>(std::move(InnerMatchers)));
152
153 case VO_UnaryNot:
154 // FIXME: Implement the Not operator to take a single matcher instead of a
155 // vector.
156 return DynTypedMatcher(
157 SupportedKind, RestrictKind,
158 new VariadicMatcher<NotUnaryOperator>(std::move(InnerMatchers)));
159 }
160 llvm_unreachable("Invalid Op value.");
Samuel Benzaquenf28d9972014-10-01 15:08:07 +0000161}
162
Samuel Benzaquen96039d72014-10-09 19:28:18 +0000163DynTypedMatcher DynTypedMatcher::trueMatcher(
164 ast_type_traits::ASTNodeKind NodeKind) {
Benjamin Kramer967c0792014-10-24 13:29:21 +0000165 return DynTypedMatcher(NodeKind, NodeKind, &*TrueMatcherInstance);
Samuel Benzaquen96039d72014-10-09 19:28:18 +0000166}
167
Samuel Benzaquen074bbb62014-11-24 21:21:09 +0000168bool DynTypedMatcher::canMatchNodesOfKind(
169 ast_type_traits::ASTNodeKind Kind) const {
170 return RestrictKind.isBaseOf(Kind);
171}
172
Samuel Benzaquenf28d9972014-10-01 15:08:07 +0000173DynTypedMatcher DynTypedMatcher::dynCastTo(
174 const ast_type_traits::ASTNodeKind Kind) const {
175 auto Copy = *this;
176 Copy.SupportedKind = Kind;
Samuel Benzaquena1170022014-10-06 13:14:30 +0000177 Copy.RestrictKind =
178 ast_type_traits::ASTNodeKind::getMostDerivedType(Kind, RestrictKind);
Samuel Benzaquenf28d9972014-10-01 15:08:07 +0000179 return Copy;
180}
181
182bool DynTypedMatcher::matches(const ast_type_traits::DynTypedNode &DynNode,
183 ASTMatchFinder *Finder,
184 BoundNodesTreeBuilder *Builder) const {
185 if (RestrictKind.isBaseOf(DynNode.getNodeKind()) &&
186 Implementation->dynMatches(DynNode, Finder, Builder)) {
187 return true;
188 }
189 // Delete all bindings when a matcher does not match.
190 // This prevents unexpected exposure of bound nodes in unmatches
191 // branches of the match tree.
192 Builder->removeBindings([](const BoundNodesMap &) { return true; });
193 return false;
194}
195
Samuel Benzaquen074bbb62014-11-24 21:21:09 +0000196bool DynTypedMatcher::matchesNoKindCheck(
197 const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder,
198 BoundNodesTreeBuilder *Builder) const {
199 assert(RestrictKind.isBaseOf(DynNode.getNodeKind()));
200 if (Implementation->dynMatches(DynNode, Finder, Builder)) {
201 return true;
202 }
203 // Delete all bindings when a matcher does not match.
204 // This prevents unexpected exposure of bound nodes in unmatches
205 // branches of the match tree.
206 Builder->removeBindings([](const BoundNodesMap &) { return true; });
207 return false;
208}
209
Samuel Benzaquenf28d9972014-10-01 15:08:07 +0000210llvm::Optional<DynTypedMatcher> DynTypedMatcher::tryBind(StringRef ID) const {
211 if (!AllowBind) return llvm::None;
212 auto Result = *this;
213 Result.Implementation = new IdDynMatcher(ID, Result.Implementation);
214 return Result;
215}
216
Samuel Benzaquenab005ed2014-09-04 14:13:58 +0000217bool DynTypedMatcher::canConvertTo(ast_type_traits::ASTNodeKind To) const {
218 const auto From = getSupportedKind();
219 auto QualKind = ast_type_traits::ASTNodeKind::getFromNodeKind<QualType>();
220 auto TypeKind = ast_type_traits::ASTNodeKind::getFromNodeKind<Type>();
221 /// Mimic the implicit conversions of Matcher<>.
222 /// - From Matcher<Type> to Matcher<QualType>
223 if (From.isSame(TypeKind) && To.isSame(QualKind)) return true;
224 /// - From Matcher<Base> to Matcher<Derived>
225 return From.isBaseOf(To);
226}
227
Manuel Klimeka0c025f2013-06-19 15:42:45 +0000228void BoundNodesTreeBuilder::addMatch(const BoundNodesTreeBuilder &Other) {
Benjamin Kramer79f15902014-10-24 13:29:15 +0000229 Bindings.append(Other.Bindings.begin(), Other.Bindings.end());
Manuel Klimek021d56f2012-08-28 23:26:39 +0000230}
231
Hans Wennborgb27f2492015-07-14 16:50:14 +0000232bool NotUnaryOperator(const ast_type_traits::DynTypedNode &DynNode,
Samuel Benzaquen4d058742013-11-22 14:41:48 +0000233 ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder,
234 ArrayRef<DynTypedMatcher> InnerMatchers) {
235 if (InnerMatchers.size() != 1)
236 return false;
237
238 // The 'unless' matcher will always discard the result:
239 // If the inner matcher doesn't match, unless returns true,
240 // but the inner matcher cannot have bound anything.
241 // If the inner matcher matches, the result is false, and
242 // any possible binding will be discarded.
243 // We still need to hand in all the bound nodes up to this
244 // point so the inner matcher can depend on bound nodes,
245 // and we need to actively discard the bound nodes, otherwise
246 // the inner matcher will reset the bound nodes if it doesn't
247 // match, but this would be inversed by 'unless'.
248 BoundNodesTreeBuilder Discard(*Builder);
249 return !InnerMatchers[0].matches(DynNode, Finder, &Discard);
250}
251
Hans Wennborgb27f2492015-07-14 16:50:14 +0000252bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode,
Samuel Benzaquen85ec25d2013-08-27 15:11:16 +0000253 ASTMatchFinder *Finder,
254 BoundNodesTreeBuilder *Builder,
Samuel Benzaquenf34ac3e2013-10-29 14:37:15 +0000255 ArrayRef<DynTypedMatcher> InnerMatchers) {
Samuel Benzaquen85ec25d2013-08-27 15:11:16 +0000256 // allOf leads to one matcher for each alternative in the first
257 // matcher combined with each alternative in the second matcher.
258 // Thus, we can reuse the same Builder.
Benjamin Kramer79f15902014-10-24 13:29:15 +0000259 for (const DynTypedMatcher &InnerMatcher : InnerMatchers) {
Samuel Benzaquen95636e52014-12-01 14:46:14 +0000260 if (!InnerMatcher.matchesNoKindCheck(DynNode, Finder, Builder))
Samuel Benzaquen85ec25d2013-08-27 15:11:16 +0000261 return false;
262 }
263 return true;
264}
265
Hans Wennborgb27f2492015-07-14 16:50:14 +0000266bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode,
Samuel Benzaquen85ec25d2013-08-27 15:11:16 +0000267 ASTMatchFinder *Finder,
268 BoundNodesTreeBuilder *Builder,
Samuel Benzaquenf34ac3e2013-10-29 14:37:15 +0000269 ArrayRef<DynTypedMatcher> InnerMatchers) {
Samuel Benzaquen85ec25d2013-08-27 15:11:16 +0000270 BoundNodesTreeBuilder Result;
271 bool Matched = false;
Benjamin Kramer79f15902014-10-24 13:29:15 +0000272 for (const DynTypedMatcher &InnerMatcher : InnerMatchers) {
Samuel Benzaquen85ec25d2013-08-27 15:11:16 +0000273 BoundNodesTreeBuilder BuilderInner(*Builder);
Benjamin Kramer79f15902014-10-24 13:29:15 +0000274 if (InnerMatcher.matches(DynNode, Finder, &BuilderInner)) {
Samuel Benzaquen85ec25d2013-08-27 15:11:16 +0000275 Matched = true;
276 Result.addMatch(BuilderInner);
277 }
278 }
Benjamin Kramerd9c91622014-08-29 11:22:47 +0000279 *Builder = std::move(Result);
Samuel Benzaquen85ec25d2013-08-27 15:11:16 +0000280 return Matched;
281}
282
Hans Wennborgb27f2492015-07-14 16:50:14 +0000283bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode,
Samuel Benzaquen85ec25d2013-08-27 15:11:16 +0000284 ASTMatchFinder *Finder,
285 BoundNodesTreeBuilder *Builder,
Samuel Benzaquenf34ac3e2013-10-29 14:37:15 +0000286 ArrayRef<DynTypedMatcher> InnerMatchers) {
Benjamin Kramer79f15902014-10-24 13:29:15 +0000287 for (const DynTypedMatcher &InnerMatcher : InnerMatchers) {
Samuel Benzaquen85ec25d2013-08-27 15:11:16 +0000288 BoundNodesTreeBuilder Result = *Builder;
Benjamin Kramer79f15902014-10-24 13:29:15 +0000289 if (InnerMatcher.matches(DynNode, Finder, &Result)) {
Benjamin Kramerd9c91622014-08-29 11:22:47 +0000290 *Builder = std::move(Result);
Samuel Benzaquen85ec25d2013-08-27 15:11:16 +0000291 return true;
292 }
293 }
294 return false;
295}
296
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000297Matcher<NamedDecl> hasAnyNameFunc(ArrayRef<const StringRef *> NameRefs) {
298 std::vector<std::string> Names;
299 for (auto *Name : NameRefs)
300 Names.emplace_back(*Name);
301 return internal::Matcher<NamedDecl>(
302 new internal::HasNameMatcher(std::move(Names)));
303}
304
305HasNameMatcher::HasNameMatcher(std::vector<std::string> N)
306 : UseUnqualifiedMatch(std::all_of(
307 N.begin(), N.end(),
308 [](StringRef Name) { return Name.find("::") == Name.npos; })),
309 Names(std::move(N)) {
310 for (StringRef Name : Names)
311 assert(!Name.empty());
Samuel Benzaquen8513d622014-10-15 14:58:46 +0000312}
313
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000314namespace {
315
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000316bool consumeNameSuffix(StringRef &FullName, StringRef Suffix) {
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000317 StringRef Name = FullName;
318 if (!Name.endswith(Suffix))
319 return false;
320 Name = Name.drop_back(Suffix.size());
321 if (!Name.empty()) {
322 if (!Name.endswith("::"))
323 return false;
324 Name = Name.drop_back(2);
Samuel Benzaquenb6f73bc2014-10-16 17:50:19 +0000325 }
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000326 FullName = Name;
327 return true;
328}
329
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000330StringRef getNodeName(const NamedDecl &Node, llvm::SmallString<128> &Scratch) {
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000331 // Simple name.
332 if (Node.getIdentifier())
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000333 return Node.getName();
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000334
Samuel Benzaquenb6f73bc2014-10-16 17:50:19 +0000335 if (Node.getDeclName()) {
Samuel Benzaquen8513d622014-10-15 14:58:46 +0000336 // Name needs to be constructed.
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000337 Scratch.clear();
338 llvm::raw_svector_ostream OS(Scratch);
Samuel Benzaquen8513d622014-10-15 14:58:46 +0000339 Node.printName(OS);
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000340 return OS.str();
Samuel Benzaquen8513d622014-10-15 14:58:46 +0000341 }
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000342
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000343 return "(anonymous)";
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000344}
345
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000346StringRef getNodeName(const RecordDecl &Node, llvm::SmallString<128> &Scratch) {
347 if (Node.getIdentifier()) {
348 return Node.getName();
349 }
350 Scratch.clear();
351 return ("(anonymous " + Node.getKindName() + ")").toStringRef(Scratch);
352}
353
354StringRef getNodeName(const NamespaceDecl &Node,
355 llvm::SmallString<128> &Scratch) {
356 return Node.isAnonymousNamespace() ? "(anonymous namespace)" : Node.getName();
357}
358
359
360class PatternSet {
361public:
362 PatternSet(ArrayRef<std::string> Names) {
363 for (StringRef Name : Names)
364 Patterns.push_back({Name, Name.startswith("::")});
365 }
366
367 /// Consumes the name suffix from each pattern in the set and removes the ones
368 /// that didn't match.
369 /// Return true if there are still any patterns left.
370 bool consumeNameSuffix(StringRef NodeName, bool CanSkip) {
371 for (size_t I = 0; I < Patterns.size();) {
Hans Wennborg157a5d52016-02-22 22:21:58 +0000372 if (internal::consumeNameSuffix(Patterns[I].P, NodeName) ||
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000373 CanSkip) {
374 ++I;
375 } else {
376 Patterns.erase(Patterns.begin() + I);
377 }
378 }
379 return !Patterns.empty();
380 }
381
382 /// Check if any of the patterns are a match.
383 /// A match will be a pattern that was fully consumed, that also matches the
384 /// 'fully qualified' requirement.
385 bool foundMatch(bool AllowFullyQualified) const {
386 for (auto& P: Patterns)
Hans Wennborg157a5d52016-02-22 22:21:58 +0000387 if (P.P.empty() && (AllowFullyQualified || !P.IsFullyQualified))
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000388 return true;
389 return false;
390 }
391
392private:
393 struct Pattern {
Hans Wennborg157a5d52016-02-22 22:21:58 +0000394 StringRef P;
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000395 bool IsFullyQualified;
396 };
397 llvm::SmallVector<Pattern, 8> Patterns;
398};
399
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000400} // namespace
401
402bool HasNameMatcher::matchesNodeUnqualified(const NamedDecl &Node) const {
403 assert(UseUnqualifiedMatch);
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000404 llvm::SmallString<128> Scratch;
405 StringRef NodeName = getNodeName(Node, Scratch);
406 return std::any_of(Names.begin(), Names.end(), [&](StringRef Name) {
407 return consumeNameSuffix(Name, NodeName) && Name.empty();
408 });
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000409}
410
411bool HasNameMatcher::matchesNodeFullFast(const NamedDecl &Node) const {
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000412 PatternSet Patterns(Names);
413 llvm::SmallString<128> Scratch;
414
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000415 // This function is copied and adapted from NamedDecl::printQualifiedName()
416 // By matching each part individually we optimize in a couple of ways:
417 // - We can exit early on the first failure.
418 // - We can skip inline/anonymous namespaces without another pass.
419 // - We print one name at a time, reducing the chance of overflowing the
420 // inlined space of the SmallString.
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000421
422 // First, match the name.
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000423 if (!Patterns.consumeNameSuffix(getNodeName(Node, Scratch),
424 /*CanSkip=*/false))
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000425 return false;
426
427 // Try to match each declaration context.
428 // We are allowed to skip anonymous and inline namespaces if they don't match.
429 const DeclContext *Ctx = Node.getDeclContext();
430
431 if (Ctx->isFunctionOrMethod())
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000432 return Patterns.foundMatch(/*AllowFullyQualified=*/false);
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000433
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000434 for (; Ctx && isa<NamedDecl>(Ctx); Ctx = Ctx->getParent()) {
435 if (Patterns.foundMatch(/*AllowFullyQualified=*/false))
436 return true;
437
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000438 if (const auto *ND = dyn_cast<NamespaceDecl>(Ctx)) {
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000439 // If it matches (or we can skip it), continue.
440 if (Patterns.consumeNameSuffix(getNodeName(*ND, Scratch),
441 /*CanSkip=*/ND->isAnonymousNamespace() ||
442 ND->isInline()))
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000443 continue;
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000444 return false;
445 }
446 if (const auto *RD = dyn_cast<RecordDecl>(Ctx)) {
447 if (!isa<ClassTemplateSpecializationDecl>(Ctx)) {
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000448 if (Patterns.consumeNameSuffix(getNodeName(*RD, Scratch),
449 /*CanSkip=*/false))
450 continue;
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000451
452 return false;
453 }
454 }
455
456 // We don't know how to deal with this DeclContext.
457 // Fallback to the slow version of the code.
458 return matchesNodeFullSlow(Node);
459 }
460
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000461 return Patterns.foundMatch(/*AllowFullyQualified=*/true);
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000462}
463
464bool HasNameMatcher::matchesNodeFullSlow(const NamedDecl &Node) const {
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000465 const bool SkipUnwrittenCases[] = {false, true};
466 for (bool SkipUnwritten : SkipUnwrittenCases) {
467 llvm::SmallString<128> NodeName = StringRef("::");
468 llvm::raw_svector_ostream OS(NodeName);
469
470 if (SkipUnwritten) {
471 PrintingPolicy Policy = Node.getASTContext().getPrintingPolicy();
472 Policy.SuppressUnwrittenScope = true;
473 Node.printQualifiedName(OS, Policy);
474 } else {
475 Node.printQualifiedName(OS);
476 }
477
478 const StringRef FullName = OS.str();
479
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000480 for (const StringRef Pattern : Names) {
481 if (Pattern.startswith("::")) {
482 if (FullName == Pattern)
483 return true;
484 } else if (FullName.endswith(Pattern) &&
485 FullName.drop_back(Pattern.size()).endswith("::")) {
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000486 return true;
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000487 }
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000488 }
489 }
490
Samuel Benzaquenb6f73bc2014-10-16 17:50:19 +0000491 return false;
Samuel Benzaquen8513d622014-10-15 14:58:46 +0000492}
493
Samuel Benzaquen8513d622014-10-15 14:58:46 +0000494bool HasNameMatcher::matchesNode(const NamedDecl &Node) const {
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000495 assert(matchesNodeFullFast(Node) == matchesNodeFullSlow(Node));
Samuel Benzaquen8513d622014-10-15 14:58:46 +0000496 if (UseUnqualifiedMatch) {
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000497 assert(matchesNodeUnqualified(Node) == matchesNodeFullFast(Node));
Samuel Benzaquen8513d622014-10-15 14:58:46 +0000498 return matchesNodeUnqualified(Node);
499 }
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000500 return matchesNodeFullFast(Node);
Samuel Benzaquen8513d622014-10-15 14:58:46 +0000501}
502
Manuel Klimek04616e42012-07-06 05:48:52 +0000503} // end namespace internal
504} // end namespace ast_matchers
505} // end namespace clang