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