blob: f0bfbf9e32d87306e1a75e78590d1af40859d728 [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 {
Benjamin Kramer018b6d42016-07-21 15:06:51 +000075public:
Samuel Benzaquenf28d9972014-10-01 15:08:07 +000076 IdDynMatcher(StringRef ID,
Benjamin Kramer018b6d42016-07-21 15:06:51 +000077 IntrusiveRefCntPtr<DynMatcherInterface> InnerMatcher)
78 : ID(ID), InnerMatcher(std::move(InnerMatcher)) {}
Samuel Benzaquenf28d9972014-10-01 15:08:07 +000079
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
Benjamin Kramer018b6d42016-07-21 15:06:51 +000088private:
Samuel Benzaquenf28d9972014-10-01 15:08:07 +000089 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;
Benjamin Kramer018b6d42016-07-21 15:06:51 +0000213 Result.Implementation =
214 new IdDynMatcher(ID, std::move(Result.Implementation));
215 return std::move(Result);
Samuel Benzaquenf28d9972014-10-01 15:08:07 +0000216}
217
Samuel Benzaquenab005ed2014-09-04 14:13:58 +0000218bool DynTypedMatcher::canConvertTo(ast_type_traits::ASTNodeKind To) const {
219 const auto From = getSupportedKind();
220 auto QualKind = ast_type_traits::ASTNodeKind::getFromNodeKind<QualType>();
221 auto TypeKind = ast_type_traits::ASTNodeKind::getFromNodeKind<Type>();
222 /// Mimic the implicit conversions of Matcher<>.
223 /// - From Matcher<Type> to Matcher<QualType>
224 if (From.isSame(TypeKind) && To.isSame(QualKind)) return true;
225 /// - From Matcher<Base> to Matcher<Derived>
226 return From.isBaseOf(To);
227}
228
Manuel Klimeka0c025f2013-06-19 15:42:45 +0000229void BoundNodesTreeBuilder::addMatch(const BoundNodesTreeBuilder &Other) {
Benjamin Kramer79f15902014-10-24 13:29:15 +0000230 Bindings.append(Other.Bindings.begin(), Other.Bindings.end());
Manuel Klimek021d56f2012-08-28 23:26:39 +0000231}
232
Hans Wennborgb27f2492015-07-14 16:50:14 +0000233bool NotUnaryOperator(const ast_type_traits::DynTypedNode &DynNode,
Samuel Benzaquen4d058742013-11-22 14:41:48 +0000234 ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder,
235 ArrayRef<DynTypedMatcher> InnerMatchers) {
236 if (InnerMatchers.size() != 1)
237 return false;
238
239 // The 'unless' matcher will always discard the result:
240 // If the inner matcher doesn't match, unless returns true,
241 // but the inner matcher cannot have bound anything.
242 // If the inner matcher matches, the result is false, and
243 // any possible binding will be discarded.
244 // We still need to hand in all the bound nodes up to this
245 // point so the inner matcher can depend on bound nodes,
246 // and we need to actively discard the bound nodes, otherwise
247 // the inner matcher will reset the bound nodes if it doesn't
248 // match, but this would be inversed by 'unless'.
249 BoundNodesTreeBuilder Discard(*Builder);
250 return !InnerMatchers[0].matches(DynNode, Finder, &Discard);
251}
252
Hans Wennborgb27f2492015-07-14 16:50:14 +0000253bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode,
Samuel Benzaquen85ec25d2013-08-27 15:11:16 +0000254 ASTMatchFinder *Finder,
255 BoundNodesTreeBuilder *Builder,
Samuel Benzaquenf34ac3e2013-10-29 14:37:15 +0000256 ArrayRef<DynTypedMatcher> InnerMatchers) {
Samuel Benzaquen85ec25d2013-08-27 15:11:16 +0000257 // allOf leads to one matcher for each alternative in the first
258 // matcher combined with each alternative in the second matcher.
259 // Thus, we can reuse the same Builder.
Benjamin Kramer79f15902014-10-24 13:29:15 +0000260 for (const DynTypedMatcher &InnerMatcher : InnerMatchers) {
Samuel Benzaquen95636e52014-12-01 14:46:14 +0000261 if (!InnerMatcher.matchesNoKindCheck(DynNode, Finder, Builder))
Samuel Benzaquen85ec25d2013-08-27 15:11:16 +0000262 return false;
263 }
264 return true;
265}
266
Hans Wennborgb27f2492015-07-14 16:50:14 +0000267bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode,
Samuel Benzaquen85ec25d2013-08-27 15:11:16 +0000268 ASTMatchFinder *Finder,
269 BoundNodesTreeBuilder *Builder,
Samuel Benzaquenf34ac3e2013-10-29 14:37:15 +0000270 ArrayRef<DynTypedMatcher> InnerMatchers) {
Samuel Benzaquen85ec25d2013-08-27 15:11:16 +0000271 BoundNodesTreeBuilder Result;
272 bool Matched = false;
Benjamin Kramer79f15902014-10-24 13:29:15 +0000273 for (const DynTypedMatcher &InnerMatcher : InnerMatchers) {
Samuel Benzaquen85ec25d2013-08-27 15:11:16 +0000274 BoundNodesTreeBuilder BuilderInner(*Builder);
Benjamin Kramer79f15902014-10-24 13:29:15 +0000275 if (InnerMatcher.matches(DynNode, Finder, &BuilderInner)) {
Samuel Benzaquen85ec25d2013-08-27 15:11:16 +0000276 Matched = true;
277 Result.addMatch(BuilderInner);
278 }
279 }
Benjamin Kramerd9c91622014-08-29 11:22:47 +0000280 *Builder = std::move(Result);
Samuel Benzaquen85ec25d2013-08-27 15:11:16 +0000281 return Matched;
282}
283
Hans Wennborgb27f2492015-07-14 16:50:14 +0000284bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode,
Samuel Benzaquen85ec25d2013-08-27 15:11:16 +0000285 ASTMatchFinder *Finder,
286 BoundNodesTreeBuilder *Builder,
Samuel Benzaquenf34ac3e2013-10-29 14:37:15 +0000287 ArrayRef<DynTypedMatcher> InnerMatchers) {
Benjamin Kramer79f15902014-10-24 13:29:15 +0000288 for (const DynTypedMatcher &InnerMatcher : InnerMatchers) {
Samuel Benzaquen85ec25d2013-08-27 15:11:16 +0000289 BoundNodesTreeBuilder Result = *Builder;
Benjamin Kramer79f15902014-10-24 13:29:15 +0000290 if (InnerMatcher.matches(DynNode, Finder, &Result)) {
Benjamin Kramerd9c91622014-08-29 11:22:47 +0000291 *Builder = std::move(Result);
Samuel Benzaquen85ec25d2013-08-27 15:11:16 +0000292 return true;
293 }
294 }
295 return false;
296}
297
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000298Matcher<NamedDecl> hasAnyNameFunc(ArrayRef<const StringRef *> NameRefs) {
299 std::vector<std::string> Names;
300 for (auto *Name : NameRefs)
301 Names.emplace_back(*Name);
302 return internal::Matcher<NamedDecl>(
303 new internal::HasNameMatcher(std::move(Names)));
304}
305
306HasNameMatcher::HasNameMatcher(std::vector<std::string> N)
307 : UseUnqualifiedMatch(std::all_of(
308 N.begin(), N.end(),
309 [](StringRef Name) { return Name.find("::") == Name.npos; })),
310 Names(std::move(N)) {
Alexander Kornienko1eeac192016-02-23 10:29:04 +0000311#ifndef NDEBUG
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000312 for (StringRef Name : Names)
313 assert(!Name.empty());
Alexander Kornienko1eeac192016-02-23 10:29:04 +0000314#endif
Samuel Benzaquen8513d622014-10-15 14:58:46 +0000315}
316
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000317namespace {
318
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000319bool consumeNameSuffix(StringRef &FullName, StringRef Suffix) {
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000320 StringRef Name = FullName;
321 if (!Name.endswith(Suffix))
322 return false;
323 Name = Name.drop_back(Suffix.size());
324 if (!Name.empty()) {
325 if (!Name.endswith("::"))
326 return false;
327 Name = Name.drop_back(2);
Samuel Benzaquenb6f73bc2014-10-16 17:50:19 +0000328 }
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000329 FullName = Name;
330 return true;
331}
332
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000333StringRef getNodeName(const NamedDecl &Node, llvm::SmallString<128> &Scratch) {
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000334 // Simple name.
335 if (Node.getIdentifier())
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000336 return Node.getName();
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000337
Samuel Benzaquenb6f73bc2014-10-16 17:50:19 +0000338 if (Node.getDeclName()) {
Samuel Benzaquen8513d622014-10-15 14:58:46 +0000339 // Name needs to be constructed.
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000340 Scratch.clear();
341 llvm::raw_svector_ostream OS(Scratch);
Samuel Benzaquen8513d622014-10-15 14:58:46 +0000342 Node.printName(OS);
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000343 return OS.str();
Samuel Benzaquen8513d622014-10-15 14:58:46 +0000344 }
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000345
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000346 return "(anonymous)";
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000347}
348
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000349StringRef getNodeName(const RecordDecl &Node, llvm::SmallString<128> &Scratch) {
350 if (Node.getIdentifier()) {
351 return Node.getName();
352 }
353 Scratch.clear();
354 return ("(anonymous " + Node.getKindName() + ")").toStringRef(Scratch);
355}
356
357StringRef getNodeName(const NamespaceDecl &Node,
358 llvm::SmallString<128> &Scratch) {
359 return Node.isAnonymousNamespace() ? "(anonymous namespace)" : Node.getName();
360}
361
362
363class PatternSet {
364public:
365 PatternSet(ArrayRef<std::string> Names) {
366 for (StringRef Name : Names)
367 Patterns.push_back({Name, Name.startswith("::")});
368 }
369
370 /// Consumes the name suffix from each pattern in the set and removes the ones
371 /// that didn't match.
372 /// Return true if there are still any patterns left.
373 bool consumeNameSuffix(StringRef NodeName, bool CanSkip) {
374 for (size_t I = 0; I < Patterns.size();) {
Hans Wennborg157a5d52016-02-22 22:21:58 +0000375 if (internal::consumeNameSuffix(Patterns[I].P, NodeName) ||
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000376 CanSkip) {
377 ++I;
378 } else {
379 Patterns.erase(Patterns.begin() + I);
380 }
381 }
382 return !Patterns.empty();
383 }
384
385 /// Check if any of the patterns are a match.
386 /// A match will be a pattern that was fully consumed, that also matches the
387 /// 'fully qualified' requirement.
388 bool foundMatch(bool AllowFullyQualified) const {
389 for (auto& P: Patterns)
Hans Wennborg157a5d52016-02-22 22:21:58 +0000390 if (P.P.empty() && (AllowFullyQualified || !P.IsFullyQualified))
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000391 return true;
392 return false;
393 }
394
395private:
396 struct Pattern {
Hans Wennborg157a5d52016-02-22 22:21:58 +0000397 StringRef P;
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000398 bool IsFullyQualified;
399 };
400 llvm::SmallVector<Pattern, 8> Patterns;
401};
402
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000403} // namespace
404
405bool HasNameMatcher::matchesNodeUnqualified(const NamedDecl &Node) const {
406 assert(UseUnqualifiedMatch);
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000407 llvm::SmallString<128> Scratch;
408 StringRef NodeName = getNodeName(Node, Scratch);
409 return std::any_of(Names.begin(), Names.end(), [&](StringRef Name) {
410 return consumeNameSuffix(Name, NodeName) && Name.empty();
411 });
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000412}
413
414bool HasNameMatcher::matchesNodeFullFast(const NamedDecl &Node) const {
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000415 PatternSet Patterns(Names);
416 llvm::SmallString<128> Scratch;
417
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000418 // This function is copied and adapted from NamedDecl::printQualifiedName()
419 // By matching each part individually we optimize in a couple of ways:
420 // - We can exit early on the first failure.
421 // - We can skip inline/anonymous namespaces without another pass.
422 // - We print one name at a time, reducing the chance of overflowing the
423 // inlined space of the SmallString.
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000424
425 // First, match the name.
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000426 if (!Patterns.consumeNameSuffix(getNodeName(Node, Scratch),
427 /*CanSkip=*/false))
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000428 return false;
429
430 // Try to match each declaration context.
431 // We are allowed to skip anonymous and inline namespaces if they don't match.
432 const DeclContext *Ctx = Node.getDeclContext();
433
434 if (Ctx->isFunctionOrMethod())
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000435 return Patterns.foundMatch(/*AllowFullyQualified=*/false);
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000436
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000437 for (; Ctx && isa<NamedDecl>(Ctx); Ctx = Ctx->getParent()) {
438 if (Patterns.foundMatch(/*AllowFullyQualified=*/false))
439 return true;
440
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000441 if (const auto *ND = dyn_cast<NamespaceDecl>(Ctx)) {
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000442 // If it matches (or we can skip it), continue.
443 if (Patterns.consumeNameSuffix(getNodeName(*ND, Scratch),
444 /*CanSkip=*/ND->isAnonymousNamespace() ||
445 ND->isInline()))
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000446 continue;
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000447 return false;
448 }
449 if (const auto *RD = dyn_cast<RecordDecl>(Ctx)) {
450 if (!isa<ClassTemplateSpecializationDecl>(Ctx)) {
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000451 if (Patterns.consumeNameSuffix(getNodeName(*RD, Scratch),
452 /*CanSkip=*/false))
453 continue;
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000454
455 return false;
456 }
457 }
458
459 // We don't know how to deal with this DeclContext.
460 // Fallback to the slow version of the code.
461 return matchesNodeFullSlow(Node);
462 }
463
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000464 return Patterns.foundMatch(/*AllowFullyQualified=*/true);
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000465}
466
467bool HasNameMatcher::matchesNodeFullSlow(const NamedDecl &Node) const {
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000468 const bool SkipUnwrittenCases[] = {false, true};
469 for (bool SkipUnwritten : SkipUnwrittenCases) {
470 llvm::SmallString<128> NodeName = StringRef("::");
471 llvm::raw_svector_ostream OS(NodeName);
472
473 if (SkipUnwritten) {
474 PrintingPolicy Policy = Node.getASTContext().getPrintingPolicy();
475 Policy.SuppressUnwrittenScope = true;
476 Node.printQualifiedName(OS, Policy);
477 } else {
478 Node.printQualifiedName(OS);
479 }
480
481 const StringRef FullName = OS.str();
482
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000483 for (const StringRef Pattern : Names) {
484 if (Pattern.startswith("::")) {
485 if (FullName == Pattern)
486 return true;
487 } else if (FullName.endswith(Pattern) &&
488 FullName.drop_back(Pattern.size()).endswith("::")) {
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000489 return true;
Samuel Benzaquen922bef42016-02-22 21:13:02 +0000490 }
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000491 }
492 }
493
Samuel Benzaquenb6f73bc2014-10-16 17:50:19 +0000494 return false;
Samuel Benzaquen8513d622014-10-15 14:58:46 +0000495}
496
Samuel Benzaquen8513d622014-10-15 14:58:46 +0000497bool HasNameMatcher::matchesNode(const NamedDecl &Node) const {
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000498 assert(matchesNodeFullFast(Node) == matchesNodeFullSlow(Node));
Samuel Benzaquen8513d622014-10-15 14:58:46 +0000499 if (UseUnqualifiedMatch) {
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000500 assert(matchesNodeUnqualified(Node) == matchesNodeFullFast(Node));
Samuel Benzaquen8513d622014-10-15 14:58:46 +0000501 return matchesNodeUnqualified(Node);
502 }
Samuel Benzaquen8e566f32016-02-05 18:29:24 +0000503 return matchesNodeFullFast(Node);
Samuel Benzaquen8513d622014-10-15 14:58:46 +0000504}
505
Manuel Klimek04616e42012-07-06 05:48:52 +0000506} // end namespace internal
507} // end namespace ast_matchers
508} // end namespace clang