1 | //= unittests/ASTMatchers/ASTMatchersTraversalTest.cpp - matchers unit tests =// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "ASTMatchersTest.h" |
10 | #include "clang/AST/Attrs.inc" |
11 | #include "clang/AST/DeclCXX.h" |
12 | #include "clang/AST/PrettyPrinter.h" |
13 | #include "clang/ASTMatchers/ASTMatchFinder.h" |
14 | #include "clang/ASTMatchers/ASTMatchers.h" |
15 | #include "clang/Tooling/Tooling.h" |
16 | #include "llvm/ADT/StringRef.h" |
17 | #include "llvm/TargetParser/Host.h" |
18 | #include "llvm/TargetParser/Triple.h" |
19 | #include "gtest/gtest.h" |
20 | |
21 | namespace clang { |
22 | namespace ast_matchers { |
23 | |
24 | TEST(DeclarationMatcher, hasMethod) { |
25 | EXPECT_TRUE(matches("class A { void func(); };" , |
26 | cxxRecordDecl(hasMethod(hasName("func" ))))); |
27 | EXPECT_TRUE(notMatches("class A { void func(); };" , |
28 | cxxRecordDecl(hasMethod(isPublic())))); |
29 | } |
30 | |
31 | TEST(DeclarationMatcher, ClassDerivedFromDependentTemplateSpecialization) { |
32 | EXPECT_TRUE(matches( |
33 | "template <typename T> struct A {" |
34 | " template <typename T2> struct F {};" |
35 | "};" |
36 | "template <typename T> struct B : A<T>::template F<T> {};" |
37 | "B<int> b;" , |
38 | cxxRecordDecl(hasName("B" ), isDerivedFrom(recordDecl())))); |
39 | } |
40 | |
41 | TEST(DeclarationMatcher, hasDeclContext) { |
42 | EXPECT_TRUE(matches( |
43 | "namespace N {" |
44 | " namespace M {" |
45 | " class D {};" |
46 | " }" |
47 | "}" , |
48 | recordDecl(hasDeclContext(namespaceDecl(hasName("M" )))))); |
49 | EXPECT_TRUE(notMatches( |
50 | "namespace N {" |
51 | " namespace M {" |
52 | " class D {};" |
53 | " }" |
54 | "}" , |
55 | recordDecl(hasDeclContext(namespaceDecl(hasName("N" )))))); |
56 | |
57 | EXPECT_TRUE(matches("namespace {" |
58 | " namespace M {" |
59 | " class D {};" |
60 | " }" |
61 | "}" , |
62 | recordDecl(hasDeclContext(namespaceDecl( |
63 | hasName("M" ), hasDeclContext(namespaceDecl())))))); |
64 | |
65 | EXPECT_TRUE(matches("class D{};" , decl(hasDeclContext(decl())))); |
66 | } |
67 | |
68 | TEST(HasDescendant, MatchesDescendantTypes) { |
69 | EXPECT_TRUE(matches("void f() { int i = 3; }" , |
70 | decl(hasDescendant(loc(builtinType()))))); |
71 | EXPECT_TRUE(matches("void f() { int i = 3; }" , |
72 | stmt(hasDescendant(builtinType())))); |
73 | |
74 | EXPECT_TRUE(matches("void f() { int i = 3; }" , |
75 | stmt(hasDescendant(loc(builtinType()))))); |
76 | EXPECT_TRUE(matches("void f() { int i = 3; }" , |
77 | stmt(hasDescendant(qualType(builtinType()))))); |
78 | |
79 | EXPECT_TRUE(notMatches("void f() { float f = 2.0f; }" , |
80 | stmt(hasDescendant(isInteger())))); |
81 | |
82 | EXPECT_TRUE(matchAndVerifyResultTrue( |
83 | "void f() { int a; float c; int d; int e; }" , |
84 | functionDecl(forEachDescendant( |
85 | varDecl(hasDescendant(isInteger())).bind("x" ))), |
86 | std::make_unique<VerifyIdIsBoundTo<Decl>>("x" , 3))); |
87 | } |
88 | |
89 | TEST(HasDescendant, MatchesDescendantsOfTypes) { |
90 | EXPECT_TRUE(matches("void f() { int*** i; }" , |
91 | qualType(hasDescendant(builtinType())))); |
92 | EXPECT_TRUE(matches("void f() { int*** i; }" , |
93 | qualType(hasDescendant( |
94 | pointerType(pointee(builtinType())))))); |
95 | EXPECT_TRUE(matches("void f() { int*** i; }" , |
96 | typeLoc(hasDescendant(loc(builtinType()))))); |
97 | |
98 | EXPECT_TRUE(matchAndVerifyResultTrue( |
99 | "void f() { int*** i; }" , |
100 | qualType(asString("int ***" ), forEachDescendant(pointerType().bind("x" ))), |
101 | std::make_unique<VerifyIdIsBoundTo<Type>>("x" , 2))); |
102 | } |
103 | |
104 | |
105 | TEST(Has, MatchesChildrenOfTypes) { |
106 | EXPECT_TRUE(matches("int i;" , |
107 | varDecl(hasName("i" ), has(isInteger())))); |
108 | EXPECT_TRUE(notMatches("int** i;" , |
109 | varDecl(hasName("i" ), has(isInteger())))); |
110 | EXPECT_TRUE(matchAndVerifyResultTrue( |
111 | "int (*f)(float, int);" , |
112 | qualType(functionType(), forEach(qualType(isInteger()).bind("x" ))), |
113 | std::make_unique<VerifyIdIsBoundTo<QualType>>("x" , 2))); |
114 | } |
115 | |
116 | TEST(Has, MatchesChildTypes) { |
117 | EXPECT_TRUE(matches( |
118 | "int* i;" , |
119 | varDecl(hasName("i" ), hasType(qualType(has(builtinType())))))); |
120 | EXPECT_TRUE(notMatches( |
121 | "int* i;" , |
122 | varDecl(hasName("i" ), hasType(qualType(has(pointerType())))))); |
123 | } |
124 | |
125 | TEST(StatementMatcher, Has) { |
126 | StatementMatcher HasVariableI = |
127 | expr(hasType(InnerMatcher: pointsTo(InnerMatcher: recordDecl(hasName(Name: "X" )))), |
128 | has(ignoringParenImpCasts(InnerMatcher: declRefExpr(to(InnerMatcher: varDecl(hasName(Name: "i" ))))))); |
129 | |
130 | EXPECT_TRUE(matches( |
131 | "class X; X *x(int); void c() { int i; x(i); }" , HasVariableI)); |
132 | EXPECT_TRUE(notMatches( |
133 | "class X; X *x(int); void c() { int i; x(42); }" , HasVariableI)); |
134 | } |
135 | |
136 | TEST(StatementMatcher, HasDescendant) { |
137 | StatementMatcher HasDescendantVariableI = |
138 | expr(hasType(InnerMatcher: pointsTo(InnerMatcher: recordDecl(hasName(Name: "X" )))), |
139 | hasDescendant(declRefExpr(to(InnerMatcher: varDecl(hasName(Name: "i" )))))); |
140 | |
141 | EXPECT_TRUE(matches( |
142 | "class X; X *x(bool); bool b(int); void c() { int i; x(b(i)); }" , |
143 | HasDescendantVariableI)); |
144 | EXPECT_TRUE(notMatches( |
145 | "class X; X *x(bool); bool b(int); void c() { int i; x(b(42)); }" , |
146 | HasDescendantVariableI)); |
147 | } |
148 | |
149 | TEST(TypeMatcher, MatchesClassType) { |
150 | TypeMatcher TypeA = hasDeclaration(InnerMatcher: recordDecl(hasName(Name: "A" ))); |
151 | |
152 | EXPECT_TRUE(matches("class A { public: A *a; };" , TypeA)); |
153 | EXPECT_TRUE(notMatches("class A {};" , TypeA)); |
154 | |
155 | TypeMatcher TypeDerivedFromA = |
156 | hasDeclaration(InnerMatcher: cxxRecordDecl(isDerivedFrom(BaseName: "A" ))); |
157 | |
158 | EXPECT_TRUE(matches("class A {}; class B : public A { public: B *b; };" , |
159 | TypeDerivedFromA)); |
160 | EXPECT_TRUE(notMatches("class A {};" , TypeA)); |
161 | |
162 | TypeMatcher TypeAHasClassB = hasDeclaration( |
163 | InnerMatcher: recordDecl(hasName(Name: "A" ), has(recordDecl(hasName(Name: "B" ))))); |
164 | |
165 | EXPECT_TRUE( |
166 | matches("class A { public: A *a; class B {}; };" , TypeAHasClassB)); |
167 | |
168 | EXPECT_TRUE(matchesC("struct S {}; void f(void) { struct S s; }" , |
169 | varDecl(hasType(namedDecl(hasName("S" )))))); |
170 | } |
171 | |
172 | TEST(TypeMatcher, MatchesDeclTypes) { |
173 | // TypedefType -> TypedefNameDecl |
174 | EXPECT_TRUE(matches("typedef int I; void f(I i);" , |
175 | parmVarDecl(hasType(namedDecl(hasName("I" )))))); |
176 | // ObjCObjectPointerType |
177 | EXPECT_TRUE(matchesObjC("@interface Foo @end void f(Foo *f);" , |
178 | parmVarDecl(hasType(objcObjectPointerType())))); |
179 | // ObjCObjectPointerType -> ObjCInterfaceType -> ObjCInterfaceDecl |
180 | EXPECT_TRUE(matchesObjC( |
181 | "@interface Foo @end void f(Foo *f);" , |
182 | parmVarDecl(hasType(pointsTo(objcInterfaceDecl(hasName("Foo" ))))))); |
183 | // TemplateTypeParmType |
184 | EXPECT_TRUE(matches("template <typename T> void f(T t);" , |
185 | parmVarDecl(hasType(templateTypeParmType())))); |
186 | // TemplateTypeParmType -> TemplateTypeParmDecl |
187 | EXPECT_TRUE(matches("template <typename T> void f(T t);" , |
188 | parmVarDecl(hasType(namedDecl(hasName("T" )))))); |
189 | // InjectedClassNameType |
190 | EXPECT_TRUE(matches("template <typename T> struct S {" |
191 | " void f(S s);" |
192 | "};" , |
193 | parmVarDecl(hasType(elaboratedType( |
194 | namesType(injectedClassNameType())))))); |
195 | EXPECT_TRUE(notMatches("template <typename T> struct S {" |
196 | " void g(S<T> s);" |
197 | "};" , |
198 | parmVarDecl(hasType(elaboratedType( |
199 | namesType(injectedClassNameType())))))); |
200 | // InjectedClassNameType -> CXXRecordDecl |
201 | EXPECT_TRUE(matches("template <typename T> struct S {" |
202 | " void f(S s);" |
203 | "};" , |
204 | parmVarDecl(hasType(namedDecl(hasName("S" )))))); |
205 | |
206 | static const char Using[] = "template <typename T>" |
207 | "struct Base {" |
208 | " typedef T Foo;" |
209 | "};" |
210 | "" |
211 | "template <typename T>" |
212 | "struct S : private Base<T> {" |
213 | " using typename Base<T>::Foo;" |
214 | " void f(Foo);" |
215 | "};" ; |
216 | // UnresolvedUsingTypenameDecl |
217 | EXPECT_TRUE(matches(Using, unresolvedUsingTypenameDecl(hasName("Foo" )))); |
218 | // UnresolvedUsingTypenameType -> UnresolvedUsingTypenameDecl |
219 | EXPECT_TRUE(matches(Using, parmVarDecl(hasType(namedDecl(hasName("Foo" )))))); |
220 | } |
221 | |
222 | TEST(HasDeclaration, HasDeclarationOfEnumType) { |
223 | EXPECT_TRUE(matches("enum X {}; void y(X *x) { x; }" , |
224 | expr(hasType(pointsTo( |
225 | qualType(hasDeclaration(enumDecl(hasName("X" ))))))))); |
226 | } |
227 | |
228 | TEST(HasDeclaration, HasGetDeclTraitTest) { |
229 | static_assert(internal::has_getDecl<TypedefType>::value, |
230 | "Expected TypedefType to have a getDecl." ); |
231 | static_assert(internal::has_getDecl<RecordType>::value, |
232 | "Expected RecordType to have a getDecl." ); |
233 | static_assert(!internal::has_getDecl<TemplateSpecializationType>::value, |
234 | "Expected TemplateSpecializationType to *not* have a getDecl." ); |
235 | } |
236 | |
237 | TEST(HasDeclaration, ElaboratedType) { |
238 | EXPECT_TRUE(matches( |
239 | "namespace n { template <typename T> struct X {}; }" |
240 | "void f(n::X<int>);" , |
241 | parmVarDecl(hasType(qualType(hasDeclaration(cxxRecordDecl())))))); |
242 | EXPECT_TRUE(matches( |
243 | "namespace n { template <typename T> struct X {}; }" |
244 | "void f(n::X<int>);" , |
245 | parmVarDecl(hasType(elaboratedType(hasDeclaration(cxxRecordDecl())))))); |
246 | } |
247 | |
248 | TEST(HasDeclaration, HasDeclarationOfTypeWithDecl) { |
249 | EXPECT_TRUE(matches( |
250 | "typedef int X; X a;" , |
251 | varDecl(hasName("a" ), hasType(elaboratedType(namesType( |
252 | typedefType(hasDeclaration(decl())))))))); |
253 | |
254 | // FIXME: Add tests for other types with getDecl() (e.g. RecordType) |
255 | } |
256 | |
257 | TEST(HasDeclaration, HasDeclarationOfTemplateSpecializationType) { |
258 | EXPECT_TRUE(matches( |
259 | "template <typename T> class A {}; A<int> a;" , |
260 | varDecl(hasType(elaboratedType(namesType(templateSpecializationType( |
261 | hasDeclaration(namedDecl(hasName("A" )))))))))); |
262 | EXPECT_TRUE(matches( |
263 | "template <typename T> class A {};" |
264 | "template <typename T> class B { A<T> a; };" , |
265 | fieldDecl(hasType(elaboratedType(namesType(templateSpecializationType( |
266 | hasDeclaration(namedDecl(hasName("A" )))))))))); |
267 | EXPECT_TRUE(matches( |
268 | "template <typename T> class A {}; A<int> a;" , |
269 | varDecl(hasType(elaboratedType(namesType( |
270 | templateSpecializationType(hasDeclaration(cxxRecordDecl())))))))); |
271 | } |
272 | |
273 | TEST(HasDeclaration, HasDeclarationOfCXXNewExpr) { |
274 | EXPECT_TRUE( |
275 | matches("int *A = new int();" , |
276 | cxxNewExpr(hasDeclaration(functionDecl(parameterCountIs(1)))))); |
277 | } |
278 | |
279 | TEST(HasDeclaration, HasDeclarationOfTypeAlias) { |
280 | EXPECT_TRUE(matches( |
281 | "template <typename T> using C = T; C<int> c;" , |
282 | varDecl(hasType(elaboratedType(namesType(templateSpecializationType( |
283 | hasDeclaration(typeAliasTemplateDecl())))))))); |
284 | } |
285 | |
286 | TEST(HasUnqualifiedDesugaredType, DesugarsUsing) { |
287 | EXPECT_TRUE( |
288 | matches("struct A {}; using B = A; B b;" , |
289 | varDecl(hasType(hasUnqualifiedDesugaredType(recordType()))))); |
290 | EXPECT_TRUE( |
291 | matches("struct A {}; using B = A; using C = B; C b;" , |
292 | varDecl(hasType(hasUnqualifiedDesugaredType(recordType()))))); |
293 | } |
294 | |
295 | TEST(HasUnderlyingDecl, Matches) { |
296 | EXPECT_TRUE(matches("namespace N { template <class T> void f(T t); }" |
297 | "template <class T> void g() { using N::f; f(T()); }" , |
298 | unresolvedLookupExpr(hasAnyDeclaration( |
299 | namedDecl(hasUnderlyingDecl(hasName("::N::f" ))))))); |
300 | EXPECT_TRUE(matches( |
301 | "namespace N { template <class T> void f(T t); }" |
302 | "template <class T> void g() { N::f(T()); }" , |
303 | unresolvedLookupExpr(hasAnyDeclaration(namedDecl(hasName("::N::f" )))))); |
304 | EXPECT_TRUE(notMatches( |
305 | "namespace N { template <class T> void f(T t); }" |
306 | "template <class T> void g() { using N::f; f(T()); }" , |
307 | unresolvedLookupExpr(hasAnyDeclaration(namedDecl(hasName("::N::f" )))))); |
308 | } |
309 | |
310 | TEST(HasType, TakesQualTypeMatcherAndMatchesExpr) { |
311 | TypeMatcher ClassX = hasDeclaration(InnerMatcher: recordDecl(hasName(Name: "X" ))); |
312 | EXPECT_TRUE( |
313 | matches("class X {}; void y(X &x) { x; }" , expr(hasType(ClassX)))); |
314 | EXPECT_TRUE( |
315 | notMatches("class X {}; void y(X *x) { x; }" , |
316 | expr(hasType(ClassX)))); |
317 | EXPECT_TRUE( |
318 | matches("class X {}; void y(X *x) { x; }" , |
319 | expr(hasType(pointsTo(ClassX))))); |
320 | } |
321 | |
322 | TEST(HasType, TakesQualTypeMatcherAndMatchesValueDecl) { |
323 | TypeMatcher ClassX = hasDeclaration(InnerMatcher: recordDecl(hasName(Name: "X" ))); |
324 | EXPECT_TRUE( |
325 | matches("class X {}; void y() { X x; }" , varDecl(hasType(ClassX)))); |
326 | EXPECT_TRUE( |
327 | notMatches("class X {}; void y() { X *x; }" , varDecl(hasType(ClassX)))); |
328 | EXPECT_TRUE( |
329 | matches("class X {}; void y() { X *x; }" , |
330 | varDecl(hasType(pointsTo(ClassX))))); |
331 | } |
332 | |
333 | TEST(HasType, TakesQualTypeMatcherAndMatchesCXXBaseSpecifier) { |
334 | TypeMatcher ClassX = hasDeclaration(InnerMatcher: recordDecl(hasName(Name: "X" ))); |
335 | CXXBaseSpecifierMatcher BaseClassX = cxxBaseSpecifier(hasType(InnerMatcher: ClassX)); |
336 | DeclarationMatcher ClassHasBaseClassX = |
337 | cxxRecordDecl(hasDirectBase(BaseSpecMatcher: BaseClassX)); |
338 | EXPECT_TRUE(matches("class X {}; class Y : X {};" , ClassHasBaseClassX)); |
339 | EXPECT_TRUE(notMatches("class Z {}; class Y : Z {};" , ClassHasBaseClassX)); |
340 | } |
341 | |
342 | TEST(HasType, TakesDeclMatcherAndMatchesExpr) { |
343 | DeclarationMatcher ClassX = recordDecl(hasName(Name: "X" )); |
344 | EXPECT_TRUE( |
345 | matches("class X {}; void y(X &x) { x; }" , expr(hasType(ClassX)))); |
346 | EXPECT_TRUE( |
347 | notMatches("class X {}; void y(X *x) { x; }" , |
348 | expr(hasType(ClassX)))); |
349 | } |
350 | |
351 | TEST(HasType, TakesDeclMatcherAndMatchesValueDecl) { |
352 | DeclarationMatcher ClassX = recordDecl(hasName(Name: "X" )); |
353 | EXPECT_TRUE( |
354 | matches("class X {}; void y() { X x; }" , varDecl(hasType(ClassX)))); |
355 | EXPECT_TRUE( |
356 | notMatches("class X {}; void y() { X *x; }" , varDecl(hasType(ClassX)))); |
357 | } |
358 | |
359 | TEST(HasType, TakesDeclMatcherAndMatchesCXXBaseSpecifier) { |
360 | DeclarationMatcher ClassX = recordDecl(hasName(Name: "X" )); |
361 | CXXBaseSpecifierMatcher BaseClassX = cxxBaseSpecifier(hasType(InnerMatcher: ClassX)); |
362 | DeclarationMatcher ClassHasBaseClassX = |
363 | cxxRecordDecl(hasDirectBase(BaseSpecMatcher: BaseClassX)); |
364 | EXPECT_TRUE(matches("class X {}; class Y : X {};" , ClassHasBaseClassX)); |
365 | EXPECT_TRUE(notMatches("class Z {}; class Y : Z {};" , ClassHasBaseClassX)); |
366 | } |
367 | |
368 | TEST(HasType, MatchesTypedefDecl) { |
369 | EXPECT_TRUE(matches("typedef int X;" , typedefDecl(hasType(asString("int" ))))); |
370 | EXPECT_TRUE(matches("typedef const int T;" , |
371 | typedefDecl(hasType(asString("const int" ))))); |
372 | EXPECT_TRUE(notMatches("typedef const int T;" , |
373 | typedefDecl(hasType(asString("int" ))))); |
374 | EXPECT_TRUE(matches("typedef int foo; typedef foo bar;" , |
375 | typedefDecl(hasType(asString("foo" )), hasName("bar" )))); |
376 | } |
377 | |
378 | TEST(HasType, MatchesTypedefNameDecl) { |
379 | EXPECT_TRUE(matches("using X = int;" , typedefNameDecl(hasType(asString("int" ))))); |
380 | EXPECT_TRUE(matches("using T = const int;" , |
381 | typedefNameDecl(hasType(asString("const int" ))))); |
382 | EXPECT_TRUE(notMatches("using T = const int;" , |
383 | typedefNameDecl(hasType(asString("int" ))))); |
384 | EXPECT_TRUE(matches("using foo = int; using bar = foo;" , |
385 | typedefNameDecl(hasType(asString("foo" )), hasName("bar" )))); |
386 | } |
387 | |
388 | TEST(HasTypeLoc, MatchesBlockDecl) { |
389 | EXPECT_TRUE(matchesConditionally( |
390 | "auto x = ^int (int a, int b) { return a + b; };" , |
391 | blockDecl(hasTypeLoc(loc(asString("int (int, int)" )))), true, |
392 | {"-fblocks" })); |
393 | } |
394 | |
395 | TEST(HasTypeLoc, MatchesCXXBaseSpecifierAndCtorInitializer) { |
396 | llvm::StringRef code = R"cpp( |
397 | class Foo {}; |
398 | class Bar : public Foo { |
399 | Bar() : Foo() {} |
400 | }; |
401 | )cpp" ; |
402 | |
403 | EXPECT_TRUE(matches( |
404 | code, cxxRecordDecl(hasAnyBase(hasTypeLoc(loc(asString("Foo" ))))))); |
405 | EXPECT_TRUE( |
406 | matches(code, cxxCtorInitializer(hasTypeLoc(loc(asString("Foo" )))))); |
407 | } |
408 | |
409 | TEST(HasTypeLoc, MatchesCXXFunctionalCastExpr) { |
410 | EXPECT_TRUE(matches("auto x = int(3);" , |
411 | cxxFunctionalCastExpr(hasTypeLoc(loc(asString("int" )))))); |
412 | } |
413 | |
414 | TEST(HasTypeLoc, MatchesCXXNewExpr) { |
415 | EXPECT_TRUE(matches("auto* x = new int(3);" , |
416 | cxxNewExpr(hasTypeLoc(loc(asString("int" )))))); |
417 | EXPECT_TRUE(matches("class Foo{}; auto* x = new Foo();" , |
418 | cxxNewExpr(hasTypeLoc(loc(asString("Foo" )))))); |
419 | } |
420 | |
421 | TEST(HasTypeLoc, MatchesCXXTemporaryObjectExpr) { |
422 | EXPECT_TRUE( |
423 | matches("struct Foo { Foo(int, int); }; auto x = Foo(1, 2);" , |
424 | cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("Foo" )))))); |
425 | } |
426 | |
427 | TEST(HasTypeLoc, MatchesCXXUnresolvedConstructExpr) { |
428 | EXPECT_TRUE( |
429 | matches("template <typename T> T make() { return T(); }" , |
430 | cxxUnresolvedConstructExpr(hasTypeLoc(loc(asString("T" )))))); |
431 | } |
432 | |
433 | TEST(HasTypeLoc, MatchesClassTemplateSpecializationDecl) { |
434 | EXPECT_TRUE(matches( |
435 | "template <typename T> class Foo; template <> class Foo<int> {};" , |
436 | classTemplateSpecializationDecl(hasTypeLoc(loc(asString("Foo<int>" )))))); |
437 | } |
438 | |
439 | TEST(HasTypeLoc, MatchesCompoundLiteralExpr) { |
440 | EXPECT_TRUE( |
441 | matches("int* x = (int[2]) { 0, 1 };" , |
442 | compoundLiteralExpr(hasTypeLoc(loc(asString("int[2]" )))))); |
443 | } |
444 | |
445 | TEST(HasTypeLoc, MatchesDeclaratorDecl) { |
446 | EXPECT_TRUE(matches("int x;" , |
447 | varDecl(hasName("x" ), hasTypeLoc(loc(asString("int" )))))); |
448 | EXPECT_TRUE(matches("int x(3);" , |
449 | varDecl(hasName("x" ), hasTypeLoc(loc(asString("int" )))))); |
450 | EXPECT_TRUE(matches("struct Foo { Foo(int, int); }; Foo x(1, 2);" , |
451 | varDecl(hasName("x" ), hasTypeLoc(loc(asString("Foo" )))))); |
452 | |
453 | // Make sure we don't crash on implicit constructors. |
454 | EXPECT_TRUE(notMatches("class X {}; X x;" , |
455 | declaratorDecl(hasTypeLoc(loc(asString("int" )))))); |
456 | } |
457 | |
458 | TEST(HasTypeLoc, MatchesExplicitCastExpr) { |
459 | EXPECT_TRUE(matches("auto x = (int) 3;" , |
460 | explicitCastExpr(hasTypeLoc(loc(asString("int" )))))); |
461 | EXPECT_TRUE(matches("auto x = static_cast<int>(3);" , |
462 | explicitCastExpr(hasTypeLoc(loc(asString("int" )))))); |
463 | } |
464 | |
465 | TEST(HasTypeLoc, MatchesObjCPropertyDecl) { |
466 | EXPECT_TRUE(matchesObjC(R"objc( |
467 | @interface Foo |
468 | @property int enabled; |
469 | @end |
470 | )objc" , |
471 | objcPropertyDecl(hasTypeLoc(loc(asString("int" )))))); |
472 | } |
473 | |
474 | TEST(HasTypeLoc, MatchesTemplateArgumentLoc) { |
475 | EXPECT_TRUE(matches("template <typename T> class Foo {}; Foo<int> x;" , |
476 | templateArgumentLoc(hasTypeLoc(loc(asString("int" )))))); |
477 | } |
478 | |
479 | TEST(HasTypeLoc, MatchesTypedefNameDecl) { |
480 | EXPECT_TRUE(matches("typedef int X;" , |
481 | typedefNameDecl(hasTypeLoc(loc(asString("int" )))))); |
482 | EXPECT_TRUE(matches("using X = int;" , |
483 | typedefNameDecl(hasTypeLoc(loc(asString("int" )))))); |
484 | } |
485 | |
486 | TEST(Callee, MatchesDeclarations) { |
487 | StatementMatcher CallMethodX = callExpr(callee(InnerMatcher: cxxMethodDecl(hasName(Name: "x" )))); |
488 | |
489 | EXPECT_TRUE(matches("class Y { void x() { x(); } };" , CallMethodX)); |
490 | EXPECT_TRUE(notMatches("class Y { void x() {} };" , CallMethodX)); |
491 | |
492 | CallMethodX = traverse(TK: TK_AsIs, InnerMatcher: callExpr(callee(InnerMatcher: cxxConversionDecl()))); |
493 | EXPECT_TRUE( |
494 | matches("struct Y { operator int() const; }; int i = Y();" , CallMethodX)); |
495 | EXPECT_TRUE(notMatches("struct Y { operator int() const; }; Y y = Y();" , |
496 | CallMethodX)); |
497 | } |
498 | |
499 | TEST(Callee, MatchesMemberExpressions) { |
500 | EXPECT_TRUE(matches("class Y { void x() { this->x(); } };" , |
501 | callExpr(callee(memberExpr())))); |
502 | EXPECT_TRUE( |
503 | notMatches("class Y { void x() { this->x(); } };" , callExpr(callee(callExpr())))); |
504 | } |
505 | |
506 | TEST(Matcher, Argument) { |
507 | StatementMatcher CallArgumentY = callExpr( |
508 | hasArgument(N: 0, InnerMatcher: declRefExpr(to(InnerMatcher: varDecl(hasName(Name: "y" )))))); |
509 | |
510 | EXPECT_TRUE(matches("void x(int) { int y; x(y); }" , CallArgumentY)); |
511 | EXPECT_TRUE( |
512 | matches("class X { void x(int) { int y; x(y); } };" , CallArgumentY)); |
513 | EXPECT_TRUE(notMatches("void x(int) { int z; x(z); }" , CallArgumentY)); |
514 | |
515 | StatementMatcher WrongIndex = callExpr( |
516 | hasArgument(N: 42, InnerMatcher: declRefExpr(to(InnerMatcher: varDecl(hasName(Name: "y" )))))); |
517 | EXPECT_TRUE(notMatches("void x(int) { int y; x(y); }" , WrongIndex)); |
518 | } |
519 | |
520 | TEST(Matcher, AnyArgument) { |
521 | auto HasArgumentY = hasAnyArgument( |
522 | InnerMatcher: ignoringParenImpCasts(InnerMatcher: declRefExpr(to(InnerMatcher: varDecl(hasName(Name: "y" )))))); |
523 | StatementMatcher CallArgumentY = callExpr(HasArgumentY); |
524 | StatementMatcher CtorArgumentY = cxxConstructExpr(HasArgumentY); |
525 | StatementMatcher UnresolvedCtorArgumentY = |
526 | cxxUnresolvedConstructExpr(HasArgumentY); |
527 | StatementMatcher ObjCCallArgumentY = objcMessageExpr(HasArgumentY); |
528 | EXPECT_TRUE(matches("void x(int, int) { int y; x(1, y); }" , CallArgumentY)); |
529 | EXPECT_TRUE(matches("void x(int, int) { int y; x(y, 42); }" , CallArgumentY)); |
530 | EXPECT_TRUE(matches("struct Y { Y(int, int); };" |
531 | "void x() { int y; (void)Y(1, y); }" , |
532 | CtorArgumentY)); |
533 | EXPECT_TRUE(matches("struct Y { Y(int, int); };" |
534 | "void x() { int y; (void)Y(y, 42); }" , |
535 | CtorArgumentY)); |
536 | EXPECT_TRUE(matches("template <class Y> void x() { int y; (void)Y(1, y); }" , |
537 | UnresolvedCtorArgumentY)); |
538 | EXPECT_TRUE(matches("template <class Y> void x() { int y; (void)Y(y, 42); }" , |
539 | UnresolvedCtorArgumentY)); |
540 | EXPECT_TRUE(matchesObjC("@interface I -(void)f:(int) y; @end " |
541 | "void x(I* i) { int y; [i f:y]; }" , |
542 | ObjCCallArgumentY)); |
543 | EXPECT_FALSE(matchesObjC("@interface I -(void)f:(int) z; @end " |
544 | "void x(I* i) { int z; [i f:z]; }" , |
545 | ObjCCallArgumentY)); |
546 | EXPECT_TRUE(notMatches("void x(int, int) { x(1, 2); }" , CallArgumentY)); |
547 | EXPECT_TRUE(notMatches("struct Y { Y(int, int); };" |
548 | "void x() { int y; (void)Y(1, 2); }" , |
549 | CtorArgumentY)); |
550 | EXPECT_TRUE(notMatches("template <class Y>" |
551 | "void x() { int y; (void)Y(1, 2); }" , |
552 | UnresolvedCtorArgumentY)); |
553 | |
554 | StatementMatcher ImplicitCastedArgument = |
555 | traverse(TK: TK_AsIs, InnerMatcher: callExpr(hasAnyArgument(InnerMatcher: implicitCastExpr()))); |
556 | EXPECT_TRUE(matches("void x(long) { int y; x(y); }" , ImplicitCastedArgument)); |
557 | } |
558 | |
559 | TEST(Matcher, HasReceiver) { |
560 | EXPECT_TRUE(matchesObjC( |
561 | "@interface NSString @end " |
562 | "void f(NSString *x) {" |
563 | "[x containsString];" |
564 | "}" , |
565 | objcMessageExpr(hasReceiver(declRefExpr(to(varDecl(hasName("x" )))))))); |
566 | |
567 | EXPECT_FALSE(matchesObjC( |
568 | "@interface NSString +(NSString *) stringWithFormat; @end " |
569 | "void f() { [NSString stringWithFormat]; }" , |
570 | objcMessageExpr(hasReceiver(declRefExpr(to(varDecl(hasName("x" )))))))); |
571 | } |
572 | |
573 | TEST(Matcher, MatchesMethodsOnLambda) { |
574 | StringRef Code = R"cpp( |
575 | struct A { |
576 | ~A() {} |
577 | }; |
578 | void foo() |
579 | { |
580 | A a; |
581 | auto l = [a] { }; |
582 | auto lCopy = l; |
583 | auto lPtrDecay = +[] { }; |
584 | (void)lPtrDecay; |
585 | } |
586 | )cpp" ; |
587 | |
588 | EXPECT_TRUE(matches( |
589 | Code, cxxConstructorDecl( |
590 | hasBody(compoundStmt()), |
591 | hasAncestor(lambdaExpr(hasAncestor(varDecl(hasName("l" ))))), |
592 | isCopyConstructor()))); |
593 | EXPECT_TRUE(matches( |
594 | Code, cxxConstructorDecl( |
595 | hasBody(compoundStmt()), |
596 | hasAncestor(lambdaExpr(hasAncestor(varDecl(hasName("l" ))))), |
597 | isMoveConstructor()))); |
598 | EXPECT_TRUE(matches( |
599 | Code, cxxDestructorDecl( |
600 | hasBody(compoundStmt()), |
601 | hasAncestor(lambdaExpr(hasAncestor(varDecl(hasName("l" )))))))); |
602 | EXPECT_TRUE(matches( |
603 | Code, cxxConversionDecl(hasBody(compoundStmt(has(returnStmt( |
604 | hasReturnValue(implicitCastExpr()))))), |
605 | hasAncestor(lambdaExpr(hasAncestor( |
606 | varDecl(hasName("lPtrDecay" )))))))); |
607 | } |
608 | |
609 | TEST(Matcher, MatchesCoroutine) { |
610 | FileContentMappings M; |
611 | M.push_back(x: std::make_pair(x: "/coro_header" , y: R"cpp( |
612 | namespace std { |
613 | |
614 | template <class... Args> |
615 | struct void_t_imp { |
616 | using type = void; |
617 | }; |
618 | template <class... Args> |
619 | using void_t = typename void_t_imp<Args...>::type; |
620 | |
621 | template <class T, class = void> |
622 | struct traits_sfinae_base {}; |
623 | |
624 | template <class T> |
625 | struct traits_sfinae_base<T, void_t<typename T::promise_type>> { |
626 | using promise_type = typename T::promise_type; |
627 | }; |
628 | |
629 | template <class Ret, class... Args> |
630 | struct coroutine_traits : public traits_sfinae_base<Ret> {}; |
631 | } // namespace std |
632 | struct awaitable { |
633 | bool await_ready() noexcept; |
634 | template <typename F> |
635 | void await_suspend(F) noexcept; |
636 | void await_resume() noexcept; |
637 | } a; |
638 | struct promise { |
639 | void get_return_object(); |
640 | awaitable initial_suspend(); |
641 | awaitable final_suspend() noexcept; |
642 | awaitable yield_value(int); // expected-note 2{{candidate}} |
643 | void return_value(int); // expected-note 2{{here}} |
644 | void unhandled_exception(); |
645 | }; |
646 | template <typename... T> |
647 | struct std::coroutine_traits<void, T...> { using promise_type = promise; }; |
648 | namespace std { |
649 | template <class PromiseType = void> |
650 | struct coroutine_handle { |
651 | static coroutine_handle from_address(void *) noexcept; |
652 | }; |
653 | } // namespace std |
654 | )cpp" )); |
655 | StringRef CoReturnCode = R"cpp( |
656 | #include <coro_header> |
657 | void check_match_co_return() { |
658 | co_return 1; |
659 | } |
660 | )cpp" ; |
661 | EXPECT_TRUE(matchesConditionally(CoReturnCode, |
662 | coreturnStmt(isExpansionInMainFile()), true, |
663 | {"-std=c++20" , "-I/" }, M)); |
664 | StringRef CoAwaitCode = R"cpp( |
665 | #include <coro_header> |
666 | void check_match_co_await() { |
667 | co_await a; |
668 | } |
669 | )cpp" ; |
670 | EXPECT_TRUE(matchesConditionally(CoAwaitCode, |
671 | coawaitExpr(isExpansionInMainFile()), true, |
672 | {"-std=c++20" , "-I/" }, M)); |
673 | StringRef CoYieldCode = R"cpp( |
674 | #include <coro_header> |
675 | void check_match_co_yield() { |
676 | co_yield 1.0; |
677 | } |
678 | )cpp" ; |
679 | EXPECT_TRUE(matchesConditionally(CoYieldCode, |
680 | coyieldExpr(isExpansionInMainFile()), true, |
681 | {"-std=c++20" , "-I/" }, M)); |
682 | |
683 | StringRef NonCoroCode = R"cpp( |
684 | #include <coro_header> |
685 | void non_coro_function() { |
686 | } |
687 | )cpp" ; |
688 | |
689 | EXPECT_TRUE(matchesConditionally(CoReturnCode, coroutineBodyStmt(), true, |
690 | {"-std=c++20" , "-I/" }, M)); |
691 | EXPECT_TRUE(matchesConditionally(CoAwaitCode, coroutineBodyStmt(), true, |
692 | {"-std=c++20" , "-I/" }, M)); |
693 | EXPECT_TRUE(matchesConditionally(CoYieldCode, coroutineBodyStmt(), true, |
694 | {"-std=c++20" , "-I/" }, M)); |
695 | |
696 | EXPECT_FALSE(matchesConditionally(NonCoroCode, coroutineBodyStmt(), true, |
697 | {"-std=c++20" , "-I/" }, M)); |
698 | |
699 | StringRef CoroWithDeclCode = R"cpp( |
700 | #include <coro_header> |
701 | void coro() { |
702 | int thevar; |
703 | co_return 1; |
704 | } |
705 | )cpp" ; |
706 | EXPECT_TRUE(matchesConditionally( |
707 | CoroWithDeclCode, |
708 | coroutineBodyStmt(hasBody(compoundStmt( |
709 | has(declStmt(containsDeclaration(0, varDecl(hasName("thevar" )))))))), |
710 | true, {"-std=c++20" , "-I/" }, M)); |
711 | |
712 | StringRef CoroWithTryCatchDeclCode = R"cpp( |
713 | #include <coro_header> |
714 | void coro() try { |
715 | int thevar; |
716 | co_return 1; |
717 | } catch (...) {} |
718 | )cpp" ; |
719 | EXPECT_TRUE(matchesConditionally( |
720 | CoroWithTryCatchDeclCode, |
721 | coroutineBodyStmt(hasBody(compoundStmt(has(cxxTryStmt(has(compoundStmt(has( |
722 | declStmt(containsDeclaration(0, varDecl(hasName("thevar" )))))))))))), |
723 | true, {"-std=c++20" , "-I/" }, M)); |
724 | } |
725 | |
726 | TEST(Matcher, isClassMessage) { |
727 | EXPECT_TRUE(matchesObjC( |
728 | "@interface NSString +(NSString *) stringWithFormat; @end " |
729 | "void f() { [NSString stringWithFormat]; }" , |
730 | objcMessageExpr(isClassMessage()))); |
731 | |
732 | EXPECT_FALSE(matchesObjC( |
733 | "@interface NSString @end " |
734 | "void f(NSString *x) {" |
735 | "[x containsString];" |
736 | "}" , |
737 | objcMessageExpr(isClassMessage()))); |
738 | } |
739 | |
740 | TEST(Matcher, isInstanceMessage) { |
741 | EXPECT_TRUE(matchesObjC( |
742 | "@interface NSString @end " |
743 | "void f(NSString *x) {" |
744 | "[x containsString];" |
745 | "}" , |
746 | objcMessageExpr(isInstanceMessage()))); |
747 | |
748 | EXPECT_FALSE(matchesObjC( |
749 | "@interface NSString +(NSString *) stringWithFormat; @end " |
750 | "void f() { [NSString stringWithFormat]; }" , |
751 | objcMessageExpr(isInstanceMessage()))); |
752 | |
753 | } |
754 | |
755 | TEST(Matcher, isClassMethod) { |
756 | EXPECT_TRUE(matchesObjC( |
757 | "@interface Bar + (void)bar; @end" , |
758 | objcMethodDecl(isClassMethod()))); |
759 | |
760 | EXPECT_TRUE(matchesObjC( |
761 | "@interface Bar @end" |
762 | "@implementation Bar + (void)bar {} @end" , |
763 | objcMethodDecl(isClassMethod()))); |
764 | |
765 | EXPECT_FALSE(matchesObjC( |
766 | "@interface Foo - (void)foo; @end" , |
767 | objcMethodDecl(isClassMethod()))); |
768 | |
769 | EXPECT_FALSE(matchesObjC( |
770 | "@interface Foo @end " |
771 | "@implementation Foo - (void)foo {} @end" , |
772 | objcMethodDecl(isClassMethod()))); |
773 | } |
774 | |
775 | TEST(Matcher, isInstanceMethod) { |
776 | EXPECT_TRUE(matchesObjC( |
777 | "@interface Foo - (void)foo; @end" , |
778 | objcMethodDecl(isInstanceMethod()))); |
779 | |
780 | EXPECT_TRUE(matchesObjC( |
781 | "@interface Foo @end " |
782 | "@implementation Foo - (void)foo {} @end" , |
783 | objcMethodDecl(isInstanceMethod()))); |
784 | |
785 | EXPECT_FALSE(matchesObjC( |
786 | "@interface Bar + (void)bar; @end" , |
787 | objcMethodDecl(isInstanceMethod()))); |
788 | |
789 | EXPECT_FALSE(matchesObjC( |
790 | "@interface Bar @end" |
791 | "@implementation Bar + (void)bar {} @end" , |
792 | objcMethodDecl(isInstanceMethod()))); |
793 | } |
794 | |
795 | TEST(MatcherCXXMemberCallExpr, On) { |
796 | StringRef Snippet1 = R"cc( |
797 | struct Y { |
798 | void m(); |
799 | }; |
800 | void z(Y y) { y.m(); } |
801 | )cc" ; |
802 | StringRef Snippet2 = R"cc( |
803 | struct Y { |
804 | void m(); |
805 | }; |
806 | struct X : public Y {}; |
807 | void z(X x) { x.m(); } |
808 | )cc" ; |
809 | auto MatchesY = cxxMemberCallExpr(on(InnerMatcher: hasType(InnerMatcher: cxxRecordDecl(hasName(Name: "Y" ))))); |
810 | EXPECT_TRUE(matches(Snippet1, MatchesY)); |
811 | EXPECT_TRUE(notMatches(Snippet2, MatchesY)); |
812 | |
813 | auto MatchesX = cxxMemberCallExpr(on(InnerMatcher: hasType(InnerMatcher: cxxRecordDecl(hasName(Name: "X" ))))); |
814 | EXPECT_TRUE(matches(Snippet2, MatchesX)); |
815 | |
816 | // Parens are ignored. |
817 | StringRef Snippet3 = R"cc( |
818 | struct Y { |
819 | void m(); |
820 | }; |
821 | Y g(); |
822 | void z(Y y) { (g()).m(); } |
823 | )cc" ; |
824 | auto MatchesCall = cxxMemberCallExpr(on(InnerMatcher: callExpr())); |
825 | EXPECT_TRUE(matches(Snippet3, MatchesCall)); |
826 | } |
827 | |
828 | TEST(MatcherCXXMemberCallExpr, OnImplicitObjectArgument) { |
829 | StringRef Snippet1 = R"cc( |
830 | struct Y { |
831 | void m(); |
832 | }; |
833 | void z(Y y) { y.m(); } |
834 | )cc" ; |
835 | StringRef Snippet2 = R"cc( |
836 | struct Y { |
837 | void m(); |
838 | }; |
839 | struct X : public Y {}; |
840 | void z(X x) { x.m(); } |
841 | )cc" ; |
842 | auto MatchesY = traverse(TK: TK_AsIs, InnerMatcher: cxxMemberCallExpr(onImplicitObjectArgument( |
843 | InnerMatcher: hasType(InnerMatcher: cxxRecordDecl(hasName(Name: "Y" )))))); |
844 | EXPECT_TRUE(matches(Snippet1, MatchesY)); |
845 | EXPECT_TRUE(matches(Snippet2, MatchesY)); |
846 | |
847 | auto MatchesX = traverse(TK: TK_AsIs, InnerMatcher: cxxMemberCallExpr(onImplicitObjectArgument( |
848 | InnerMatcher: hasType(InnerMatcher: cxxRecordDecl(hasName(Name: "X" )))))); |
849 | EXPECT_TRUE(notMatches(Snippet2, MatchesX)); |
850 | |
851 | // Parens are not ignored. |
852 | StringRef Snippet3 = R"cc( |
853 | struct Y { |
854 | void m(); |
855 | }; |
856 | Y g(); |
857 | void z(Y y) { (g()).m(); } |
858 | )cc" ; |
859 | auto MatchesCall = traverse( |
860 | TK: TK_AsIs, InnerMatcher: cxxMemberCallExpr(onImplicitObjectArgument(InnerMatcher: callExpr()))); |
861 | EXPECT_TRUE(notMatches(Snippet3, MatchesCall)); |
862 | } |
863 | |
864 | TEST(Matcher, HasObjectExpr) { |
865 | StringRef Snippet1 = R"cc( |
866 | struct X { |
867 | int m; |
868 | int f(X x) { return x.m; } |
869 | }; |
870 | )cc" ; |
871 | StringRef Snippet2 = R"cc( |
872 | struct X { |
873 | int m; |
874 | int f(X x) { return m; } |
875 | }; |
876 | )cc" ; |
877 | auto MatchesX = |
878 | memberExpr(hasObjectExpression(InnerMatcher: hasType(InnerMatcher: cxxRecordDecl(hasName(Name: "X" ))))); |
879 | EXPECT_TRUE(matches(Snippet1, MatchesX)); |
880 | EXPECT_TRUE(notMatches(Snippet2, MatchesX)); |
881 | |
882 | auto MatchesXPointer = memberExpr( |
883 | hasObjectExpression(InnerMatcher: hasType(InnerMatcher: pointsTo(InnerMatcher: cxxRecordDecl(hasName(Name: "X" )))))); |
884 | EXPECT_TRUE(notMatches(Snippet1, MatchesXPointer)); |
885 | EXPECT_TRUE(matches(Snippet2, MatchesXPointer)); |
886 | } |
887 | |
888 | TEST(ForEachArgumentWithParam, ReportsNoFalsePositives) { |
889 | StatementMatcher ArgumentY = |
890 | declRefExpr(to(InnerMatcher: varDecl(hasName(Name: "y" )))).bind(ID: "arg" ); |
891 | DeclarationMatcher IntParam = parmVarDecl(hasType(InnerMatcher: isInteger())).bind(ID: "param" ); |
892 | StatementMatcher CallExpr = |
893 | callExpr(forEachArgumentWithParam(ArgMatcher: ArgumentY, ParamMatcher: IntParam)); |
894 | |
895 | // IntParam does not match. |
896 | EXPECT_TRUE(notMatches("void f(int* i) { int* y; f(y); }" , CallExpr)); |
897 | // ArgumentY does not match. |
898 | EXPECT_TRUE(notMatches("void f(int i) { int x; f(x); }" , CallExpr)); |
899 | } |
900 | |
901 | TEST(ForEachArgumentWithParam, MatchesCXXMemberCallExpr) { |
902 | StatementMatcher ArgumentY = |
903 | declRefExpr(to(InnerMatcher: varDecl(hasName(Name: "y" )))).bind(ID: "arg" ); |
904 | DeclarationMatcher IntParam = parmVarDecl(hasType(InnerMatcher: isInteger())).bind(ID: "param" ); |
905 | StatementMatcher CallExpr = |
906 | callExpr(forEachArgumentWithParam(ArgMatcher: ArgumentY, ParamMatcher: IntParam)); |
907 | EXPECT_TRUE(matchAndVerifyResultTrue( |
908 | "struct S {" |
909 | " const S& operator[](int i) { return *this; }" |
910 | "};" |
911 | "void f(S S1) {" |
912 | " int y = 1;" |
913 | " S1[y];" |
914 | "}" , |
915 | CallExpr, std::make_unique<VerifyIdIsBoundTo<ParmVarDecl>>("param" , 1))); |
916 | |
917 | StatementMatcher CallExpr2 = |
918 | callExpr(forEachArgumentWithParam(ArgMatcher: ArgumentY, ParamMatcher: IntParam)); |
919 | EXPECT_TRUE(matchAndVerifyResultTrue( |
920 | "struct S {" |
921 | " static void g(int i);" |
922 | "};" |
923 | "void f() {" |
924 | " int y = 1;" |
925 | " S::g(y);" |
926 | "}" , |
927 | CallExpr2, std::make_unique<VerifyIdIsBoundTo<ParmVarDecl>>("param" , 1))); |
928 | } |
929 | |
930 | TEST(ForEachArgumentWithParam, MatchesCallExpr) { |
931 | StatementMatcher ArgumentY = |
932 | declRefExpr(to(InnerMatcher: varDecl(hasName(Name: "y" )))).bind(ID: "arg" ); |
933 | DeclarationMatcher IntParam = parmVarDecl(hasType(InnerMatcher: isInteger())).bind(ID: "param" ); |
934 | StatementMatcher CallExpr = |
935 | callExpr(forEachArgumentWithParam(ArgMatcher: ArgumentY, ParamMatcher: IntParam)); |
936 | |
937 | EXPECT_TRUE( |
938 | matchAndVerifyResultTrue("void f(int i) { int y; f(y); }" , CallExpr, |
939 | std::make_unique<VerifyIdIsBoundTo<ParmVarDecl>>( |
940 | "param" ))); |
941 | EXPECT_TRUE( |
942 | matchAndVerifyResultTrue("void f(int i) { int y; f(y); }" , CallExpr, |
943 | std::make_unique<VerifyIdIsBoundTo<DeclRefExpr>>( |
944 | "arg" ))); |
945 | |
946 | EXPECT_TRUE(matchAndVerifyResultTrue( |
947 | "void f(int i, int j) { int y; f(y, y); }" , CallExpr, |
948 | std::make_unique<VerifyIdIsBoundTo<ParmVarDecl>>("param" , 2))); |
949 | EXPECT_TRUE(matchAndVerifyResultTrue( |
950 | "void f(int i, int j) { int y; f(y, y); }" , CallExpr, |
951 | std::make_unique<VerifyIdIsBoundTo<DeclRefExpr>>("arg" , 2))); |
952 | } |
953 | |
954 | TEST(ForEachArgumentWithParam, MatchesConstructExpr) { |
955 | StatementMatcher ArgumentY = |
956 | declRefExpr(to(InnerMatcher: varDecl(hasName(Name: "y" )))).bind(ID: "arg" ); |
957 | DeclarationMatcher IntParam = parmVarDecl(hasType(InnerMatcher: isInteger())).bind(ID: "param" ); |
958 | StatementMatcher ConstructExpr = traverse( |
959 | TK: TK_AsIs, InnerMatcher: cxxConstructExpr(forEachArgumentWithParam(ArgMatcher: ArgumentY, ParamMatcher: IntParam))); |
960 | |
961 | EXPECT_TRUE(matchAndVerifyResultTrue( |
962 | "struct C {" |
963 | " C(int i) {}" |
964 | "};" |
965 | "int y = 0;" |
966 | "C Obj(y);" , |
967 | ConstructExpr, |
968 | std::make_unique<VerifyIdIsBoundTo<ParmVarDecl>>("param" ))); |
969 | } |
970 | |
971 | TEST(ForEachArgumentWithParam, HandlesBoundNodesForNonMatches) { |
972 | EXPECT_TRUE(matchAndVerifyResultTrue( |
973 | "void g(int i, int j) {" |
974 | " int a;" |
975 | " int b;" |
976 | " int c;" |
977 | " g(a, 0);" |
978 | " g(a, b);" |
979 | " g(0, b);" |
980 | "}" , |
981 | functionDecl( |
982 | forEachDescendant(varDecl().bind("v" )), |
983 | forEachDescendant(callExpr(forEachArgumentWithParam( |
984 | declRefExpr(to(decl(equalsBoundNode("v" )))), parmVarDecl())))), |
985 | std::make_unique<VerifyIdIsBoundTo<VarDecl>>("v" , 4))); |
986 | } |
987 | |
988 | TEST_P(ASTMatchersTest, |
989 | ForEachArgumentWithParamMatchesExplicitObjectParamOnOperatorCalls) { |
990 | if (!GetParam().isCXX23OrLater()) { |
991 | return; |
992 | } |
993 | |
994 | auto DeclRef = declRefExpr(to(InnerMatcher: varDecl().bind(ID: "declOfArg" ))).bind(ID: "arg" ); |
995 | auto SelfParam = parmVarDecl().bind(ID: "param" ); |
996 | StatementMatcher CallExpr = |
997 | callExpr(forEachArgumentWithParam(ArgMatcher: DeclRef, ParamMatcher: SelfParam)); |
998 | |
999 | StringRef S = R"cpp( |
1000 | struct A { |
1001 | int operator()(this const A &self); |
1002 | }; |
1003 | A obj; |
1004 | int global = obj(); |
1005 | )cpp" ; |
1006 | |
1007 | auto Args = GetParam().getCommandLineArgs(); |
1008 | auto Filename = getFilenameForTesting(Lang: GetParam().Language); |
1009 | |
1010 | EXPECT_TRUE(matchAndVerifyResultTrue( |
1011 | S, CallExpr, |
1012 | std::make_unique<VerifyIdIsBoundTo<ParmVarDecl>>("param" , "self" ), Args, |
1013 | Filename)); |
1014 | EXPECT_TRUE(matchAndVerifyResultTrue( |
1015 | S, CallExpr, |
1016 | std::make_unique<VerifyIdIsBoundTo<VarDecl>>("declOfArg" , "obj" ), Args, |
1017 | Filename)); |
1018 | } |
1019 | |
1020 | TEST(ForEachArgumentWithParamType, ReportsNoFalsePositives) { |
1021 | StatementMatcher ArgumentY = |
1022 | declRefExpr(to(InnerMatcher: varDecl(hasName(Name: "y" )))).bind(ID: "arg" ); |
1023 | TypeMatcher IntType = qualType(isInteger()).bind(ID: "type" ); |
1024 | StatementMatcher CallExpr = |
1025 | callExpr(forEachArgumentWithParamType(ArgMatcher: ArgumentY, ParamMatcher: IntType)); |
1026 | |
1027 | // IntParam does not match. |
1028 | EXPECT_TRUE(notMatches("void f(int* i) { int* y; f(y); }" , CallExpr)); |
1029 | // ArgumentY does not match. |
1030 | EXPECT_TRUE(notMatches("void f(int i) { int x; f(x); }" , CallExpr)); |
1031 | } |
1032 | |
1033 | TEST(ForEachArgumentWithParamType, MatchesCXXMemberCallExpr) { |
1034 | StatementMatcher ArgumentY = |
1035 | declRefExpr(to(InnerMatcher: varDecl(hasName(Name: "y" )))).bind(ID: "arg" ); |
1036 | TypeMatcher IntType = qualType(isInteger()).bind(ID: "type" ); |
1037 | StatementMatcher CallExpr = |
1038 | callExpr(forEachArgumentWithParamType(ArgMatcher: ArgumentY, ParamMatcher: IntType)); |
1039 | EXPECT_TRUE(matchAndVerifyResultTrue( |
1040 | "struct S {" |
1041 | " const S& operator[](int i) { return *this; }" |
1042 | "};" |
1043 | "void f(S S1) {" |
1044 | " int y = 1;" |
1045 | " S1[y];" |
1046 | "}" , |
1047 | CallExpr, std::make_unique<VerifyIdIsBoundTo<QualType>>("type" , 1))); |
1048 | |
1049 | StatementMatcher CallExpr2 = |
1050 | callExpr(forEachArgumentWithParamType(ArgMatcher: ArgumentY, ParamMatcher: IntType)); |
1051 | EXPECT_TRUE(matchAndVerifyResultTrue( |
1052 | "struct S {" |
1053 | " static void g(int i);" |
1054 | "};" |
1055 | "void f() {" |
1056 | " int y = 1;" |
1057 | " S::g(y);" |
1058 | "}" , |
1059 | CallExpr2, std::make_unique<VerifyIdIsBoundTo<QualType>>("type" , 1))); |
1060 | } |
1061 | |
1062 | TEST(ForEachArgumentWithParamType, MatchesCallExpr) { |
1063 | StatementMatcher ArgumentY = |
1064 | declRefExpr(to(InnerMatcher: varDecl(hasName(Name: "y" )))).bind(ID: "arg" ); |
1065 | TypeMatcher IntType = qualType(isInteger()).bind(ID: "type" ); |
1066 | StatementMatcher CallExpr = |
1067 | callExpr(forEachArgumentWithParamType(ArgMatcher: ArgumentY, ParamMatcher: IntType)); |
1068 | |
1069 | EXPECT_TRUE(matchAndVerifyResultTrue( |
1070 | "void f(int i) { int y; f(y); }" , CallExpr, |
1071 | std::make_unique<VerifyIdIsBoundTo<QualType>>("type" ))); |
1072 | EXPECT_TRUE(matchAndVerifyResultTrue( |
1073 | "void f(int i) { int y; f(y); }" , CallExpr, |
1074 | std::make_unique<VerifyIdIsBoundTo<DeclRefExpr>>("arg" ))); |
1075 | |
1076 | EXPECT_TRUE(matchAndVerifyResultTrue( |
1077 | "void f(int i, int j) { int y; f(y, y); }" , CallExpr, |
1078 | std::make_unique<VerifyIdIsBoundTo<QualType>>("type" , 2))); |
1079 | EXPECT_TRUE(matchAndVerifyResultTrue( |
1080 | "void f(int i, int j) { int y; f(y, y); }" , CallExpr, |
1081 | std::make_unique<VerifyIdIsBoundTo<DeclRefExpr>>("arg" , 2))); |
1082 | } |
1083 | |
1084 | TEST(ForEachArgumentWithParamType, MatchesConstructExpr) { |
1085 | StatementMatcher ArgumentY = |
1086 | declRefExpr(to(InnerMatcher: varDecl(hasName(Name: "y" )))).bind(ID: "arg" ); |
1087 | TypeMatcher IntType = qualType(isInteger()).bind(ID: "type" ); |
1088 | StatementMatcher ConstructExpr = |
1089 | cxxConstructExpr(forEachArgumentWithParamType(ArgMatcher: ArgumentY, ParamMatcher: IntType)); |
1090 | |
1091 | EXPECT_TRUE(matchAndVerifyResultTrue( |
1092 | "struct C {" |
1093 | " C(int i) {}" |
1094 | "};" |
1095 | "int y = 0;" |
1096 | "C Obj(y);" , |
1097 | ConstructExpr, std::make_unique<VerifyIdIsBoundTo<QualType>>("type" ))); |
1098 | EXPECT_TRUE(matchAndVerifyResultTrue( |
1099 | "struct C {" |
1100 | " C(int i) {}" |
1101 | "};" |
1102 | "int y = 0;" |
1103 | "C Obj(y);" , |
1104 | ConstructExpr, std::make_unique<VerifyIdIsBoundTo<DeclRefExpr>>("arg" ))); |
1105 | } |
1106 | |
1107 | TEST(ForEachArgumentWithParamType, HandlesKandRFunctions) { |
1108 | StatementMatcher ArgumentY = |
1109 | declRefExpr(to(InnerMatcher: varDecl(hasName(Name: "y" )))).bind(ID: "arg" ); |
1110 | TypeMatcher IntType = qualType(isInteger()).bind(ID: "type" ); |
1111 | StatementMatcher CallExpr = |
1112 | callExpr(forEachArgumentWithParamType(ArgMatcher: ArgumentY, ParamMatcher: IntType)); |
1113 | |
1114 | EXPECT_TRUE(matchesC("void f();\n" |
1115 | "void call_it(void) { int x, y; f(x, y); }\n" |
1116 | "void f(a, b) int a, b; {}\n" |
1117 | "void call_it2(void) { int x, y; f(x, y); }" , |
1118 | CallExpr)); |
1119 | } |
1120 | |
1121 | TEST(ForEachArgumentWithParamType, HandlesBoundNodesForNonMatches) { |
1122 | EXPECT_TRUE(matchAndVerifyResultTrue( |
1123 | "void g(int i, int j) {" |
1124 | " int a;" |
1125 | " int b;" |
1126 | " int c;" |
1127 | " g(a, 0);" |
1128 | " g(a, b);" |
1129 | " g(0, b);" |
1130 | "}" , |
1131 | functionDecl( |
1132 | forEachDescendant(varDecl().bind("v" )), |
1133 | forEachDescendant(callExpr(forEachArgumentWithParamType( |
1134 | declRefExpr(to(decl(equalsBoundNode("v" )))), qualType())))), |
1135 | std::make_unique<VerifyIdIsBoundTo<VarDecl>>("v" , 4))); |
1136 | } |
1137 | |
1138 | TEST(ForEachArgumentWithParamType, MatchesFunctionPtrCalls) { |
1139 | StatementMatcher ArgumentY = |
1140 | declRefExpr(to(InnerMatcher: varDecl(hasName(Name: "y" )))).bind(ID: "arg" ); |
1141 | TypeMatcher IntType = qualType(builtinType()).bind(ID: "type" ); |
1142 | StatementMatcher CallExpr = |
1143 | callExpr(forEachArgumentWithParamType(ArgMatcher: ArgumentY, ParamMatcher: IntType)); |
1144 | |
1145 | EXPECT_TRUE(matchAndVerifyResultTrue( |
1146 | "void f(int i) {" |
1147 | "void (*f_ptr)(int) = f; int y; f_ptr(y); }" , |
1148 | CallExpr, std::make_unique<VerifyIdIsBoundTo<QualType>>("type" ))); |
1149 | EXPECT_TRUE(matchAndVerifyResultTrue( |
1150 | "void f(int i) {" |
1151 | "void (*f_ptr)(int) = f; int y; f_ptr(y); }" , |
1152 | CallExpr, std::make_unique<VerifyIdIsBoundTo<DeclRefExpr>>("arg" ))); |
1153 | } |
1154 | |
1155 | TEST(ForEachArgumentWithParamType, MatchesMemberFunctionPtrCalls) { |
1156 | StatementMatcher ArgumentY = |
1157 | declRefExpr(to(InnerMatcher: varDecl(hasName(Name: "y" )))).bind(ID: "arg" ); |
1158 | TypeMatcher IntType = qualType(builtinType()).bind(ID: "type" ); |
1159 | StatementMatcher CallExpr = |
1160 | callExpr(forEachArgumentWithParamType(ArgMatcher: ArgumentY, ParamMatcher: IntType)); |
1161 | |
1162 | StringRef S = "struct A {\n" |
1163 | " int f(int i) { return i + 1; }\n" |
1164 | " int (A::*x)(int);\n" |
1165 | "};\n" |
1166 | "void f() {\n" |
1167 | " int y = 42;\n" |
1168 | " A a;\n" |
1169 | " a.x = &A::f;\n" |
1170 | " (a.*(a.x))(y);\n" |
1171 | "}" ; |
1172 | EXPECT_TRUE(matchAndVerifyResultTrue( |
1173 | S, CallExpr, std::make_unique<VerifyIdIsBoundTo<QualType>>("type" ))); |
1174 | EXPECT_TRUE(matchAndVerifyResultTrue( |
1175 | S, CallExpr, std::make_unique<VerifyIdIsBoundTo<DeclRefExpr>>("arg" ))); |
1176 | } |
1177 | |
1178 | TEST(ForEachArgumentWithParamType, MatchesVariadicFunctionPtrCalls) { |
1179 | StatementMatcher ArgumentY = |
1180 | declRefExpr(to(InnerMatcher: varDecl(hasName(Name: "y" )))).bind(ID: "arg" ); |
1181 | TypeMatcher IntType = qualType(builtinType()).bind(ID: "type" ); |
1182 | StatementMatcher CallExpr = |
1183 | callExpr(forEachArgumentWithParamType(ArgMatcher: ArgumentY, ParamMatcher: IntType)); |
1184 | |
1185 | StringRef S = R"cpp( |
1186 | void fcntl(int fd, int cmd, ...) {} |
1187 | |
1188 | template <typename Func> |
1189 | void f(Func F) { |
1190 | int y = 42; |
1191 | F(y, 1, 3); |
1192 | } |
1193 | |
1194 | void g() { f(fcntl); } |
1195 | )cpp" ; |
1196 | |
1197 | EXPECT_TRUE(matchAndVerifyResultTrue( |
1198 | S, CallExpr, std::make_unique<VerifyIdIsBoundTo<QualType>>("type" ))); |
1199 | EXPECT_TRUE(matchAndVerifyResultTrue( |
1200 | S, CallExpr, std::make_unique<VerifyIdIsBoundTo<DeclRefExpr>>("arg" ))); |
1201 | } |
1202 | |
1203 | TEST_P(ASTMatchersTest, |
1204 | ForEachArgumentWithParamTypeMatchesExplicitObjectParamOnOperatorCalls) { |
1205 | if (!GetParam().isCXX23OrLater()) { |
1206 | return; |
1207 | } |
1208 | |
1209 | auto DeclRef = declRefExpr(to(InnerMatcher: varDecl().bind(ID: "declOfArg" ))).bind(ID: "arg" ); |
1210 | auto SelfTy = qualType(asString(Name: "const A &" )).bind(ID: "selfType" ); |
1211 | StatementMatcher CallExpr = |
1212 | callExpr(forEachArgumentWithParamType(ArgMatcher: DeclRef, ParamMatcher: SelfTy)); |
1213 | |
1214 | StringRef S = R"cpp( |
1215 | struct A { |
1216 | int operator()(this const A &self); |
1217 | }; |
1218 | A obj; |
1219 | int global = obj(); |
1220 | )cpp" ; |
1221 | |
1222 | auto Args = GetParam().getCommandLineArgs(); |
1223 | auto Filename = getFilenameForTesting(Lang: GetParam().Language); |
1224 | |
1225 | EXPECT_TRUE(matchAndVerifyResultTrue( |
1226 | S, CallExpr, std::make_unique<VerifyIdIsBoundTo<QualType>>("selfType" ), |
1227 | Args, Filename)); |
1228 | EXPECT_TRUE(matchAndVerifyResultTrue( |
1229 | S, CallExpr, |
1230 | std::make_unique<VerifyIdIsBoundTo<VarDecl>>("declOfArg" , "obj" ), Args, |
1231 | Filename)); |
1232 | } |
1233 | |
1234 | TEST(QualType, hasCanonicalType) { |
1235 | EXPECT_TRUE(notMatches("typedef int &int_ref;" |
1236 | "int a;" |
1237 | "int_ref b = a;" , |
1238 | varDecl(hasType(qualType(referenceType()))))); |
1239 | EXPECT_TRUE( |
1240 | matches("typedef int &int_ref;" |
1241 | "int a;" |
1242 | "int_ref b = a;" , |
1243 | varDecl(hasType(qualType(hasCanonicalType(referenceType())))))); |
1244 | } |
1245 | |
1246 | TEST(HasParameter, CallsInnerMatcher) { |
1247 | EXPECT_TRUE(matches("class X { void x(int) {} };" , |
1248 | cxxMethodDecl(hasParameter(0, varDecl())))); |
1249 | EXPECT_TRUE(notMatches("class X { void x(int) {} };" , |
1250 | cxxMethodDecl(hasParameter(0, hasName("x" ))))); |
1251 | EXPECT_TRUE(matchesObjC("@interface I -(void)f:(int) x; @end" , |
1252 | objcMethodDecl(hasParameter(0, hasName("x" ))))); |
1253 | EXPECT_TRUE(matchesObjC("int main() { void (^b)(int) = ^(int p) {}; }" , |
1254 | blockDecl(hasParameter(0, hasName("p" ))))); |
1255 | } |
1256 | |
1257 | TEST(HasParameter, DoesNotMatchIfIndexOutOfBounds) { |
1258 | EXPECT_TRUE(notMatches("class X { void x(int) {} };" , |
1259 | cxxMethodDecl(hasParameter(42, varDecl())))); |
1260 | } |
1261 | |
1262 | TEST(HasType, MatchesParameterVariableTypesStrictly) { |
1263 | EXPECT_TRUE(matches( |
1264 | "class X { void x(X x) {} };" , |
1265 | cxxMethodDecl(hasParameter(0, hasType(recordDecl(hasName("X" ))))))); |
1266 | EXPECT_TRUE(notMatches( |
1267 | "class X { void x(const X &x) {} };" , |
1268 | cxxMethodDecl(hasParameter(0, hasType(recordDecl(hasName("X" ))))))); |
1269 | EXPECT_TRUE(matches("class X { void x(const X *x) {} };" , |
1270 | cxxMethodDecl(hasParameter( |
1271 | 0, hasType(pointsTo(recordDecl(hasName("X" )))))))); |
1272 | EXPECT_TRUE(matches("class X { void x(const X &x) {} };" , |
1273 | cxxMethodDecl(hasParameter( |
1274 | 0, hasType(references(recordDecl(hasName("X" )))))))); |
1275 | } |
1276 | |
1277 | TEST(HasAnyParameter, MatchesIndependentlyOfPosition) { |
1278 | EXPECT_TRUE(matches( |
1279 | "class Y {}; class X { void x(X x, Y y) {} };" , |
1280 | cxxMethodDecl(hasAnyParameter(hasType(recordDecl(hasName("X" ))))))); |
1281 | EXPECT_TRUE(matches( |
1282 | "class Y {}; class X { void x(Y y, X x) {} };" , |
1283 | cxxMethodDecl(hasAnyParameter(hasType(recordDecl(hasName("X" ))))))); |
1284 | EXPECT_TRUE(matchesObjC("@interface I -(void)f:(int) x; @end" , |
1285 | objcMethodDecl(hasAnyParameter(hasName("x" ))))); |
1286 | EXPECT_TRUE(matchesObjC("int main() { void (^b)(int) = ^(int p) {}; }" , |
1287 | blockDecl(hasAnyParameter(hasName("p" ))))); |
1288 | } |
1289 | |
1290 | TEST(Returns, MatchesReturnTypes) { |
1291 | EXPECT_TRUE(matches("class Y { int f() { return 1; } };" , |
1292 | functionDecl(returns(asString("int" ))))); |
1293 | EXPECT_TRUE(notMatches("class Y { int f() { return 1; } };" , |
1294 | functionDecl(returns(asString("float" ))))); |
1295 | EXPECT_TRUE(matches("class Y { Y getMe() { return *this; } };" , |
1296 | functionDecl(returns(hasDeclaration( |
1297 | recordDecl(hasName("Y" ))))))); |
1298 | } |
1299 | |
1300 | TEST(HasAnyParameter, DoesntMatchIfInnerMatcherDoesntMatch) { |
1301 | EXPECT_TRUE(notMatches( |
1302 | "class Y {}; class X { void x(int) {} };" , |
1303 | cxxMethodDecl(hasAnyParameter(hasType(recordDecl(hasName("X" ))))))); |
1304 | } |
1305 | |
1306 | TEST(HasAnyParameter, DoesNotMatchThisPointer) { |
1307 | EXPECT_TRUE(notMatches("class Y {}; class X { void x() {} };" , |
1308 | cxxMethodDecl(hasAnyParameter( |
1309 | hasType(pointsTo(recordDecl(hasName("X" )))))))); |
1310 | } |
1311 | |
1312 | TEST(HasName, MatchesParameterVariableDeclarations) { |
1313 | EXPECT_TRUE(matches("class Y {}; class X { void x(int x) {} };" , |
1314 | cxxMethodDecl(hasAnyParameter(hasName("x" ))))); |
1315 | EXPECT_TRUE(notMatches("class Y {}; class X { void x(int) {} };" , |
1316 | cxxMethodDecl(hasAnyParameter(hasName("x" ))))); |
1317 | } |
1318 | |
1319 | TEST(Matcher, MatchesTypeTemplateArgument) { |
1320 | EXPECT_TRUE(matches( |
1321 | "template<typename T> struct B {};" |
1322 | "B<int> b;" , |
1323 | classTemplateSpecializationDecl(hasAnyTemplateArgument(refersToType( |
1324 | asString("int" )))))); |
1325 | } |
1326 | |
1327 | TEST(Matcher, MatchesTemplateTemplateArgument) { |
1328 | EXPECT_TRUE(matches("template<template <typename> class S> class X {};" |
1329 | "template<typename T> class Y {};" |
1330 | "X<Y> xi;" , |
1331 | classTemplateSpecializationDecl(hasAnyTemplateArgument( |
1332 | refersToTemplate(templateName()))))); |
1333 | } |
1334 | |
1335 | TEST(Matcher, MatchesDeclarationReferenceTemplateArgument) { |
1336 | EXPECT_TRUE(matches( |
1337 | "struct B { int next; };" |
1338 | "template<int(B::*next_ptr)> struct A {};" |
1339 | "A<&B::next> a;" , |
1340 | classTemplateSpecializationDecl(hasAnyTemplateArgument( |
1341 | refersToDeclaration(fieldDecl(hasName("next" ))))))); |
1342 | |
1343 | EXPECT_TRUE(notMatches( |
1344 | "template <typename T> struct A {};" |
1345 | "A<int> a;" , |
1346 | classTemplateSpecializationDecl(hasAnyTemplateArgument( |
1347 | refersToDeclaration(decl()))))); |
1348 | |
1349 | EXPECT_TRUE(matches( |
1350 | "struct B { int next; };" |
1351 | "template<int(B::*next_ptr)> struct A {};" |
1352 | "A<&B::next> a;" , |
1353 | templateSpecializationType(hasAnyTemplateArgument(isExpr( |
1354 | hasDescendant(declRefExpr(to(fieldDecl(hasName("next" )))))))))); |
1355 | |
1356 | EXPECT_TRUE(notMatches( |
1357 | "template <typename T> struct A {};" |
1358 | "A<int> a;" , |
1359 | templateSpecializationType(hasAnyTemplateArgument( |
1360 | refersToDeclaration(decl()))))); |
1361 | } |
1362 | |
1363 | |
1364 | TEST(Matcher, MatchesSpecificArgument) { |
1365 | EXPECT_TRUE(matches( |
1366 | "template<typename T, typename U> class A {};" |
1367 | "A<bool, int> a;" , |
1368 | classTemplateSpecializationDecl(hasTemplateArgument( |
1369 | 1, refersToType(asString("int" )))))); |
1370 | EXPECT_TRUE(notMatches( |
1371 | "template<typename T, typename U> class A {};" |
1372 | "A<int, bool> a;" , |
1373 | classTemplateSpecializationDecl(hasTemplateArgument( |
1374 | 1, refersToType(asString("int" )))))); |
1375 | |
1376 | EXPECT_TRUE(matches( |
1377 | "template<typename T, typename U> class A {};" |
1378 | "A<bool, int> a;" , |
1379 | templateSpecializationType(hasTemplateArgument( |
1380 | 1, refersToType(asString("int" )))))); |
1381 | EXPECT_TRUE(notMatches( |
1382 | "template<typename T, typename U> class A {};" |
1383 | "A<int, bool> a;" , |
1384 | templateSpecializationType(hasTemplateArgument( |
1385 | 1, refersToType(asString("int" )))))); |
1386 | |
1387 | EXPECT_TRUE(matches( |
1388 | "template<typename T> void f() {};" |
1389 | "void func() { f<int>(); }" , |
1390 | functionDecl(hasTemplateArgument(0, refersToType(asString("int" )))))); |
1391 | EXPECT_TRUE(notMatches( |
1392 | "template<typename T> void f() {};" , |
1393 | functionDecl(hasTemplateArgument(0, refersToType(asString("int" )))))); |
1394 | } |
1395 | |
1396 | TEST(TemplateArgument, Matches) { |
1397 | EXPECT_TRUE(matches("template<typename T> struct C {}; C<int> c;" , |
1398 | classTemplateSpecializationDecl( |
1399 | hasAnyTemplateArgument(templateArgument())))); |
1400 | EXPECT_TRUE(matches( |
1401 | "template<typename T> struct C {}; C<int> c;" , |
1402 | templateSpecializationType(hasAnyTemplateArgument(templateArgument())))); |
1403 | |
1404 | EXPECT_TRUE(matches( |
1405 | "template<typename T> void f() {};" |
1406 | "void func() { f<int>(); }" , |
1407 | functionDecl(hasAnyTemplateArgument(templateArgument())))); |
1408 | } |
1409 | |
1410 | TEST(TemplateTypeParmDecl, CXXMethodDecl) { |
1411 | const char input[] = |
1412 | "template<typename T>\n" |
1413 | "class Class {\n" |
1414 | " void method();\n" |
1415 | "};\n" |
1416 | "template<typename U>\n" |
1417 | "void Class<U>::method() {}\n" ; |
1418 | EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("T" )))); |
1419 | EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("U" )))); |
1420 | } |
1421 | |
1422 | TEST(TemplateTypeParmDecl, VarDecl) { |
1423 | const char input[] = |
1424 | "template<typename T>\n" |
1425 | "class Class {\n" |
1426 | " static T pi;\n" |
1427 | "};\n" |
1428 | "template<typename U>\n" |
1429 | "U Class<U>::pi = U(3.1415926535897932385);\n" ; |
1430 | EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("T" )))); |
1431 | EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("U" )))); |
1432 | } |
1433 | |
1434 | TEST(TemplateTypeParmDecl, VarTemplatePartialSpecializationDecl) { |
1435 | const char input[] = |
1436 | "template<typename T>\n" |
1437 | "struct Struct {\n" |
1438 | " template<typename T2> static int field;\n" |
1439 | "};\n" |
1440 | "template<typename U>\n" |
1441 | "template<typename U2>\n" |
1442 | "int Struct<U>::field<U2*> = 123;\n" ; |
1443 | EXPECT_TRUE( |
1444 | matches(input, templateTypeParmDecl(hasName("T" )), langCxx14OrLater())); |
1445 | EXPECT_TRUE( |
1446 | matches(input, templateTypeParmDecl(hasName("T2" )), langCxx14OrLater())); |
1447 | EXPECT_TRUE( |
1448 | matches(input, templateTypeParmDecl(hasName("U" )), langCxx14OrLater())); |
1449 | EXPECT_TRUE( |
1450 | matches(input, templateTypeParmDecl(hasName("U2" )), langCxx14OrLater())); |
1451 | } |
1452 | |
1453 | TEST(TemplateTypeParmDecl, ClassTemplatePartialSpecializationDecl) { |
1454 | const char input[] = |
1455 | "template<typename T>\n" |
1456 | "class Class {\n" |
1457 | " template<typename T2> struct Struct;\n" |
1458 | "};\n" |
1459 | "template<typename U>\n" |
1460 | "template<typename U2>\n" |
1461 | "struct Class<U>::Struct<U2*> {};\n" ; |
1462 | EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("T" )))); |
1463 | EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("T2" )))); |
1464 | EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("U" )))); |
1465 | EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("U2" )))); |
1466 | } |
1467 | |
1468 | TEST(TemplateTypeParmDecl, EnumDecl) { |
1469 | const char input[] = |
1470 | "template<typename T>\n" |
1471 | "struct Struct {\n" |
1472 | " enum class Enum : T;\n" |
1473 | "};\n" |
1474 | "template<typename U>\n" |
1475 | "enum class Struct<U>::Enum : U {\n" |
1476 | " e1,\n" |
1477 | " e2\n" |
1478 | "};\n" ; |
1479 | EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("T" )))); |
1480 | EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("U" )))); |
1481 | } |
1482 | |
1483 | TEST(TemplateTypeParmDecl, RecordDecl) { |
1484 | const char input[] = |
1485 | "template<typename T>\n" |
1486 | "class Class {\n" |
1487 | " struct Struct;\n" |
1488 | "};\n" |
1489 | "template<typename U>\n" |
1490 | "struct Class<U>::Struct {\n" |
1491 | " U field;\n" |
1492 | "};\n" ; |
1493 | EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("T" )))); |
1494 | EXPECT_TRUE(matches(input, templateTypeParmDecl(hasName("U" )))); |
1495 | } |
1496 | |
1497 | TEST(RefersToIntegralType, Matches) { |
1498 | EXPECT_TRUE(matches("template<int T> struct C {}; C<42> c;" , |
1499 | classTemplateSpecializationDecl( |
1500 | hasAnyTemplateArgument(refersToIntegralType( |
1501 | asString("int" )))))); |
1502 | EXPECT_TRUE(notMatches("template<unsigned T> struct C {}; C<42> c;" , |
1503 | classTemplateSpecializationDecl(hasAnyTemplateArgument( |
1504 | refersToIntegralType(asString("int" )))))); |
1505 | } |
1506 | |
1507 | TEST(ConstructorDeclaration, SimpleCase) { |
1508 | EXPECT_TRUE(matches("class Foo { Foo(int i); };" , |
1509 | cxxConstructorDecl(ofClass(hasName("Foo" ))))); |
1510 | EXPECT_TRUE(notMatches("class Foo { Foo(int i); };" , |
1511 | cxxConstructorDecl(ofClass(hasName("Bar" ))))); |
1512 | } |
1513 | |
1514 | TEST(DestructorDeclaration, MatchesVirtualDestructor) { |
1515 | EXPECT_TRUE(matches("class Foo { virtual ~Foo(); };" , |
1516 | cxxDestructorDecl(ofClass(hasName("Foo" ))))); |
1517 | } |
1518 | |
1519 | TEST(DestructorDeclaration, DoesNotMatchImplicitDestructor) { |
1520 | EXPECT_TRUE(notMatches("class Foo {};" , |
1521 | cxxDestructorDecl(ofClass(hasName("Foo" ))))); |
1522 | } |
1523 | |
1524 | TEST(HasAnyConstructorInitializer, SimpleCase) { |
1525 | EXPECT_TRUE( |
1526 | notMatches("class Foo { Foo() { } };" , |
1527 | cxxConstructorDecl(hasAnyConstructorInitializer(anything())))); |
1528 | EXPECT_TRUE( |
1529 | matches("class Foo {" |
1530 | " Foo() : foo_() { }" |
1531 | " int foo_;" |
1532 | "};" , |
1533 | cxxConstructorDecl(hasAnyConstructorInitializer(anything())))); |
1534 | } |
1535 | |
1536 | TEST(HasAnyConstructorInitializer, ForField) { |
1537 | static const char Code[] = |
1538 | "class Baz { };" |
1539 | "class Foo {" |
1540 | " Foo() : foo_(), bar_() { }" |
1541 | " Baz foo_;" |
1542 | " struct {" |
1543 | " Baz bar_;" |
1544 | " };" |
1545 | "};" ; |
1546 | EXPECT_TRUE(matches(Code, cxxConstructorDecl(hasAnyConstructorInitializer( |
1547 | forField(hasType(recordDecl(hasName("Baz" )))))))); |
1548 | EXPECT_TRUE(matches(Code, cxxConstructorDecl(hasAnyConstructorInitializer( |
1549 | forField(hasName("foo_" )))))); |
1550 | EXPECT_TRUE(matches(Code, cxxConstructorDecl(hasAnyConstructorInitializer( |
1551 | forField(hasName("bar_" )))))); |
1552 | EXPECT_TRUE(notMatches(Code, cxxConstructorDecl(hasAnyConstructorInitializer( |
1553 | forField(hasType(recordDecl(hasName("Bar" )))))))); |
1554 | } |
1555 | |
1556 | TEST(HasAnyConstructorInitializer, WithInitializer) { |
1557 | static const char Code[] = |
1558 | "class Foo {" |
1559 | " Foo() : foo_(0) { }" |
1560 | " int foo_;" |
1561 | "};" ; |
1562 | EXPECT_TRUE(matches(Code, cxxConstructorDecl(hasAnyConstructorInitializer( |
1563 | withInitializer(integerLiteral(equals(0))))))); |
1564 | EXPECT_TRUE(notMatches(Code, cxxConstructorDecl(hasAnyConstructorInitializer( |
1565 | withInitializer(integerLiteral(equals(1))))))); |
1566 | } |
1567 | |
1568 | TEST(HasAnyConstructorInitializer, IsWritten) { |
1569 | static const char Code[] = |
1570 | "struct Bar { Bar(){} };" |
1571 | "class Foo {" |
1572 | " Foo() : foo_() { }" |
1573 | " Bar foo_;" |
1574 | " Bar bar_;" |
1575 | "};" ; |
1576 | EXPECT_TRUE(matches(Code, cxxConstructorDecl(hasAnyConstructorInitializer( |
1577 | allOf(forField(hasName("foo_" )), isWritten()))))); |
1578 | EXPECT_TRUE(notMatches(Code, cxxConstructorDecl(hasAnyConstructorInitializer( |
1579 | allOf(forField(hasName("bar_" )), isWritten()))))); |
1580 | EXPECT_TRUE(matches(Code, cxxConstructorDecl(hasAnyConstructorInitializer( |
1581 | allOf(forField(hasName("bar_" )), unless(isWritten())))))); |
1582 | } |
1583 | |
1584 | TEST(HasAnyConstructorInitializer, IsBaseInitializer) { |
1585 | static const char Code[] = |
1586 | "struct B {};" |
1587 | "struct D : B {" |
1588 | " int I;" |
1589 | " D(int i) : I(i) {}" |
1590 | "};" |
1591 | "struct E : B {" |
1592 | " E() : B() {}" |
1593 | "};" ; |
1594 | EXPECT_TRUE(matches(Code, cxxConstructorDecl(allOf( |
1595 | hasAnyConstructorInitializer(allOf(isBaseInitializer(), isWritten())), |
1596 | hasName("E" ))))); |
1597 | EXPECT_TRUE(notMatches(Code, cxxConstructorDecl(allOf( |
1598 | hasAnyConstructorInitializer(allOf(isBaseInitializer(), isWritten())), |
1599 | hasName("D" ))))); |
1600 | EXPECT_TRUE(matches(Code, cxxConstructorDecl(allOf( |
1601 | hasAnyConstructorInitializer(allOf(isMemberInitializer(), isWritten())), |
1602 | hasName("D" ))))); |
1603 | EXPECT_TRUE(notMatches(Code, cxxConstructorDecl(allOf( |
1604 | hasAnyConstructorInitializer(allOf(isMemberInitializer(), isWritten())), |
1605 | hasName("E" ))))); |
1606 | } |
1607 | |
1608 | TEST(IfStmt, ChildTraversalMatchers) { |
1609 | EXPECT_TRUE(matches("void f() { if (false) true; else false; }" , |
1610 | ifStmt(hasThen(cxxBoolLiteral(equals(true)))))); |
1611 | EXPECT_TRUE(notMatches("void f() { if (false) false; else true; }" , |
1612 | ifStmt(hasThen(cxxBoolLiteral(equals(true)))))); |
1613 | EXPECT_TRUE(matches("void f() { if (false) false; else true; }" , |
1614 | ifStmt(hasElse(cxxBoolLiteral(equals(true)))))); |
1615 | EXPECT_TRUE(notMatches("void f() { if (false) true; else false; }" , |
1616 | ifStmt(hasElse(cxxBoolLiteral(equals(true)))))); |
1617 | } |
1618 | |
1619 | TEST(MatchBinaryOperator, HasOperatorName) { |
1620 | StatementMatcher OperatorOr = binaryOperator(hasOperatorName(Name: "||" )); |
1621 | |
1622 | EXPECT_TRUE(matches("void x() { true || false; }" , OperatorOr)); |
1623 | EXPECT_TRUE(notMatches("void x() { true && false; }" , OperatorOr)); |
1624 | } |
1625 | |
1626 | TEST(MatchBinaryOperator, HasAnyOperatorName) { |
1627 | StatementMatcher Matcher = |
1628 | binaryOperator(hasAnyOperatorName("+" , "-" , "*" , "/" )); |
1629 | |
1630 | EXPECT_TRUE(matches("int x(int I) { return I + 2; }" , Matcher)); |
1631 | EXPECT_TRUE(matches("int x(int I) { return I - 2; }" , Matcher)); |
1632 | EXPECT_TRUE(matches("int x(int I) { return I * 2; }" , Matcher)); |
1633 | EXPECT_TRUE(matches("int x(int I) { return I / 2; }" , Matcher)); |
1634 | EXPECT_TRUE(notMatches("int x(int I) { return I % 2; }" , Matcher)); |
1635 | // Ensure '+= isn't mistaken. |
1636 | EXPECT_TRUE(notMatches("void x(int &I) { I += 1; }" , Matcher)); |
1637 | } |
1638 | |
1639 | TEST(MatchBinaryOperator, HasLHSAndHasRHS) { |
1640 | StatementMatcher OperatorTrueFalse = |
1641 | binaryOperator(hasLHS(InnerMatcher: cxxBoolLiteral(equals(Value: true))), |
1642 | hasRHS(InnerMatcher: cxxBoolLiteral(equals(Value: false)))); |
1643 | |
1644 | EXPECT_TRUE(matches("void x() { true || false; }" , OperatorTrueFalse)); |
1645 | EXPECT_TRUE(matches("void x() { true && false; }" , OperatorTrueFalse)); |
1646 | EXPECT_TRUE(notMatches("void x() { false || true; }" , OperatorTrueFalse)); |
1647 | |
1648 | StatementMatcher OperatorIntPointer = arraySubscriptExpr( |
1649 | hasLHS(InnerMatcher: hasType(InnerMatcher: isInteger())), |
1650 | traverse(TK: TK_AsIs, InnerMatcher: hasRHS(InnerMatcher: hasType(InnerMatcher: pointsTo(InnerMatcher: qualType()))))); |
1651 | EXPECT_TRUE(matches("void x() { 1[\"abc\"]; }" , OperatorIntPointer)); |
1652 | EXPECT_TRUE(notMatches("void x() { \"abc\"[1]; }" , OperatorIntPointer)); |
1653 | |
1654 | StringRef Code = R"cpp( |
1655 | struct HasOpEqMem |
1656 | { |
1657 | bool operator==(const HasOpEqMem& other) const |
1658 | { |
1659 | return true; |
1660 | } |
1661 | }; |
1662 | |
1663 | struct HasOpFree |
1664 | { |
1665 | }; |
1666 | bool operator==(const HasOpFree& lhs, const HasOpFree& rhs) |
1667 | { |
1668 | return true; |
1669 | } |
1670 | |
1671 | void opMem() |
1672 | { |
1673 | HasOpEqMem s1; |
1674 | HasOpEqMem s2; |
1675 | if (s1 == s2) |
1676 | return; |
1677 | } |
1678 | |
1679 | void opFree() |
1680 | { |
1681 | HasOpFree s1; |
1682 | HasOpFree s2; |
1683 | if (s1 == s2) |
1684 | return; |
1685 | } |
1686 | )cpp" ; |
1687 | auto s1Expr = declRefExpr(to(InnerMatcher: varDecl(hasName(Name: "s1" )))); |
1688 | auto s2Expr = declRefExpr(to(InnerMatcher: varDecl(hasName(Name: "s2" )))); |
1689 | EXPECT_TRUE(matches( |
1690 | Code, |
1691 | traverse(TK_IgnoreUnlessSpelledInSource, |
1692 | cxxOperatorCallExpr(forFunction(functionDecl(hasName("opMem" ))), |
1693 | hasOperatorName("==" ), hasLHS(s1Expr), |
1694 | hasRHS(s2Expr))))); |
1695 | EXPECT_TRUE(matches( |
1696 | Code, traverse(TK_IgnoreUnlessSpelledInSource, |
1697 | cxxOperatorCallExpr( |
1698 | forFunction(functionDecl(hasName("opMem" ))), |
1699 | hasAnyOperatorName("!=" , "==" ), hasLHS(s1Expr))))); |
1700 | EXPECT_TRUE(matches( |
1701 | Code, traverse(TK_IgnoreUnlessSpelledInSource, |
1702 | cxxOperatorCallExpr( |
1703 | forFunction(functionDecl(hasName("opMem" ))), |
1704 | hasOperatorName("==" ), hasOperands(s1Expr, s2Expr))))); |
1705 | EXPECT_TRUE(matches( |
1706 | Code, traverse(TK_IgnoreUnlessSpelledInSource, |
1707 | cxxOperatorCallExpr( |
1708 | forFunction(functionDecl(hasName("opMem" ))), |
1709 | hasOperatorName("==" ), hasEitherOperand(s2Expr))))); |
1710 | |
1711 | EXPECT_TRUE(matches( |
1712 | Code, |
1713 | traverse(TK_IgnoreUnlessSpelledInSource, |
1714 | cxxOperatorCallExpr(forFunction(functionDecl(hasName("opFree" ))), |
1715 | hasOperatorName("==" ), hasLHS(s1Expr), |
1716 | hasRHS(s2Expr))))); |
1717 | EXPECT_TRUE(matches( |
1718 | Code, traverse(TK_IgnoreUnlessSpelledInSource, |
1719 | cxxOperatorCallExpr( |
1720 | forFunction(functionDecl(hasName("opFree" ))), |
1721 | hasAnyOperatorName("!=" , "==" ), hasLHS(s1Expr))))); |
1722 | EXPECT_TRUE(matches( |
1723 | Code, traverse(TK_IgnoreUnlessSpelledInSource, |
1724 | cxxOperatorCallExpr( |
1725 | forFunction(functionDecl(hasName("opFree" ))), |
1726 | hasOperatorName("==" ), hasOperands(s1Expr, s2Expr))))); |
1727 | EXPECT_TRUE(matches( |
1728 | Code, traverse(TK_IgnoreUnlessSpelledInSource, |
1729 | cxxOperatorCallExpr( |
1730 | forFunction(functionDecl(hasName("opFree" ))), |
1731 | hasOperatorName("==" ), hasEitherOperand(s2Expr))))); |
1732 | } |
1733 | |
1734 | TEST(MatchBinaryOperator, HasEitherOperand) { |
1735 | StatementMatcher HasOperand = |
1736 | binaryOperator(hasEitherOperand(InnerMatcher: cxxBoolLiteral(equals(Value: false)))); |
1737 | |
1738 | EXPECT_TRUE(matches("void x() { true || false; }" , HasOperand)); |
1739 | EXPECT_TRUE(matches("void x() { false && true; }" , HasOperand)); |
1740 | EXPECT_TRUE(notMatches("void x() { true || true; }" , HasOperand)); |
1741 | } |
1742 | |
1743 | TEST(MatchBinaryOperator, HasOperands) { |
1744 | StatementMatcher HasOperands = binaryOperator( |
1745 | hasOperands(Matcher1: integerLiteral(equals(Value: 1)), Matcher2: integerLiteral(equals(Value: 2)))); |
1746 | EXPECT_TRUE(matches("void x() { 1 + 2; }" , HasOperands)); |
1747 | EXPECT_TRUE(matches("void x() { 2 + 1; }" , HasOperands)); |
1748 | EXPECT_TRUE(notMatches("void x() { 1 + 1; }" , HasOperands)); |
1749 | EXPECT_TRUE(notMatches("void x() { 2 + 2; }" , HasOperands)); |
1750 | EXPECT_TRUE(notMatches("void x() { 0 + 0; }" , HasOperands)); |
1751 | EXPECT_TRUE(notMatches("void x() { 0 + 1; }" , HasOperands)); |
1752 | } |
1753 | |
1754 | TEST(Matcher, BinaryOperatorTypes) { |
1755 | // Integration test that verifies the AST provides all binary operators in |
1756 | // a way we expect. |
1757 | // FIXME: Operator ',' |
1758 | EXPECT_TRUE( |
1759 | matches("void x() { 3, 4; }" , binaryOperator(hasOperatorName("," )))); |
1760 | EXPECT_TRUE( |
1761 | matches("bool b; bool c = (b = true);" , |
1762 | binaryOperator(hasOperatorName("=" )))); |
1763 | EXPECT_TRUE( |
1764 | matches("bool b = 1 != 2;" , binaryOperator(hasOperatorName("!=" )))); |
1765 | EXPECT_TRUE( |
1766 | matches("bool b = 1 == 2;" , binaryOperator(hasOperatorName("==" )))); |
1767 | EXPECT_TRUE(matches("bool b = 1 < 2;" , binaryOperator(hasOperatorName("<" )))); |
1768 | EXPECT_TRUE( |
1769 | matches("bool b = 1 <= 2;" , binaryOperator(hasOperatorName("<=" )))); |
1770 | EXPECT_TRUE( |
1771 | matches("int i = 1 << 2;" , binaryOperator(hasOperatorName("<<" )))); |
1772 | EXPECT_TRUE( |
1773 | matches("int i = 1; int j = (i <<= 2);" , |
1774 | binaryOperator(hasOperatorName("<<=" )))); |
1775 | EXPECT_TRUE(matches("bool b = 1 > 2;" , binaryOperator(hasOperatorName(">" )))); |
1776 | EXPECT_TRUE( |
1777 | matches("bool b = 1 >= 2;" , binaryOperator(hasOperatorName(">=" )))); |
1778 | EXPECT_TRUE( |
1779 | matches("int i = 1 >> 2;" , binaryOperator(hasOperatorName(">>" )))); |
1780 | EXPECT_TRUE( |
1781 | matches("int i = 1; int j = (i >>= 2);" , |
1782 | binaryOperator(hasOperatorName(">>=" )))); |
1783 | EXPECT_TRUE( |
1784 | matches("int i = 42 ^ 23;" , binaryOperator(hasOperatorName("^" )))); |
1785 | EXPECT_TRUE( |
1786 | matches("int i = 42; int j = (i ^= 42);" , |
1787 | binaryOperator(hasOperatorName("^=" )))); |
1788 | EXPECT_TRUE( |
1789 | matches("int i = 42 % 23;" , binaryOperator(hasOperatorName("%" )))); |
1790 | EXPECT_TRUE( |
1791 | matches("int i = 42; int j = (i %= 42);" , |
1792 | binaryOperator(hasOperatorName("%=" )))); |
1793 | EXPECT_TRUE( |
1794 | matches("bool b = 42 &23;" , binaryOperator(hasOperatorName("&" )))); |
1795 | EXPECT_TRUE( |
1796 | matches("bool b = true && false;" , |
1797 | binaryOperator(hasOperatorName("&&" )))); |
1798 | EXPECT_TRUE( |
1799 | matches("bool b = true; bool c = (b &= false);" , |
1800 | binaryOperator(hasOperatorName("&=" )))); |
1801 | EXPECT_TRUE( |
1802 | matches("bool b = 42 | 23;" , binaryOperator(hasOperatorName("|" )))); |
1803 | EXPECT_TRUE( |
1804 | matches("bool b = true || false;" , |
1805 | binaryOperator(hasOperatorName("||" )))); |
1806 | EXPECT_TRUE( |
1807 | matches("bool b = true; bool c = (b |= false);" , |
1808 | binaryOperator(hasOperatorName("|=" )))); |
1809 | EXPECT_TRUE( |
1810 | matches("int i = 42 *23;" , binaryOperator(hasOperatorName("*" )))); |
1811 | EXPECT_TRUE( |
1812 | matches("int i = 42; int j = (i *= 23);" , |
1813 | binaryOperator(hasOperatorName("*=" )))); |
1814 | EXPECT_TRUE( |
1815 | matches("int i = 42 / 23;" , binaryOperator(hasOperatorName("/" )))); |
1816 | EXPECT_TRUE( |
1817 | matches("int i = 42; int j = (i /= 23);" , |
1818 | binaryOperator(hasOperatorName("/=" )))); |
1819 | EXPECT_TRUE( |
1820 | matches("int i = 42 + 23;" , binaryOperator(hasOperatorName("+" )))); |
1821 | EXPECT_TRUE( |
1822 | matches("int i = 42; int j = (i += 23);" , |
1823 | binaryOperator(hasOperatorName("+=" )))); |
1824 | EXPECT_TRUE( |
1825 | matches("int i = 42 - 23;" , binaryOperator(hasOperatorName("-" )))); |
1826 | EXPECT_TRUE( |
1827 | matches("int i = 42; int j = (i -= 23);" , |
1828 | binaryOperator(hasOperatorName("-=" )))); |
1829 | EXPECT_TRUE( |
1830 | matches("struct A { void x() { void (A::*a)(); (this->*a)(); } };" , |
1831 | binaryOperator(hasOperatorName("->*" )))); |
1832 | EXPECT_TRUE( |
1833 | matches("struct A { void x() { void (A::*a)(); ((*this).*a)(); } };" , |
1834 | binaryOperator(hasOperatorName(".*" )))); |
1835 | |
1836 | // Member expressions as operators are not supported in matches. |
1837 | EXPECT_TRUE( |
1838 | notMatches("struct A { void x(A *a) { a->x(this); } };" , |
1839 | binaryOperator(hasOperatorName("->" )))); |
1840 | |
1841 | // Initializer assignments are not represented as operator equals. |
1842 | EXPECT_TRUE( |
1843 | notMatches("bool b = true;" , binaryOperator(hasOperatorName("=" )))); |
1844 | |
1845 | // Array indexing is not represented as operator. |
1846 | EXPECT_TRUE(notMatches("int a[42]; void x() { a[23]; }" , unaryOperator())); |
1847 | |
1848 | // Overloaded operators do not match at all. |
1849 | EXPECT_TRUE(notMatches( |
1850 | "struct A { bool operator&&(const A &a) const { return false; } };" |
1851 | "void x() { A a, b; a && b; }" , |
1852 | binaryOperator())); |
1853 | } |
1854 | |
1855 | TEST(MatchUnaryOperator, HasOperatorName) { |
1856 | StatementMatcher OperatorNot = unaryOperator(hasOperatorName(Name: "!" )); |
1857 | |
1858 | EXPECT_TRUE(matches("void x() { !true; } " , OperatorNot)); |
1859 | EXPECT_TRUE(notMatches("void x() { true; } " , OperatorNot)); |
1860 | } |
1861 | |
1862 | TEST(MatchUnaryOperator, HasAnyOperatorName) { |
1863 | StatementMatcher Matcher = unaryOperator(hasAnyOperatorName("-" , "*" , "++" )); |
1864 | |
1865 | EXPECT_TRUE(matches("int x(int *I) { return *I; }" , Matcher)); |
1866 | EXPECT_TRUE(matches("int x(int I) { return -I; }" , Matcher)); |
1867 | EXPECT_TRUE(matches("void x(int &I) { I++; }" , Matcher)); |
1868 | EXPECT_TRUE(matches("void x(int &I) { ++I; }" , Matcher)); |
1869 | EXPECT_TRUE(notMatches("void x(int &I) { I--; }" , Matcher)); |
1870 | EXPECT_TRUE(notMatches("void x(int &I) { --I; }" , Matcher)); |
1871 | EXPECT_TRUE(notMatches("int *x(int &I) { return &I; }" , Matcher)); |
1872 | } |
1873 | |
1874 | TEST(MatchUnaryOperator, HasUnaryOperand) { |
1875 | StatementMatcher OperatorOnFalse = |
1876 | unaryOperator(hasUnaryOperand(InnerMatcher: cxxBoolLiteral(equals(Value: false)))); |
1877 | |
1878 | EXPECT_TRUE(matches("void x() { !false; }" , OperatorOnFalse)); |
1879 | EXPECT_TRUE(notMatches("void x() { !true; }" , OperatorOnFalse)); |
1880 | |
1881 | StringRef Code = R"cpp( |
1882 | struct HasOpBangMem |
1883 | { |
1884 | bool operator!() const |
1885 | { |
1886 | return false; |
1887 | } |
1888 | }; |
1889 | struct HasOpBangFree |
1890 | { |
1891 | }; |
1892 | bool operator!(HasOpBangFree const&) |
1893 | { |
1894 | return false; |
1895 | } |
1896 | |
1897 | void opMem() |
1898 | { |
1899 | HasOpBangMem s1; |
1900 | if (!s1) |
1901 | return; |
1902 | } |
1903 | void opFree() |
1904 | { |
1905 | HasOpBangFree s1; |
1906 | if (!s1) |
1907 | return; |
1908 | } |
1909 | )cpp" ; |
1910 | auto s1Expr = declRefExpr(to(InnerMatcher: varDecl(hasName(Name: "s1" )))); |
1911 | EXPECT_TRUE(matches( |
1912 | Code, traverse(TK_IgnoreUnlessSpelledInSource, |
1913 | cxxOperatorCallExpr( |
1914 | forFunction(functionDecl(hasName("opMem" ))), |
1915 | hasOperatorName("!" ), hasUnaryOperand(s1Expr))))); |
1916 | EXPECT_TRUE(matches( |
1917 | Code, |
1918 | traverse(TK_IgnoreUnlessSpelledInSource, |
1919 | cxxOperatorCallExpr(forFunction(functionDecl(hasName("opMem" ))), |
1920 | hasAnyOperatorName("+" , "!" ), |
1921 | hasUnaryOperand(s1Expr))))); |
1922 | |
1923 | EXPECT_TRUE(matches( |
1924 | Code, traverse(TK_IgnoreUnlessSpelledInSource, |
1925 | cxxOperatorCallExpr( |
1926 | forFunction(functionDecl(hasName("opFree" ))), |
1927 | hasOperatorName("!" ), hasUnaryOperand(s1Expr))))); |
1928 | EXPECT_TRUE(matches( |
1929 | Code, |
1930 | traverse(TK_IgnoreUnlessSpelledInSource, |
1931 | cxxOperatorCallExpr(forFunction(functionDecl(hasName("opFree" ))), |
1932 | hasAnyOperatorName("+" , "!" ), |
1933 | hasUnaryOperand(s1Expr))))); |
1934 | |
1935 | Code = R"cpp( |
1936 | struct HasIncOperatorsMem |
1937 | { |
1938 | HasIncOperatorsMem& operator++(); |
1939 | HasIncOperatorsMem operator++(int); |
1940 | }; |
1941 | struct HasIncOperatorsFree |
1942 | { |
1943 | }; |
1944 | HasIncOperatorsFree& operator++(HasIncOperatorsFree&); |
1945 | HasIncOperatorsFree operator++(HasIncOperatorsFree&, int); |
1946 | |
1947 | void prefixIncOperatorMem() |
1948 | { |
1949 | HasIncOperatorsMem s1; |
1950 | ++s1; |
1951 | } |
1952 | void prefixIncOperatorFree() |
1953 | { |
1954 | HasIncOperatorsFree s1; |
1955 | ++s1; |
1956 | } |
1957 | void postfixIncOperatorMem() |
1958 | { |
1959 | HasIncOperatorsMem s1; |
1960 | s1++; |
1961 | } |
1962 | void postfixIncOperatorFree() |
1963 | { |
1964 | HasIncOperatorsFree s1; |
1965 | s1++; |
1966 | } |
1967 | |
1968 | struct HasOpPlusInt |
1969 | { |
1970 | HasOpPlusInt& operator+(int); |
1971 | }; |
1972 | void plusIntOperator() |
1973 | { |
1974 | HasOpPlusInt s1; |
1975 | s1+1; |
1976 | } |
1977 | )cpp" ; |
1978 | |
1979 | EXPECT_TRUE(matches( |
1980 | Code, |
1981 | traverse(TK_IgnoreUnlessSpelledInSource, |
1982 | cxxOperatorCallExpr( |
1983 | forFunction(functionDecl(hasName("prefixIncOperatorMem" ))), |
1984 | hasOperatorName("++" ), hasUnaryOperand(declRefExpr()))))); |
1985 | |
1986 | EXPECT_TRUE(matches( |
1987 | Code, |
1988 | traverse(TK_IgnoreUnlessSpelledInSource, |
1989 | cxxOperatorCallExpr( |
1990 | forFunction(functionDecl(hasName("prefixIncOperatorFree" ))), |
1991 | hasOperatorName("++" ), hasUnaryOperand(declRefExpr()))))); |
1992 | |
1993 | EXPECT_TRUE(matches( |
1994 | Code, |
1995 | traverse(TK_IgnoreUnlessSpelledInSource, |
1996 | cxxOperatorCallExpr( |
1997 | forFunction(functionDecl(hasName("postfixIncOperatorMem" ))), |
1998 | hasOperatorName("++" ), hasUnaryOperand(declRefExpr()))))); |
1999 | |
2000 | EXPECT_TRUE(matches( |
2001 | Code, |
2002 | traverse(TK_IgnoreUnlessSpelledInSource, |
2003 | cxxOperatorCallExpr( |
2004 | forFunction(functionDecl(hasName("postfixIncOperatorFree" ))), |
2005 | hasOperatorName("++" ), hasUnaryOperand(declRefExpr()))))); |
2006 | |
2007 | EXPECT_FALSE(matches( |
2008 | Code, traverse(TK_IgnoreUnlessSpelledInSource, |
2009 | cxxOperatorCallExpr( |
2010 | forFunction(functionDecl(hasName("plusIntOperator" ))), |
2011 | hasOperatorName("+" ), hasUnaryOperand(expr()))))); |
2012 | |
2013 | Code = R"cpp( |
2014 | struct HasOpArrow |
2015 | { |
2016 | int& operator*(); |
2017 | }; |
2018 | void foo() |
2019 | { |
2020 | HasOpArrow s1; |
2021 | *s1; |
2022 | } |
2023 | )cpp" ; |
2024 | |
2025 | EXPECT_TRUE( |
2026 | matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, |
2027 | cxxOperatorCallExpr(hasOperatorName("*" ), |
2028 | hasUnaryOperand(expr()))))); |
2029 | } |
2030 | |
2031 | TEST(Matcher, UnaryOperatorTypes) { |
2032 | // Integration test that verifies the AST provides all unary operators in |
2033 | // a way we expect. |
2034 | EXPECT_TRUE(matches("bool b = !true;" , unaryOperator(hasOperatorName("!" )))); |
2035 | EXPECT_TRUE( |
2036 | matches("bool b; bool *p = &b;" , unaryOperator(hasOperatorName("&" )))); |
2037 | EXPECT_TRUE(matches("int i = ~ 1;" , unaryOperator(hasOperatorName("~" )))); |
2038 | EXPECT_TRUE( |
2039 | matches("bool *p; bool b = *p;" , unaryOperator(hasOperatorName("*" )))); |
2040 | EXPECT_TRUE( |
2041 | matches("int i; int j = +i;" , unaryOperator(hasOperatorName("+" )))); |
2042 | EXPECT_TRUE( |
2043 | matches("int i; int j = -i;" , unaryOperator(hasOperatorName("-" )))); |
2044 | EXPECT_TRUE( |
2045 | matches("int i; int j = ++i;" , unaryOperator(hasOperatorName("++" )))); |
2046 | EXPECT_TRUE( |
2047 | matches("int i; int j = i++;" , unaryOperator(hasOperatorName("++" )))); |
2048 | EXPECT_TRUE( |
2049 | matches("int i; int j = --i;" , unaryOperator(hasOperatorName("--" )))); |
2050 | EXPECT_TRUE( |
2051 | matches("int i; int j = i--;" , unaryOperator(hasOperatorName("--" )))); |
2052 | |
2053 | // We don't match conversion operators. |
2054 | EXPECT_TRUE(notMatches("int i; double d = (double)i;" , unaryOperator())); |
2055 | |
2056 | // Function calls are not represented as operator. |
2057 | EXPECT_TRUE(notMatches("void f(); void x() { f(); }" , unaryOperator())); |
2058 | |
2059 | // Overloaded operators do not match at all. |
2060 | // FIXME: We probably want to add that. |
2061 | EXPECT_TRUE(notMatches( |
2062 | "struct A { bool operator!() const { return false; } };" |
2063 | "void x() { A a; !a; }" , unaryOperator(hasOperatorName("!" )))); |
2064 | } |
2065 | |
2066 | TEST_P(ASTMatchersTest, HasInit) { |
2067 | if (!GetParam().isCXX11OrLater()) { |
2068 | // FIXME: Add a test for `hasInit()` that does not depend on C++. |
2069 | return; |
2070 | } |
2071 | |
2072 | EXPECT_TRUE(matches("int x{0};" , initListExpr(hasInit(0, expr())))); |
2073 | EXPECT_FALSE(matches("int x{0};" , initListExpr(hasInit(1, expr())))); |
2074 | EXPECT_FALSE(matches("int x;" , initListExpr(hasInit(0, expr())))); |
2075 | } |
2076 | |
2077 | TEST_P(ASTMatchersTest, HasFoldInit) { |
2078 | if (!GetParam().isCXX17OrLater()) { |
2079 | return; |
2080 | } |
2081 | |
2082 | EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " |
2083 | "return (0 + ... + args); }" , |
2084 | cxxFoldExpr(hasFoldInit(expr())))); |
2085 | EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " |
2086 | "return (args + ... + 0); }" , |
2087 | cxxFoldExpr(hasFoldInit(expr())))); |
2088 | EXPECT_FALSE(matches("template <typename... Args> auto sum(Args... args) { " |
2089 | "return (... + args); };" , |
2090 | cxxFoldExpr(hasFoldInit(expr())))); |
2091 | } |
2092 | |
2093 | TEST_P(ASTMatchersTest, HasPattern) { |
2094 | if (!GetParam().isCXX17OrLater()) { |
2095 | return; |
2096 | } |
2097 | |
2098 | EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " |
2099 | "return (0 + ... + args); }" , |
2100 | cxxFoldExpr(hasPattern(expr())))); |
2101 | EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " |
2102 | "return (args + ... + 0); }" , |
2103 | cxxFoldExpr(hasPattern(expr())))); |
2104 | EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " |
2105 | "return (... + args); };" , |
2106 | cxxFoldExpr(hasPattern(expr())))); |
2107 | } |
2108 | |
2109 | TEST_P(ASTMatchersTest, HasLHSAndHasRHS) { |
2110 | if (!GetParam().isCXX17OrLater()) { |
2111 | return; |
2112 | } |
2113 | |
2114 | EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " |
2115 | "return (0 + ... + args); }" , |
2116 | cxxFoldExpr(hasLHS(expr())))); |
2117 | EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " |
2118 | "return (args + ... + 0); }" , |
2119 | cxxFoldExpr(hasLHS(expr())))); |
2120 | EXPECT_FALSE(matches("template <typename... Args> auto sum(Args... args) { " |
2121 | "return (... + args); };" , |
2122 | cxxFoldExpr(hasLHS(expr())))); |
2123 | EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " |
2124 | "return (args + ...); };" , |
2125 | cxxFoldExpr(hasLHS(expr())))); |
2126 | |
2127 | EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " |
2128 | "return (0 + ... + args); }" , |
2129 | cxxFoldExpr(hasRHS(expr())))); |
2130 | EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " |
2131 | "return (args + ... + 0); }" , |
2132 | cxxFoldExpr(hasRHS(expr())))); |
2133 | EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " |
2134 | "return (... + args); };" , |
2135 | cxxFoldExpr(hasRHS(expr())))); |
2136 | EXPECT_FALSE(matches("template <typename... Args> auto sum(Args... args) { " |
2137 | "return (args + ...); };" , |
2138 | cxxFoldExpr(hasRHS(expr())))); |
2139 | } |
2140 | |
2141 | TEST_P(ASTMatchersTest, HasEitherOperandAndHasOperands) { |
2142 | if (!GetParam().isCXX17OrLater()) { |
2143 | return; |
2144 | } |
2145 | |
2146 | EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " |
2147 | "return (0 + ... + args); }" , |
2148 | cxxFoldExpr(hasEitherOperand(integerLiteral())))); |
2149 | EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " |
2150 | "return (args + ... + 0); }" , |
2151 | cxxFoldExpr(hasEitherOperand(integerLiteral())))); |
2152 | |
2153 | EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " |
2154 | "return (0 + ... + args); }" , |
2155 | cxxFoldExpr(hasEitherOperand( |
2156 | declRefExpr(to(namedDecl(hasName("args" )))))))); |
2157 | EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " |
2158 | "return (args + ... + 0); }" , |
2159 | cxxFoldExpr(hasEitherOperand( |
2160 | declRefExpr(to(namedDecl(hasName("args" )))))))); |
2161 | EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " |
2162 | "return (... + args); };" , |
2163 | cxxFoldExpr(hasEitherOperand( |
2164 | declRefExpr(to(namedDecl(hasName("args" )))))))); |
2165 | EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " |
2166 | "return (args + ...); };" , |
2167 | cxxFoldExpr(hasEitherOperand( |
2168 | declRefExpr(to(namedDecl(hasName("args" )))))))); |
2169 | |
2170 | EXPECT_TRUE(matches( |
2171 | "template <typename... Args> auto sum(Args... args) { " |
2172 | "return (0 + ... + args); }" , |
2173 | cxxFoldExpr(hasOperands(declRefExpr(to(namedDecl(hasName("args" )))), |
2174 | integerLiteral())))); |
2175 | EXPECT_TRUE(matches( |
2176 | "template <typename... Args> auto sum(Args... args) { " |
2177 | "return (args + ... + 0); }" , |
2178 | cxxFoldExpr(hasOperands(declRefExpr(to(namedDecl(hasName("args" )))), |
2179 | integerLiteral())))); |
2180 | EXPECT_FALSE(matches( |
2181 | "template <typename... Args> auto sum(Args... args) { " |
2182 | "return (... + args); };" , |
2183 | cxxFoldExpr(hasOperands(declRefExpr(to(namedDecl(hasName("args" )))), |
2184 | integerLiteral())))); |
2185 | EXPECT_FALSE(matches( |
2186 | "template <typename... Args> auto sum(Args... args) { " |
2187 | "return (args + ...); };" , |
2188 | cxxFoldExpr(hasOperands(declRefExpr(to(namedDecl(hasName("args" )))), |
2189 | integerLiteral())))); |
2190 | } |
2191 | |
2192 | TEST_P(ASTMatchersTest, Callee) { |
2193 | if (!GetParam().isCXX17OrLater()) { |
2194 | return; |
2195 | } |
2196 | |
2197 | EXPECT_TRUE(matches( |
2198 | "struct Dummy {}; Dummy operator+(Dummy, Dummy); template " |
2199 | "<typename... Args> auto sum(Args... args) { return (0 + ... + args); }" , |
2200 | cxxFoldExpr(callee(expr())))); |
2201 | EXPECT_FALSE(matches("template <typename... Args> auto sum(Args... args) { " |
2202 | "return (0 + ... + args); }" , |
2203 | cxxFoldExpr(callee(expr())))); |
2204 | } |
2205 | |
2206 | TEST(ArraySubscriptMatchers, ArrayIndex) { |
2207 | EXPECT_TRUE(matches( |
2208 | "int i[2]; void f() { i[1] = 1; }" , |
2209 | arraySubscriptExpr(hasIndex(integerLiteral(equals(1)))))); |
2210 | EXPECT_TRUE(matches( |
2211 | "int i[2]; void f() { 1[i] = 1; }" , |
2212 | arraySubscriptExpr(hasIndex(integerLiteral(equals(1)))))); |
2213 | EXPECT_TRUE(notMatches( |
2214 | "int i[2]; void f() { i[1] = 1; }" , |
2215 | arraySubscriptExpr(hasIndex(integerLiteral(equals(0)))))); |
2216 | } |
2217 | |
2218 | TEST(ArraySubscriptMatchers, MatchesArrayBase) { |
2219 | EXPECT_TRUE( |
2220 | matches("int i[2]; void f() { i[1] = 2; }" , |
2221 | traverse(TK_AsIs, arraySubscriptExpr(hasBase(implicitCastExpr( |
2222 | hasSourceExpression(declRefExpr()))))))); |
2223 | } |
2224 | |
2225 | TEST(Matcher, OfClass) { |
2226 | StatementMatcher Constructor = cxxConstructExpr(hasDeclaration(InnerMatcher: cxxMethodDecl( |
2227 | ofClass(InnerMatcher: hasName(Name: "X" ))))); |
2228 | |
2229 | EXPECT_TRUE( |
2230 | matches("class X { public: X(); }; void x(int) { X x; }" , Constructor)); |
2231 | EXPECT_TRUE( |
2232 | matches("class X { public: X(); }; void x(int) { X x = X(); }" , |
2233 | Constructor)); |
2234 | EXPECT_TRUE( |
2235 | notMatches("class Y { public: Y(); }; void x(int) { Y y; }" , |
2236 | Constructor)); |
2237 | } |
2238 | |
2239 | TEST(Matcher, VisitsTemplateInstantiations) { |
2240 | EXPECT_TRUE(matches( |
2241 | "class A { public: void x(); };" |
2242 | "template <typename T> class B { public: void y() { T t; t.x(); } };" |
2243 | "void f() { B<A> b; b.y(); }" , |
2244 | callExpr(callee(cxxMethodDecl(hasName("x" )))))); |
2245 | |
2246 | EXPECT_TRUE(matches( |
2247 | "class A { public: void x(); };" |
2248 | "class C {" |
2249 | " public:" |
2250 | " template <typename T> class B { public: void y() { T t; t.x(); } };" |
2251 | "};" |
2252 | "void f() {" |
2253 | " C::B<A> b; b.y();" |
2254 | "}" , |
2255 | recordDecl(hasName("C" ), hasDescendant(callExpr( |
2256 | callee(cxxMethodDecl(hasName("x" )))))))); |
2257 | } |
2258 | |
2259 | TEST(Matcher, HasCondition) { |
2260 | StatementMatcher IfStmt = |
2261 | ifStmt(hasCondition(InnerMatcher: cxxBoolLiteral(equals(Value: true)))); |
2262 | EXPECT_TRUE(matches("void x() { if (true) {} }" , IfStmt)); |
2263 | EXPECT_TRUE(notMatches("void x() { if (false) {} }" , IfStmt)); |
2264 | |
2265 | StatementMatcher ForStmt = |
2266 | forStmt(hasCondition(InnerMatcher: cxxBoolLiteral(equals(Value: true)))); |
2267 | EXPECT_TRUE(matches("void x() { for (;true;) {} }" , ForStmt)); |
2268 | EXPECT_TRUE(notMatches("void x() { for (;false;) {} }" , ForStmt)); |
2269 | |
2270 | StatementMatcher WhileStmt = |
2271 | whileStmt(hasCondition(InnerMatcher: cxxBoolLiteral(equals(Value: true)))); |
2272 | EXPECT_TRUE(matches("void x() { while (true) {} }" , WhileStmt)); |
2273 | EXPECT_TRUE(notMatches("void x() { while (false) {} }" , WhileStmt)); |
2274 | |
2275 | StatementMatcher SwitchStmt = |
2276 | switchStmt(hasCondition(InnerMatcher: integerLiteral(equals(Value: 42)))); |
2277 | EXPECT_TRUE(matches("void x() { switch (42) {case 42:;} }" , SwitchStmt)); |
2278 | EXPECT_TRUE(notMatches("void x() { switch (43) {case 43:;} }" , SwitchStmt)); |
2279 | } |
2280 | |
2281 | TEST(For, ForLoopInternals) { |
2282 | EXPECT_TRUE(matches("void f(){ int i; for (; i < 3 ; ); }" , |
2283 | forStmt(hasCondition(anything())))); |
2284 | EXPECT_TRUE(matches("void f() { for (int i = 0; ;); }" , |
2285 | forStmt(hasLoopInit(anything())))); |
2286 | } |
2287 | |
2288 | TEST(For, ForRangeLoopInternals) { |
2289 | EXPECT_TRUE(matches("void f(){ int a[] {1, 2}; for (int i : a); }" , |
2290 | cxxForRangeStmt(hasLoopVariable(anything())))); |
2291 | EXPECT_TRUE(matches( |
2292 | "void f(){ int a[] {1, 2}; for (int i : a); }" , |
2293 | cxxForRangeStmt(hasRangeInit(declRefExpr(to(varDecl(hasName("a" )))))))); |
2294 | } |
2295 | |
2296 | TEST(For, NegativeForLoopInternals) { |
2297 | EXPECT_TRUE(notMatches("void f(){ for (int i = 0; ; ++i); }" , |
2298 | forStmt(hasCondition(expr())))); |
2299 | EXPECT_TRUE(notMatches("void f() {int i; for (; i < 4; ++i) {} }" , |
2300 | forStmt(hasLoopInit(anything())))); |
2301 | } |
2302 | |
2303 | TEST(HasBody, FindsBodyOfForWhileDoLoops) { |
2304 | EXPECT_TRUE(matches("void f() { for(;;) {} }" , |
2305 | forStmt(hasBody(compoundStmt())))); |
2306 | EXPECT_TRUE(notMatches("void f() { for(;;); }" , |
2307 | forStmt(hasBody(compoundStmt())))); |
2308 | EXPECT_TRUE(matches("void f() { while(true) {} }" , |
2309 | whileStmt(hasBody(compoundStmt())))); |
2310 | EXPECT_TRUE(matches("void f() { do {} while(true); }" , |
2311 | doStmt(hasBody(compoundStmt())))); |
2312 | EXPECT_TRUE(matches("void f() { int p[2]; for (auto x : p) {} }" , |
2313 | cxxForRangeStmt(hasBody(compoundStmt())))); |
2314 | } |
2315 | |
2316 | TEST(HasBody, FindsBodyOfFunctions) { |
2317 | EXPECT_TRUE(matches("void f() {}" , functionDecl(hasBody(compoundStmt())))); |
2318 | EXPECT_TRUE(notMatches("void f();" , functionDecl(hasBody(compoundStmt())))); |
2319 | EXPECT_TRUE(matchAndVerifyResultTrue( |
2320 | "void f(); void f() {}" , |
2321 | functionDecl(hasBody(compoundStmt())).bind("func" ), |
2322 | std::make_unique<VerifyIdIsBoundTo<FunctionDecl>>("func" , 1))); |
2323 | EXPECT_TRUE(matchAndVerifyResultTrue( |
2324 | "class C { void f(); }; void C::f() {}" , |
2325 | cxxMethodDecl(hasBody(compoundStmt())).bind("met" ), |
2326 | std::make_unique<VerifyIdIsBoundTo<CXXMethodDecl>>("met" , 1))); |
2327 | EXPECT_TRUE(matchAndVerifyResultTrue( |
2328 | "class C { C(); }; C::C() {}" , |
2329 | cxxConstructorDecl(hasBody(compoundStmt())).bind("ctr" ), |
2330 | std::make_unique<VerifyIdIsBoundTo<CXXConstructorDecl>>("ctr" , 1))); |
2331 | EXPECT_TRUE(matchAndVerifyResultTrue( |
2332 | "class C { ~C(); }; C::~C() {}" , |
2333 | cxxDestructorDecl(hasBody(compoundStmt())).bind("dtr" ), |
2334 | std::make_unique<VerifyIdIsBoundTo<CXXDestructorDecl>>("dtr" , 1))); |
2335 | } |
2336 | |
2337 | TEST(HasAnyBody, FindsAnyBodyOfFunctions) { |
2338 | EXPECT_TRUE(matches("void f() {}" , functionDecl(hasAnyBody(compoundStmt())))); |
2339 | EXPECT_TRUE(notMatches("void f();" , |
2340 | functionDecl(hasAnyBody(compoundStmt())))); |
2341 | EXPECT_TRUE(matchAndVerifyResultTrue( |
2342 | "void f(); void f() {}" , |
2343 | functionDecl(hasAnyBody(compoundStmt())).bind("func" ), |
2344 | std::make_unique<VerifyIdIsBoundTo<FunctionDecl>>("func" , 2))); |
2345 | EXPECT_TRUE(matchAndVerifyResultTrue( |
2346 | "class C { void f(); }; void C::f() {}" , |
2347 | cxxMethodDecl(hasAnyBody(compoundStmt())).bind("met" ), |
2348 | std::make_unique<VerifyIdIsBoundTo<CXXMethodDecl>>("met" , 2))); |
2349 | EXPECT_TRUE(matchAndVerifyResultTrue( |
2350 | "class C { C(); }; C::C() {}" , |
2351 | cxxConstructorDecl(hasAnyBody(compoundStmt())).bind("ctr" ), |
2352 | std::make_unique<VerifyIdIsBoundTo<CXXConstructorDecl>>("ctr" , 2))); |
2353 | EXPECT_TRUE(matchAndVerifyResultTrue( |
2354 | "class C { ~C(); }; C::~C() {}" , |
2355 | cxxDestructorDecl(hasAnyBody(compoundStmt())).bind("dtr" ), |
2356 | std::make_unique<VerifyIdIsBoundTo<CXXDestructorDecl>>("dtr" , 2))); |
2357 | } |
2358 | |
2359 | TEST(HasAnySubstatement, MatchesForTopLevelCompoundStatement) { |
2360 | // The simplest case: every compound statement is in a function |
2361 | // definition, and the function body itself must be a compound |
2362 | // statement. |
2363 | EXPECT_TRUE(matches("void f() { for (;;); }" , |
2364 | compoundStmt(hasAnySubstatement(forStmt())))); |
2365 | } |
2366 | |
2367 | TEST(HasAnySubstatement, IsNotRecursive) { |
2368 | // It's really "has any immediate substatement". |
2369 | EXPECT_TRUE(notMatches("void f() { if (true) for (;;); }" , |
2370 | compoundStmt(hasAnySubstatement(forStmt())))); |
2371 | } |
2372 | |
2373 | TEST(HasAnySubstatement, MatchesInNestedCompoundStatements) { |
2374 | EXPECT_TRUE(matches("void f() { if (true) { for (;;); } }" , |
2375 | compoundStmt(hasAnySubstatement(forStmt())))); |
2376 | } |
2377 | |
2378 | TEST(HasAnySubstatement, FindsSubstatementBetweenOthers) { |
2379 | EXPECT_TRUE(matches("void f() { 1; 2; 3; for (;;); 4; 5; 6; }" , |
2380 | compoundStmt(hasAnySubstatement(forStmt())))); |
2381 | } |
2382 | |
2383 | TEST(Member, MatchesMemberAllocationFunction) { |
2384 | // Fails in C++11 mode |
2385 | EXPECT_TRUE(matchesConditionally( |
2386 | "namespace std { typedef typeof(sizeof(int)) size_t; }" |
2387 | "class X { void *operator new(std::size_t); };" , |
2388 | cxxMethodDecl(ofClass(hasName("X" ))), true, {"-std=gnu++03" })); |
2389 | |
2390 | EXPECT_TRUE(matches("class X { void operator delete(void*); };" , |
2391 | cxxMethodDecl(ofClass(hasName("X" ))))); |
2392 | |
2393 | // Fails in C++11 mode |
2394 | EXPECT_TRUE(matchesConditionally( |
2395 | "namespace std { typedef typeof(sizeof(int)) size_t; }" |
2396 | "class X { void operator delete[](void*, std::size_t); };" , |
2397 | cxxMethodDecl(ofClass(hasName("X" ))), true, {"-std=gnu++03" })); |
2398 | } |
2399 | |
2400 | TEST(HasDestinationType, MatchesSimpleCase) { |
2401 | EXPECT_TRUE(matches("char* p = static_cast<char*>(0);" , |
2402 | cxxStaticCastExpr(hasDestinationType( |
2403 | pointsTo(TypeMatcher(anything())))))); |
2404 | } |
2405 | |
2406 | TEST(HasImplicitDestinationType, MatchesSimpleCase) { |
2407 | // This test creates an implicit const cast. |
2408 | EXPECT_TRUE(matches( |
2409 | "int x; const int i = x;" , |
2410 | traverse(TK_AsIs, |
2411 | implicitCastExpr(hasImplicitDestinationType(isInteger()))))); |
2412 | // This test creates an implicit array-to-pointer cast. |
2413 | EXPECT_TRUE( |
2414 | matches("int arr[3]; int *p = arr;" , |
2415 | traverse(TK_AsIs, implicitCastExpr(hasImplicitDestinationType( |
2416 | pointsTo(TypeMatcher(anything()))))))); |
2417 | } |
2418 | |
2419 | TEST(HasImplicitDestinationType, DoesNotMatchIncorrectly) { |
2420 | // This test creates an implicit cast from int to char. |
2421 | EXPECT_TRUE(notMatches("char c = 0;" , |
2422 | implicitCastExpr(hasImplicitDestinationType( |
2423 | unless(anything()))))); |
2424 | // This test creates an implicit array-to-pointer cast. |
2425 | EXPECT_TRUE(notMatches("int arr[3]; int *p = arr;" , |
2426 | implicitCastExpr(hasImplicitDestinationType( |
2427 | unless(anything()))))); |
2428 | } |
2429 | |
2430 | TEST(Matcher, IgnoresElidableConstructors) { |
2431 | EXPECT_TRUE( |
2432 | matches("struct H {};" |
2433 | "template<typename T> H B(T A);" |
2434 | "void f() {" |
2435 | " H D1;" |
2436 | " D1 = B(B(1));" |
2437 | "}" , |
2438 | cxxOperatorCallExpr(hasArgument( |
2439 | 1, callExpr(hasArgument( |
2440 | 0, ignoringElidableConstructorCall(callExpr()))))), |
2441 | langCxx11OrLater())); |
2442 | EXPECT_TRUE( |
2443 | matches("struct H {};" |
2444 | "template<typename T> H B(T A);" |
2445 | "void f() {" |
2446 | " H D1;" |
2447 | " D1 = B(1);" |
2448 | "}" , |
2449 | cxxOperatorCallExpr(hasArgument( |
2450 | 1, callExpr(hasArgument(0, ignoringElidableConstructorCall( |
2451 | integerLiteral()))))), |
2452 | langCxx11OrLater())); |
2453 | EXPECT_TRUE(matches( |
2454 | "struct H {};" |
2455 | "H G();" |
2456 | "void f() {" |
2457 | " H D = G();" |
2458 | "}" , |
2459 | varDecl(hasInitializer(anyOf( |
2460 | ignoringElidableConstructorCall(callExpr()), |
2461 | exprWithCleanups(has(ignoringElidableConstructorCall(callExpr())))))), |
2462 | langCxx11OrLater())); |
2463 | } |
2464 | |
2465 | TEST(Matcher, IgnoresElidableInReturn) { |
2466 | auto matcher = expr(ignoringElidableConstructorCall(InnerMatcher: declRefExpr())); |
2467 | EXPECT_TRUE(matches("struct H {};" |
2468 | "H f() {" |
2469 | " H g;" |
2470 | " return g;" |
2471 | "}" , |
2472 | matcher, langCxx11OrLater())); |
2473 | EXPECT_TRUE(notMatches("struct H {};" |
2474 | "H f() {" |
2475 | " return H();" |
2476 | "}" , |
2477 | matcher, langCxx11OrLater())); |
2478 | } |
2479 | |
2480 | TEST(Matcher, IgnoreElidableConstructorDoesNotMatchConstructors) { |
2481 | EXPECT_TRUE(matches("struct H {};" |
2482 | "void f() {" |
2483 | " H D;" |
2484 | "}" , |
2485 | varDecl(hasInitializer( |
2486 | ignoringElidableConstructorCall(cxxConstructExpr()))), |
2487 | langCxx11OrLater())); |
2488 | } |
2489 | |
2490 | TEST(Matcher, IgnoresElidableDoesNotPreventMatches) { |
2491 | EXPECT_TRUE(matches("void f() {" |
2492 | " int D = 10;" |
2493 | "}" , |
2494 | expr(ignoringElidableConstructorCall(integerLiteral())), |
2495 | langCxx11OrLater())); |
2496 | } |
2497 | |
2498 | TEST(Matcher, IgnoresElidableInVarInit) { |
2499 | auto matcher = |
2500 | varDecl(hasInitializer(InnerMatcher: ignoringElidableConstructorCall(InnerMatcher: callExpr()))); |
2501 | EXPECT_TRUE(matches("struct H {};" |
2502 | "H G();" |
2503 | "void f(H D = G()) {" |
2504 | " return;" |
2505 | "}" , |
2506 | matcher, langCxx11OrLater())); |
2507 | EXPECT_TRUE(matches("struct H {};" |
2508 | "H G();" |
2509 | "void f() {" |
2510 | " H D = G();" |
2511 | "}" , |
2512 | matcher, langCxx11OrLater())); |
2513 | } |
2514 | |
2515 | TEST(IgnoringImplicit, MatchesImplicit) { |
2516 | EXPECT_TRUE(matches("class C {}; C a = C();" , |
2517 | varDecl(has(ignoringImplicit(cxxConstructExpr()))))); |
2518 | } |
2519 | |
2520 | TEST(IgnoringImplicit, MatchesNestedImplicit) { |
2521 | StringRef Code = R"( |
2522 | |
2523 | struct OtherType; |
2524 | |
2525 | struct SomeType |
2526 | { |
2527 | SomeType() {} |
2528 | SomeType(const OtherType&) {} |
2529 | SomeType& operator=(OtherType const&) { return *this; } |
2530 | }; |
2531 | |
2532 | struct OtherType |
2533 | { |
2534 | OtherType() {} |
2535 | ~OtherType() {} |
2536 | }; |
2537 | |
2538 | OtherType something() |
2539 | { |
2540 | return {}; |
2541 | } |
2542 | |
2543 | int main() |
2544 | { |
2545 | SomeType i = something(); |
2546 | } |
2547 | )" ; |
2548 | EXPECT_TRUE(matches( |
2549 | Code, |
2550 | traverse(TK_AsIs, |
2551 | varDecl(hasName("i" ), |
2552 | hasInitializer(exprWithCleanups(has(cxxConstructExpr( |
2553 | has(expr(ignoringImplicit(cxxConstructExpr(has( |
2554 | expr(ignoringImplicit(callExpr()))))))))))))))); |
2555 | } |
2556 | |
2557 | TEST(IgnoringImplicit, DoesNotMatchIncorrectly) { |
2558 | EXPECT_TRUE(notMatches("class C {}; C a = C();" , |
2559 | traverse(TK_AsIs, varDecl(has(cxxConstructExpr()))))); |
2560 | } |
2561 | |
2562 | TEST(Traversal, traverseMatcher) { |
2563 | |
2564 | StringRef VarDeclCode = R"cpp( |
2565 | void foo() |
2566 | { |
2567 | int i = 3.0; |
2568 | } |
2569 | )cpp" ; |
2570 | |
2571 | auto Matcher = varDecl(hasInitializer(InnerMatcher: floatLiteral())); |
2572 | |
2573 | EXPECT_TRUE(notMatches(VarDeclCode, traverse(TK_AsIs, Matcher))); |
2574 | EXPECT_TRUE( |
2575 | matches(VarDeclCode, traverse(TK_IgnoreUnlessSpelledInSource, Matcher))); |
2576 | |
2577 | auto ParentMatcher = floatLiteral(hasParent(varDecl(hasName(Name: "i" )))); |
2578 | |
2579 | EXPECT_TRUE(notMatches(VarDeclCode, traverse(TK_AsIs, ParentMatcher))); |
2580 | EXPECT_TRUE(matches(VarDeclCode, |
2581 | traverse(TK_IgnoreUnlessSpelledInSource, ParentMatcher))); |
2582 | |
2583 | EXPECT_TRUE(matches( |
2584 | VarDeclCode, decl(traverse(TK_AsIs, anyOf(cxxRecordDecl(), varDecl()))))); |
2585 | |
2586 | EXPECT_TRUE( |
2587 | matches(VarDeclCode, |
2588 | floatLiteral(traverse(TK_AsIs, hasParent(implicitCastExpr()))))); |
2589 | |
2590 | EXPECT_TRUE( |
2591 | matches(VarDeclCode, floatLiteral(traverse(TK_IgnoreUnlessSpelledInSource, |
2592 | hasParent(varDecl()))))); |
2593 | |
2594 | EXPECT_TRUE( |
2595 | matches(VarDeclCode, varDecl(traverse(TK_IgnoreUnlessSpelledInSource, |
2596 | unless(parmVarDecl()))))); |
2597 | |
2598 | EXPECT_TRUE( |
2599 | notMatches(VarDeclCode, varDecl(traverse(TK_IgnoreUnlessSpelledInSource, |
2600 | has(implicitCastExpr()))))); |
2601 | |
2602 | EXPECT_TRUE(matches(VarDeclCode, |
2603 | varDecl(traverse(TK_AsIs, has(implicitCastExpr()))))); |
2604 | |
2605 | EXPECT_TRUE(matches( |
2606 | VarDeclCode, traverse(TK_IgnoreUnlessSpelledInSource, |
2607 | // The has() below strips away the ImplicitCastExpr |
2608 | // before the traverse(AsIs) gets to process it. |
2609 | varDecl(has(traverse(TK_AsIs, floatLiteral())))))); |
2610 | |
2611 | EXPECT_TRUE( |
2612 | matches(VarDeclCode, functionDecl(traverse(TK_AsIs, hasName("foo" ))))); |
2613 | |
2614 | EXPECT_TRUE(matches( |
2615 | VarDeclCode, |
2616 | functionDecl(traverse(TK_IgnoreUnlessSpelledInSource, hasName("foo" ))))); |
2617 | |
2618 | EXPECT_TRUE(matches( |
2619 | VarDeclCode, functionDecl(traverse(TK_AsIs, hasAnyName("foo" , "bar" ))))); |
2620 | |
2621 | EXPECT_TRUE( |
2622 | matches(VarDeclCode, functionDecl(traverse(TK_IgnoreUnlessSpelledInSource, |
2623 | hasAnyName("foo" , "bar" ))))); |
2624 | |
2625 | StringRef Code = R"cpp( |
2626 | void foo(int a) |
2627 | { |
2628 | int i = 3.0 + a; |
2629 | } |
2630 | void bar() |
2631 | { |
2632 | foo(7.0); |
2633 | } |
2634 | )cpp" ; |
2635 | EXPECT_TRUE( |
2636 | matches(Code, callExpr(traverse(TK_IgnoreUnlessSpelledInSource, |
2637 | hasArgument(0, floatLiteral()))))); |
2638 | |
2639 | EXPECT_TRUE( |
2640 | matches(Code, callExpr(traverse(TK_IgnoreUnlessSpelledInSource, |
2641 | hasAnyArgument(floatLiteral()))))); |
2642 | |
2643 | EXPECT_TRUE(matches( |
2644 | R"cpp( |
2645 | void takesBool(bool){} |
2646 | |
2647 | template <typename T> |
2648 | void neverInstantiatedTemplate() { |
2649 | takesBool(T{}); |
2650 | } |
2651 | )cpp" , |
2652 | traverse(TK_IgnoreUnlessSpelledInSource, |
2653 | callExpr(unless(callExpr(hasDeclaration(functionDecl()))))))); |
2654 | |
2655 | EXPECT_TRUE( |
2656 | matches(VarDeclCode, varDecl(traverse(TK_IgnoreUnlessSpelledInSource, |
2657 | hasType(builtinType()))))); |
2658 | |
2659 | EXPECT_TRUE( |
2660 | matches(VarDeclCode, |
2661 | functionDecl(hasName("foo" ), |
2662 | traverse(TK_AsIs, hasDescendant(floatLiteral()))))); |
2663 | |
2664 | EXPECT_TRUE(notMatches( |
2665 | Code, traverse(TK_AsIs, floatLiteral(hasParent(callExpr( |
2666 | callee(functionDecl(hasName("foo" ))))))))); |
2667 | EXPECT_TRUE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, |
2668 | floatLiteral(hasParent(callExpr(callee( |
2669 | functionDecl(hasName("foo" ))))))))); |
2670 | |
2671 | Code = R"cpp( |
2672 | void foo() |
2673 | { |
2674 | int i = (3); |
2675 | } |
2676 | )cpp" ; |
2677 | EXPECT_TRUE(matches( |
2678 | Code, traverse(TK_IgnoreUnlessSpelledInSource, |
2679 | varDecl(hasInitializer(integerLiteral(equals(3))))))); |
2680 | EXPECT_TRUE(matches( |
2681 | Code, |
2682 | traverse(TK_IgnoreUnlessSpelledInSource, |
2683 | integerLiteral(equals(3), hasParent(varDecl(hasName("i" ))))))); |
2684 | |
2685 | Code = R"cpp( |
2686 | const char *SomeString{"str"}; |
2687 | )cpp" ; |
2688 | EXPECT_TRUE( |
2689 | matches(Code, traverse(TK_AsIs, stringLiteral(hasParent(implicitCastExpr( |
2690 | hasParent(initListExpr()))))))); |
2691 | EXPECT_TRUE( |
2692 | matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, |
2693 | stringLiteral(hasParent(initListExpr()))))); |
2694 | |
2695 | Code = R"cpp( |
2696 | struct String |
2697 | { |
2698 | String(const char*, int = -1) {} |
2699 | }; |
2700 | |
2701 | void stringConstruct() |
2702 | { |
2703 | String s = "foo"; |
2704 | s = "bar"; |
2705 | } |
2706 | )cpp" ; |
2707 | EXPECT_TRUE(matches( |
2708 | Code, |
2709 | traverse( |
2710 | TK_AsIs, |
2711 | functionDecl( |
2712 | hasName("stringConstruct" ), |
2713 | hasDescendant(varDecl( |
2714 | hasName("s" ), |
2715 | hasInitializer(ignoringImplicit(cxxConstructExpr(hasArgument( |
2716 | 0, ignoringImplicit(cxxConstructExpr(hasArgument( |
2717 | 0, ignoringImplicit(stringLiteral())))))))))))))); |
2718 | |
2719 | EXPECT_TRUE(matches( |
2720 | Code, |
2721 | traverse( |
2722 | TK_AsIs, |
2723 | functionDecl(hasName("stringConstruct" ), |
2724 | hasDescendant(cxxOperatorCallExpr( |
2725 | isAssignmentOperator(), |
2726 | hasArgument(1, ignoringImplicit( |
2727 | cxxConstructExpr(hasArgument( |
2728 | 0, ignoringImplicit(stringLiteral()))))) |
2729 | )))))); |
2730 | |
2731 | EXPECT_TRUE(matches( |
2732 | Code, traverse(TK_IgnoreUnlessSpelledInSource, |
2733 | functionDecl(hasName("stringConstruct" ), |
2734 | hasDescendant(varDecl( |
2735 | hasName("s" ), |
2736 | hasInitializer(stringLiteral()))))))); |
2737 | |
2738 | EXPECT_TRUE( |
2739 | matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, |
2740 | functionDecl(hasName("stringConstruct" ), |
2741 | hasDescendant(cxxOperatorCallExpr( |
2742 | isAssignmentOperator(), |
2743 | hasArgument(1, stringLiteral()))))))); |
2744 | |
2745 | Code = R"cpp( |
2746 | |
2747 | struct C1 {}; |
2748 | struct C2 { operator C1(); }; |
2749 | |
2750 | void conversionOperator() |
2751 | { |
2752 | C2* c2; |
2753 | C1 c1 = (*c2); |
2754 | } |
2755 | |
2756 | )cpp" ; |
2757 | EXPECT_TRUE(matches( |
2758 | Code, |
2759 | traverse( |
2760 | TK_AsIs, |
2761 | functionDecl( |
2762 | hasName("conversionOperator" ), |
2763 | hasDescendant( |
2764 | varDecl( |
2765 | hasName("c1" ), |
2766 | hasInitializer( |
2767 | ignoringImplicit(cxxConstructExpr(hasArgument( |
2768 | 0, ignoringImplicit( |
2769 | cxxMemberCallExpr(onImplicitObjectArgument( |
2770 | ignoringParenImpCasts(unaryOperator( |
2771 | hasOperatorName("*" ))))))))))) |
2772 | .bind("c1" )))))); |
2773 | |
2774 | EXPECT_TRUE(matches( |
2775 | Code, |
2776 | traverse(TK_IgnoreUnlessSpelledInSource, |
2777 | functionDecl(hasName("conversionOperator" ), |
2778 | hasDescendant(varDecl( |
2779 | hasName("c1" ), hasInitializer(unaryOperator( |
2780 | hasOperatorName("*" ))))))))); |
2781 | |
2782 | Code = R"cpp( |
2783 | |
2784 | template <unsigned alignment> |
2785 | void template_test() { |
2786 | static_assert(alignment, ""); |
2787 | } |
2788 | void actual_template_test() { |
2789 | template_test<4>(); |
2790 | } |
2791 | |
2792 | )cpp" ; |
2793 | EXPECT_TRUE(matches( |
2794 | Code, |
2795 | traverse(TK_AsIs, |
2796 | staticAssertDecl(has(implicitCastExpr(has( |
2797 | substNonTypeTemplateParmExpr(has(integerLiteral()))))))))); |
2798 | EXPECT_TRUE(matches( |
2799 | Code, traverse(TK_IgnoreUnlessSpelledInSource, |
2800 | staticAssertDecl(has(declRefExpr( |
2801 | to(nonTypeTemplateParmDecl(hasName("alignment" ))), |
2802 | hasType(asString("unsigned int" )))))))); |
2803 | |
2804 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, staticAssertDecl(hasDescendant( |
2805 | integerLiteral()))))); |
2806 | EXPECT_FALSE(matches( |
2807 | Code, traverse(TK_IgnoreUnlessSpelledInSource, |
2808 | staticAssertDecl(hasDescendant(integerLiteral()))))); |
2809 | |
2810 | Code = R"cpp( |
2811 | |
2812 | struct OneParamCtor { |
2813 | explicit OneParamCtor(int); |
2814 | }; |
2815 | struct TwoParamCtor { |
2816 | explicit TwoParamCtor(int, int); |
2817 | }; |
2818 | |
2819 | void varDeclCtors() { |
2820 | { |
2821 | auto var1 = OneParamCtor(5); |
2822 | auto var2 = TwoParamCtor(6, 7); |
2823 | } |
2824 | { |
2825 | OneParamCtor var3(5); |
2826 | TwoParamCtor var4(6, 7); |
2827 | } |
2828 | int i = 0; |
2829 | { |
2830 | auto var5 = OneParamCtor(i); |
2831 | auto var6 = TwoParamCtor(i, 7); |
2832 | } |
2833 | { |
2834 | OneParamCtor var7(i); |
2835 | TwoParamCtor var8(i, 7); |
2836 | } |
2837 | } |
2838 | |
2839 | )cpp" ; |
2840 | EXPECT_TRUE(matches( |
2841 | Code, |
2842 | traverse(TK_AsIs, varDecl(hasName("var1" ), hasInitializer(hasDescendant( |
2843 | cxxConstructExpr())))))); |
2844 | EXPECT_TRUE(matches( |
2845 | Code, |
2846 | traverse(TK_AsIs, varDecl(hasName("var2" ), hasInitializer(hasDescendant( |
2847 | cxxConstructExpr())))))); |
2848 | EXPECT_TRUE(matches( |
2849 | Code, traverse(TK_AsIs, varDecl(hasName("var3" ), |
2850 | hasInitializer(cxxConstructExpr()))))); |
2851 | EXPECT_TRUE(matches( |
2852 | Code, traverse(TK_AsIs, varDecl(hasName("var4" ), |
2853 | hasInitializer(cxxConstructExpr()))))); |
2854 | EXPECT_TRUE(matches( |
2855 | Code, |
2856 | traverse(TK_AsIs, varDecl(hasName("var5" ), hasInitializer(hasDescendant( |
2857 | cxxConstructExpr())))))); |
2858 | EXPECT_TRUE(matches( |
2859 | Code, |
2860 | traverse(TK_AsIs, varDecl(hasName("var6" ), hasInitializer(hasDescendant( |
2861 | cxxConstructExpr())))))); |
2862 | EXPECT_TRUE(matches( |
2863 | Code, traverse(TK_AsIs, varDecl(hasName("var7" ), |
2864 | hasInitializer(cxxConstructExpr()))))); |
2865 | EXPECT_TRUE(matches( |
2866 | Code, traverse(TK_AsIs, varDecl(hasName("var8" ), |
2867 | hasInitializer(cxxConstructExpr()))))); |
2868 | |
2869 | EXPECT_TRUE(matches( |
2870 | Code, |
2871 | traverse(TK_IgnoreUnlessSpelledInSource, |
2872 | varDecl(hasName("var1" ), hasInitializer(cxxConstructExpr()))))); |
2873 | EXPECT_TRUE(matches( |
2874 | Code, |
2875 | traverse(TK_IgnoreUnlessSpelledInSource, |
2876 | varDecl(hasName("var2" ), hasInitializer(cxxConstructExpr()))))); |
2877 | EXPECT_TRUE(matches( |
2878 | Code, |
2879 | traverse(TK_IgnoreUnlessSpelledInSource, |
2880 | varDecl(hasName("var3" ), hasInitializer(cxxConstructExpr()))))); |
2881 | EXPECT_TRUE(matches( |
2882 | Code, |
2883 | traverse(TK_IgnoreUnlessSpelledInSource, |
2884 | varDecl(hasName("var4" ), hasInitializer(cxxConstructExpr()))))); |
2885 | EXPECT_TRUE(matches( |
2886 | Code, |
2887 | traverse(TK_IgnoreUnlessSpelledInSource, |
2888 | varDecl(hasName("var5" ), hasInitializer(cxxConstructExpr()))))); |
2889 | EXPECT_TRUE(matches( |
2890 | Code, |
2891 | traverse(TK_IgnoreUnlessSpelledInSource, |
2892 | varDecl(hasName("var6" ), hasInitializer(cxxConstructExpr()))))); |
2893 | EXPECT_TRUE(matches( |
2894 | Code, |
2895 | traverse(TK_IgnoreUnlessSpelledInSource, |
2896 | varDecl(hasName("var7" ), hasInitializer(cxxConstructExpr()))))); |
2897 | EXPECT_TRUE(matches( |
2898 | Code, |
2899 | traverse(TK_IgnoreUnlessSpelledInSource, |
2900 | varDecl(hasName("var8" ), hasInitializer(cxxConstructExpr()))))); |
2901 | |
2902 | Code = R"cpp( |
2903 | |
2904 | template<typename T> |
2905 | struct TemplStruct { |
2906 | TemplStruct() {} |
2907 | ~TemplStruct() {} |
2908 | |
2909 | void outOfLine(T); |
2910 | |
2911 | private: |
2912 | T m_t; |
2913 | }; |
2914 | |
2915 | template<typename T> |
2916 | void TemplStruct<T>::outOfLine(T) |
2917 | { |
2918 | |
2919 | } |
2920 | |
2921 | template<typename T> |
2922 | T timesTwo(T input) |
2923 | { |
2924 | return input * 2; |
2925 | } |
2926 | |
2927 | void instantiate() |
2928 | { |
2929 | TemplStruct<int> ti; |
2930 | TemplStruct<double> td; |
2931 | (void)timesTwo<int>(2); |
2932 | (void)timesTwo<double>(2); |
2933 | } |
2934 | |
2935 | template class TemplStruct<float>; |
2936 | |
2937 | extern template class TemplStruct<long>; |
2938 | |
2939 | template<> class TemplStruct<bool> { |
2940 | TemplStruct() {} |
2941 | ~TemplStruct() {} |
2942 | |
2943 | void boolSpecializationMethodOnly() {} |
2944 | private: |
2945 | bool m_t; |
2946 | }; |
2947 | |
2948 | template float timesTwo(float); |
2949 | template<> bool timesTwo<bool>(bool){ |
2950 | return true; |
2951 | } |
2952 | )cpp" ; |
2953 | { |
2954 | auto M = cxxRecordDecl(hasName(Name: "TemplStruct" ), |
2955 | has(fieldDecl(hasType(InnerMatcher: asString(Name: "int" ))))); |
2956 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
2957 | EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
2958 | } |
2959 | { |
2960 | auto M = cxxRecordDecl(hasName(Name: "TemplStruct" ), |
2961 | has(fieldDecl(hasType(InnerMatcher: asString(Name: "double" ))))); |
2962 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
2963 | EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
2964 | } |
2965 | { |
2966 | auto M = |
2967 | functionDecl(hasName(Name: "timesTwo" ), |
2968 | hasParameter(N: 0, InnerMatcher: parmVarDecl(hasType(InnerMatcher: asString(Name: "int" ))))); |
2969 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
2970 | EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
2971 | } |
2972 | { |
2973 | auto M = |
2974 | functionDecl(hasName(Name: "timesTwo" ), |
2975 | hasParameter(N: 0, InnerMatcher: parmVarDecl(hasType(InnerMatcher: asString(Name: "double" ))))); |
2976 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
2977 | EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
2978 | } |
2979 | { |
2980 | // Match on the integer literal in the explicit instantiation: |
2981 | auto MDef = |
2982 | functionDecl(hasName(Name: "timesTwo" ), |
2983 | hasParameter(N: 0, InnerMatcher: parmVarDecl(hasType(InnerMatcher: asString(Name: "float" )))), |
2984 | hasDescendant(integerLiteral(equals(Value: 2)))); |
2985 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, MDef))); |
2986 | EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, MDef))); |
2987 | |
2988 | auto MTempl = |
2989 | functionDecl(hasName(Name: "timesTwo" ), |
2990 | hasTemplateArgument(N: 0, InnerMatcher: refersToType(InnerMatcher: asString(Name: "float" )))); |
2991 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, MTempl))); |
2992 | // TODO: If we could match on explicit instantiations of function templates, |
2993 | // this would be EXPECT_TRUE. See Sema::ActOnExplicitInstantiation. |
2994 | EXPECT_FALSE( |
2995 | matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, MTempl))); |
2996 | } |
2997 | { |
2998 | auto M = functionDecl(hasName(Name: "timesTwo" ), |
2999 | hasParameter(N: 0, InnerMatcher: parmVarDecl(hasType(InnerMatcher: booleanType())))); |
3000 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3001 | EXPECT_TRUE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3002 | } |
3003 | { |
3004 | // Match on the field within the explicit instantiation: |
3005 | auto MRecord = cxxRecordDecl(hasName(Name: "TemplStruct" ), |
3006 | has(fieldDecl(hasType(InnerMatcher: asString(Name: "float" ))))); |
3007 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, MRecord))); |
3008 | EXPECT_FALSE( |
3009 | matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, MRecord))); |
3010 | |
3011 | // Match on the explicit template instantiation itself: |
3012 | auto MTempl = classTemplateSpecializationDecl( |
3013 | hasName(Name: "TemplStruct" ), |
3014 | hasTemplateArgument(N: 0, |
3015 | InnerMatcher: templateArgument(refersToType(InnerMatcher: asString(Name: "float" ))))); |
3016 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, MTempl))); |
3017 | EXPECT_TRUE( |
3018 | matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, MTempl))); |
3019 | } |
3020 | { |
3021 | // The template argument is matchable, but the instantiation is not: |
3022 | auto M = classTemplateSpecializationDecl( |
3023 | hasName(Name: "TemplStruct" ), |
3024 | hasTemplateArgument(N: 0, |
3025 | InnerMatcher: templateArgument(refersToType(InnerMatcher: asString(Name: "float" )))), |
3026 | has(cxxConstructorDecl(hasName(Name: "TemplStruct" )))); |
3027 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3028 | EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3029 | } |
3030 | { |
3031 | // The template argument is matchable, but the instantiation is not: |
3032 | auto M = classTemplateSpecializationDecl( |
3033 | hasName(Name: "TemplStruct" ), |
3034 | hasTemplateArgument(N: 0, |
3035 | InnerMatcher: templateArgument(refersToType(InnerMatcher: asString(Name: "long" )))), |
3036 | has(cxxConstructorDecl(hasName(Name: "TemplStruct" )))); |
3037 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3038 | EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3039 | } |
3040 | { |
3041 | // Instantiated, out-of-line methods are not matchable. |
3042 | auto M = |
3043 | cxxMethodDecl(hasName(Name: "outOfLine" ), isDefinition(), |
3044 | hasParameter(N: 0, InnerMatcher: parmVarDecl(hasType(InnerMatcher: asString(Name: "float" ))))); |
3045 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3046 | EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3047 | } |
3048 | { |
3049 | // Explicit specialization is written in source and it matches: |
3050 | auto M = classTemplateSpecializationDecl( |
3051 | hasName(Name: "TemplStruct" ), |
3052 | hasTemplateArgument(N: 0, InnerMatcher: templateArgument(refersToType(InnerMatcher: booleanType()))), |
3053 | has(cxxConstructorDecl(hasName(Name: "TemplStruct" ))), |
3054 | has(cxxMethodDecl(hasName(Name: "boolSpecializationMethodOnly" )))); |
3055 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3056 | EXPECT_TRUE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3057 | } |
3058 | |
3059 | Code = R"cpp( |
3060 | struct B { |
3061 | B(int); |
3062 | }; |
3063 | |
3064 | B func1() { return 42; } |
3065 | )cpp" ; |
3066 | { |
3067 | auto M = expr(ignoringImplicit(InnerMatcher: integerLiteral(equals(Value: 42)).bind(ID: "intLit" ))); |
3068 | EXPECT_TRUE(matchAndVerifyResultTrue( |
3069 | Code, traverse(TK_AsIs, M), |
3070 | std::make_unique<VerifyIdIsBoundTo<Expr>>("intLit" , 1))); |
3071 | EXPECT_TRUE(matchAndVerifyResultTrue( |
3072 | Code, traverse(TK_IgnoreUnlessSpelledInSource, M), |
3073 | std::make_unique<VerifyIdIsBoundTo<Expr>>("intLit" , 1))); |
3074 | } |
3075 | { |
3076 | auto M = expr(unless(integerLiteral(equals(Value: 24)))).bind(ID: "intLit" ); |
3077 | EXPECT_TRUE(matchAndVerifyResultTrue( |
3078 | Code, traverse(TK_AsIs, M), |
3079 | std::make_unique<VerifyIdIsBoundTo<Expr>>("intLit" , 6))); |
3080 | EXPECT_TRUE(matchAndVerifyResultTrue( |
3081 | Code, traverse(TK_IgnoreUnlessSpelledInSource, M), |
3082 | std::make_unique<VerifyIdIsBoundTo<Expr>>("intLit" , 1))); |
3083 | } |
3084 | { |
3085 | auto M = |
3086 | expr(anyOf(integerLiteral(equals(Value: 42)).bind(ID: "intLit" ), unless(expr()))); |
3087 | EXPECT_TRUE(matchAndVerifyResultTrue( |
3088 | Code, traverse(TK_AsIs, M), |
3089 | std::make_unique<VerifyIdIsBoundTo<Expr>>("intLit" , 1))); |
3090 | EXPECT_TRUE(matchAndVerifyResultTrue( |
3091 | Code, traverse(TK_IgnoreUnlessSpelledInSource, M), |
3092 | std::make_unique<VerifyIdIsBoundTo<Expr>>("intLit" , 1))); |
3093 | } |
3094 | { |
3095 | auto M = expr(allOf(integerLiteral(equals(Value: 42)).bind(ID: "intLit" ), expr())); |
3096 | EXPECT_TRUE(matchAndVerifyResultTrue( |
3097 | Code, traverse(TK_AsIs, M), |
3098 | std::make_unique<VerifyIdIsBoundTo<Expr>>("intLit" , 1))); |
3099 | EXPECT_TRUE(matchAndVerifyResultTrue( |
3100 | Code, traverse(TK_IgnoreUnlessSpelledInSource, M), |
3101 | std::make_unique<VerifyIdIsBoundTo<Expr>>("intLit" , 1))); |
3102 | } |
3103 | { |
3104 | auto M = expr(integerLiteral(equals(Value: 42)).bind(ID: "intLit" ), expr()); |
3105 | EXPECT_TRUE(matchAndVerifyResultTrue( |
3106 | Code, traverse(TK_AsIs, M), |
3107 | std::make_unique<VerifyIdIsBoundTo<Expr>>("intLit" , 1))); |
3108 | EXPECT_TRUE(matchAndVerifyResultTrue( |
3109 | Code, traverse(TK_IgnoreUnlessSpelledInSource, M), |
3110 | std::make_unique<VerifyIdIsBoundTo<Expr>>("intLit" , 1))); |
3111 | } |
3112 | { |
3113 | auto M = expr(optionally(integerLiteral(equals(Value: 42)).bind(ID: "intLit" ))); |
3114 | EXPECT_TRUE(matchAndVerifyResultTrue( |
3115 | Code, traverse(TK_AsIs, M), |
3116 | std::make_unique<VerifyIdIsBoundTo<Expr>>("intLit" , 1))); |
3117 | EXPECT_TRUE(matchAndVerifyResultTrue( |
3118 | Code, traverse(TK_IgnoreUnlessSpelledInSource, M), |
3119 | std::make_unique<VerifyIdIsBoundTo<Expr>>("intLit" , 1))); |
3120 | } |
3121 | { |
3122 | auto M = expr().bind(ID: "allExprs" ); |
3123 | EXPECT_TRUE(matchAndVerifyResultTrue( |
3124 | Code, traverse(TK_AsIs, M), |
3125 | std::make_unique<VerifyIdIsBoundTo<Expr>>("allExprs" , 6))); |
3126 | EXPECT_TRUE(matchAndVerifyResultTrue( |
3127 | Code, traverse(TK_IgnoreUnlessSpelledInSource, M), |
3128 | std::make_unique<VerifyIdIsBoundTo<Expr>>("allExprs" , 1))); |
3129 | } |
3130 | |
3131 | Code = R"cpp( |
3132 | void foo() |
3133 | { |
3134 | int arr[3]; |
3135 | auto &[f, s, t] = arr; |
3136 | |
3137 | f = 42; |
3138 | } |
3139 | )cpp" ; |
3140 | { |
3141 | auto M = bindingDecl(hasName(Name: "f" )); |
3142 | EXPECT_TRUE( |
3143 | matchesConditionally(Code, traverse(TK_AsIs, M), true, {"-std=c++17" })); |
3144 | EXPECT_TRUE( |
3145 | matchesConditionally(Code, traverse(TK_IgnoreUnlessSpelledInSource, M), |
3146 | true, {"-std=c++17" })); |
3147 | } |
3148 | { |
3149 | auto M = bindingDecl(hasName(Name: "f" ), has(expr())); |
3150 | EXPECT_TRUE( |
3151 | matchesConditionally(Code, traverse(TK_AsIs, M), true, {"-std=c++17" })); |
3152 | EXPECT_FALSE( |
3153 | matchesConditionally(Code, traverse(TK_IgnoreUnlessSpelledInSource, M), |
3154 | true, {"-std=c++17" })); |
3155 | } |
3156 | { |
3157 | auto M = integerLiteral(hasAncestor(bindingDecl(hasName(Name: "f" )))); |
3158 | EXPECT_TRUE( |
3159 | matchesConditionally(Code, traverse(TK_AsIs, M), true, {"-std=c++17" })); |
3160 | EXPECT_FALSE( |
3161 | matchesConditionally(Code, traverse(TK_IgnoreUnlessSpelledInSource, M), |
3162 | true, {"-std=c++17" })); |
3163 | } |
3164 | { |
3165 | auto M = declRefExpr(hasAncestor(bindingDecl(hasName(Name: "f" )))); |
3166 | EXPECT_TRUE( |
3167 | matchesConditionally(Code, traverse(TK_AsIs, M), true, {"-std=c++17" })); |
3168 | EXPECT_FALSE( |
3169 | matchesConditionally(Code, traverse(TK_IgnoreUnlessSpelledInSource, M), |
3170 | true, {"-std=c++17" })); |
3171 | } |
3172 | } |
3173 | |
3174 | TEST(Traversal, traverseNoImplicit) { |
3175 | StringRef Code = R"cpp( |
3176 | struct NonTrivial { |
3177 | NonTrivial() {} |
3178 | NonTrivial(const NonTrivial&) {} |
3179 | NonTrivial& operator=(const NonTrivial&) { return *this; } |
3180 | |
3181 | ~NonTrivial() {} |
3182 | }; |
3183 | |
3184 | struct NoSpecialMethods { |
3185 | NonTrivial nt; |
3186 | }; |
3187 | |
3188 | struct ContainsArray { |
3189 | NonTrivial arr[2]; |
3190 | ContainsArray& operator=(const ContainsArray &other) = default; |
3191 | }; |
3192 | |
3193 | void copyIt() |
3194 | { |
3195 | NoSpecialMethods nc1; |
3196 | NoSpecialMethods nc2(nc1); |
3197 | nc2 = nc1; |
3198 | |
3199 | ContainsArray ca; |
3200 | ContainsArray ca2; |
3201 | ca2 = ca; |
3202 | } |
3203 | |
3204 | struct HasCtorInits : NoSpecialMethods, NonTrivial |
3205 | { |
3206 | int m_i; |
3207 | NonTrivial m_nt; |
3208 | HasCtorInits() : NoSpecialMethods(), m_i(42) {} |
3209 | }; |
3210 | |
3211 | struct CtorInitsNonTrivial : NonTrivial |
3212 | { |
3213 | int m_i; |
3214 | NonTrivial m_nt; |
3215 | CtorInitsNonTrivial() : NonTrivial(), m_i(42) {} |
3216 | }; |
3217 | |
3218 | )cpp" ; |
3219 | { |
3220 | auto M = cxxRecordDecl(hasName(Name: "NoSpecialMethods" ), |
3221 | has(cxxRecordDecl(hasName(Name: "NoSpecialMethods" )))); |
3222 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3223 | EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3224 | |
3225 | M = cxxRecordDecl(hasName(Name: "NoSpecialMethods" ), |
3226 | has(cxxConstructorDecl(isCopyConstructor()))); |
3227 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3228 | EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3229 | |
3230 | M = cxxRecordDecl(hasName(Name: "NoSpecialMethods" ), |
3231 | has(cxxMethodDecl(isCopyAssignmentOperator()))); |
3232 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3233 | EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3234 | |
3235 | M = cxxRecordDecl(hasName(Name: "NoSpecialMethods" ), |
3236 | has(cxxConstructorDecl(isDefaultConstructor()))); |
3237 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3238 | EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3239 | |
3240 | M = cxxRecordDecl(hasName(Name: "NoSpecialMethods" ), has(cxxDestructorDecl())); |
3241 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3242 | EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3243 | |
3244 | M = cxxRecordDecl(hasName(Name: "NoSpecialMethods" ), |
3245 | hasMethod(InnerMatcher: cxxConstructorDecl(isCopyConstructor()))); |
3246 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3247 | EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3248 | |
3249 | M = cxxRecordDecl(hasName(Name: "NoSpecialMethods" ), |
3250 | hasMethod(InnerMatcher: cxxMethodDecl(isCopyAssignmentOperator()))); |
3251 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3252 | EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3253 | |
3254 | M = cxxRecordDecl(hasName(Name: "NoSpecialMethods" ), |
3255 | hasMethod(InnerMatcher: cxxConstructorDecl(isDefaultConstructor()))); |
3256 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3257 | EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3258 | |
3259 | M = cxxRecordDecl(hasName(Name: "NoSpecialMethods" ), |
3260 | hasMethod(InnerMatcher: cxxDestructorDecl())); |
3261 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3262 | EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3263 | } |
3264 | { |
3265 | // Because the copy-assignment operator is not spelled in the |
3266 | // source (ie, isImplicit()), we don't match it |
3267 | auto M = |
3268 | cxxOperatorCallExpr(hasType(InnerMatcher: cxxRecordDecl(hasName(Name: "NoSpecialMethods" ))), |
3269 | callee(InnerMatcher: cxxMethodDecl(isCopyAssignmentOperator()))); |
3270 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3271 | EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3272 | } |
3273 | { |
3274 | // Compiler generates a forStmt to copy the array |
3275 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, forStmt()))); |
3276 | EXPECT_FALSE( |
3277 | matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, forStmt()))); |
3278 | } |
3279 | { |
3280 | // The defaulted method declaration can be matched, but not its |
3281 | // definition, in IgnoreUnlessSpelledInSource mode |
3282 | auto MDecl = cxxMethodDecl(ofClass(InnerMatcher: cxxRecordDecl(hasName(Name: "ContainsArray" ))), |
3283 | isCopyAssignmentOperator(), isDefaulted()); |
3284 | |
3285 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, MDecl))); |
3286 | EXPECT_TRUE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, MDecl))); |
3287 | |
3288 | auto MDef = cxxMethodDecl(MDecl, has(compoundStmt())); |
3289 | |
3290 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, MDef))); |
3291 | EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, MDef))); |
3292 | |
3293 | auto MBody = cxxMethodDecl(MDecl, hasBody(InnerMatcher: compoundStmt())); |
3294 | |
3295 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, MBody))); |
3296 | EXPECT_FALSE( |
3297 | matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, MBody))); |
3298 | |
3299 | auto MIsDefn = cxxMethodDecl(MDecl, isDefinition()); |
3300 | |
3301 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, MIsDefn))); |
3302 | EXPECT_TRUE( |
3303 | matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, MIsDefn))); |
3304 | |
3305 | auto MIsInline = cxxMethodDecl(MDecl, isInline()); |
3306 | |
3307 | EXPECT_FALSE(matches(Code, traverse(TK_AsIs, MIsInline))); |
3308 | EXPECT_FALSE( |
3309 | matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, MIsInline))); |
3310 | |
3311 | // The parameter of the defaulted method can still be matched. |
3312 | auto MParm = |
3313 | cxxMethodDecl(MDecl, hasParameter(N: 0, InnerMatcher: parmVarDecl(hasName(Name: "other" )))); |
3314 | |
3315 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, MParm))); |
3316 | EXPECT_TRUE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, MParm))); |
3317 | } |
3318 | { |
3319 | auto M = |
3320 | cxxConstructorDecl(hasName(Name: "HasCtorInits" ), |
3321 | has(cxxCtorInitializer(forField(InnerMatcher: hasName(Name: "m_i" ))))); |
3322 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3323 | EXPECT_TRUE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3324 | } |
3325 | { |
3326 | auto M = |
3327 | cxxConstructorDecl(hasName(Name: "HasCtorInits" ), |
3328 | has(cxxCtorInitializer(forField(InnerMatcher: hasName(Name: "m_nt" ))))); |
3329 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3330 | EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3331 | } |
3332 | { |
3333 | auto M = cxxConstructorDecl(hasName(Name: "HasCtorInits" ), |
3334 | hasAnyConstructorInitializer(InnerMatcher: cxxCtorInitializer( |
3335 | forField(InnerMatcher: hasName(Name: "m_nt" ))))); |
3336 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3337 | EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3338 | } |
3339 | { |
3340 | auto M = |
3341 | cxxConstructorDecl(hasName(Name: "HasCtorInits" ), |
3342 | forEachConstructorInitializer( |
3343 | InnerMatcher: cxxCtorInitializer(forField(InnerMatcher: hasName(Name: "m_nt" ))))); |
3344 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3345 | EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3346 | } |
3347 | { |
3348 | auto M = cxxConstructorDecl( |
3349 | hasName(Name: "CtorInitsNonTrivial" ), |
3350 | has(cxxCtorInitializer(withInitializer(InnerMatcher: cxxConstructExpr( |
3351 | hasDeclaration(InnerMatcher: cxxConstructorDecl(hasName(Name: "NonTrivial" )))))))); |
3352 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3353 | EXPECT_TRUE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3354 | } |
3355 | { |
3356 | auto M = cxxConstructorDecl( |
3357 | hasName(Name: "HasCtorInits" ), |
3358 | has(cxxCtorInitializer(withInitializer(InnerMatcher: cxxConstructExpr(hasDeclaration( |
3359 | InnerMatcher: cxxConstructorDecl(hasName(Name: "NoSpecialMethods" )))))))); |
3360 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3361 | EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3362 | } |
3363 | { |
3364 | auto M = cxxCtorInitializer(forField(InnerMatcher: hasName(Name: "m_nt" ))); |
3365 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3366 | EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3367 | } |
3368 | |
3369 | Code = R"cpp( |
3370 | void rangeFor() |
3371 | { |
3372 | int arr[2]; |
3373 | for (auto i : arr) |
3374 | { |
3375 | if (true) |
3376 | { |
3377 | } |
3378 | } |
3379 | } |
3380 | )cpp" ; |
3381 | { |
3382 | auto M = cxxForRangeStmt(has(binaryOperator(hasOperatorName(Name: "!=" )))); |
3383 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3384 | EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3385 | } |
3386 | { |
3387 | auto M = |
3388 | cxxForRangeStmt(hasDescendant(binaryOperator(hasOperatorName(Name: "+" )))); |
3389 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3390 | EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3391 | } |
3392 | { |
3393 | auto M = |
3394 | cxxForRangeStmt(hasDescendant(unaryOperator(hasOperatorName(Name: "++" )))); |
3395 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3396 | EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3397 | } |
3398 | { |
3399 | auto M = cxxForRangeStmt(has(declStmt())); |
3400 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3401 | EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3402 | } |
3403 | { |
3404 | auto M = |
3405 | cxxForRangeStmt(hasLoopVariable(InnerMatcher: varDecl(hasName(Name: "i" ))), |
3406 | hasRangeInit(InnerMatcher: declRefExpr(to(InnerMatcher: varDecl(hasName(Name: "arr" )))))); |
3407 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3408 | EXPECT_TRUE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3409 | } |
3410 | { |
3411 | auto M = cxxForRangeStmt(unless(hasInitStatement(InnerMatcher: stmt()))); |
3412 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3413 | EXPECT_TRUE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3414 | } |
3415 | { |
3416 | auto M = cxxForRangeStmt(hasBody(InnerMatcher: stmt())); |
3417 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3418 | EXPECT_TRUE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3419 | } |
3420 | { |
3421 | auto M = cxxForRangeStmt(hasDescendant(ifStmt())); |
3422 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3423 | EXPECT_TRUE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3424 | } |
3425 | { |
3426 | EXPECT_TRUE(matches( |
3427 | Code, traverse(TK_AsIs, cxxForRangeStmt(has(declStmt( |
3428 | hasSingleDecl(varDecl(hasName("i" ))))))))); |
3429 | EXPECT_TRUE( |
3430 | matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, |
3431 | cxxForRangeStmt(has(varDecl(hasName("i" ))))))); |
3432 | } |
3433 | { |
3434 | EXPECT_TRUE(matches( |
3435 | Code, traverse(TK_AsIs, cxxForRangeStmt(has(declStmt(hasSingleDecl( |
3436 | varDecl(hasInitializer(declRefExpr( |
3437 | to(varDecl(hasName("arr" ))))))))))))); |
3438 | EXPECT_TRUE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, |
3439 | cxxForRangeStmt(has(declRefExpr( |
3440 | to(varDecl(hasName("arr" ))))))))); |
3441 | } |
3442 | { |
3443 | auto M = cxxForRangeStmt(has(compoundStmt())); |
3444 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3445 | EXPECT_TRUE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3446 | } |
3447 | { |
3448 | auto M = binaryOperator(hasOperatorName(Name: "!=" )); |
3449 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3450 | EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3451 | } |
3452 | { |
3453 | auto M = unaryOperator(hasOperatorName(Name: "++" )); |
3454 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3455 | EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3456 | } |
3457 | { |
3458 | auto M = declStmt(hasSingleDecl(InnerMatcher: varDecl(matchesName(RegExp: "__range" )))); |
3459 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3460 | EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3461 | } |
3462 | { |
3463 | auto M = declStmt(hasSingleDecl(InnerMatcher: varDecl(matchesName(RegExp: "__begin" )))); |
3464 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3465 | EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3466 | } |
3467 | { |
3468 | auto M = declStmt(hasSingleDecl(InnerMatcher: varDecl(matchesName(RegExp: "__end" )))); |
3469 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3470 | EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3471 | } |
3472 | { |
3473 | auto M = ifStmt(hasParent(compoundStmt(hasParent(cxxForRangeStmt())))); |
3474 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3475 | EXPECT_TRUE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3476 | } |
3477 | { |
3478 | auto M = cxxForRangeStmt( |
3479 | has(varDecl(hasName(Name: "i" ), hasParent(cxxForRangeStmt())))); |
3480 | EXPECT_FALSE(matches(Code, traverse(TK_AsIs, M))); |
3481 | EXPECT_TRUE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3482 | } |
3483 | { |
3484 | auto M = cxxForRangeStmt(hasDescendant(varDecl( |
3485 | hasName(Name: "i" ), hasParent(declStmt(hasParent(cxxForRangeStmt())))))); |
3486 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3487 | EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3488 | } |
3489 | { |
3490 | auto M = cxxForRangeStmt(hasRangeInit(InnerMatcher: declRefExpr( |
3491 | to(InnerMatcher: varDecl(hasName(Name: "arr" ))), hasParent(cxxForRangeStmt())))); |
3492 | EXPECT_FALSE(matches(Code, traverse(TK_AsIs, M))); |
3493 | EXPECT_TRUE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3494 | } |
3495 | |
3496 | { |
3497 | auto M = cxxForRangeStmt(hasRangeInit(InnerMatcher: declRefExpr( |
3498 | to(InnerMatcher: varDecl(hasName(Name: "arr" ))), hasParent(varDecl(hasParent(declStmt( |
3499 | hasParent(cxxForRangeStmt())))))))); |
3500 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3501 | EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3502 | } |
3503 | |
3504 | Code = R"cpp( |
3505 | struct Range { |
3506 | int* begin() const; |
3507 | int* end() const; |
3508 | }; |
3509 | Range getRange(int); |
3510 | |
3511 | void rangeFor() |
3512 | { |
3513 | for (auto i : getRange(42)) |
3514 | { |
3515 | } |
3516 | } |
3517 | )cpp" ; |
3518 | { |
3519 | auto M = integerLiteral(equals(Value: 42)); |
3520 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3521 | EXPECT_TRUE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3522 | } |
3523 | { |
3524 | auto M = callExpr(hasDescendant(integerLiteral(equals(Value: 42)))); |
3525 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3526 | EXPECT_TRUE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3527 | } |
3528 | { |
3529 | auto M = compoundStmt(hasDescendant(integerLiteral(equals(Value: 42)))); |
3530 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3531 | EXPECT_TRUE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3532 | } |
3533 | |
3534 | Code = R"cpp( |
3535 | void rangeFor() |
3536 | { |
3537 | int arr[2]; |
3538 | for (auto& a = arr; auto i : a) |
3539 | { |
3540 | |
3541 | } |
3542 | } |
3543 | )cpp" ; |
3544 | { |
3545 | auto M = cxxForRangeStmt(has(binaryOperator(hasOperatorName(Name: "!=" )))); |
3546 | EXPECT_TRUE( |
3547 | matchesConditionally(Code, traverse(TK_AsIs, M), true, {"-std=c++20" })); |
3548 | EXPECT_FALSE( |
3549 | matchesConditionally(Code, traverse(TK_IgnoreUnlessSpelledInSource, M), |
3550 | true, {"-std=c++20" })); |
3551 | } |
3552 | { |
3553 | auto M = |
3554 | cxxForRangeStmt(hasDescendant(binaryOperator(hasOperatorName(Name: "+" )))); |
3555 | EXPECT_TRUE( |
3556 | matchesConditionally(Code, traverse(TK_AsIs, M), true, {"-std=c++20" })); |
3557 | EXPECT_FALSE( |
3558 | matchesConditionally(Code, traverse(TK_IgnoreUnlessSpelledInSource, M), |
3559 | true, {"-std=c++20" })); |
3560 | } |
3561 | { |
3562 | auto M = |
3563 | cxxForRangeStmt(hasDescendant(unaryOperator(hasOperatorName(Name: "++" )))); |
3564 | EXPECT_TRUE( |
3565 | matchesConditionally(Code, traverse(TK_AsIs, M), true, {"-std=c++20" })); |
3566 | EXPECT_FALSE( |
3567 | matchesConditionally(Code, traverse(TK_IgnoreUnlessSpelledInSource, M), |
3568 | true, {"-std=c++20" })); |
3569 | } |
3570 | { |
3571 | auto M = |
3572 | cxxForRangeStmt(has(declStmt(hasSingleDecl(InnerMatcher: varDecl(hasName(Name: "i" )))))); |
3573 | EXPECT_TRUE( |
3574 | matchesConditionally(Code, traverse(TK_AsIs, M), true, {"-std=c++20" })); |
3575 | EXPECT_FALSE( |
3576 | matchesConditionally(Code, traverse(TK_IgnoreUnlessSpelledInSource, M), |
3577 | true, {"-std=c++20" })); |
3578 | } |
3579 | { |
3580 | auto M = cxxForRangeStmt( |
3581 | hasInitStatement(InnerMatcher: declStmt(hasSingleDecl(InnerMatcher: varDecl( |
3582 | hasName(Name: "a" ), |
3583 | hasInitializer(InnerMatcher: declRefExpr(to(InnerMatcher: varDecl(hasName(Name: "arr" ))))))))), |
3584 | hasLoopVariable(InnerMatcher: varDecl(hasName(Name: "i" ))), |
3585 | hasRangeInit(InnerMatcher: declRefExpr(to(InnerMatcher: varDecl(hasName(Name: "a" )))))); |
3586 | EXPECT_TRUE( |
3587 | matchesConditionally(Code, traverse(TK_AsIs, M), true, {"-std=c++20" })); |
3588 | EXPECT_TRUE( |
3589 | matchesConditionally(Code, traverse(TK_IgnoreUnlessSpelledInSource, M), |
3590 | true, {"-std=c++20" })); |
3591 | } |
3592 | { |
3593 | auto M = cxxForRangeStmt( |
3594 | has(declStmt(hasSingleDecl(InnerMatcher: varDecl( |
3595 | hasName(Name: "a" ), |
3596 | hasInitializer(InnerMatcher: declRefExpr(to(InnerMatcher: varDecl(hasName(Name: "arr" ))))))))), |
3597 | hasLoopVariable(InnerMatcher: varDecl(hasName(Name: "i" ))), |
3598 | hasRangeInit(InnerMatcher: declRefExpr(to(InnerMatcher: varDecl(hasName(Name: "a" )))))); |
3599 | EXPECT_TRUE( |
3600 | matchesConditionally(Code, traverse(TK_AsIs, M), true, {"-std=c++20" })); |
3601 | EXPECT_TRUE( |
3602 | matchesConditionally(Code, traverse(TK_IgnoreUnlessSpelledInSource, M), |
3603 | true, {"-std=c++20" })); |
3604 | } |
3605 | { |
3606 | auto M = cxxForRangeStmt(hasInitStatement(InnerMatcher: declStmt( |
3607 | hasSingleDecl(InnerMatcher: varDecl(hasName(Name: "a" ))), hasParent(cxxForRangeStmt())))); |
3608 | EXPECT_TRUE( |
3609 | matchesConditionally(Code, traverse(TK_AsIs, M), true, {"-std=c++20" })); |
3610 | EXPECT_TRUE( |
3611 | matchesConditionally(Code, traverse(TK_IgnoreUnlessSpelledInSource, M), |
3612 | true, {"-std=c++20" })); |
3613 | } |
3614 | |
3615 | Code = R"cpp( |
3616 | struct Range { |
3617 | int* begin() const; |
3618 | int* end() const; |
3619 | }; |
3620 | Range getRange(int); |
3621 | |
3622 | int getNum(int); |
3623 | |
3624 | void rangeFor() |
3625 | { |
3626 | for (auto j = getNum(42); auto i : getRange(j)) |
3627 | { |
3628 | } |
3629 | } |
3630 | )cpp" ; |
3631 | { |
3632 | auto M = integerLiteral(equals(Value: 42)); |
3633 | EXPECT_TRUE( |
3634 | matchesConditionally(Code, traverse(TK_AsIs, M), true, {"-std=c++20" })); |
3635 | EXPECT_TRUE( |
3636 | matchesConditionally(Code, traverse(TK_IgnoreUnlessSpelledInSource, M), |
3637 | true, {"-std=c++20" })); |
3638 | } |
3639 | { |
3640 | auto M = compoundStmt(hasDescendant(integerLiteral(equals(Value: 42)))); |
3641 | EXPECT_TRUE( |
3642 | matchesConditionally(Code, traverse(TK_AsIs, M), true, {"-std=c++20" })); |
3643 | EXPECT_TRUE( |
3644 | matchesConditionally(Code, traverse(TK_IgnoreUnlessSpelledInSource, M), |
3645 | true, {"-std=c++20" })); |
3646 | } |
3647 | |
3648 | Code = R"cpp( |
3649 | void hasDefaultArg(int i, int j = 0) |
3650 | { |
3651 | } |
3652 | void callDefaultArg() |
3653 | { |
3654 | hasDefaultArg(42); |
3655 | } |
3656 | )cpp" ; |
3657 | auto hasDefaultArgCall = [](auto InnerMatcher) { |
3658 | return callExpr(callee(InnerMatcher: functionDecl(hasName(Name: "hasDefaultArg" ))), |
3659 | InnerMatcher); |
3660 | }; |
3661 | { |
3662 | auto M = hasDefaultArgCall(has(integerLiteral(equals(Value: 42)))); |
3663 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3664 | EXPECT_TRUE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3665 | } |
3666 | { |
3667 | auto M = hasDefaultArgCall(has(cxxDefaultArgExpr())); |
3668 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3669 | EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3670 | } |
3671 | { |
3672 | auto M = hasDefaultArgCall(argumentCountIs(N: 2)); |
3673 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3674 | EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3675 | } |
3676 | { |
3677 | auto M = hasDefaultArgCall(argumentCountIs(N: 1)); |
3678 | EXPECT_FALSE(matches(Code, traverse(TK_AsIs, M))); |
3679 | EXPECT_TRUE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3680 | } |
3681 | { |
3682 | auto M = hasDefaultArgCall(hasArgument(N: 1, InnerMatcher: cxxDefaultArgExpr())); |
3683 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3684 | EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3685 | } |
3686 | { |
3687 | auto M = hasDefaultArgCall(hasAnyArgument(InnerMatcher: cxxDefaultArgExpr())); |
3688 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3689 | EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3690 | } |
3691 | Code = R"cpp( |
3692 | struct A |
3693 | { |
3694 | ~A(); |
3695 | private: |
3696 | int i; |
3697 | }; |
3698 | |
3699 | A::~A() = default; |
3700 | )cpp" ; |
3701 | { |
3702 | auto M = cxxDestructorDecl(isDefaulted(), |
3703 | ofClass(InnerMatcher: cxxRecordDecl(has(fieldDecl())))); |
3704 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); |
3705 | EXPECT_TRUE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); |
3706 | } |
3707 | Code = R"cpp( |
3708 | struct S |
3709 | { |
3710 | static constexpr bool getTrue() { return true; } |
3711 | }; |
3712 | |
3713 | struct A |
3714 | { |
3715 | explicit(S::getTrue()) A(); |
3716 | }; |
3717 | |
3718 | A::A() = default; |
3719 | )cpp" ; |
3720 | { |
3721 | EXPECT_TRUE(matchesConditionally( |
3722 | Code, |
3723 | traverse(TK_AsIs, |
3724 | cxxConstructorDecl( |
3725 | isDefaulted(), |
3726 | hasExplicitSpecifier(expr(ignoringImplicit( |
3727 | callExpr(has(ignoringImplicit(declRefExpr())))))))), |
3728 | true, {"-std=c++20" })); |
3729 | EXPECT_TRUE(matchesConditionally( |
3730 | Code, |
3731 | traverse(TK_IgnoreUnlessSpelledInSource, |
3732 | cxxConstructorDecl( |
3733 | isDefaulted(), |
3734 | hasExplicitSpecifier(callExpr(has(declRefExpr()))))), |
3735 | true, {"-std=c++20" })); |
3736 | } |
3737 | } |
3738 | |
3739 | template <typename MatcherT> |
3740 | bool matcherTemplateWithBinding(StringRef Code, const MatcherT &M) { |
3741 | return matchAndVerifyResultTrue( |
3742 | Code, M.bind("matchedStmt" ), |
3743 | std::make_unique<VerifyIdIsBoundTo<ReturnStmt>>(args: "matchedStmt" , args: 1)); |
3744 | } |
3745 | |
3746 | TEST(Traversal, traverseWithBinding) { |
3747 | // Some existing matcher code expects to take a matcher as a |
3748 | // template arg and bind to it. Verify that that works. |
3749 | |
3750 | llvm::StringRef Code = R"cpp( |
3751 | int foo() |
3752 | { |
3753 | return 42.0; |
3754 | } |
3755 | )cpp" ; |
3756 | EXPECT_TRUE(matcherTemplateWithBinding( |
3757 | Code, traverse(TK_AsIs, |
3758 | returnStmt(has(implicitCastExpr(has(floatLiteral()))))))); |
3759 | } |
3760 | |
3761 | TEST(Traversal, traverseMatcherNesting) { |
3762 | |
3763 | StringRef Code = R"cpp( |
3764 | float bar(int i) |
3765 | { |
3766 | return i; |
3767 | } |
3768 | |
3769 | void foo() |
3770 | { |
3771 | bar(bar(3.0)); |
3772 | } |
3773 | )cpp" ; |
3774 | |
3775 | EXPECT_TRUE( |
3776 | matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, |
3777 | callExpr(has(callExpr(traverse( |
3778 | TK_AsIs, callExpr(has(implicitCastExpr( |
3779 | has(floatLiteral()))))))))))); |
3780 | |
3781 | EXPECT_TRUE(matches( |
3782 | Code, |
3783 | traverse(TK_IgnoreUnlessSpelledInSource, |
3784 | traverse(TK_AsIs, implicitCastExpr(has(floatLiteral())))))); |
3785 | } |
3786 | |
3787 | TEST(Traversal, traverseMatcherThroughImplicit) { |
3788 | StringRef Code = R"cpp( |
3789 | struct S { |
3790 | S(int x); |
3791 | }; |
3792 | |
3793 | void constructImplicit() { |
3794 | int a = 8; |
3795 | S s(a); |
3796 | } |
3797 | )cpp" ; |
3798 | |
3799 | auto Matcher = traverse(TK: TK_IgnoreUnlessSpelledInSource, InnerMatcher: implicitCastExpr()); |
3800 | |
3801 | // Verfiy that it does not segfault |
3802 | EXPECT_FALSE(matches(Code, Matcher)); |
3803 | } |
3804 | |
3805 | TEST(Traversal, traverseMatcherThroughMemoization) { |
3806 | |
3807 | StringRef Code = R"cpp( |
3808 | void foo() |
3809 | { |
3810 | int i = 3.0; |
3811 | } |
3812 | )cpp" ; |
3813 | |
3814 | auto Matcher = varDecl(hasInitializer(InnerMatcher: floatLiteral())); |
3815 | |
3816 | // Matchers such as hasDescendant memoize their result regarding AST |
3817 | // nodes. In the matcher below, the first use of hasDescendant(Matcher) |
3818 | // fails, and the use of it inside the traverse() matcher should pass |
3819 | // causing the overall matcher to be a true match. |
3820 | // This test verifies that the first false result is not re-used, which |
3821 | // would cause the overall matcher to be incorrectly false. |
3822 | |
3823 | EXPECT_TRUE(matches( |
3824 | Code, |
3825 | functionDecl(anyOf(hasDescendant(Matcher), |
3826 | traverse(TK_IgnoreUnlessSpelledInSource, |
3827 | functionDecl(hasDescendant(Matcher))))))); |
3828 | } |
3829 | |
3830 | TEST(Traversal, traverseUnlessSpelledInSource) { |
3831 | |
3832 | StringRef Code = R"cpp( |
3833 | |
3834 | struct A |
3835 | { |
3836 | }; |
3837 | |
3838 | struct B |
3839 | { |
3840 | B(int); |
3841 | B(A const& a); |
3842 | B(); |
3843 | }; |
3844 | |
3845 | struct C |
3846 | { |
3847 | operator B(); |
3848 | }; |
3849 | |
3850 | B func1() { |
3851 | return 42; |
3852 | } |
3853 | |
3854 | B func2() { |
3855 | return B{42}; |
3856 | } |
3857 | |
3858 | B func3() { |
3859 | return B(42); |
3860 | } |
3861 | |
3862 | B func4() { |
3863 | return B(); |
3864 | } |
3865 | |
3866 | B func5() { |
3867 | return B{}; |
3868 | } |
3869 | |
3870 | B func6() { |
3871 | return C(); |
3872 | } |
3873 | |
3874 | B func7() { |
3875 | return A(); |
3876 | } |
3877 | |
3878 | B func8() { |
3879 | return C{}; |
3880 | } |
3881 | |
3882 | B func9() { |
3883 | return A{}; |
3884 | } |
3885 | |
3886 | B func10() { |
3887 | A a; |
3888 | return a; |
3889 | } |
3890 | |
3891 | B func11() { |
3892 | B b; |
3893 | return b; |
3894 | } |
3895 | |
3896 | B func12() { |
3897 | C c; |
3898 | return c; |
3899 | } |
3900 | |
3901 | void func13() { |
3902 | int a = 0; |
3903 | int c = 0; |
3904 | |
3905 | [a, b = c](int d) { int e = d; }; |
3906 | } |
3907 | |
3908 | void func14() { |
3909 | [] <typename TemplateType> (TemplateType t, TemplateType u) { int e = t + u; }; |
3910 | float i = 42.0; |
3911 | } |
3912 | |
3913 | void func15() { |
3914 | int count = 0; |
3915 | auto l = [&] { ++count; }; |
3916 | (void)l; |
3917 | } |
3918 | |
3919 | )cpp" ; |
3920 | |
3921 | EXPECT_TRUE( |
3922 | matches(Code, |
3923 | traverse(TK_IgnoreUnlessSpelledInSource, |
3924 | returnStmt(forFunction(functionDecl(hasName("func1" ))), |
3925 | hasReturnValue(integerLiteral(equals(42))))), |
3926 | langCxx20OrLater())); |
3927 | |
3928 | EXPECT_TRUE( |
3929 | matches(Code, |
3930 | traverse(TK_IgnoreUnlessSpelledInSource, |
3931 | integerLiteral(equals(42), |
3932 | hasParent(returnStmt(forFunction( |
3933 | functionDecl(hasName("func1" ))))))), |
3934 | langCxx20OrLater())); |
3935 | |
3936 | EXPECT_TRUE(matches( |
3937 | Code, |
3938 | traverse(TK_IgnoreUnlessSpelledInSource, |
3939 | returnStmt(forFunction(functionDecl(hasName("func2" ))), |
3940 | hasReturnValue(cxxTemporaryObjectExpr( |
3941 | hasArgument(0, integerLiteral(equals(42))))))), |
3942 | langCxx20OrLater())); |
3943 | EXPECT_TRUE(matches( |
3944 | Code, |
3945 | traverse( |
3946 | TK_IgnoreUnlessSpelledInSource, |
3947 | integerLiteral(equals(42), |
3948 | hasParent(cxxTemporaryObjectExpr(hasParent(returnStmt( |
3949 | forFunction(functionDecl(hasName("func2" ))))))))), |
3950 | langCxx20OrLater())); |
3951 | |
3952 | EXPECT_TRUE( |
3953 | matches(Code, |
3954 | traverse(TK_IgnoreUnlessSpelledInSource, |
3955 | returnStmt(forFunction(functionDecl(hasName("func3" ))), |
3956 | hasReturnValue(cxxConstructExpr(hasArgument( |
3957 | 0, integerLiteral(equals(42))))))), |
3958 | langCxx20OrLater())); |
3959 | |
3960 | EXPECT_TRUE(matches( |
3961 | Code, |
3962 | traverse( |
3963 | TK_IgnoreUnlessSpelledInSource, |
3964 | integerLiteral(equals(42), |
3965 | hasParent(cxxConstructExpr(hasParent(returnStmt( |
3966 | forFunction(functionDecl(hasName("func3" ))))))))), |
3967 | langCxx20OrLater())); |
3968 | |
3969 | EXPECT_TRUE( |
3970 | matches(Code, |
3971 | traverse(TK_IgnoreUnlessSpelledInSource, |
3972 | returnStmt(forFunction(functionDecl(hasName("func4" ))), |
3973 | hasReturnValue(cxxTemporaryObjectExpr()))), |
3974 | langCxx20OrLater())); |
3975 | |
3976 | EXPECT_TRUE( |
3977 | matches(Code, |
3978 | traverse(TK_IgnoreUnlessSpelledInSource, |
3979 | returnStmt(forFunction(functionDecl(hasName("func5" ))), |
3980 | hasReturnValue(cxxTemporaryObjectExpr()))), |
3981 | langCxx20OrLater())); |
3982 | |
3983 | EXPECT_TRUE( |
3984 | matches(Code, |
3985 | traverse(TK_IgnoreUnlessSpelledInSource, |
3986 | returnStmt(forFunction(functionDecl(hasName("func6" ))), |
3987 | hasReturnValue(cxxTemporaryObjectExpr()))), |
3988 | langCxx20OrLater())); |
3989 | |
3990 | EXPECT_TRUE( |
3991 | matches(Code, |
3992 | traverse(TK_IgnoreUnlessSpelledInSource, |
3993 | returnStmt(forFunction(functionDecl(hasName("func7" ))), |
3994 | hasReturnValue(cxxTemporaryObjectExpr()))), |
3995 | langCxx20OrLater())); |
3996 | |
3997 | EXPECT_TRUE( |
3998 | matches(Code, |
3999 | traverse(TK_IgnoreUnlessSpelledInSource, |
4000 | returnStmt(forFunction(functionDecl(hasName("func8" ))), |
4001 | hasReturnValue(cxxFunctionalCastExpr( |
4002 | hasSourceExpression(initListExpr()))))), |
4003 | langCxx20OrLater())); |
4004 | |
4005 | EXPECT_TRUE( |
4006 | matches(Code, |
4007 | traverse(TK_IgnoreUnlessSpelledInSource, |
4008 | returnStmt(forFunction(functionDecl(hasName("func9" ))), |
4009 | hasReturnValue(cxxFunctionalCastExpr( |
4010 | hasSourceExpression(initListExpr()))))), |
4011 | langCxx20OrLater())); |
4012 | |
4013 | EXPECT_TRUE(matches( |
4014 | Code, |
4015 | traverse( |
4016 | TK_IgnoreUnlessSpelledInSource, |
4017 | returnStmt(forFunction(functionDecl(hasName("func10" ))), |
4018 | hasReturnValue(declRefExpr(to(varDecl(hasName("a" ))))))), |
4019 | langCxx20OrLater())); |
4020 | |
4021 | EXPECT_TRUE( |
4022 | matches(Code, |
4023 | traverse(TK_IgnoreUnlessSpelledInSource, |
4024 | declRefExpr(to(varDecl(hasName("a" ))), |
4025 | hasParent(returnStmt(forFunction( |
4026 | functionDecl(hasName("func10" ))))))), |
4027 | langCxx20OrLater())); |
4028 | |
4029 | EXPECT_TRUE(matches( |
4030 | Code, |
4031 | traverse( |
4032 | TK_IgnoreUnlessSpelledInSource, |
4033 | returnStmt(forFunction(functionDecl(hasName("func11" ))), |
4034 | hasReturnValue(declRefExpr(to(varDecl(hasName("b" ))))))), |
4035 | langCxx20OrLater())); |
4036 | |
4037 | EXPECT_TRUE( |
4038 | matches(Code, |
4039 | traverse(TK_IgnoreUnlessSpelledInSource, |
4040 | declRefExpr(to(varDecl(hasName("b" ))), |
4041 | hasParent(returnStmt(forFunction( |
4042 | functionDecl(hasName("func11" ))))))), |
4043 | langCxx20OrLater())); |
4044 | |
4045 | EXPECT_TRUE(matches( |
4046 | Code, |
4047 | traverse( |
4048 | TK_IgnoreUnlessSpelledInSource, |
4049 | returnStmt(forFunction(functionDecl(hasName("func12" ))), |
4050 | hasReturnValue(declRefExpr(to(varDecl(hasName("c" ))))))), |
4051 | langCxx20OrLater())); |
4052 | |
4053 | EXPECT_TRUE( |
4054 | matches(Code, |
4055 | traverse(TK_IgnoreUnlessSpelledInSource, |
4056 | declRefExpr(to(varDecl(hasName("c" ))), |
4057 | hasParent(returnStmt(forFunction( |
4058 | functionDecl(hasName("func12" ))))))), |
4059 | langCxx20OrLater())); |
4060 | |
4061 | EXPECT_TRUE(matches( |
4062 | Code, |
4063 | traverse( |
4064 | TK_IgnoreUnlessSpelledInSource, |
4065 | lambdaExpr(forFunction(functionDecl(hasName("func13" ))), |
4066 | has(compoundStmt(hasDescendant(varDecl(hasName("e" ))))), |
4067 | has(declRefExpr(to(varDecl(hasName("a" ))))), |
4068 | has(varDecl(hasName("b" ), hasInitializer(declRefExpr(to( |
4069 | varDecl(hasName("c" ))))))), |
4070 | has(parmVarDecl(hasName("d" ))))), |
4071 | langCxx20OrLater())); |
4072 | |
4073 | EXPECT_TRUE( |
4074 | matches(Code, |
4075 | traverse(TK_IgnoreUnlessSpelledInSource, |
4076 | declRefExpr(to(varDecl(hasName("a" ))), |
4077 | hasParent(lambdaExpr(forFunction( |
4078 | functionDecl(hasName("func13" ))))))), |
4079 | langCxx20OrLater())); |
4080 | |
4081 | EXPECT_TRUE(matches( |
4082 | Code, |
4083 | traverse(TK_IgnoreUnlessSpelledInSource, |
4084 | varDecl(hasName("b" ), |
4085 | hasInitializer(declRefExpr(to(varDecl(hasName("c" ))))), |
4086 | hasParent(lambdaExpr( |
4087 | forFunction(functionDecl(hasName("func13" ))))))), |
4088 | langCxx20OrLater())); |
4089 | |
4090 | EXPECT_TRUE(matches(Code, |
4091 | traverse(TK_IgnoreUnlessSpelledInSource, |
4092 | compoundStmt(hasParent(lambdaExpr(forFunction( |
4093 | functionDecl(hasName("func13" ))))))), |
4094 | langCxx20OrLater())); |
4095 | |
4096 | EXPECT_TRUE(matches( |
4097 | Code, |
4098 | traverse(TK_IgnoreUnlessSpelledInSource, |
4099 | templateTypeParmDecl(hasName("TemplateType" ), |
4100 | hasParent(lambdaExpr(forFunction( |
4101 | functionDecl(hasName("func14" ))))))), |
4102 | langCxx20OrLater())); |
4103 | |
4104 | EXPECT_TRUE(matches( |
4105 | Code, |
4106 | traverse(TK_IgnoreUnlessSpelledInSource, |
4107 | lambdaExpr(forFunction(functionDecl(hasName("func14" ))), |
4108 | has(templateTypeParmDecl(hasName("TemplateType" ))))), |
4109 | langCxx20OrLater())); |
4110 | |
4111 | EXPECT_TRUE(matches( |
4112 | Code, |
4113 | traverse(TK_IgnoreUnlessSpelledInSource, |
4114 | functionDecl(hasName("func14" ), hasDescendant(floatLiteral()))), |
4115 | langCxx20OrLater())); |
4116 | |
4117 | EXPECT_TRUE(matches( |
4118 | Code, |
4119 | traverse(TK_IgnoreUnlessSpelledInSource, |
4120 | compoundStmt( |
4121 | hasDescendant(varDecl(hasName("count" )).bind("countVar" )), |
4122 | hasDescendant( |
4123 | declRefExpr(to(varDecl(equalsBoundNode("countVar" ))))))), |
4124 | langCxx20OrLater())); |
4125 | |
4126 | Code = R"cpp( |
4127 | void foo() { |
4128 | int explicit_captured = 0; |
4129 | int implicit_captured = 0; |
4130 | auto l = [&, explicit_captured](int i) { |
4131 | if (i || explicit_captured || implicit_captured) return; |
4132 | }; |
4133 | } |
4134 | )cpp" ; |
4135 | |
4136 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, ifStmt()))); |
4137 | EXPECT_TRUE( |
4138 | matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, ifStmt()))); |
4139 | |
4140 | auto lambdaExplicitCapture = declRefExpr( |
4141 | to(InnerMatcher: varDecl(hasName(Name: "explicit_captured" ))), unless(hasAncestor(ifStmt()))); |
4142 | auto lambdaImplicitCapture = declRefExpr( |
4143 | to(InnerMatcher: varDecl(hasName(Name: "implicit_captured" ))), unless(hasAncestor(ifStmt()))); |
4144 | |
4145 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, lambdaExplicitCapture))); |
4146 | EXPECT_TRUE(matches( |
4147 | Code, traverse(TK_IgnoreUnlessSpelledInSource, lambdaExplicitCapture))); |
4148 | |
4149 | EXPECT_TRUE(matches(Code, traverse(TK_AsIs, lambdaImplicitCapture))); |
4150 | EXPECT_FALSE(matches( |
4151 | Code, traverse(TK_IgnoreUnlessSpelledInSource, lambdaImplicitCapture))); |
4152 | |
4153 | Code = R"cpp( |
4154 | struct S {}; |
4155 | |
4156 | struct HasOpEq |
4157 | { |
4158 | bool operator==(const S& other) |
4159 | { |
4160 | return true; |
4161 | } |
4162 | }; |
4163 | |
4164 | void binop() |
4165 | { |
4166 | HasOpEq s1; |
4167 | S s2; |
4168 | if (s1 != s2) |
4169 | return; |
4170 | } |
4171 | )cpp" ; |
4172 | { |
4173 | auto M = unaryOperator( |
4174 | hasOperatorName(Name: "!" ), |
4175 | has(cxxOperatorCallExpr(hasOverloadedOperatorName(Name: "==" )))); |
4176 | EXPECT_TRUE( |
4177 | matchesConditionally(Code, traverse(TK_AsIs, M), true, {"-std=c++20" })); |
4178 | EXPECT_FALSE( |
4179 | matchesConditionally(Code, traverse(TK_IgnoreUnlessSpelledInSource, M), |
4180 | true, {"-std=c++20" })); |
4181 | } |
4182 | { |
4183 | auto M = declRefExpr(to(InnerMatcher: varDecl(hasName(Name: "s1" )))); |
4184 | EXPECT_TRUE( |
4185 | matchesConditionally(Code, traverse(TK_AsIs, M), true, {"-std=c++20" })); |
4186 | EXPECT_TRUE( |
4187 | matchesConditionally(Code, traverse(TK_IgnoreUnlessSpelledInSource, M), |
4188 | true, {"-std=c++20" })); |
4189 | } |
4190 | { |
4191 | auto M = cxxOperatorCallExpr(hasOverloadedOperatorName(Name: "==" )); |
4192 | EXPECT_TRUE( |
4193 | matchesConditionally(Code, traverse(TK_AsIs, M), true, {"-std=c++20" })); |
4194 | EXPECT_FALSE( |
4195 | matchesConditionally(Code, traverse(TK_IgnoreUnlessSpelledInSource, M), |
4196 | true, {"-std=c++20" })); |
4197 | } |
4198 | { |
4199 | auto M = cxxOperatorCallExpr(hasOverloadedOperatorName(Name: "!=" )); |
4200 | EXPECT_FALSE( |
4201 | matchesConditionally(Code, traverse(TK_AsIs, M), true, {"-std=c++20" })); |
4202 | EXPECT_FALSE( |
4203 | matchesConditionally(Code, traverse(TK_IgnoreUnlessSpelledInSource, M), |
4204 | true, {"-std=c++20" })); |
4205 | } |
4206 | auto withDescendants = [](StringRef lName, StringRef rName) { |
4207 | return stmt(hasDescendant(declRefExpr(to(InnerMatcher: varDecl(hasName(Name: lName))))), |
4208 | hasDescendant(declRefExpr(to(InnerMatcher: varDecl(hasName(Name: rName)))))); |
4209 | }; |
4210 | { |
4211 | auto M = cxxRewrittenBinaryOperator(withDescendants("s1" , "s2" )); |
4212 | EXPECT_TRUE( |
4213 | matchesConditionally(Code, traverse(TK_AsIs, M), true, {"-std=c++20" })); |
4214 | EXPECT_TRUE( |
4215 | matchesConditionally(Code, traverse(TK_IgnoreUnlessSpelledInSource, M), |
4216 | true, {"-std=c++20" })); |
4217 | } |
4218 | { |
4219 | auto M = cxxRewrittenBinaryOperator( |
4220 | has(declRefExpr(to(InnerMatcher: varDecl(hasName(Name: "s1" ))))), |
4221 | has(declRefExpr(to(InnerMatcher: varDecl(hasName(Name: "s2" )))))); |
4222 | EXPECT_FALSE( |
4223 | matchesConditionally(Code, traverse(TK_AsIs, M), true, {"-std=c++20" })); |
4224 | EXPECT_TRUE( |
4225 | matchesConditionally(Code, traverse(TK_IgnoreUnlessSpelledInSource, M), |
4226 | true, {"-std=c++20" })); |
4227 | } |
4228 | { |
4229 | auto M = cxxRewrittenBinaryOperator( |
4230 | hasLHS(InnerMatcher: expr(hasParent(cxxRewrittenBinaryOperator()))), |
4231 | hasRHS(InnerMatcher: expr(hasParent(cxxRewrittenBinaryOperator())))); |
4232 | EXPECT_FALSE( |
4233 | matchesConditionally(Code, traverse(TK_AsIs, M), true, {"-std=c++20" })); |
4234 | EXPECT_TRUE( |
4235 | matchesConditionally(Code, traverse(TK_IgnoreUnlessSpelledInSource, M), |
4236 | true, {"-std=c++20" })); |
4237 | } |
4238 | { |
4239 | EXPECT_TRUE(matchesConditionally( |
4240 | Code, |
4241 | traverse(TK_AsIs, |
4242 | cxxRewrittenBinaryOperator( |
4243 | hasOperatorName("!=" ), hasAnyOperatorName("<" , "!=" ), |
4244 | isComparisonOperator(), |
4245 | hasLHS(ignoringImplicit( |
4246 | declRefExpr(to(varDecl(hasName("s1" )))))), |
4247 | hasRHS(ignoringImplicit( |
4248 | declRefExpr(to(varDecl(hasName("s2" )))))), |
4249 | hasEitherOperand(ignoringImplicit( |
4250 | declRefExpr(to(varDecl(hasName("s2" )))))), |
4251 | hasOperands(ignoringImplicit( |
4252 | declRefExpr(to(varDecl(hasName("s1" ))))), |
4253 | ignoringImplicit(declRefExpr( |
4254 | to(varDecl(hasName("s2" )))))))), |
4255 | true, {"-std=c++20" })); |
4256 | EXPECT_TRUE(matchesConditionally( |
4257 | Code, |
4258 | traverse(TK_IgnoreUnlessSpelledInSource, |
4259 | cxxRewrittenBinaryOperator( |
4260 | hasOperatorName("!=" ), hasAnyOperatorName("<" , "!=" ), |
4261 | isComparisonOperator(), |
4262 | hasLHS(declRefExpr(to(varDecl(hasName("s1" ))))), |
4263 | hasRHS(declRefExpr(to(varDecl(hasName("s2" ))))), |
4264 | hasEitherOperand(declRefExpr(to(varDecl(hasName("s2" ))))), |
4265 | hasOperands(declRefExpr(to(varDecl(hasName("s1" )))), |
4266 | declRefExpr(to(varDecl(hasName("s2" ))))))), |
4267 | true, {"-std=c++20" })); |
4268 | } |
4269 | |
4270 | Code = R"cpp( |
4271 | namespace std { |
4272 | struct strong_ordering { |
4273 | int n; |
4274 | constexpr operator int() const { return n; } |
4275 | static const strong_ordering equal, greater, less; |
4276 | }; |
4277 | constexpr strong_ordering strong_ordering::equal = {0}; |
4278 | constexpr strong_ordering strong_ordering::greater = {1}; |
4279 | constexpr strong_ordering strong_ordering::less = {-1}; |
4280 | } |
4281 | |
4282 | struct HasSpaceshipMem { |
4283 | int a; |
4284 | constexpr auto operator<=>(const HasSpaceshipMem&) const = default; |
4285 | }; |
4286 | |
4287 | void binop() |
4288 | { |
4289 | HasSpaceshipMem hs1, hs2; |
4290 | if (hs1 == hs2) |
4291 | return; |
4292 | |
4293 | HasSpaceshipMem hs3, hs4; |
4294 | if (hs3 != hs4) |
4295 | return; |
4296 | |
4297 | HasSpaceshipMem hs5, hs6; |
4298 | if (hs5 < hs6) |
4299 | return; |
4300 | |
4301 | HasSpaceshipMem hs7, hs8; |
4302 | if (hs7 > hs8) |
4303 | return; |
4304 | |
4305 | HasSpaceshipMem hs9, hs10; |
4306 | if (hs9 <= hs10) |
4307 | return; |
4308 | |
4309 | HasSpaceshipMem hs11, hs12; |
4310 | if (hs11 >= hs12) |
4311 | return; |
4312 | } |
4313 | )cpp" ; |
4314 | auto withArgs = [](StringRef lName, StringRef rName) { |
4315 | return cxxOperatorCallExpr( |
4316 | hasArgument(N: 0, InnerMatcher: declRefExpr(to(InnerMatcher: varDecl(hasName(Name: lName))))), |
4317 | hasArgument(N: 1, InnerMatcher: declRefExpr(to(InnerMatcher: varDecl(hasName(Name: rName)))))); |
4318 | }; |
4319 | { |
4320 | auto M = ifStmt(hasCondition(InnerMatcher: cxxOperatorCallExpr( |
4321 | hasOverloadedOperatorName(Name: "==" ), withArgs("hs1" , "hs2" )))); |
4322 | EXPECT_TRUE( |
4323 | matchesConditionally(Code, traverse(TK_AsIs, M), true, {"-std=c++20" })); |
4324 | EXPECT_TRUE( |
4325 | matchesConditionally(Code, traverse(TK_IgnoreUnlessSpelledInSource, M), |
4326 | true, {"-std=c++20" })); |
4327 | } |
4328 | { |
4329 | auto M = |
4330 | unaryOperator(hasOperatorName(Name: "!" ), |
4331 | has(cxxOperatorCallExpr(hasOverloadedOperatorName(Name: "==" ), |
4332 | withArgs("hs3" , "hs4" )))); |
4333 | EXPECT_TRUE( |
4334 | matchesConditionally(Code, traverse(TK_AsIs, M), true, {"-std=c++20" })); |
4335 | EXPECT_FALSE( |
4336 | matchesConditionally(Code, traverse(TK_IgnoreUnlessSpelledInSource, M), |
4337 | true, {"-std=c++20" })); |
4338 | } |
4339 | { |
4340 | auto M = |
4341 | unaryOperator(hasOperatorName(Name: "!" ), |
4342 | has(cxxOperatorCallExpr(hasOverloadedOperatorName(Name: "==" ), |
4343 | withArgs("hs3" , "hs4" )))); |
4344 | EXPECT_TRUE( |
4345 | matchesConditionally(Code, traverse(TK_AsIs, M), true, {"-std=c++20" })); |
4346 | EXPECT_FALSE( |
4347 | matchesConditionally(Code, traverse(TK_IgnoreUnlessSpelledInSource, M), |
4348 | true, {"-std=c++20" })); |
4349 | } |
4350 | { |
4351 | auto M = binaryOperator( |
4352 | hasOperatorName(Name: "<" ), |
4353 | hasLHS(InnerMatcher: hasDescendant(cxxOperatorCallExpr( |
4354 | hasOverloadedOperatorName(Name: "<=>" ), withArgs("hs5" , "hs6" )))), |
4355 | hasRHS(InnerMatcher: integerLiteral(equals(Value: 0)))); |
4356 | EXPECT_TRUE( |
4357 | matchesConditionally(Code, traverse(TK_AsIs, M), true, {"-std=c++20" })); |
4358 | EXPECT_FALSE( |
4359 | matchesConditionally(Code, traverse(TK_IgnoreUnlessSpelledInSource, M), |
4360 | true, {"-std=c++20" })); |
4361 | } |
4362 | { |
4363 | auto M = cxxRewrittenBinaryOperator(withDescendants("hs3" , "hs4" )); |
4364 | EXPECT_TRUE( |
4365 | matchesConditionally(Code, traverse(TK_AsIs, M), true, {"-std=c++20" })); |
4366 | EXPECT_TRUE( |
4367 | matchesConditionally(Code, traverse(TK_IgnoreUnlessSpelledInSource, M), |
4368 | true, {"-std=c++20" })); |
4369 | } |
4370 | { |
4371 | auto M = declRefExpr(to(InnerMatcher: varDecl(hasName(Name: "hs3" )))); |
4372 | EXPECT_TRUE( |
4373 | matchesConditionally(Code, traverse(TK_AsIs, M), true, {"-std=c++20" })); |
4374 | EXPECT_TRUE( |
4375 | matchesConditionally(Code, traverse(TK_IgnoreUnlessSpelledInSource, M), |
4376 | true, {"-std=c++20" })); |
4377 | } |
4378 | { |
4379 | auto M = cxxRewrittenBinaryOperator(has( |
4380 | unaryOperator(hasOperatorName(Name: "!" ), withDescendants("hs3" , "hs4" )))); |
4381 | EXPECT_TRUE( |
4382 | matchesConditionally(Code, traverse(TK_AsIs, M), true, {"-std=c++20" })); |
4383 | EXPECT_FALSE( |
4384 | matchesConditionally(Code, traverse(TK_IgnoreUnlessSpelledInSource, M), |
4385 | true, {"-std=c++20" })); |
4386 | } |
4387 | { |
4388 | auto M = cxxRewrittenBinaryOperator( |
4389 | has(declRefExpr(to(InnerMatcher: varDecl(hasName(Name: "hs3" ))))), |
4390 | has(declRefExpr(to(InnerMatcher: varDecl(hasName(Name: "hs4" )))))); |
4391 | EXPECT_FALSE( |
4392 | matchesConditionally(Code, traverse(TK_AsIs, M), true, {"-std=c++20" })); |
4393 | EXPECT_TRUE( |
4394 | matchesConditionally(Code, traverse(TK_IgnoreUnlessSpelledInSource, M), |
4395 | true, {"-std=c++20" })); |
4396 | } |
4397 | { |
4398 | EXPECT_TRUE(matchesConditionally( |
4399 | Code, |
4400 | traverse(TK_AsIs, |
4401 | cxxRewrittenBinaryOperator( |
4402 | hasOperatorName("!=" ), hasAnyOperatorName("<" , "!=" ), |
4403 | isComparisonOperator(), |
4404 | hasLHS(ignoringImplicit( |
4405 | declRefExpr(to(varDecl(hasName("hs3" )))))), |
4406 | hasRHS(ignoringImplicit( |
4407 | declRefExpr(to(varDecl(hasName("hs4" )))))), |
4408 | hasEitherOperand(ignoringImplicit( |
4409 | declRefExpr(to(varDecl(hasName("hs3" )))))), |
4410 | hasOperands(ignoringImplicit( |
4411 | declRefExpr(to(varDecl(hasName("hs3" ))))), |
4412 | ignoringImplicit(declRefExpr( |
4413 | to(varDecl(hasName("hs4" )))))))), |
4414 | true, {"-std=c++20" })); |
4415 | EXPECT_TRUE(matchesConditionally( |
4416 | Code, |
4417 | traverse(TK_IgnoreUnlessSpelledInSource, |
4418 | cxxRewrittenBinaryOperator( |
4419 | hasOperatorName("!=" ), hasAnyOperatorName("<" , "!=" ), |
4420 | isComparisonOperator(), |
4421 | hasLHS(declRefExpr(to(varDecl(hasName("hs3" ))))), |
4422 | hasRHS(declRefExpr(to(varDecl(hasName("hs4" ))))), |
4423 | hasEitherOperand(declRefExpr(to(varDecl(hasName("hs3" ))))), |
4424 | hasOperands(declRefExpr(to(varDecl(hasName("hs3" )))), |
4425 | declRefExpr(to(varDecl(hasName("hs4" ))))))), |
4426 | true, {"-std=c++20" })); |
4427 | } |
4428 | { |
4429 | EXPECT_TRUE(matchesConditionally( |
4430 | Code, |
4431 | traverse(TK_AsIs, |
4432 | cxxRewrittenBinaryOperator( |
4433 | hasOperatorName("<" ), hasAnyOperatorName("<" , "!=" ), |
4434 | isComparisonOperator(), |
4435 | hasLHS(ignoringImplicit( |
4436 | declRefExpr(to(varDecl(hasName("hs5" )))))), |
4437 | hasRHS(ignoringImplicit( |
4438 | declRefExpr(to(varDecl(hasName("hs6" )))))), |
4439 | hasEitherOperand(ignoringImplicit( |
4440 | declRefExpr(to(varDecl(hasName("hs5" )))))), |
4441 | hasOperands(ignoringImplicit( |
4442 | declRefExpr(to(varDecl(hasName("hs5" ))))), |
4443 | ignoringImplicit(declRefExpr( |
4444 | to(varDecl(hasName("hs6" )))))))), |
4445 | true, {"-std=c++20" })); |
4446 | EXPECT_TRUE(matchesConditionally( |
4447 | Code, |
4448 | traverse(TK_IgnoreUnlessSpelledInSource, |
4449 | cxxRewrittenBinaryOperator( |
4450 | hasOperatorName("<" ), hasAnyOperatorName("<" , "!=" ), |
4451 | isComparisonOperator(), |
4452 | hasLHS(declRefExpr(to(varDecl(hasName("hs5" ))))), |
4453 | hasRHS(declRefExpr(to(varDecl(hasName("hs6" ))))), |
4454 | hasEitherOperand(declRefExpr(to(varDecl(hasName("hs5" ))))), |
4455 | hasOperands(declRefExpr(to(varDecl(hasName("hs5" )))), |
4456 | declRefExpr(to(varDecl(hasName("hs6" ))))))), |
4457 | true, {"-std=c++20" })); |
4458 | } |
4459 | { |
4460 | EXPECT_TRUE(matchesConditionally( |
4461 | Code, |
4462 | traverse(TK_AsIs, |
4463 | cxxRewrittenBinaryOperator( |
4464 | hasOperatorName(">" ), hasAnyOperatorName("<" , ">" ), |
4465 | isComparisonOperator(), |
4466 | hasLHS(ignoringImplicit( |
4467 | declRefExpr(to(varDecl(hasName("hs7" )))))), |
4468 | hasRHS(ignoringImplicit( |
4469 | declRefExpr(to(varDecl(hasName("hs8" )))))), |
4470 | hasEitherOperand(ignoringImplicit( |
4471 | declRefExpr(to(varDecl(hasName("hs7" )))))), |
4472 | hasOperands(ignoringImplicit( |
4473 | declRefExpr(to(varDecl(hasName("hs7" ))))), |
4474 | ignoringImplicit(declRefExpr( |
4475 | to(varDecl(hasName("hs8" )))))))), |
4476 | true, {"-std=c++20" })); |
4477 | EXPECT_TRUE(matchesConditionally( |
4478 | Code, |
4479 | traverse(TK_IgnoreUnlessSpelledInSource, |
4480 | cxxRewrittenBinaryOperator( |
4481 | hasOperatorName(">" ), hasAnyOperatorName("<" , ">" ), |
4482 | isComparisonOperator(), |
4483 | hasLHS(declRefExpr(to(varDecl(hasName("hs7" ))))), |
4484 | hasRHS(declRefExpr(to(varDecl(hasName("hs8" ))))), |
4485 | hasEitherOperand(declRefExpr(to(varDecl(hasName("hs7" ))))), |
4486 | hasOperands(declRefExpr(to(varDecl(hasName("hs7" )))), |
4487 | declRefExpr(to(varDecl(hasName("hs8" ))))))), |
4488 | true, {"-std=c++20" })); |
4489 | } |
4490 | { |
4491 | EXPECT_TRUE(matchesConditionally( |
4492 | Code, |
4493 | traverse(TK_AsIs, |
4494 | cxxRewrittenBinaryOperator( |
4495 | hasOperatorName("<=" ), hasAnyOperatorName("<" , "<=" ), |
4496 | isComparisonOperator(), |
4497 | hasLHS(ignoringImplicit( |
4498 | declRefExpr(to(varDecl(hasName("hs9" )))))), |
4499 | hasRHS(ignoringImplicit( |
4500 | declRefExpr(to(varDecl(hasName("hs10" )))))), |
4501 | hasEitherOperand(ignoringImplicit( |
4502 | declRefExpr(to(varDecl(hasName("hs9" )))))), |
4503 | hasOperands(ignoringImplicit( |
4504 | declRefExpr(to(varDecl(hasName("hs9" ))))), |
4505 | ignoringImplicit(declRefExpr( |
4506 | to(varDecl(hasName("hs10" )))))))), |
4507 | true, {"-std=c++20" })); |
4508 | EXPECT_TRUE(matchesConditionally( |
4509 | Code, |
4510 | traverse(TK_IgnoreUnlessSpelledInSource, |
4511 | cxxRewrittenBinaryOperator( |
4512 | hasOperatorName("<=" ), hasAnyOperatorName("<" , "<=" ), |
4513 | isComparisonOperator(), |
4514 | hasLHS(declRefExpr(to(varDecl(hasName("hs9" ))))), |
4515 | hasRHS(declRefExpr(to(varDecl(hasName("hs10" ))))), |
4516 | hasEitherOperand(declRefExpr(to(varDecl(hasName("hs9" ))))), |
4517 | hasOperands(declRefExpr(to(varDecl(hasName("hs9" )))), |
4518 | declRefExpr(to(varDecl(hasName("hs10" ))))))), |
4519 | true, {"-std=c++20" })); |
4520 | } |
4521 | { |
4522 | EXPECT_TRUE(matchesConditionally( |
4523 | Code, |
4524 | traverse(TK_AsIs, |
4525 | cxxRewrittenBinaryOperator( |
4526 | hasOperatorName(">=" ), hasAnyOperatorName("<" , ">=" ), |
4527 | isComparisonOperator(), |
4528 | hasLHS(ignoringImplicit( |
4529 | declRefExpr(to(varDecl(hasName("hs11" )))))), |
4530 | hasRHS(ignoringImplicit( |
4531 | declRefExpr(to(varDecl(hasName("hs12" )))))), |
4532 | hasEitherOperand(ignoringImplicit( |
4533 | declRefExpr(to(varDecl(hasName("hs11" )))))), |
4534 | hasOperands(ignoringImplicit( |
4535 | declRefExpr(to(varDecl(hasName("hs11" ))))), |
4536 | ignoringImplicit(declRefExpr( |
4537 | to(varDecl(hasName("hs12" )))))))), |
4538 | true, {"-std=c++20" })); |
4539 | EXPECT_TRUE(matchesConditionally( |
4540 | Code, |
4541 | traverse( |
4542 | TK_IgnoreUnlessSpelledInSource, |
4543 | cxxRewrittenBinaryOperator( |
4544 | hasOperatorName(">=" ), hasAnyOperatorName("<" , ">=" ), |
4545 | isComparisonOperator(), |
4546 | hasLHS(declRefExpr(to(varDecl(hasName("hs11" ))))), |
4547 | hasRHS(declRefExpr(to(varDecl(hasName("hs12" ))))), |
4548 | hasEitherOperand(declRefExpr(to(varDecl(hasName("hs11" ))))), |
4549 | hasOperands(declRefExpr(to(varDecl(hasName("hs11" )))), |
4550 | declRefExpr(to(varDecl(hasName("hs12" ))))))), |
4551 | true, {"-std=c++20" })); |
4552 | } |
4553 | |
4554 | Code = R"cpp( |
4555 | struct S {}; |
4556 | |
4557 | struct HasOpEq |
4558 | { |
4559 | bool operator==(const S& other) const |
4560 | { |
4561 | return true; |
4562 | } |
4563 | }; |
4564 | |
4565 | struct HasOpEqMem { |
4566 | bool operator==(const HasOpEqMem&) const { return true; } |
4567 | }; |
4568 | |
4569 | struct HasOpEqFree { |
4570 | }; |
4571 | bool operator==(const HasOpEqFree&, const HasOpEqFree&) { return true; } |
4572 | |
4573 | void binop() |
4574 | { |
4575 | { |
4576 | HasOpEq s1; |
4577 | S s2; |
4578 | if (s1 != s2) |
4579 | return; |
4580 | } |
4581 | |
4582 | { |
4583 | int i1; |
4584 | int i2; |
4585 | if (i1 != i2) |
4586 | return; |
4587 | } |
4588 | |
4589 | { |
4590 | HasOpEqMem M1; |
4591 | HasOpEqMem M2; |
4592 | if (M1 == M2) |
4593 | return; |
4594 | } |
4595 | |
4596 | { |
4597 | HasOpEqFree F1; |
4598 | HasOpEqFree F2; |
4599 | if (F1 == F2) |
4600 | return; |
4601 | } |
4602 | } |
4603 | )cpp" ; |
4604 | { |
4605 | EXPECT_TRUE(matchesConditionally( |
4606 | Code, |
4607 | traverse(TK_AsIs, |
4608 | binaryOperation( |
4609 | hasOperatorName("!=" ), hasAnyOperatorName("<" , "!=" ), |
4610 | isComparisonOperator(), |
4611 | hasLHS(ignoringImplicit( |
4612 | declRefExpr(to(varDecl(hasName("s1" )))))), |
4613 | hasRHS(ignoringImplicit( |
4614 | declRefExpr(to(varDecl(hasName("s2" )))))), |
4615 | hasEitherOperand(ignoringImplicit( |
4616 | declRefExpr(to(varDecl(hasName("s2" )))))), |
4617 | hasOperands(ignoringImplicit( |
4618 | declRefExpr(to(varDecl(hasName("s1" ))))), |
4619 | ignoringImplicit(declRefExpr( |
4620 | to(varDecl(hasName("s2" )))))))), |
4621 | true, {"-std=c++20" })); |
4622 | EXPECT_TRUE(matchesConditionally( |
4623 | Code, |
4624 | traverse(TK_AsIs, binaryOperation(hasOperatorName("!=" ), |
4625 | hasLHS(ignoringImplicit(declRefExpr( |
4626 | to(varDecl(hasName("i1" )))))), |
4627 | hasRHS(ignoringImplicit(declRefExpr( |
4628 | to(varDecl(hasName("i2" )))))))), |
4629 | true, {"-std=c++20" })); |
4630 | EXPECT_TRUE(matchesConditionally( |
4631 | Code, |
4632 | traverse(TK_AsIs, binaryOperation(hasOperatorName("==" ), |
4633 | hasLHS(ignoringImplicit(declRefExpr( |
4634 | to(varDecl(hasName("M1" )))))), |
4635 | hasRHS(ignoringImplicit(declRefExpr( |
4636 | to(varDecl(hasName("M2" )))))))), |
4637 | true, {"-std=c++20" })); |
4638 | EXPECT_TRUE(matchesConditionally( |
4639 | Code, |
4640 | traverse(TK_AsIs, binaryOperation(hasOperatorName("==" ), |
4641 | hasLHS(ignoringImplicit(declRefExpr( |
4642 | to(varDecl(hasName("F1" )))))), |
4643 | hasRHS(ignoringImplicit(declRefExpr( |
4644 | to(varDecl(hasName("F2" )))))))), |
4645 | true, {"-std=c++20" })); |
4646 | EXPECT_TRUE(matchesConditionally( |
4647 | Code, |
4648 | traverse(TK_IgnoreUnlessSpelledInSource, |
4649 | binaryOperation( |
4650 | hasOperatorName("!=" ), hasAnyOperatorName("<" , "!=" ), |
4651 | isComparisonOperator(), |
4652 | hasLHS(declRefExpr(to(varDecl(hasName("s1" ))))), |
4653 | hasRHS(declRefExpr(to(varDecl(hasName("s2" ))))), |
4654 | hasEitherOperand(declRefExpr(to(varDecl(hasName("s2" ))))), |
4655 | hasOperands(declRefExpr(to(varDecl(hasName("s1" )))), |
4656 | declRefExpr(to(varDecl(hasName("s2" ))))))), |
4657 | true, {"-std=c++20" })); |
4658 | EXPECT_TRUE(matchesConditionally( |
4659 | Code, |
4660 | traverse( |
4661 | TK_IgnoreUnlessSpelledInSource, |
4662 | binaryOperation(hasOperatorName("!=" ), |
4663 | hasLHS(declRefExpr(to(varDecl(hasName("i1" ))))), |
4664 | hasRHS(declRefExpr(to(varDecl(hasName("i2" ))))))), |
4665 | true, {"-std=c++20" })); |
4666 | EXPECT_TRUE(matchesConditionally( |
4667 | Code, |
4668 | traverse( |
4669 | TK_IgnoreUnlessSpelledInSource, |
4670 | binaryOperation(hasOperatorName("==" ), |
4671 | hasLHS(declRefExpr(to(varDecl(hasName("M1" ))))), |
4672 | hasRHS(declRefExpr(to(varDecl(hasName("M2" ))))))), |
4673 | true, {"-std=c++20" })); |
4674 | EXPECT_TRUE(matchesConditionally( |
4675 | Code, |
4676 | traverse( |
4677 | TK_IgnoreUnlessSpelledInSource, |
4678 | binaryOperation(hasOperatorName("==" ), |
4679 | hasLHS(declRefExpr(to(varDecl(hasName("F1" ))))), |
4680 | hasRHS(declRefExpr(to(varDecl(hasName("F2" ))))))), |
4681 | true, {"-std=c++20" })); |
4682 | } |
4683 | } |
4684 | |
4685 | TEST(IgnoringImpCasts, PathologicalLambda) { |
4686 | |
4687 | // Test that deeply nested lambdas are not a performance penalty |
4688 | StringRef Code = R"cpp( |
4689 | void f() { |
4690 | [] { |
4691 | [] { |
4692 | [] { |
4693 | [] { |
4694 | [] { |
4695 | [] { |
4696 | [] { |
4697 | [] { |
4698 | [] { |
4699 | [] { |
4700 | [] { |
4701 | [] { |
4702 | [] { |
4703 | [] { |
4704 | [] { |
4705 | [] { |
4706 | [] { |
4707 | [] { |
4708 | [] { |
4709 | [] { |
4710 | [] { |
4711 | [] { |
4712 | [] { |
4713 | [] { |
4714 | [] { |
4715 | [] { |
4716 | [] { |
4717 | [] { |
4718 | [] { |
4719 | int i = 42; |
4720 | (void)i; |
4721 | }(); |
4722 | }(); |
4723 | }(); |
4724 | }(); |
4725 | }(); |
4726 | }(); |
4727 | }(); |
4728 | }(); |
4729 | }(); |
4730 | }(); |
4731 | }(); |
4732 | }(); |
4733 | }(); |
4734 | }(); |
4735 | }(); |
4736 | }(); |
4737 | }(); |
4738 | }(); |
4739 | }(); |
4740 | }(); |
4741 | }(); |
4742 | }(); |
4743 | }(); |
4744 | }(); |
4745 | }(); |
4746 | }(); |
4747 | }(); |
4748 | }(); |
4749 | }(); |
4750 | } |
4751 | )cpp" ; |
4752 | |
4753 | EXPECT_TRUE(matches(Code, integerLiteral(equals(42)))); |
4754 | EXPECT_TRUE(matches(Code, functionDecl(hasDescendant(integerLiteral(equals(42)))))); |
4755 | } |
4756 | |
4757 | TEST(IgnoringImpCasts, MatchesImpCasts) { |
4758 | // This test checks that ignoringImpCasts matches when implicit casts are |
4759 | // present and its inner matcher alone does not match. |
4760 | // Note that this test creates an implicit const cast. |
4761 | EXPECT_TRUE(matches("int x = 0; const int y = x;" , |
4762 | varDecl(hasInitializer(ignoringImpCasts( |
4763 | declRefExpr(to(varDecl(hasName("x" ))))))))); |
4764 | // This test creates an implict cast from int to char. |
4765 | EXPECT_TRUE(matches("char x = 0;" , |
4766 | varDecl(hasInitializer(ignoringImpCasts( |
4767 | integerLiteral(equals(0))))))); |
4768 | } |
4769 | |
4770 | TEST(IgnoringImpCasts, DoesNotMatchIncorrectly) { |
4771 | // These tests verify that ignoringImpCasts does not match if the inner |
4772 | // matcher does not match. |
4773 | // Note that the first test creates an implicit const cast. |
4774 | EXPECT_TRUE(notMatches("int x; const int y = x;" , |
4775 | varDecl(hasInitializer(ignoringImpCasts( |
4776 | unless(anything())))))); |
4777 | EXPECT_TRUE(notMatches("int x; int y = x;" , |
4778 | varDecl(hasInitializer(ignoringImpCasts( |
4779 | unless(anything())))))); |
4780 | |
4781 | // These tests verify that ignoringImplictCasts does not look through explicit |
4782 | // casts or parentheses. |
4783 | EXPECT_TRUE(notMatches("char* p = static_cast<char*>(0);" , |
4784 | varDecl(hasInitializer(ignoringImpCasts( |
4785 | integerLiteral()))))); |
4786 | EXPECT_TRUE(notMatches( |
4787 | "int i = (0);" , |
4788 | traverse(TK_AsIs, |
4789 | varDecl(hasInitializer(ignoringImpCasts(integerLiteral())))))); |
4790 | EXPECT_TRUE(notMatches("float i = (float)0;" , |
4791 | varDecl(hasInitializer(ignoringImpCasts( |
4792 | integerLiteral()))))); |
4793 | EXPECT_TRUE(notMatches("float i = float(0);" , |
4794 | varDecl(hasInitializer(ignoringImpCasts( |
4795 | integerLiteral()))))); |
4796 | } |
4797 | |
4798 | TEST(IgnoringImpCasts, MatchesWithoutImpCasts) { |
4799 | // This test verifies that expressions that do not have implicit casts |
4800 | // still match the inner matcher. |
4801 | EXPECT_TRUE(matches("int x = 0; int &y = x;" , |
4802 | varDecl(hasInitializer(ignoringImpCasts( |
4803 | declRefExpr(to(varDecl(hasName("x" ))))))))); |
4804 | } |
4805 | |
4806 | TEST(IgnoringParenCasts, MatchesParenCasts) { |
4807 | // This test checks that ignoringParenCasts matches when parentheses and/or |
4808 | // casts are present and its inner matcher alone does not match. |
4809 | EXPECT_TRUE(matches("int x = (0);" , |
4810 | varDecl(hasInitializer(ignoringParenCasts( |
4811 | integerLiteral(equals(0))))))); |
4812 | EXPECT_TRUE(matches("int x = (((((0)))));" , |
4813 | varDecl(hasInitializer(ignoringParenCasts( |
4814 | integerLiteral(equals(0))))))); |
4815 | |
4816 | // This test creates an implict cast from int to char in addition to the |
4817 | // parentheses. |
4818 | EXPECT_TRUE(matches("char x = (0);" , |
4819 | varDecl(hasInitializer(ignoringParenCasts( |
4820 | integerLiteral(equals(0))))))); |
4821 | |
4822 | EXPECT_TRUE(matches("char x = (char)0;" , |
4823 | varDecl(hasInitializer(ignoringParenCasts( |
4824 | integerLiteral(equals(0))))))); |
4825 | EXPECT_TRUE(matches("char* p = static_cast<char*>(0);" , |
4826 | varDecl(hasInitializer(ignoringParenCasts( |
4827 | integerLiteral(equals(0))))))); |
4828 | } |
4829 | |
4830 | TEST(IgnoringParenCasts, MatchesWithoutParenCasts) { |
4831 | // This test verifies that expressions that do not have any casts still match. |
4832 | EXPECT_TRUE(matches("int x = 0;" , |
4833 | varDecl(hasInitializer(ignoringParenCasts( |
4834 | integerLiteral(equals(0))))))); |
4835 | } |
4836 | |
4837 | TEST(IgnoringParenCasts, DoesNotMatchIncorrectly) { |
4838 | // These tests verify that ignoringImpCasts does not match if the inner |
4839 | // matcher does not match. |
4840 | EXPECT_TRUE(notMatches("int x = ((0));" , |
4841 | varDecl(hasInitializer(ignoringParenCasts( |
4842 | unless(anything())))))); |
4843 | |
4844 | // This test creates an implicit cast from int to char in addition to the |
4845 | // parentheses. |
4846 | EXPECT_TRUE(notMatches("char x = ((0));" , |
4847 | varDecl(hasInitializer(ignoringParenCasts( |
4848 | unless(anything())))))); |
4849 | |
4850 | EXPECT_TRUE(notMatches("char *x = static_cast<char *>((0));" , |
4851 | varDecl(hasInitializer(ignoringParenCasts( |
4852 | unless(anything())))))); |
4853 | } |
4854 | |
4855 | TEST(IgnoringParenAndImpCasts, MatchesParenImpCasts) { |
4856 | // This test checks that ignoringParenAndImpCasts matches when |
4857 | // parentheses and/or implicit casts are present and its inner matcher alone |
4858 | // does not match. |
4859 | // Note that this test creates an implicit const cast. |
4860 | EXPECT_TRUE(matches("int x = 0; const int y = x;" , |
4861 | varDecl(hasInitializer(ignoringParenImpCasts( |
4862 | declRefExpr(to(varDecl(hasName("x" ))))))))); |
4863 | // This test creates an implicit cast from int to char. |
4864 | EXPECT_TRUE(matches("const char x = (0);" , |
4865 | varDecl(hasInitializer(ignoringParenImpCasts( |
4866 | integerLiteral(equals(0))))))); |
4867 | } |
4868 | |
4869 | TEST(IgnoringParenAndImpCasts, MatchesWithoutParenImpCasts) { |
4870 | // This test verifies that expressions that do not have parentheses or |
4871 | // implicit casts still match. |
4872 | EXPECT_TRUE(matches("int x = 0; int &y = x;" , |
4873 | varDecl(hasInitializer(ignoringParenImpCasts( |
4874 | declRefExpr(to(varDecl(hasName("x" ))))))))); |
4875 | EXPECT_TRUE(matches("int x = 0;" , |
4876 | varDecl(hasInitializer(ignoringParenImpCasts( |
4877 | integerLiteral(equals(0))))))); |
4878 | } |
4879 | |
4880 | TEST(IgnoringParenAndImpCasts, DoesNotMatchIncorrectly) { |
4881 | // These tests verify that ignoringParenImpCasts does not match if |
4882 | // the inner matcher does not match. |
4883 | // This test creates an implicit cast. |
4884 | EXPECT_TRUE(notMatches("char c = ((3));" , |
4885 | varDecl(hasInitializer(ignoringParenImpCasts( |
4886 | unless(anything())))))); |
4887 | // These tests verify that ignoringParenAndImplictCasts does not look |
4888 | // through explicit casts. |
4889 | EXPECT_TRUE(notMatches("float y = (float(0));" , |
4890 | varDecl(hasInitializer(ignoringParenImpCasts( |
4891 | integerLiteral()))))); |
4892 | EXPECT_TRUE(notMatches("float y = (float)0;" , |
4893 | varDecl(hasInitializer(ignoringParenImpCasts( |
4894 | integerLiteral()))))); |
4895 | EXPECT_TRUE(notMatches("char* p = static_cast<char*>(0);" , |
4896 | varDecl(hasInitializer(ignoringParenImpCasts( |
4897 | integerLiteral()))))); |
4898 | } |
4899 | |
4900 | TEST(HasSourceExpression, MatchesImplicitCasts) { |
4901 | EXPECT_TRUE(matches("class string {}; class URL { public: URL(string s); };" |
4902 | "void r() {string a_string; URL url = a_string; }" , |
4903 | traverse(TK_AsIs, implicitCastExpr(hasSourceExpression( |
4904 | cxxConstructExpr()))))); |
4905 | } |
4906 | |
4907 | TEST(HasSourceExpression, MatchesExplicitCasts) { |
4908 | EXPECT_TRUE( |
4909 | matches("float x = static_cast<float>(42);" , |
4910 | traverse(TK_AsIs, explicitCastExpr(hasSourceExpression( |
4911 | hasDescendant(expr(integerLiteral()))))))); |
4912 | } |
4913 | |
4914 | TEST(UsingDeclaration, MatchesSpecificTarget) { |
4915 | EXPECT_TRUE(matches("namespace f { int a; void b(); } using f::b;" , |
4916 | usingDecl(hasAnyUsingShadowDecl( |
4917 | hasTargetDecl(functionDecl()))))); |
4918 | EXPECT_TRUE(notMatches("namespace f { int a; void b(); } using f::a;" , |
4919 | usingDecl(hasAnyUsingShadowDecl( |
4920 | hasTargetDecl(functionDecl()))))); |
4921 | } |
4922 | |
4923 | TEST(UsingDeclaration, ThroughUsingDeclaration) { |
4924 | EXPECT_TRUE(matches( |
4925 | "namespace a { void f(); } using a::f; void g() { f(); }" , |
4926 | declRefExpr(throughUsingDecl(anything())))); |
4927 | EXPECT_TRUE(notMatches( |
4928 | "namespace a { void f(); } using a::f; void g() { a::f(); }" , |
4929 | declRefExpr(throughUsingDecl(anything())))); |
4930 | } |
4931 | |
4932 | TEST(SingleDecl, IsSingleDecl) { |
4933 | StatementMatcher SingleDeclStmt = |
4934 | declStmt(hasSingleDecl(InnerMatcher: varDecl(hasInitializer(InnerMatcher: anything())))); |
4935 | EXPECT_TRUE(matches("void f() {int a = 4;}" , SingleDeclStmt)); |
4936 | EXPECT_TRUE(notMatches("void f() {int a;}" , SingleDeclStmt)); |
4937 | EXPECT_TRUE(notMatches("void f() {int a = 4, b = 3;}" , |
4938 | SingleDeclStmt)); |
4939 | } |
4940 | |
4941 | TEST(DeclStmt, ContainsDeclaration) { |
4942 | DeclarationMatcher MatchesInit = varDecl(hasInitializer(InnerMatcher: anything())); |
4943 | |
4944 | EXPECT_TRUE(matches("void f() {int a = 4;}" , |
4945 | declStmt(containsDeclaration(0, MatchesInit)))); |
4946 | EXPECT_TRUE(matches("void f() {int a = 4, b = 3;}" , |
4947 | declStmt(containsDeclaration(0, MatchesInit), |
4948 | containsDeclaration(1, MatchesInit)))); |
4949 | unsigned WrongIndex = 42; |
4950 | EXPECT_TRUE(notMatches("void f() {int a = 4, b = 3;}" , |
4951 | declStmt(containsDeclaration(WrongIndex, |
4952 | MatchesInit)))); |
4953 | } |
4954 | |
4955 | TEST(SwitchCase, MatchesEachCase) { |
4956 | EXPECT_TRUE(notMatches("void x() { switch(42); }" , |
4957 | switchStmt(forEachSwitchCase(caseStmt())))); |
4958 | EXPECT_TRUE(matches("void x() { switch(42) case 42:; }" , |
4959 | switchStmt(forEachSwitchCase(caseStmt())))); |
4960 | EXPECT_TRUE(matches("void x() { switch(42) { case 42:; } }" , |
4961 | switchStmt(forEachSwitchCase(caseStmt())))); |
4962 | EXPECT_TRUE(notMatches( |
4963 | "void x() { if (1) switch(42) { case 42: switch (42) { default:; } } }" , |
4964 | ifStmt(has(switchStmt(forEachSwitchCase(defaultStmt())))))); |
4965 | EXPECT_TRUE(matches( |
4966 | "void x() { switch(42) { case 1+1: case 4:; } }" , |
4967 | traverse(TK_AsIs, switchStmt(forEachSwitchCase(caseStmt(hasCaseConstant( |
4968 | constantExpr(has(integerLiteral()))))))))); |
4969 | EXPECT_TRUE(notMatches( |
4970 | "void x() { switch(42) { case 1+1: case 2+2:; } }" , |
4971 | traverse(TK_AsIs, switchStmt(forEachSwitchCase(caseStmt(hasCaseConstant( |
4972 | constantExpr(has(integerLiteral()))))))))); |
4973 | EXPECT_TRUE(notMatches( |
4974 | "void x() { switch(42) { case 1 ... 2:; } }" , |
4975 | traverse(TK_AsIs, switchStmt(forEachSwitchCase(caseStmt(hasCaseConstant( |
4976 | constantExpr(has(integerLiteral()))))))))); |
4977 | EXPECT_TRUE(matchAndVerifyResultTrue( |
4978 | "void x() { switch (42) { case 1: case 2: case 3: default:; } }" , |
4979 | switchStmt(forEachSwitchCase(caseStmt().bind("x" ))), |
4980 | std::make_unique<VerifyIdIsBoundTo<CaseStmt>>("x" , 3))); |
4981 | } |
4982 | |
4983 | TEST(Declaration, HasExplicitSpecifier) { |
4984 | |
4985 | EXPECT_TRUE(notMatches("void f();" , |
4986 | functionDecl(hasExplicitSpecifier(constantExpr())), |
4987 | langCxx20OrLater())); |
4988 | EXPECT_TRUE( |
4989 | notMatches("template<bool b> struct S { explicit operator int(); };" , |
4990 | cxxConversionDecl( |
4991 | hasExplicitSpecifier(constantExpr(has(cxxBoolLiteral())))), |
4992 | langCxx20OrLater())); |
4993 | EXPECT_TRUE( |
4994 | notMatches("template<bool b> struct S { explicit(b) operator int(); };" , |
4995 | cxxConversionDecl( |
4996 | hasExplicitSpecifier(constantExpr(has(cxxBoolLiteral())))), |
4997 | langCxx20OrLater())); |
4998 | EXPECT_TRUE( |
4999 | matches("struct S { explicit(true) operator int(); };" , |
5000 | traverse(TK_AsIs, cxxConversionDecl(hasExplicitSpecifier( |
5001 | constantExpr(has(cxxBoolLiteral()))))), |
5002 | langCxx20OrLater())); |
5003 | EXPECT_TRUE( |
5004 | matches("struct S { explicit(false) operator int(); };" , |
5005 | traverse(TK_AsIs, cxxConversionDecl(hasExplicitSpecifier( |
5006 | constantExpr(has(cxxBoolLiteral()))))), |
5007 | langCxx20OrLater())); |
5008 | EXPECT_TRUE( |
5009 | notMatches("template<bool b> struct S { explicit(b) S(int); };" , |
5010 | traverse(TK_AsIs, cxxConstructorDecl(hasExplicitSpecifier( |
5011 | constantExpr(has(cxxBoolLiteral()))))), |
5012 | langCxx20OrLater())); |
5013 | EXPECT_TRUE( |
5014 | matches("struct S { explicit(true) S(int); };" , |
5015 | traverse(TK_AsIs, cxxConstructorDecl(hasExplicitSpecifier( |
5016 | constantExpr(has(cxxBoolLiteral()))))), |
5017 | langCxx20OrLater())); |
5018 | EXPECT_TRUE( |
5019 | matches("struct S { explicit(false) S(int); };" , |
5020 | traverse(TK_AsIs, cxxConstructorDecl(hasExplicitSpecifier( |
5021 | constantExpr(has(cxxBoolLiteral()))))), |
5022 | langCxx20OrLater())); |
5023 | EXPECT_TRUE( |
5024 | notMatches("template<typename T> struct S { S(int); };" |
5025 | "template<bool b = true> explicit(b) S(int) -> S<int>;" , |
5026 | traverse(TK_AsIs, cxxDeductionGuideDecl(hasExplicitSpecifier( |
5027 | constantExpr(has(cxxBoolLiteral()))))), |
5028 | langCxx20OrLater())); |
5029 | EXPECT_TRUE( |
5030 | matches("template<typename T> struct S { S(int); };" |
5031 | "explicit(true) S(int) -> S<int>;" , |
5032 | traverse(TK_AsIs, cxxDeductionGuideDecl(hasExplicitSpecifier( |
5033 | constantExpr(has(cxxBoolLiteral()))))), |
5034 | langCxx20OrLater())); |
5035 | EXPECT_TRUE( |
5036 | matches("template<typename T> struct S { S(int); };" |
5037 | "explicit(false) S(int) -> S<int>;" , |
5038 | traverse(TK_AsIs, cxxDeductionGuideDecl(hasExplicitSpecifier( |
5039 | constantExpr(has(cxxBoolLiteral()))))), |
5040 | langCxx20OrLater())); |
5041 | } |
5042 | |
5043 | TEST(ForEachConstructorInitializer, MatchesInitializers) { |
5044 | EXPECT_TRUE(matches( |
5045 | "struct X { X() : i(42), j(42) {} int i, j; };" , |
5046 | cxxConstructorDecl(forEachConstructorInitializer(cxxCtorInitializer())))); |
5047 | } |
5048 | |
5049 | TEST(ForEachLambdaCapture, MatchesCaptures) { |
5050 | EXPECT_TRUE(matches( |
5051 | "int main() { int x, y; auto f = [x, y]() { return x + y; }; }" , |
5052 | lambdaExpr(forEachLambdaCapture(lambdaCapture())), langCxx11OrLater())); |
5053 | auto matcher = lambdaExpr(forEachLambdaCapture( |
5054 | InnerMatcher: lambdaCapture(capturesVar(InnerMatcher: varDecl(hasType(InnerMatcher: isInteger())))).bind(ID: "LC" ))); |
5055 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5056 | "int main() { int x, y; float z; auto f = [=]() { return x + y + z; }; }" , |
5057 | matcher, std::make_unique<VerifyIdIsBoundTo<LambdaCapture>>("LC" , 2))); |
5058 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5059 | "int main() { int x, y; float z; auto f = [x, y, z]() { return x + y + " |
5060 | "z; }; }" , |
5061 | matcher, std::make_unique<VerifyIdIsBoundTo<LambdaCapture>>("LC" , 2))); |
5062 | } |
5063 | |
5064 | TEST(ForEachLambdaCapture, IgnoreUnlessSpelledInSource) { |
5065 | auto matcher = |
5066 | traverse(TK: TK_IgnoreUnlessSpelledInSource, |
5067 | InnerMatcher: lambdaExpr(forEachLambdaCapture( |
5068 | InnerMatcher: lambdaCapture(capturesVar(InnerMatcher: varDecl(hasType(InnerMatcher: isInteger())))) |
5069 | .bind(ID: "LC" )))); |
5070 | EXPECT_TRUE( |
5071 | notMatches("int main() { int x, y; auto f = [=]() { return x + y; }; }" , |
5072 | matcher, langCxx11OrLater())); |
5073 | EXPECT_TRUE( |
5074 | notMatches("int main() { int x, y; auto f = [&]() { return x + y; }; }" , |
5075 | matcher, langCxx11OrLater())); |
5076 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5077 | R"cc( |
5078 | int main() { |
5079 | int x, y; |
5080 | float z; |
5081 | auto f = [=, &y]() { return x + y + z; }; |
5082 | } |
5083 | )cc" , |
5084 | matcher, std::make_unique<VerifyIdIsBoundTo<LambdaCapture>>("LC" , 1))); |
5085 | } |
5086 | |
5087 | TEST(ForEachLambdaCapture, MatchImplicitCapturesOnly) { |
5088 | auto matcher = |
5089 | lambdaExpr(forEachLambdaCapture(InnerMatcher: lambdaCapture(isImplicit()).bind(ID: "LC" ))); |
5090 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5091 | "int main() { int x, y, z; auto f = [=, &z]() { return x + y + z; }; }" , |
5092 | matcher, std::make_unique<VerifyIdIsBoundTo<LambdaCapture>>("LC" , 2))); |
5093 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5094 | "int main() { int x, y, z; auto f = [&, z]() { return x + y + z; }; }" , |
5095 | matcher, std::make_unique<VerifyIdIsBoundTo<LambdaCapture>>("LC" , 2))); |
5096 | } |
5097 | |
5098 | TEST(ForEachLambdaCapture, MatchExplicitCapturesOnly) { |
5099 | auto matcher = lambdaExpr( |
5100 | forEachLambdaCapture(InnerMatcher: lambdaCapture(unless(isImplicit())).bind(ID: "LC" ))); |
5101 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5102 | "int main() { int x, y, z; auto f = [=, &z]() { return x + y + z; }; }" , |
5103 | matcher, std::make_unique<VerifyIdIsBoundTo<LambdaCapture>>("LC" , 1))); |
5104 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5105 | "int main() { int x, y, z; auto f = [&, z]() { return x + y + z; }; }" , |
5106 | matcher, std::make_unique<VerifyIdIsBoundTo<LambdaCapture>>("LC" , 1))); |
5107 | } |
5108 | |
5109 | TEST(HasConditionVariableStatement, DoesNotMatchCondition) { |
5110 | EXPECT_TRUE(notMatches( |
5111 | "void x() { if(true) {} }" , |
5112 | ifStmt(hasConditionVariableStatement(declStmt())))); |
5113 | EXPECT_TRUE(notMatches( |
5114 | "void x() { int x; if((x = 42)) {} }" , |
5115 | ifStmt(hasConditionVariableStatement(declStmt())))); |
5116 | } |
5117 | |
5118 | TEST(HasConditionVariableStatement, MatchesConditionVariables) { |
5119 | EXPECT_TRUE(matches( |
5120 | "void x() { if(int* a = 0) {} }" , |
5121 | ifStmt(hasConditionVariableStatement(declStmt())))); |
5122 | } |
5123 | |
5124 | TEST(ForEach, BindsOneNode) { |
5125 | EXPECT_TRUE(matchAndVerifyResultTrue("class C { int x; };" , |
5126 | recordDecl(hasName("C" ), forEach(fieldDecl(hasName("x" )).bind("x" ))), |
5127 | std::make_unique<VerifyIdIsBoundTo<FieldDecl>>("x" , 1))); |
5128 | } |
5129 | |
5130 | TEST(ForEach, BindsMultipleNodes) { |
5131 | EXPECT_TRUE(matchAndVerifyResultTrue("class C { int x; int y; int z; };" , |
5132 | recordDecl(hasName("C" ), forEach(fieldDecl().bind("f" ))), |
5133 | std::make_unique<VerifyIdIsBoundTo<FieldDecl>>("f" , 3))); |
5134 | } |
5135 | |
5136 | TEST(ForEach, BindsRecursiveCombinations) { |
5137 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5138 | "class C { class D { int x; int y; }; class E { int y; int z; }; };" , |
5139 | recordDecl(hasName("C" ), |
5140 | forEach(recordDecl(forEach(fieldDecl().bind("f" ))))), |
5141 | std::make_unique<VerifyIdIsBoundTo<FieldDecl>>("f" , 4))); |
5142 | } |
5143 | |
5144 | TEST(ForEach, DoesNotIgnoreImplicit) { |
5145 | StringRef Code = R"cpp( |
5146 | void foo() |
5147 | { |
5148 | int i = 0; |
5149 | int b = 4; |
5150 | i < b; |
5151 | } |
5152 | )cpp" ; |
5153 | EXPECT_TRUE(matchAndVerifyResultFalse( |
5154 | Code, binaryOperator(forEach(declRefExpr().bind("dre" ))), |
5155 | std::make_unique<VerifyIdIsBoundTo<DeclRefExpr>>("dre" , 0))); |
5156 | |
5157 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5158 | Code, |
5159 | binaryOperator(forEach( |
5160 | implicitCastExpr(hasSourceExpression(declRefExpr().bind("dre" ))))), |
5161 | std::make_unique<VerifyIdIsBoundTo<DeclRefExpr>>("dre" , 2))); |
5162 | |
5163 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5164 | Code, |
5165 | binaryOperator( |
5166 | forEach(expr(ignoringImplicit(declRefExpr().bind("dre" ))))), |
5167 | std::make_unique<VerifyIdIsBoundTo<DeclRefExpr>>("dre" , 2))); |
5168 | |
5169 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5170 | Code, |
5171 | traverse(TK_IgnoreUnlessSpelledInSource, |
5172 | binaryOperator(forEach(declRefExpr().bind("dre" )))), |
5173 | std::make_unique<VerifyIdIsBoundTo<DeclRefExpr>>("dre" , 2))); |
5174 | } |
5175 | |
5176 | TEST(ForEachDescendant, BindsOneNode) { |
5177 | EXPECT_TRUE(matchAndVerifyResultTrue("class C { class D { int x; }; };" , |
5178 | recordDecl(hasName("C" ), |
5179 | forEachDescendant(fieldDecl(hasName("x" )).bind("x" ))), |
5180 | std::make_unique<VerifyIdIsBoundTo<FieldDecl>>("x" , 1))); |
5181 | } |
5182 | |
5183 | TEST(ForEachDescendant, NestedForEachDescendant) { |
5184 | DeclarationMatcher m = recordDecl( |
5185 | isDefinition(), decl().bind(ID: "x" ), hasName(Name: "C" )); |
5186 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5187 | "class A { class B { class C {}; }; };" , |
5188 | recordDecl(hasName("A" ), anyOf(m, forEachDescendant(m))), |
5189 | std::make_unique<VerifyIdIsBoundTo<Decl>>("x" , "C" ))); |
5190 | |
5191 | // Check that a partial match of 'm' that binds 'x' in the |
5192 | // first part of anyOf(m, anything()) will not overwrite the |
5193 | // binding created by the earlier binding in the hasDescendant. |
5194 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5195 | "class A { class B { class C {}; }; };" , |
5196 | recordDecl(hasName("A" ), allOf(hasDescendant(m), anyOf(m, anything()))), |
5197 | std::make_unique<VerifyIdIsBoundTo<Decl>>("x" , "C" ))); |
5198 | } |
5199 | |
5200 | TEST(ForEachDescendant, BindsMultipleNodes) { |
5201 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5202 | "class C { class D { int x; int y; }; " |
5203 | " class E { class F { int y; int z; }; }; };" , |
5204 | recordDecl(hasName("C" ), forEachDescendant(fieldDecl().bind("f" ))), |
5205 | std::make_unique<VerifyIdIsBoundTo<FieldDecl>>("f" , 4))); |
5206 | } |
5207 | |
5208 | TEST(ForEachDescendant, BindsRecursiveCombinations) { |
5209 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5210 | "class C { class D { " |
5211 | " class E { class F { class G { int y; int z; }; }; }; }; };" , |
5212 | recordDecl(hasName("C" ), forEachDescendant(recordDecl( |
5213 | forEachDescendant(fieldDecl().bind("f" ))))), |
5214 | std::make_unique<VerifyIdIsBoundTo<FieldDecl>>("f" , 8))); |
5215 | } |
5216 | |
5217 | TEST(ForEachDescendant, BindsCombinations) { |
5218 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5219 | "void f() { if(true) {} if (true) {} while (true) {} if (true) {} while " |
5220 | "(true) {} }" , |
5221 | compoundStmt(forEachDescendant(ifStmt().bind("if" )), |
5222 | forEachDescendant(whileStmt().bind("while" ))), |
5223 | std::make_unique<VerifyIdIsBoundTo<IfStmt>>("if" , 6))); |
5224 | } |
5225 | |
5226 | TEST(ForEachTemplateArgument, OnFunctionDecl) { |
5227 | const std::string Code = R"( |
5228 | template <typename T, typename U> void f(T, U) {} |
5229 | void test() { |
5230 | int I = 1; |
5231 | bool B = false; |
5232 | f(I, B); |
5233 | })" ; |
5234 | EXPECT_TRUE(matches( |
5235 | Code, functionDecl(forEachTemplateArgument(refersToType(builtinType()))), |
5236 | langCxx11OrLater())); |
5237 | auto matcher = |
5238 | functionDecl(forEachTemplateArgument( |
5239 | InnerMatcher: templateArgument(refersToType(InnerMatcher: builtinType().bind(ID: "BT" ))) |
5240 | .bind(ID: "TA" ))) |
5241 | .bind(ID: "FN" ); |
5242 | |
5243 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5244 | Code, matcher, |
5245 | std::make_unique<VerifyIdIsBoundTo<FunctionDecl>>("FN" , 2))); |
5246 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5247 | Code, matcher, |
5248 | std::make_unique<VerifyIdIsBoundTo<TemplateArgument>>("TA" , 2))); |
5249 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5250 | Code, matcher, |
5251 | std::make_unique<VerifyIdIsBoundTo<BuiltinType>>("BT" , 2))); |
5252 | } |
5253 | |
5254 | TEST(ForEachTemplateArgument, OnClassTemplateSpecialization) { |
5255 | const std::string Code = R"( |
5256 | template <typename T, unsigned N, unsigned M> |
5257 | struct Matrix {}; |
5258 | |
5259 | static constexpr unsigned R = 2; |
5260 | |
5261 | Matrix<int, R * 2, R * 4> M; |
5262 | )" ; |
5263 | EXPECT_TRUE(matches( |
5264 | Code, templateSpecializationType(forEachTemplateArgument(isExpr(expr()))), |
5265 | langCxx11OrLater())); |
5266 | auto matcher = templateSpecializationType( |
5267 | forEachTemplateArgument( |
5268 | InnerMatcher: templateArgument(isExpr(InnerMatcher: expr().bind(ID: "E" ))).bind(ID: "TA" ))) |
5269 | .bind(ID: "TST" ); |
5270 | |
5271 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5272 | Code, matcher, |
5273 | std::make_unique<VerifyIdIsBoundTo<TemplateSpecializationType>>("TST" , |
5274 | 2))); |
5275 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5276 | Code, matcher, |
5277 | std::make_unique<VerifyIdIsBoundTo<TemplateArgument>>("TA" , 2))); |
5278 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5279 | Code, matcher, std::make_unique<VerifyIdIsBoundTo<Expr>>("E" , 2))); |
5280 | } |
5281 | |
5282 | TEST(Has, DoesNotDeleteBindings) { |
5283 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5284 | "class X { int a; };" , recordDecl(decl().bind("x" ), has(fieldDecl())), |
5285 | std::make_unique<VerifyIdIsBoundTo<Decl>>("x" , 1))); |
5286 | } |
5287 | |
5288 | TEST(TemplateArgumentLoc, Matches) { |
5289 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5290 | R"cpp( |
5291 | template <typename A, int B, template <typename> class C> class X {}; |
5292 | class A {}; |
5293 | const int B = 42; |
5294 | template <typename> class C {}; |
5295 | X<A, B, C> x; |
5296 | )cpp" , |
5297 | templateArgumentLoc().bind("x" ), |
5298 | std::make_unique<VerifyIdIsBoundTo<TemplateArgumentLoc>>("x" , 3))); |
5299 | } |
5300 | |
5301 | TEST(LoopingMatchers, DoNotOverwritePreviousMatchResultOnFailure) { |
5302 | // Those matchers cover all the cases where an inner matcher is called |
5303 | // and there is not a 1:1 relationship between the match of the outer |
5304 | // matcher and the match of the inner matcher. |
5305 | // The pattern to look for is: |
5306 | // ... return InnerMatcher.matches(...); ... |
5307 | // In which case no special handling is needed. |
5308 | // |
5309 | // On the other hand, if there are multiple alternative matches |
5310 | // (for example forEach*) or matches might be discarded (for example has*) |
5311 | // the implementation must make sure that the discarded matches do not |
5312 | // affect the bindings. |
5313 | // When new such matchers are added, add a test here that: |
5314 | // - matches a simple node, and binds it as the first thing in the matcher: |
5315 | // recordDecl(decl().bind("x"), hasName("X"))) |
5316 | // - uses the matcher under test afterwards in a way that not the first |
5317 | // alternative is matched; for anyOf, that means the first branch |
5318 | // would need to return false; for hasAncestor, it means that not |
5319 | // the direct parent matches the inner matcher. |
5320 | |
5321 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5322 | "class X { int y; };" , |
5323 | recordDecl( |
5324 | recordDecl().bind("x" ), hasName("::X" ), |
5325 | anyOf(forEachDescendant(recordDecl(hasName("Y" ))), anything())), |
5326 | std::make_unique<VerifyIdIsBoundTo<CXXRecordDecl>>("x" , 1))); |
5327 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5328 | "class X {};" , recordDecl(recordDecl().bind("x" ), hasName("::X" ), |
5329 | anyOf(unless(anything()), anything())), |
5330 | std::make_unique<VerifyIdIsBoundTo<CXXRecordDecl>>("x" , 1))); |
5331 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5332 | "template<typename T1, typename T2> class X {}; X<float, int> x;" , |
5333 | classTemplateSpecializationDecl( |
5334 | decl().bind("x" ), |
5335 | hasAnyTemplateArgument(refersToType(asString("int" )))), |
5336 | std::make_unique<VerifyIdIsBoundTo<Decl>>("x" , 1))); |
5337 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5338 | "class X { void f(); void g(); };" , |
5339 | cxxRecordDecl(decl().bind("x" ), hasMethod(hasName("g" ))), |
5340 | std::make_unique<VerifyIdIsBoundTo<Decl>>("x" , 1))); |
5341 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5342 | "class X { X() : a(1), b(2) {} double a; int b; };" , |
5343 | recordDecl(decl().bind("x" ), |
5344 | has(cxxConstructorDecl( |
5345 | hasAnyConstructorInitializer(forField(hasName("b" )))))), |
5346 | std::make_unique<VerifyIdIsBoundTo<Decl>>("x" , 1))); |
5347 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5348 | "void x(int, int) { x(0, 42); }" , |
5349 | callExpr(expr().bind("x" ), hasAnyArgument(integerLiteral(equals(42)))), |
5350 | std::make_unique<VerifyIdIsBoundTo<Expr>>("x" , 1))); |
5351 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5352 | "void x(int, int y) {}" , |
5353 | functionDecl(decl().bind("x" ), hasAnyParameter(hasName("y" ))), |
5354 | std::make_unique<VerifyIdIsBoundTo<Decl>>("x" , 1))); |
5355 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5356 | "void x() { return; if (true) {} }" , |
5357 | functionDecl(decl().bind("x" ), |
5358 | has(compoundStmt(hasAnySubstatement(ifStmt())))), |
5359 | std::make_unique<VerifyIdIsBoundTo<Decl>>("x" , 1))); |
5360 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5361 | "namespace X { void b(int); void b(); }" |
5362 | "using X::b;" , |
5363 | usingDecl(decl().bind("x" ), hasAnyUsingShadowDecl(hasTargetDecl( |
5364 | functionDecl(parameterCountIs(1))))), |
5365 | std::make_unique<VerifyIdIsBoundTo<Decl>>("x" , 1))); |
5366 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5367 | "class A{}; class B{}; class C : B, A {};" , |
5368 | cxxRecordDecl(decl().bind("x" ), isDerivedFrom("::A" )), |
5369 | std::make_unique<VerifyIdIsBoundTo<Decl>>("x" , 1))); |
5370 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5371 | "class A{}; typedef A B; typedef A C; typedef A D;" |
5372 | "class E : A {};" , |
5373 | cxxRecordDecl(decl().bind("x" ), isDerivedFrom("C" )), |
5374 | std::make_unique<VerifyIdIsBoundTo<Decl>>("x" , 1))); |
5375 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5376 | "class A { class B { void f() {} }; };" , |
5377 | functionDecl(decl().bind("x" ), hasAncestor(recordDecl(hasName("::A" )))), |
5378 | std::make_unique<VerifyIdIsBoundTo<Decl>>("x" , 1))); |
5379 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5380 | "template <typename T> struct A { struct B {" |
5381 | " void f() { if(true) {} }" |
5382 | "}; };" |
5383 | "void t() { A<int>::B b; b.f(); }" , |
5384 | ifStmt(stmt().bind("x" ), hasAncestor(recordDecl(hasName("::A" )))), |
5385 | std::make_unique<VerifyIdIsBoundTo<Stmt>>("x" , 2))); |
5386 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5387 | "class A {};" , |
5388 | recordDecl(hasName("::A" ), decl().bind("x" ), unless(hasName("fooble" ))), |
5389 | std::make_unique<VerifyIdIsBoundTo<Decl>>("x" , 1))); |
5390 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5391 | "class A { A() : s(), i(42) {} const char *s; int i; };" , |
5392 | cxxConstructorDecl(hasName("::A::A" ), decl().bind("x" ), |
5393 | forEachConstructorInitializer(forField(hasName("i" )))), |
5394 | std::make_unique<VerifyIdIsBoundTo<Decl>>("x" , 1))); |
5395 | } |
5396 | |
5397 | TEST(ForEachDescendant, BindsCorrectNodes) { |
5398 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5399 | "class C { void f(); int i; };" , |
5400 | recordDecl(hasName("C" ), forEachDescendant(decl().bind("decl" ))), |
5401 | std::make_unique<VerifyIdIsBoundTo<FieldDecl>>("decl" , 1))); |
5402 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5403 | "class C { void f() {} int i; };" , |
5404 | recordDecl(hasName("C" ), forEachDescendant(decl().bind("decl" ))), |
5405 | std::make_unique<VerifyIdIsBoundTo<FunctionDecl>>("decl" , 1))); |
5406 | } |
5407 | |
5408 | TEST(FindAll, BindsNodeOnMatch) { |
5409 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5410 | "class A {};" , |
5411 | recordDecl(hasName("::A" ), findAll(recordDecl(hasName("::A" )).bind("v" ))), |
5412 | std::make_unique<VerifyIdIsBoundTo<CXXRecordDecl>>("v" , 1))); |
5413 | } |
5414 | |
5415 | TEST(FindAll, BindsDescendantNodeOnMatch) { |
5416 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5417 | "class A { int a; int b; };" , |
5418 | recordDecl(hasName("::A" ), findAll(fieldDecl().bind("v" ))), |
5419 | std::make_unique<VerifyIdIsBoundTo<FieldDecl>>("v" , 2))); |
5420 | } |
5421 | |
5422 | TEST(FindAll, BindsNodeAndDescendantNodesOnOneMatch) { |
5423 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5424 | "class A { int a; int b; };" , |
5425 | recordDecl(hasName("::A" ), |
5426 | findAll(decl(anyOf(recordDecl(hasName("::A" )).bind("v" ), |
5427 | fieldDecl().bind("v" ))))), |
5428 | std::make_unique<VerifyIdIsBoundTo<Decl>>("v" , 3))); |
5429 | |
5430 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5431 | "class A { class B {}; class C {}; };" , |
5432 | recordDecl(hasName("::A" ), findAll(recordDecl(isDefinition()).bind("v" ))), |
5433 | std::make_unique<VerifyIdIsBoundTo<CXXRecordDecl>>("v" , 3))); |
5434 | } |
5435 | |
5436 | TEST(HasAncenstor, MatchesDeclarationAncestors) { |
5437 | EXPECT_TRUE(matches( |
5438 | "class A { class B { class C {}; }; };" , |
5439 | recordDecl(hasName("C" ), hasAncestor(recordDecl(hasName("A" )))))); |
5440 | } |
5441 | |
5442 | TEST(HasAncenstor, FailsIfNoAncestorMatches) { |
5443 | EXPECT_TRUE(notMatches( |
5444 | "class A { class B { class C {}; }; };" , |
5445 | recordDecl(hasName("C" ), hasAncestor(recordDecl(hasName("X" )))))); |
5446 | } |
5447 | |
5448 | TEST(HasAncestor, MatchesDeclarationsThatGetVisitedLater) { |
5449 | EXPECT_TRUE(matches( |
5450 | "class A { class B { void f() { C c; } class C {}; }; };" , |
5451 | varDecl(hasName("c" ), hasType(recordDecl(hasName("C" ), |
5452 | hasAncestor(recordDecl(hasName("A" )))))))); |
5453 | } |
5454 | |
5455 | TEST(HasAncenstor, MatchesStatementAncestors) { |
5456 | EXPECT_TRUE(matches( |
5457 | "void f() { if (true) { while (false) { 42; } } }" , |
5458 | integerLiteral(equals(42), hasAncestor(ifStmt())))); |
5459 | } |
5460 | |
5461 | TEST(HasAncestor, DrillsThroughDifferentHierarchies) { |
5462 | EXPECT_TRUE(matches( |
5463 | "void f() { if (true) { int x = 42; } }" , |
5464 | integerLiteral(equals(42), hasAncestor(functionDecl(hasName("f" )))))); |
5465 | } |
5466 | |
5467 | TEST(HasAncestor, BindsRecursiveCombinations) { |
5468 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5469 | "class C { class D { class E { class F { int y; }; }; }; };" , |
5470 | fieldDecl(hasAncestor(recordDecl(hasAncestor(recordDecl().bind("r" ))))), |
5471 | std::make_unique<VerifyIdIsBoundTo<CXXRecordDecl>>("r" , 1))); |
5472 | } |
5473 | |
5474 | TEST(HasAncestor, BindsCombinationsWithHasDescendant) { |
5475 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5476 | "class C { class D { class E { class F { int y; }; }; }; };" , |
5477 | fieldDecl(hasAncestor( |
5478 | decl( |
5479 | hasDescendant(recordDecl(isDefinition(), |
5480 | hasAncestor(recordDecl()))) |
5481 | ).bind("d" ) |
5482 | )), |
5483 | std::make_unique<VerifyIdIsBoundTo<CXXRecordDecl>>("d" , "E" ))); |
5484 | } |
5485 | |
5486 | TEST(HasAncestor, MatchesClosestAncestor) { |
5487 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5488 | "template <typename T> struct C {" |
5489 | " void f(int) {" |
5490 | " struct I { void g(T) { int x; } } i; i.g(42);" |
5491 | " }" |
5492 | "};" |
5493 | "template struct C<int>;" , |
5494 | varDecl(hasName("x" ), |
5495 | hasAncestor(functionDecl(hasParameter( |
5496 | 0, varDecl(hasType(asString("int" ))))).bind("f" ))).bind("v" ), |
5497 | std::make_unique<VerifyIdIsBoundTo<FunctionDecl>>("f" , "g" , 2))); |
5498 | } |
5499 | |
5500 | TEST(HasAncestor, MatchesInTemplateInstantiations) { |
5501 | EXPECT_TRUE(matches( |
5502 | "template <typename T> struct A { struct B { struct C { T t; }; }; }; " |
5503 | "A<int>::B::C a;" , |
5504 | fieldDecl(hasType(asString("int" )), |
5505 | hasAncestor(recordDecl(hasName("A" )))))); |
5506 | } |
5507 | |
5508 | TEST(HasAncestor, MatchesInImplicitCode) { |
5509 | EXPECT_TRUE(matches( |
5510 | "struct X {}; struct A { A() {} X x; };" , |
5511 | cxxConstructorDecl( |
5512 | hasAnyConstructorInitializer(withInitializer(expr( |
5513 | hasAncestor(recordDecl(hasName("A" ))))))))); |
5514 | } |
5515 | |
5516 | TEST(HasParent, MatchesOnlyParent) { |
5517 | EXPECT_TRUE(matches( |
5518 | "void f() { if (true) { int x = 42; } }" , |
5519 | compoundStmt(hasParent(ifStmt())))); |
5520 | EXPECT_TRUE(notMatches( |
5521 | "void f() { for (;;) { int x = 42; } }" , |
5522 | compoundStmt(hasParent(ifStmt())))); |
5523 | EXPECT_TRUE(notMatches( |
5524 | "void f() { if (true) for (;;) { int x = 42; } }" , |
5525 | compoundStmt(hasParent(ifStmt())))); |
5526 | } |
5527 | |
5528 | TEST(MatcherMemoize, HasParentDiffersFromHas) { |
5529 | // Test introduced after detecting a bug in memoization |
5530 | constexpr auto code = "void f() { throw 1; }" ; |
5531 | EXPECT_TRUE(notMatches( |
5532 | code, |
5533 | cxxThrowExpr(hasParent(expr())))); |
5534 | EXPECT_TRUE(matches( |
5535 | code, |
5536 | cxxThrowExpr(has(expr())))); |
5537 | EXPECT_TRUE(matches( |
5538 | code, |
5539 | cxxThrowExpr(anyOf(hasParent(expr()), has(expr()))))); |
5540 | } |
5541 | |
5542 | TEST(MatcherMemoize, HasDiffersFromHasDescendant) { |
5543 | // Test introduced after detecting a bug in memoization |
5544 | constexpr auto code = "void f() { throw 1+1; }" ; |
5545 | EXPECT_TRUE(notMatches( |
5546 | code, |
5547 | cxxThrowExpr(has(integerLiteral())))); |
5548 | EXPECT_TRUE(matches( |
5549 | code, |
5550 | cxxThrowExpr(hasDescendant(integerLiteral())))); |
5551 | EXPECT_TRUE( |
5552 | notMatches(code, cxxThrowExpr(allOf(hasDescendant(integerLiteral()), |
5553 | has(integerLiteral()))))); |
5554 | } |
5555 | TEST(HasAncestor, MatchesAllAncestors) { |
5556 | EXPECT_TRUE(matches( |
5557 | "template <typename T> struct C { static void f() { 42; } };" |
5558 | "void t() { C<int>::f(); }" , |
5559 | integerLiteral( |
5560 | equals(42), |
5561 | allOf( |
5562 | hasAncestor(cxxRecordDecl(isTemplateInstantiation())), |
5563 | hasAncestor(cxxRecordDecl(unless(isTemplateInstantiation()))))))); |
5564 | } |
5565 | |
5566 | TEST(HasAncestor, ImplicitArrayCopyCtorDeclRefExpr) { |
5567 | EXPECT_TRUE(matches("struct MyClass {\n" |
5568 | " int c[1];\n" |
5569 | " static MyClass Create() { return MyClass(); }\n" |
5570 | "};" , |
5571 | declRefExpr(to(decl(hasAncestor(decl())))))); |
5572 | } |
5573 | |
5574 | TEST(HasAncestor, AnonymousUnionMemberExpr) { |
5575 | EXPECT_TRUE(matches("int F() {\n" |
5576 | " union { int i; };\n" |
5577 | " return i;\n" |
5578 | "}\n" , |
5579 | memberExpr(member(hasAncestor(decl()))))); |
5580 | EXPECT_TRUE(matches("void f() {\n" |
5581 | " struct {\n" |
5582 | " struct { int a; int b; };\n" |
5583 | " } s;\n" |
5584 | " s.a = 4;\n" |
5585 | "}\n" , |
5586 | memberExpr(member(hasAncestor(decl()))))); |
5587 | EXPECT_TRUE(matches("void f() {\n" |
5588 | " struct {\n" |
5589 | " struct { int a; int b; };\n" |
5590 | " } s;\n" |
5591 | " s.a = 4;\n" |
5592 | "}\n" , |
5593 | declRefExpr(to(decl(hasAncestor(decl())))))); |
5594 | } |
5595 | TEST(HasAncestor, NonParmDependentTemplateParmVarDeclRefExpr) { |
5596 | EXPECT_TRUE(matches("struct PartitionAllocator {\n" |
5597 | " template<typename T>\n" |
5598 | " static int quantizedSize(int count) {\n" |
5599 | " return count;\n" |
5600 | " }\n" |
5601 | " void f() { quantizedSize<int>(10); }\n" |
5602 | "};" , |
5603 | declRefExpr(to(decl(hasAncestor(decl())))))); |
5604 | } |
5605 | |
5606 | TEST(HasAncestor, AddressOfExplicitSpecializationFunction) { |
5607 | EXPECT_TRUE(matches("template <class T> void f();\n" |
5608 | "template <> void f<int>();\n" |
5609 | "void (*get_f())() { return f<int>; }\n" , |
5610 | declRefExpr(to(decl(hasAncestor(decl())))))); |
5611 | } |
5612 | |
5613 | TEST(HasParent, MatchesAllParents) { |
5614 | EXPECT_TRUE(matches( |
5615 | "template <typename T> struct C { static void f() { 42; } };" |
5616 | "void t() { C<int>::f(); }" , |
5617 | integerLiteral( |
5618 | equals(42), |
5619 | hasParent(compoundStmt(hasParent(functionDecl( |
5620 | hasParent(cxxRecordDecl(isTemplateInstantiation()))))))))); |
5621 | EXPECT_TRUE( |
5622 | matches("template <typename T> struct C { static void f() { 42; } };" |
5623 | "void t() { C<int>::f(); }" , |
5624 | integerLiteral( |
5625 | equals(42), |
5626 | hasParent(compoundStmt(hasParent(functionDecl(hasParent( |
5627 | cxxRecordDecl(unless(isTemplateInstantiation())))))))))); |
5628 | EXPECT_TRUE(matches( |
5629 | "template <typename T> struct C { static void f() { 42; } };" |
5630 | "void t() { C<int>::f(); }" , |
5631 | integerLiteral(equals(42), |
5632 | hasParent(compoundStmt( |
5633 | allOf(hasParent(functionDecl(hasParent( |
5634 | cxxRecordDecl(isTemplateInstantiation())))), |
5635 | hasParent(functionDecl(hasParent(cxxRecordDecl( |
5636 | unless(isTemplateInstantiation()))))))))))); |
5637 | EXPECT_TRUE( |
5638 | notMatches("template <typename T> struct C { static void f() {} };" |
5639 | "void t() { C<int>::f(); }" , |
5640 | compoundStmt(hasParent(recordDecl())))); |
5641 | } |
5642 | |
5643 | TEST(HasParent, NoDuplicateParents) { |
5644 | class HasDuplicateParents : public BoundNodesCallback { |
5645 | public: |
5646 | bool run(const BoundNodes *Nodes) override { return false; } |
5647 | bool run(const BoundNodes *Nodes, ASTContext *Context) override { |
5648 | const Stmt *Node = Nodes->getNodeAs<Stmt>(ID: "node" ); |
5649 | std::set<const void *> Parents; |
5650 | for (const auto &Parent : Context->getParents(Node: *Node)) { |
5651 | if (!Parents.insert(x: Parent.getMemoizationData()).second) { |
5652 | return true; |
5653 | } |
5654 | } |
5655 | return false; |
5656 | } |
5657 | }; |
5658 | EXPECT_FALSE(matchAndVerifyResultTrue( |
5659 | "template <typename T> int Foo() { return 1 + 2; }\n" |
5660 | "int x = Foo<int>() + Foo<unsigned>();" , |
5661 | stmt().bind("node" ), std::make_unique<HasDuplicateParents>())); |
5662 | } |
5663 | |
5664 | TEST(HasAnyBase, BindsInnerBoundNodes) { |
5665 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5666 | "struct Inner {}; struct Proxy : Inner {}; struct Main : public " |
5667 | "Proxy {};" , |
5668 | cxxRecordDecl(hasName("Main" ), |
5669 | hasAnyBase(cxxBaseSpecifier(hasType( |
5670 | cxxRecordDecl(hasName("Inner" )).bind("base-class" ))))) |
5671 | .bind("class" ), |
5672 | std::make_unique<VerifyIdIsBoundTo<CXXRecordDecl>>("base-class" , |
5673 | "Inner" ))); |
5674 | } |
5675 | |
5676 | TEST(TypeMatching, PointeeTypes) { |
5677 | EXPECT_TRUE(matches("int b; int &a = b;" , |
5678 | referenceType(pointee(builtinType())))); |
5679 | EXPECT_TRUE(matches("int *a;" , pointerType(pointee(builtinType())))); |
5680 | |
5681 | EXPECT_TRUE(matches("int *a;" , |
5682 | loc(pointerType(pointee(builtinType()))))); |
5683 | |
5684 | EXPECT_TRUE(matches( |
5685 | "int const *A;" , |
5686 | pointerType(pointee(isConstQualified(), builtinType())))); |
5687 | EXPECT_TRUE(notMatches( |
5688 | "int *A;" , |
5689 | pointerType(pointee(isConstQualified(), builtinType())))); |
5690 | } |
5691 | |
5692 | TEST(ElaboratedTypeNarrowing, hasQualifier) { |
5693 | EXPECT_TRUE(matches( |
5694 | "namespace N {" |
5695 | " namespace M {" |
5696 | " class D {};" |
5697 | " }" |
5698 | "}" |
5699 | "N::M::D d;" , |
5700 | elaboratedType(hasQualifier(hasPrefix(specifiesNamespace(hasName("N" ))))))); |
5701 | EXPECT_TRUE(notMatches( |
5702 | "namespace M {" |
5703 | " class D {};" |
5704 | "}" |
5705 | "M::D d;" , |
5706 | elaboratedType(hasQualifier(hasPrefix(specifiesNamespace(hasName("N" ))))))); |
5707 | EXPECT_TRUE(notMatches( |
5708 | "struct D {" |
5709 | "} d;" , |
5710 | elaboratedType(hasQualifier(nestedNameSpecifier())))); |
5711 | } |
5712 | |
5713 | TEST(ElaboratedTypeNarrowing, namesType) { |
5714 | EXPECT_TRUE(matches( |
5715 | "namespace N {" |
5716 | " namespace M {" |
5717 | " class D {};" |
5718 | " }" |
5719 | "}" |
5720 | "N::M::D d;" , |
5721 | elaboratedType(elaboratedType(namesType(recordType( |
5722 | hasDeclaration(namedDecl(hasName("D" ))))))))); |
5723 | EXPECT_TRUE(notMatches( |
5724 | "namespace M {" |
5725 | " class D {};" |
5726 | "}" |
5727 | "M::D d;" , |
5728 | elaboratedType(elaboratedType(namesType(typedefType()))))); |
5729 | } |
5730 | |
5731 | TEST(NNS, BindsNestedNameSpecifiers) { |
5732 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5733 | "namespace ns { struct E { struct B {}; }; } ns::E::B b;" , |
5734 | nestedNameSpecifier(specifiesType(asString("struct ns::E" ))).bind("nns" ), |
5735 | std::make_unique<VerifyIdIsBoundTo<NestedNameSpecifier>>( |
5736 | "nns" , "ns::struct E::" ))); |
5737 | } |
5738 | |
5739 | TEST(NNS, BindsNestedNameSpecifierLocs) { |
5740 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5741 | "namespace ns { struct B {}; } ns::B b;" , |
5742 | loc(nestedNameSpecifier()).bind("loc" ), |
5743 | std::make_unique<VerifyIdIsBoundTo<NestedNameSpecifierLoc>>("loc" , 1))); |
5744 | } |
5745 | |
5746 | TEST(NNS, DescendantsOfNestedNameSpecifiers) { |
5747 | StringRef Fragment = |
5748 | "namespace a { struct A { struct B { struct C {}; }; }; };" |
5749 | "void f() { a::A::B::C c; }" ; |
5750 | EXPECT_TRUE(matches( |
5751 | Fragment, |
5752 | nestedNameSpecifier(specifiesType(asString("struct a::A::B" )), |
5753 | hasDescendant(nestedNameSpecifier( |
5754 | specifiesNamespace(hasName("a" ))))))); |
5755 | EXPECT_TRUE(notMatches( |
5756 | Fragment, |
5757 | nestedNameSpecifier(specifiesType(asString("struct a::A::B" )), |
5758 | has(nestedNameSpecifier( |
5759 | specifiesNamespace(hasName("a" ))))))); |
5760 | EXPECT_TRUE(matches( |
5761 | Fragment, |
5762 | nestedNameSpecifier(specifiesType(asString("struct a::A" )), |
5763 | has(nestedNameSpecifier( |
5764 | specifiesNamespace(hasName("a" ))))))); |
5765 | |
5766 | // Not really useful because a NestedNameSpecifier can af at most one child, |
5767 | // but to complete the interface. |
5768 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5769 | Fragment, |
5770 | nestedNameSpecifier(specifiesType(asString("struct a::A::B" )), |
5771 | forEach(nestedNameSpecifier().bind("x" ))), |
5772 | std::make_unique<VerifyIdIsBoundTo<NestedNameSpecifier>>("x" , 1))); |
5773 | } |
5774 | |
5775 | TEST(NNS, NestedNameSpecifiersAsDescendants) { |
5776 | StringRef Fragment = |
5777 | "namespace a { struct A { struct B { struct C {}; }; }; };" |
5778 | "void f() { a::A::B::C c; }" ; |
5779 | EXPECT_TRUE(matches( |
5780 | Fragment, |
5781 | decl(hasDescendant(nestedNameSpecifier(specifiesType( |
5782 | asString("struct a::A" ))))))); |
5783 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5784 | Fragment, |
5785 | functionDecl(hasName("f" ), |
5786 | forEachDescendant(nestedNameSpecifier().bind("x" ))), |
5787 | // Nested names: a, a::A and a::A::B. |
5788 | std::make_unique<VerifyIdIsBoundTo<NestedNameSpecifier>>("x" , 3))); |
5789 | } |
5790 | |
5791 | TEST(NNSLoc, DescendantsOfNestedNameSpecifierLocs) { |
5792 | StringRef Fragment = |
5793 | "namespace a { struct A { struct B { struct C {}; }; }; };" |
5794 | "void f() { a::A::B::C c; }" ; |
5795 | EXPECT_TRUE(matches( |
5796 | Fragment, |
5797 | nestedNameSpecifierLoc(loc(specifiesType(asString("struct a::A::B" ))), |
5798 | hasDescendant(loc(nestedNameSpecifier( |
5799 | specifiesNamespace(hasName("a" )))))))); |
5800 | EXPECT_TRUE(notMatches( |
5801 | Fragment, |
5802 | nestedNameSpecifierLoc(loc(specifiesType(asString("struct a::A::B" ))), |
5803 | has(loc(nestedNameSpecifier( |
5804 | specifiesNamespace(hasName("a" )))))))); |
5805 | EXPECT_TRUE(matches( |
5806 | Fragment, |
5807 | nestedNameSpecifierLoc(loc(specifiesType(asString("struct a::A" ))), |
5808 | has(loc(nestedNameSpecifier( |
5809 | specifiesNamespace(hasName("a" )))))))); |
5810 | |
5811 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5812 | Fragment, |
5813 | nestedNameSpecifierLoc(loc(specifiesType(asString("struct a::A::B" ))), |
5814 | forEach(nestedNameSpecifierLoc().bind("x" ))), |
5815 | std::make_unique<VerifyIdIsBoundTo<NestedNameSpecifierLoc>>("x" , 1))); |
5816 | } |
5817 | |
5818 | TEST(NNSLoc, NestedNameSpecifierLocsAsDescendants) { |
5819 | StringRef Fragment = |
5820 | "namespace a { struct A { struct B { struct C {}; }; }; };" |
5821 | "void f() { a::A::B::C c; }" ; |
5822 | EXPECT_TRUE(matches( |
5823 | Fragment, |
5824 | decl(hasDescendant(loc(nestedNameSpecifier(specifiesType( |
5825 | asString("struct a::A" )))))))); |
5826 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5827 | Fragment, |
5828 | functionDecl(hasName("f" ), |
5829 | forEachDescendant(nestedNameSpecifierLoc().bind("x" ))), |
5830 | // Nested names: a, a::A and a::A::B. |
5831 | std::make_unique<VerifyIdIsBoundTo<NestedNameSpecifierLoc>>("x" , 3))); |
5832 | } |
5833 | |
5834 | TEST(Attr, AttrsAsDescendants) { |
5835 | StringRef Fragment = "namespace a { struct [[clang::warn_unused_result]] " |
5836 | "F{}; [[noreturn]] void foo(); }" ; |
5837 | EXPECT_TRUE(matches(Fragment, namespaceDecl(hasDescendant(attr())))); |
5838 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5839 | Fragment, |
5840 | namespaceDecl(hasName("a" ), |
5841 | forEachDescendant(attr(unless(isImplicit())).bind("x" ))), |
5842 | std::make_unique<VerifyIdIsBoundTo<Attr>>("x" , 2))); |
5843 | } |
5844 | |
5845 | TEST(Attr, ParentsOfAttrs) { |
5846 | StringRef Fragment = |
5847 | "namespace a { struct [[clang::warn_unused_result]] F{}; }" ; |
5848 | EXPECT_TRUE(matches(Fragment, attr(hasAncestor(namespaceDecl())))); |
5849 | } |
5850 | |
5851 | template <typename T> class VerifyMatchOnNode : public BoundNodesCallback { |
5852 | public: |
5853 | VerifyMatchOnNode(StringRef Id, const internal::Matcher<T> &InnerMatcher, |
5854 | StringRef InnerId) |
5855 | : Id(Id), InnerMatcher(InnerMatcher), InnerId(InnerId) { |
5856 | } |
5857 | |
5858 | bool run(const BoundNodes *Nodes) override { return false; } |
5859 | |
5860 | bool run(const BoundNodes *Nodes, ASTContext *Context) override { |
5861 | const T *Node = Nodes->getNodeAs<T>(Id); |
5862 | return selectFirst<T>(InnerId, match(InnerMatcher, *Node, *Context)) != |
5863 | nullptr; |
5864 | } |
5865 | private: |
5866 | std::string Id; |
5867 | internal::Matcher<T> InnerMatcher; |
5868 | std::string InnerId; |
5869 | }; |
5870 | |
5871 | TEST(MatchFinder, CanMatchDeclarationsRecursively) { |
5872 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5873 | "class X { class Y {}; };" , recordDecl(hasName("::X" )).bind("X" ), |
5874 | std::make_unique<VerifyMatchOnNode<Decl>>( |
5875 | "X" , decl(hasDescendant(recordDecl(hasName("X::Y" )).bind("Y" ))), |
5876 | "Y" ))); |
5877 | EXPECT_TRUE(matchAndVerifyResultFalse( |
5878 | "class X { class Y {}; };" , recordDecl(hasName("::X" )).bind("X" ), |
5879 | std::make_unique<VerifyMatchOnNode<Decl>>( |
5880 | "X" , decl(hasDescendant(recordDecl(hasName("X::Z" )).bind("Z" ))), |
5881 | "Z" ))); |
5882 | } |
5883 | |
5884 | TEST(MatchFinder, CanMatchStatementsRecursively) { |
5885 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5886 | "void f() { if (1) { for (;;) { } } }" , ifStmt().bind("if" ), |
5887 | std::make_unique<VerifyMatchOnNode<Stmt>>( |
5888 | "if" , stmt(hasDescendant(forStmt().bind("for" ))), "for" ))); |
5889 | EXPECT_TRUE(matchAndVerifyResultFalse( |
5890 | "void f() { if (1) { for (;;) { } } }" , ifStmt().bind("if" ), |
5891 | std::make_unique<VerifyMatchOnNode<Stmt>>( |
5892 | "if" , stmt(hasDescendant(declStmt().bind("decl" ))), "decl" ))); |
5893 | } |
5894 | |
5895 | TEST(MatchFinder, CanMatchSingleNodesRecursively) { |
5896 | EXPECT_TRUE(matchAndVerifyResultTrue( |
5897 | "class X { class Y {}; };" , recordDecl(hasName("::X" )).bind("X" ), |
5898 | std::make_unique<VerifyMatchOnNode<Decl>>( |
5899 | "X" , recordDecl(has(recordDecl(hasName("X::Y" )).bind("Y" ))), "Y" ))); |
5900 | EXPECT_TRUE(matchAndVerifyResultFalse( |
5901 | "class X { class Y {}; };" , recordDecl(hasName("::X" )).bind("X" ), |
5902 | std::make_unique<VerifyMatchOnNode<Decl>>( |
5903 | "X" , recordDecl(has(recordDecl(hasName("X::Z" )).bind("Z" ))), "Z" ))); |
5904 | } |
5905 | |
5906 | TEST(StatementMatcher, HasReturnValue) { |
5907 | StatementMatcher RetVal = returnStmt(hasReturnValue(InnerMatcher: binaryOperator())); |
5908 | EXPECT_TRUE(matches("int F() { int a, b; return a + b; }" , RetVal)); |
5909 | EXPECT_FALSE(matches("int F() { int a; return a; }" , RetVal)); |
5910 | EXPECT_FALSE(matches("void F() { return; }" , RetVal)); |
5911 | } |
5912 | |
5913 | TEST(StatementMatcher, ForFunction) { |
5914 | StringRef CppString1 = "struct PosVec {" |
5915 | " PosVec& operator=(const PosVec&) {" |
5916 | " auto x = [] { return 1; };" |
5917 | " return *this;" |
5918 | " }" |
5919 | "};" ; |
5920 | StringRef CppString2 = "void F() {" |
5921 | " struct S {" |
5922 | " void F2() {" |
5923 | " return;" |
5924 | " }" |
5925 | " };" |
5926 | "}" ; |
5927 | EXPECT_TRUE( |
5928 | matches( |
5929 | CppString1, |
5930 | returnStmt(forFunction(hasName("operator=" )), |
5931 | has(unaryOperator(hasOperatorName("*" )))))); |
5932 | EXPECT_TRUE( |
5933 | notMatches( |
5934 | CppString1, |
5935 | returnStmt(forFunction(hasName("operator=" )), |
5936 | has(integerLiteral())))); |
5937 | EXPECT_TRUE( |
5938 | matches( |
5939 | CppString1, |
5940 | returnStmt(forFunction(hasName("operator()" )), |
5941 | has(integerLiteral())))); |
5942 | EXPECT_TRUE(matches(CppString2, returnStmt(forFunction(hasName("F2" ))))); |
5943 | EXPECT_TRUE(notMatches(CppString2, returnStmt(forFunction(hasName("F" ))))); |
5944 | } |
5945 | |
5946 | TEST(StatementMatcher, ForCallable) { |
5947 | // These tests are copied over from the forFunction() test above. |
5948 | StringRef CppString1 = "struct PosVec {" |
5949 | " PosVec& operator=(const PosVec&) {" |
5950 | " auto x = [] { return 1; };" |
5951 | " return *this;" |
5952 | " }" |
5953 | "};" ; |
5954 | StringRef CppString2 = "void F() {" |
5955 | " struct S {" |
5956 | " void F2() {" |
5957 | " return;" |
5958 | " }" |
5959 | " };" |
5960 | "}" ; |
5961 | |
5962 | EXPECT_TRUE( |
5963 | matches( |
5964 | CppString1, |
5965 | returnStmt(forCallable(functionDecl(hasName("operator=" ))), |
5966 | has(unaryOperator(hasOperatorName("*" )))))); |
5967 | EXPECT_TRUE( |
5968 | notMatches( |
5969 | CppString1, |
5970 | returnStmt(forCallable(functionDecl(hasName("operator=" ))), |
5971 | has(integerLiteral())))); |
5972 | EXPECT_TRUE( |
5973 | matches( |
5974 | CppString1, |
5975 | returnStmt(forCallable(functionDecl(hasName("operator()" ))), |
5976 | has(integerLiteral())))); |
5977 | EXPECT_TRUE(matches(CppString2, |
5978 | returnStmt(forCallable(functionDecl(hasName("F2" )))))); |
5979 | EXPECT_TRUE(notMatches(CppString2, |
5980 | returnStmt(forCallable(functionDecl(hasName("F" )))))); |
5981 | |
5982 | // These tests are specific to forCallable(). |
5983 | StringRef ObjCString1 = "@interface I" |
5984 | "-(void) foo;" |
5985 | "@end" |
5986 | "@implementation I" |
5987 | "-(void) foo {" |
5988 | " void (^block)() = ^{ 0x2b | ~0x2b; };" |
5989 | "}" |
5990 | "@end" ; |
5991 | |
5992 | EXPECT_TRUE( |
5993 | matchesObjC( |
5994 | ObjCString1, |
5995 | binaryOperator(forCallable(blockDecl())))); |
5996 | |
5997 | EXPECT_TRUE( |
5998 | notMatchesObjC( |
5999 | ObjCString1, |
6000 | binaryOperator(forCallable(objcMethodDecl())))); |
6001 | |
6002 | StringRef ObjCString2 = "@interface I" |
6003 | "-(void) foo;" |
6004 | "@end" |
6005 | "@implementation I" |
6006 | "-(void) foo {" |
6007 | " 0x2b | ~0x2b;" |
6008 | " void (^block)() = ^{};" |
6009 | "}" |
6010 | "@end" ; |
6011 | |
6012 | EXPECT_TRUE( |
6013 | matchesObjC( |
6014 | ObjCString2, |
6015 | binaryOperator(forCallable(objcMethodDecl())))); |
6016 | |
6017 | EXPECT_TRUE( |
6018 | notMatchesObjC( |
6019 | ObjCString2, |
6020 | binaryOperator(forCallable(blockDecl())))); |
6021 | } |
6022 | |
6023 | TEST(Matcher, ForEachOverriden) { |
6024 | const auto ForEachOverriddenInClass = [](const char *ClassName) { |
6025 | return cxxMethodDecl(ofClass(InnerMatcher: hasName(Name: ClassName)), isVirtual(), |
6026 | forEachOverridden(InnerMatcher: cxxMethodDecl().bind(ID: "overridden" ))) |
6027 | .bind(ID: "override" ); |
6028 | }; |
6029 | static const char Code1[] = "class A { virtual void f(); };" |
6030 | "class B : public A { void f(); };" |
6031 | "class C : public B { void f(); };" ; |
6032 | // C::f overrides A::f. |
6033 | EXPECT_TRUE(matchAndVerifyResultTrue( |
6034 | Code1, ForEachOverriddenInClass("C" ), |
6035 | std::make_unique<VerifyIdIsBoundTo<CXXMethodDecl>>("override" , "f" , 1))); |
6036 | EXPECT_TRUE(matchAndVerifyResultTrue( |
6037 | Code1, ForEachOverriddenInClass("C" ), |
6038 | std::make_unique<VerifyIdIsBoundTo<CXXMethodDecl>>("overridden" , "f" , |
6039 | 1))); |
6040 | // B::f overrides A::f. |
6041 | EXPECT_TRUE(matchAndVerifyResultTrue( |
6042 | Code1, ForEachOverriddenInClass("B" ), |
6043 | std::make_unique<VerifyIdIsBoundTo<CXXMethodDecl>>("override" , "f" , 1))); |
6044 | EXPECT_TRUE(matchAndVerifyResultTrue( |
6045 | Code1, ForEachOverriddenInClass("B" ), |
6046 | std::make_unique<VerifyIdIsBoundTo<CXXMethodDecl>>("overridden" , "f" , |
6047 | 1))); |
6048 | // A::f overrides nothing. |
6049 | EXPECT_TRUE(notMatches(Code1, ForEachOverriddenInClass("A" ))); |
6050 | |
6051 | static const char Code2[] = |
6052 | "class A1 { virtual void f(); };" |
6053 | "class A2 { virtual void f(); };" |
6054 | "class B : public A1, public A2 { void f(); };" ; |
6055 | // B::f overrides A1::f and A2::f. This produces two matches. |
6056 | EXPECT_TRUE(matchAndVerifyResultTrue( |
6057 | Code2, ForEachOverriddenInClass("B" ), |
6058 | std::make_unique<VerifyIdIsBoundTo<CXXMethodDecl>>("override" , "f" , 2))); |
6059 | EXPECT_TRUE(matchAndVerifyResultTrue( |
6060 | Code2, ForEachOverriddenInClass("B" ), |
6061 | std::make_unique<VerifyIdIsBoundTo<CXXMethodDecl>>("overridden" , "f" , |
6062 | 2))); |
6063 | // A1::f overrides nothing. |
6064 | EXPECT_TRUE(notMatches(Code2, ForEachOverriddenInClass("A1" ))); |
6065 | } |
6066 | |
6067 | TEST(Matcher, HasAnyDeclaration) { |
6068 | StringRef Fragment = "void foo(int p1);" |
6069 | "void foo(int *p2);" |
6070 | "void bar(int p3);" |
6071 | "template <typename T> void baz(T t) { foo(t); }" ; |
6072 | |
6073 | EXPECT_TRUE( |
6074 | matches(Fragment, unresolvedLookupExpr(hasAnyDeclaration(functionDecl( |
6075 | hasParameter(0, parmVarDecl(hasName("p1" )))))))); |
6076 | EXPECT_TRUE( |
6077 | matches(Fragment, unresolvedLookupExpr(hasAnyDeclaration(functionDecl( |
6078 | hasParameter(0, parmVarDecl(hasName("p2" )))))))); |
6079 | EXPECT_TRUE( |
6080 | notMatches(Fragment, unresolvedLookupExpr(hasAnyDeclaration(functionDecl( |
6081 | hasParameter(0, parmVarDecl(hasName("p3" )))))))); |
6082 | EXPECT_TRUE(notMatches(Fragment, unresolvedLookupExpr(hasAnyDeclaration( |
6083 | functionDecl(hasName("bar" )))))); |
6084 | } |
6085 | |
6086 | TEST(SubstTemplateTypeParmType, HasReplacementType) { |
6087 | StringRef Fragment = "template<typename T>" |
6088 | "double F(T t);" |
6089 | "int i;" |
6090 | "double j = F(i);" ; |
6091 | EXPECT_TRUE(matches(Fragment, substTemplateTypeParmType(hasReplacementType( |
6092 | qualType(asString("int" )))))); |
6093 | EXPECT_TRUE(notMatches(Fragment, substTemplateTypeParmType(hasReplacementType( |
6094 | qualType(asString("double" )))))); |
6095 | EXPECT_TRUE( |
6096 | notMatches("template<int N>" |
6097 | "double F();" |
6098 | "double j = F<5>();" , |
6099 | substTemplateTypeParmType(hasReplacementType(qualType())))); |
6100 | } |
6101 | |
6102 | TEST(ClassTemplateSpecializationDecl, HasSpecializedTemplate) { |
6103 | auto Matcher = classTemplateSpecializationDecl( |
6104 | hasSpecializedTemplate(InnerMatcher: classTemplateDecl())); |
6105 | EXPECT_TRUE( |
6106 | matches("template<typename T> class A {}; typedef A<int> B;" , Matcher)); |
6107 | EXPECT_TRUE(notMatches("template<typename T> class A {};" , Matcher)); |
6108 | } |
6109 | |
6110 | TEST(CXXNewExpr, Array) { |
6111 | StatementMatcher NewArray = cxxNewExpr(isArray()); |
6112 | |
6113 | EXPECT_TRUE(matches("void foo() { int *Ptr = new int[10]; }" , NewArray)); |
6114 | EXPECT_TRUE(notMatches("void foo() { int *Ptr = new int; }" , NewArray)); |
6115 | |
6116 | StatementMatcher NewArraySize10 = |
6117 | cxxNewExpr(hasArraySize(InnerMatcher: integerLiteral(equals(Value: 10)))); |
6118 | EXPECT_TRUE( |
6119 | matches("void foo() { int *Ptr = new int[10]; }" , NewArraySize10)); |
6120 | EXPECT_TRUE( |
6121 | notMatches("void foo() { int *Ptr = new int[20]; }" , NewArraySize10)); |
6122 | } |
6123 | |
6124 | TEST(CXXNewExpr, PlacementArgs) { |
6125 | StatementMatcher IsPlacementNew = cxxNewExpr(hasAnyPlacementArg(InnerMatcher: anything())); |
6126 | |
6127 | EXPECT_TRUE(matches(R"( |
6128 | void* operator new(decltype(sizeof(void*)), void*); |
6129 | int *foo(void* Storage) { |
6130 | return new (Storage) int; |
6131 | })" , |
6132 | IsPlacementNew)); |
6133 | |
6134 | EXPECT_TRUE(matches(R"( |
6135 | void* operator new(decltype(sizeof(void*)), void*, unsigned); |
6136 | int *foo(void* Storage) { |
6137 | return new (Storage, 16) int; |
6138 | })" , |
6139 | cxxNewExpr(hasPlacementArg( |
6140 | 1, ignoringImpCasts(integerLiteral(equals(16))))))); |
6141 | |
6142 | EXPECT_TRUE(notMatches(R"( |
6143 | void* operator new(decltype(sizeof(void*)), void*); |
6144 | int *foo(void* Storage) { |
6145 | return new int; |
6146 | })" , |
6147 | IsPlacementNew)); |
6148 | } |
6149 | |
6150 | TEST(HasUnqualifiedLoc, BindsToConstIntVarDecl) { |
6151 | EXPECT_TRUE(matches( |
6152 | "const int x = 0;" , |
6153 | varDecl(hasName("x" ), hasTypeLoc(qualifiedTypeLoc( |
6154 | hasUnqualifiedLoc(loc(asString("int" )))))))); |
6155 | } |
6156 | |
6157 | TEST(HasUnqualifiedLoc, BindsToVolatileIntVarDecl) { |
6158 | EXPECT_TRUE(matches( |
6159 | "volatile int x = 0;" , |
6160 | varDecl(hasName("x" ), hasTypeLoc(qualifiedTypeLoc( |
6161 | hasUnqualifiedLoc(loc(asString("int" )))))))); |
6162 | } |
6163 | |
6164 | TEST(HasUnqualifiedLoc, BindsToConstVolatileIntVarDecl) { |
6165 | EXPECT_TRUE(matches( |
6166 | "const volatile int x = 0;" , |
6167 | varDecl(hasName("x" ), hasTypeLoc(qualifiedTypeLoc( |
6168 | hasUnqualifiedLoc(loc(asString("int" )))))))); |
6169 | } |
6170 | |
6171 | TEST(HasUnqualifiedLoc, BindsToConstPointerVarDecl) { |
6172 | auto matcher = varDecl( |
6173 | hasName(Name: "x" ), |
6174 | hasTypeLoc(Inner: qualifiedTypeLoc(hasUnqualifiedLoc(InnerMatcher: pointerTypeLoc())))); |
6175 | EXPECT_TRUE(matches("int* const x = 0;" , matcher)); |
6176 | EXPECT_TRUE(notMatches("int const x = 0;" , matcher)); |
6177 | } |
6178 | |
6179 | TEST(HasUnqualifiedLoc, BindsToPointerToConstVolatileIntVarDecl) { |
6180 | EXPECT_TRUE( |
6181 | matches("const volatile int* x = 0;" , |
6182 | varDecl(hasName("x" ), |
6183 | hasTypeLoc(pointerTypeLoc(hasPointeeLoc(qualifiedTypeLoc( |
6184 | hasUnqualifiedLoc(loc(asString("int" )))))))))); |
6185 | } |
6186 | |
6187 | TEST(HasUnqualifiedLoc, BindsToConstIntFunctionDecl) { |
6188 | EXPECT_TRUE( |
6189 | matches("const int f() { return 5; }" , |
6190 | functionDecl(hasName("f" ), |
6191 | hasReturnTypeLoc(qualifiedTypeLoc( |
6192 | hasUnqualifiedLoc(loc(asString("int" )))))))); |
6193 | } |
6194 | |
6195 | TEST(HasUnqualifiedLoc, FloatBindsToConstFloatVarDecl) { |
6196 | EXPECT_TRUE(matches( |
6197 | "const float x = 0;" , |
6198 | varDecl(hasName("x" ), hasTypeLoc(qualifiedTypeLoc( |
6199 | hasUnqualifiedLoc(loc(asString("float" )))))))); |
6200 | } |
6201 | |
6202 | TEST(HasUnqualifiedLoc, FloatDoesNotBindToIntVarDecl) { |
6203 | EXPECT_TRUE(notMatches( |
6204 | "int x = 0;" , |
6205 | varDecl(hasName("x" ), hasTypeLoc(qualifiedTypeLoc( |
6206 | hasUnqualifiedLoc(loc(asString("float" )))))))); |
6207 | } |
6208 | |
6209 | TEST(HasUnqualifiedLoc, FloatDoesNotBindToConstIntVarDecl) { |
6210 | EXPECT_TRUE(notMatches( |
6211 | "const int x = 0;" , |
6212 | varDecl(hasName("x" ), hasTypeLoc(qualifiedTypeLoc( |
6213 | hasUnqualifiedLoc(loc(asString("float" )))))))); |
6214 | } |
6215 | |
6216 | TEST(HasReturnTypeLoc, BindsToIntReturnTypeLoc) { |
6217 | EXPECT_TRUE(matches( |
6218 | "int f() { return 5; }" , |
6219 | functionDecl(hasName("f" ), hasReturnTypeLoc(loc(asString("int" )))))); |
6220 | } |
6221 | |
6222 | TEST(HasReturnTypeLoc, BindsToFloatReturnTypeLoc) { |
6223 | EXPECT_TRUE(matches( |
6224 | "float f() { return 5.0; }" , |
6225 | functionDecl(hasName("f" ), hasReturnTypeLoc(loc(asString("float" )))))); |
6226 | } |
6227 | |
6228 | TEST(HasReturnTypeLoc, BindsToVoidReturnTypeLoc) { |
6229 | EXPECT_TRUE(matches( |
6230 | "void f() {}" , |
6231 | functionDecl(hasName("f" ), hasReturnTypeLoc(loc(asString("void" )))))); |
6232 | } |
6233 | |
6234 | TEST(HasReturnTypeLoc, FloatDoesNotBindToIntReturnTypeLoc) { |
6235 | EXPECT_TRUE(notMatches( |
6236 | "int f() { return 5; }" , |
6237 | functionDecl(hasName("f" ), hasReturnTypeLoc(loc(asString("float" )))))); |
6238 | } |
6239 | |
6240 | TEST(HasReturnTypeLoc, IntDoesNotBindToFloatReturnTypeLoc) { |
6241 | EXPECT_TRUE(notMatches( |
6242 | "float f() { return 5.0; }" , |
6243 | functionDecl(hasName("f" ), hasReturnTypeLoc(loc(asString("int" )))))); |
6244 | } |
6245 | |
6246 | TEST(HasPointeeLoc, BindsToAnyPointeeTypeLoc) { |
6247 | auto matcher = varDecl(hasName(Name: "x" ), |
6248 | hasTypeLoc(Inner: pointerTypeLoc(hasPointeeLoc(PointeeMatcher: typeLoc())))); |
6249 | EXPECT_TRUE(matches("int* x;" , matcher)); |
6250 | EXPECT_TRUE(matches("float* x;" , matcher)); |
6251 | EXPECT_TRUE(matches("char* x;" , matcher)); |
6252 | EXPECT_TRUE(matches("void* x;" , matcher)); |
6253 | } |
6254 | |
6255 | TEST(HasPointeeLoc, DoesNotBindToTypeLocWithoutPointee) { |
6256 | auto matcher = varDecl(hasName(Name: "x" ), |
6257 | hasTypeLoc(Inner: pointerTypeLoc(hasPointeeLoc(PointeeMatcher: typeLoc())))); |
6258 | EXPECT_TRUE(notMatches("int x;" , matcher)); |
6259 | EXPECT_TRUE(notMatches("float x;" , matcher)); |
6260 | EXPECT_TRUE(notMatches("char x;" , matcher)); |
6261 | } |
6262 | |
6263 | TEST(HasPointeeLoc, BindsToTypeLocPointingToInt) { |
6264 | EXPECT_TRUE( |
6265 | matches("int* x;" , pointerTypeLoc(hasPointeeLoc(loc(asString("int" )))))); |
6266 | } |
6267 | |
6268 | TEST(HasPointeeLoc, BindsToTypeLocPointingToIntPointer) { |
6269 | EXPECT_TRUE(matches("int** x;" , |
6270 | pointerTypeLoc(hasPointeeLoc(loc(asString("int *" )))))); |
6271 | } |
6272 | |
6273 | TEST(HasPointeeLoc, BindsToTypeLocPointingToTypeLocPointingToInt) { |
6274 | EXPECT_TRUE(matches("int** x;" , pointerTypeLoc(hasPointeeLoc(pointerTypeLoc( |
6275 | hasPointeeLoc(loc(asString("int" )))))))); |
6276 | } |
6277 | |
6278 | TEST(HasPointeeLoc, BindsToTypeLocPointingToFloat) { |
6279 | EXPECT_TRUE(matches("float* x;" , |
6280 | pointerTypeLoc(hasPointeeLoc(loc(asString("float" )))))); |
6281 | } |
6282 | |
6283 | TEST(HasPointeeLoc, IntPointeeDoesNotBindToTypeLocPointingToFloat) { |
6284 | EXPECT_TRUE(notMatches("float* x;" , |
6285 | pointerTypeLoc(hasPointeeLoc(loc(asString("int" )))))); |
6286 | } |
6287 | |
6288 | TEST(HasPointeeLoc, FloatPointeeDoesNotBindToTypeLocPointingToInt) { |
6289 | EXPECT_TRUE(notMatches( |
6290 | "int* x;" , pointerTypeLoc(hasPointeeLoc(loc(asString("float" )))))); |
6291 | } |
6292 | |
6293 | TEST(HasReferentLoc, BindsToAnyReferentTypeLoc) { |
6294 | auto matcher = varDecl( |
6295 | hasName(Name: "r" ), hasTypeLoc(Inner: referenceTypeLoc(hasReferentLoc(ReferentMatcher: typeLoc())))); |
6296 | EXPECT_TRUE(matches("int rr = 3; int& r = rr;" , matcher)); |
6297 | EXPECT_TRUE(matches("int rr = 3; auto& r = rr;" , matcher)); |
6298 | EXPECT_TRUE(matches("int rr = 3; const int& r = rr;" , matcher)); |
6299 | EXPECT_TRUE(matches("float rr = 3.0; float& r = rr;" , matcher)); |
6300 | EXPECT_TRUE(matches("char rr = 'a'; char& r = rr;" , matcher)); |
6301 | } |
6302 | |
6303 | TEST(HasReferentLoc, DoesNotBindToTypeLocWithoutReferent) { |
6304 | auto matcher = varDecl( |
6305 | hasName(Name: "r" ), hasTypeLoc(Inner: referenceTypeLoc(hasReferentLoc(ReferentMatcher: typeLoc())))); |
6306 | EXPECT_TRUE(notMatches("int r;" , matcher)); |
6307 | EXPECT_TRUE(notMatches("int r = 3;" , matcher)); |
6308 | EXPECT_TRUE(notMatches("const int r = 3;" , matcher)); |
6309 | EXPECT_TRUE(notMatches("int* r;" , matcher)); |
6310 | EXPECT_TRUE(notMatches("float r;" , matcher)); |
6311 | EXPECT_TRUE(notMatches("char r;" , matcher)); |
6312 | } |
6313 | |
6314 | TEST(HasReferentLoc, BindsToAnyRvalueReference) { |
6315 | auto matcher = varDecl( |
6316 | hasName(Name: "r" ), hasTypeLoc(Inner: referenceTypeLoc(hasReferentLoc(ReferentMatcher: typeLoc())))); |
6317 | EXPECT_TRUE(matches("int&& r = 3;" , matcher)); |
6318 | EXPECT_TRUE(matches("auto&& r = 3;" , matcher)); |
6319 | EXPECT_TRUE(matches("float&& r = 3.0;" , matcher)); |
6320 | } |
6321 | |
6322 | TEST(HasReferentLoc, BindsToIntReferenceTypeLoc) { |
6323 | EXPECT_TRUE(matches("int rr = 3; int& r = rr;" , |
6324 | referenceTypeLoc(hasReferentLoc(loc(asString("int" )))))); |
6325 | } |
6326 | |
6327 | TEST(HasReferentLoc, BindsToIntRvalueReferenceTypeLoc) { |
6328 | EXPECT_TRUE(matches("int&& r = 3;" , |
6329 | referenceTypeLoc(hasReferentLoc(loc(asString("int" )))))); |
6330 | } |
6331 | |
6332 | TEST(HasReferentLoc, BindsToFloatReferenceTypeLoc) { |
6333 | EXPECT_TRUE( |
6334 | matches("float rr = 3.0; float& r = rr;" , |
6335 | referenceTypeLoc(hasReferentLoc(loc(asString("float" )))))); |
6336 | } |
6337 | |
6338 | TEST(HasReferentLoc, BindsToParameterWithIntReferenceTypeLoc) { |
6339 | EXPECT_TRUE(matches( |
6340 | "int f(int& r) { return r; }" , |
6341 | parmVarDecl(hasName("r" ), hasTypeLoc(referenceTypeLoc( |
6342 | hasReferentLoc(loc(asString("int" )))))))); |
6343 | } |
6344 | |
6345 | TEST(HasReferentLoc, IntReferenceDoesNotBindToFloatReferenceTypeLoc) { |
6346 | EXPECT_TRUE( |
6347 | notMatches("float rr = 3.0; float& r = rr;" , |
6348 | referenceTypeLoc(hasReferentLoc(loc(asString("int" )))))); |
6349 | } |
6350 | |
6351 | TEST(HasReferentLoc, FloatReferenceDoesNotBindToIntReferenceTypeLoc) { |
6352 | EXPECT_TRUE( |
6353 | notMatches("int rr = 3; int& r = rr;" , |
6354 | referenceTypeLoc(hasReferentLoc(loc(asString("float" )))))); |
6355 | } |
6356 | |
6357 | TEST(HasReferentLoc, DoesNotBindToParameterWithoutIntReferenceTypeLoc) { |
6358 | EXPECT_TRUE(notMatches( |
6359 | "int f(int r) { return r; }" , |
6360 | parmVarDecl(hasName("r" ), hasTypeLoc(referenceTypeLoc( |
6361 | hasReferentLoc(loc(asString("int" )))))))); |
6362 | } |
6363 | |
6364 | TEST(HasAnyTemplateArgumentLoc, BindsToSpecializationWithIntArgument) { |
6365 | EXPECT_TRUE(matches( |
6366 | "template<typename T> class A {}; A<int> a;" , |
6367 | varDecl(hasName("a" ), |
6368 | hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc( |
6369 | templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc( |
6370 | hasTypeLoc(loc(asString("int" ))))))))))); |
6371 | } |
6372 | |
6373 | TEST(HasAnyTemplateArgumentLoc, BindsToSpecializationWithDoubleArgument) { |
6374 | EXPECT_TRUE(matches( |
6375 | "template<typename T> class A {}; A<double> a;" , |
6376 | varDecl(hasName("a" ), |
6377 | hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc( |
6378 | templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc( |
6379 | hasTypeLoc(loc(asString("double" ))))))))))); |
6380 | } |
6381 | |
6382 | TEST(HasAnyTemplateArgumentLoc, BindsToExplicitSpecializationWithIntArgument) { |
6383 | EXPECT_TRUE(matches( |
6384 | "template<typename T> class A {}; template<> class A<int> {};" , |
6385 | classTemplateSpecializationDecl( |
6386 | hasName("A" ), |
6387 | hasTypeLoc(templateSpecializationTypeLoc( |
6388 | hasAnyTemplateArgumentLoc(hasTypeLoc(loc(asString("int" ))))))))); |
6389 | } |
6390 | |
6391 | TEST(HasAnyTemplateArgumentLoc, |
6392 | BindsToExplicitSpecializationWithDoubleArgument) { |
6393 | EXPECT_TRUE(matches( |
6394 | "template<typename T> class A {}; template<> class A<double> {};" , |
6395 | classTemplateSpecializationDecl( |
6396 | hasName("A" ), |
6397 | hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc( |
6398 | hasTypeLoc(loc(asString("double" ))))))))); |
6399 | } |
6400 | |
6401 | TEST(HasAnyTemplateArgumentLoc, BindsToSpecializationWithMultipleArguments) { |
6402 | auto code = R"( |
6403 | template<typename T, typename U> class A {}; |
6404 | template<> class A<double, int> {}; |
6405 | )" ; |
6406 | EXPECT_TRUE( |
6407 | matches(code, classTemplateSpecializationDecl( |
6408 | hasName("A" ), hasTypeLoc(templateSpecializationTypeLoc( |
6409 | hasAnyTemplateArgumentLoc(hasTypeLoc( |
6410 | loc(asString("double" ))))))))); |
6411 | EXPECT_TRUE(matches( |
6412 | code, |
6413 | classTemplateSpecializationDecl( |
6414 | hasName("A" ), |
6415 | hasTypeLoc(templateSpecializationTypeLoc( |
6416 | hasAnyTemplateArgumentLoc(hasTypeLoc(loc(asString("int" ))))))))); |
6417 | } |
6418 | |
6419 | TEST(HasAnyTemplateArgumentLoc, DoesNotBindToSpecializationWithIntArgument) { |
6420 | EXPECT_TRUE(notMatches( |
6421 | "template<typename T> class A {}; A<int> a;" , |
6422 | classTemplateSpecializationDecl( |
6423 | hasName("A" ), |
6424 | hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc( |
6425 | hasTypeLoc(loc(asString("double" ))))))))); |
6426 | } |
6427 | |
6428 | TEST(HasAnyTemplateArgumentLoc, |
6429 | DoesNotBindToExplicitSpecializationWithIntArgument) { |
6430 | EXPECT_TRUE(notMatches( |
6431 | "template<typename T> class A {}; template<> class A<int> {};" , |
6432 | classTemplateSpecializationDecl( |
6433 | hasName("A" ), |
6434 | hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc( |
6435 | hasTypeLoc(loc(asString("double" ))))))))); |
6436 | } |
6437 | |
6438 | TEST(HasTemplateArgumentLoc, BindsToSpecializationWithIntArgument) { |
6439 | EXPECT_TRUE( |
6440 | matches("template<typename T> class A {}; A<int> a;" , |
6441 | varDecl(hasName("a" ), |
6442 | hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc( |
6443 | templateSpecializationTypeLoc(hasTemplateArgumentLoc( |
6444 | 0, hasTypeLoc(loc(asString("int" ))))))))))); |
6445 | } |
6446 | |
6447 | TEST(HasTemplateArgumentLoc, BindsToSpecializationWithDoubleArgument) { |
6448 | EXPECT_TRUE( |
6449 | matches("template<typename T> class A {}; A<double> a;" , |
6450 | varDecl(hasName("a" ), |
6451 | hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc( |
6452 | templateSpecializationTypeLoc(hasTemplateArgumentLoc( |
6453 | 0, hasTypeLoc(loc(asString("double" ))))))))))); |
6454 | } |
6455 | |
6456 | TEST(HasTemplateArgumentLoc, BindsToExplicitSpecializationWithIntArgument) { |
6457 | EXPECT_TRUE(matches( |
6458 | "template<typename T> class A {}; template<> class A<int> {};" , |
6459 | classTemplateSpecializationDecl( |
6460 | hasName("A" ), |
6461 | hasTypeLoc(templateSpecializationTypeLoc( |
6462 | hasTemplateArgumentLoc(0, hasTypeLoc(loc(asString("int" ))))))))); |
6463 | } |
6464 | |
6465 | TEST(HasTemplateArgumentLoc, BindsToExplicitSpecializationWithDoubleArgument) { |
6466 | EXPECT_TRUE(matches( |
6467 | "template<typename T> class A {}; template<> class A<double> {};" , |
6468 | classTemplateSpecializationDecl( |
6469 | hasName("A" ), |
6470 | hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc( |
6471 | 0, hasTypeLoc(loc(asString("double" ))))))))); |
6472 | } |
6473 | |
6474 | TEST(HasTemplateArgumentLoc, BindsToSpecializationWithMultipleArguments) { |
6475 | auto code = R"( |
6476 | template<typename T, typename U> class A {}; |
6477 | template<> class A<double, int> {}; |
6478 | )" ; |
6479 | EXPECT_TRUE(matches( |
6480 | code, classTemplateSpecializationDecl( |
6481 | hasName("A" ), |
6482 | hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc( |
6483 | 0, hasTypeLoc(loc(asString("double" ))))))))); |
6484 | EXPECT_TRUE(matches( |
6485 | code, classTemplateSpecializationDecl( |
6486 | hasName("A" ), |
6487 | hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc( |
6488 | 1, hasTypeLoc(loc(asString("int" ))))))))); |
6489 | } |
6490 | |
6491 | TEST(HasTemplateArgumentLoc, DoesNotBindToSpecializationWithIntArgument) { |
6492 | EXPECT_TRUE(notMatches( |
6493 | "template<typename T> class A {}; A<int> a;" , |
6494 | classTemplateSpecializationDecl( |
6495 | hasName("A" ), |
6496 | hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc( |
6497 | 0, hasTypeLoc(loc(asString("double" ))))))))); |
6498 | } |
6499 | |
6500 | TEST(HasTemplateArgumentLoc, |
6501 | DoesNotBindToExplicitSpecializationWithIntArgument) { |
6502 | EXPECT_TRUE(notMatches( |
6503 | "template<typename T> class A {}; template<> class A<int> {};" , |
6504 | classTemplateSpecializationDecl( |
6505 | hasName("A" ), |
6506 | hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc( |
6507 | 0, hasTypeLoc(loc(asString("double" ))))))))); |
6508 | } |
6509 | |
6510 | TEST(HasTemplateArgumentLoc, |
6511 | DoesNotBindToSpecializationWithMisplacedArguments) { |
6512 | auto code = R"( |
6513 | template<typename T, typename U> class A {}; |
6514 | template<> class A<double, int> {}; |
6515 | )" ; |
6516 | EXPECT_TRUE(notMatches( |
6517 | code, classTemplateSpecializationDecl( |
6518 | hasName("A" ), |
6519 | hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc( |
6520 | 1, hasTypeLoc(loc(asString("double" ))))))))); |
6521 | EXPECT_TRUE(notMatches( |
6522 | code, classTemplateSpecializationDecl( |
6523 | hasName("A" ), |
6524 | hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc( |
6525 | 0, hasTypeLoc(loc(asString("int" ))))))))); |
6526 | } |
6527 | |
6528 | TEST(HasTemplateArgumentLoc, DoesNotBindWithBadIndex) { |
6529 | auto code = R"( |
6530 | template<typename T, typename U> class A {}; |
6531 | template<> class A<double, int> {}; |
6532 | )" ; |
6533 | EXPECT_TRUE(notMatches( |
6534 | code, classTemplateSpecializationDecl( |
6535 | hasName("A" ), |
6536 | hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc( |
6537 | -1, hasTypeLoc(loc(asString("double" ))))))))); |
6538 | EXPECT_TRUE(notMatches( |
6539 | code, classTemplateSpecializationDecl( |
6540 | hasName("A" ), |
6541 | hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc( |
6542 | 100, hasTypeLoc(loc(asString("int" ))))))))); |
6543 | } |
6544 | |
6545 | TEST(HasTemplateArgumentLoc, BindsToDeclRefExprWithIntArgument) { |
6546 | EXPECT_TRUE(matches(R"( |
6547 | template<typename T> T f(T t) { return t; } |
6548 | int g() { int i = f<int>(3); return i; } |
6549 | )" , |
6550 | declRefExpr(to(functionDecl(hasName("f" ))), |
6551 | hasTemplateArgumentLoc( |
6552 | 0, hasTypeLoc(loc(asString("int" ))))))); |
6553 | } |
6554 | |
6555 | TEST(HasTemplateArgumentLoc, BindsToDeclRefExprWithDoubleArgument) { |
6556 | EXPECT_TRUE(matches( |
6557 | R"( |
6558 | template<typename T> T f(T t) { return t; } |
6559 | double g() { double i = f<double>(3.0); return i; } |
6560 | )" , |
6561 | declRefExpr( |
6562 | to(functionDecl(hasName("f" ))), |
6563 | hasTemplateArgumentLoc(0, hasTypeLoc(loc(asString("double" ))))))); |
6564 | } |
6565 | |
6566 | TEST(HasTemplateArgumentLoc, DoesNotBindToDeclRefExprWithDoubleArgument) { |
6567 | EXPECT_TRUE(notMatches( |
6568 | R"( |
6569 | template<typename T> T f(T t) { return t; } |
6570 | double g() { double i = f<double>(3.0); return i; } |
6571 | )" , |
6572 | declRefExpr( |
6573 | to(functionDecl(hasName("f" ))), |
6574 | hasTemplateArgumentLoc(0, hasTypeLoc(loc(asString("int" ))))))); |
6575 | } |
6576 | |
6577 | TEST(HasNamedTypeLoc, BindsToElaboratedObjectDeclaration) { |
6578 | EXPECT_TRUE(matches( |
6579 | R"( |
6580 | template <typename T> |
6581 | class C {}; |
6582 | class C<int> c; |
6583 | )" , |
6584 | varDecl(hasName("c" ), |
6585 | hasTypeLoc(elaboratedTypeLoc( |
6586 | hasNamedTypeLoc(templateSpecializationTypeLoc( |
6587 | hasAnyTemplateArgumentLoc(templateArgumentLoc())))))))); |
6588 | } |
6589 | |
6590 | TEST(HasNamedTypeLoc, DoesNotBindToNonElaboratedObjectDeclaration) { |
6591 | EXPECT_TRUE(matches( |
6592 | R"( |
6593 | template <typename T> |
6594 | class C {}; |
6595 | C<int> c; |
6596 | )" , |
6597 | varDecl(hasName("c" ), |
6598 | hasTypeLoc(elaboratedTypeLoc( |
6599 | hasNamedTypeLoc(templateSpecializationTypeLoc( |
6600 | hasAnyTemplateArgumentLoc(templateArgumentLoc())))))))); |
6601 | } |
6602 | |
6603 | } // namespace ast_matchers |
6604 | } // namespace clang |
6605 | |