blob: 16998f2420acdfc0f5eabb42e163f5bf67477eae [file] [log] [blame]
Gabor Marton1f667532018-05-24 08:41:07 +00001#include "clang/AST/ASTContext.h"
2#include "clang/ASTMatchers/ASTMatchers.h"
3#include "clang/AST/ASTStructuralEquivalence.h"
4#include "clang/Frontend/ASTUnit.h"
5#include "clang/Tooling/Tooling.h"
6
7#include "Language.h"
8#include "DeclMatcher.h"
9
10#include "gtest/gtest.h"
11
12namespace clang {
13namespace ast_matchers {
14
15using std::get;
16
17struct StructuralEquivalenceTest : ::testing::Test {
18 std::unique_ptr<ASTUnit> AST0, AST1;
19 std::string Code0, Code1; // Buffers for SourceManager
20
Balazs Keric7797c42018-07-11 09:37:24 +000021 // Get a pair of node pointers into the synthesized AST from the given code
22 // snippets. To determine the returned node, a separate matcher is specified
23 // for both snippets. The first matching node is returned.
24 template <typename NodeType, typename MatcherType>
25 std::tuple<NodeType *, NodeType *> makeDecls(
26 const std::string &SrcCode0, const std::string &SrcCode1, Language Lang,
27 const MatcherType &Matcher0, const MatcherType &Matcher1) {
Gabor Marton1f667532018-05-24 08:41:07 +000028 this->Code0 = SrcCode0;
29 this->Code1 = SrcCode1;
30 ArgVector Args = getBasicRunOptionsForLanguage(Lang);
31
32 const char *const InputFileName = "input.cc";
33
34 AST0 = tooling::buildASTFromCodeWithArgs(Code0, Args, InputFileName);
35 AST1 = tooling::buildASTFromCodeWithArgs(Code1, Args, InputFileName);
36
Balazs Keric7797c42018-07-11 09:37:24 +000037 NodeType *D0 = FirstDeclMatcher<NodeType>().match(
38 AST0->getASTContext().getTranslationUnitDecl(), Matcher0);
39 NodeType *D1 = FirstDeclMatcher<NodeType>().match(
40 AST1->getASTContext().getTranslationUnitDecl(), Matcher1);
Gabor Marton1f667532018-05-24 08:41:07 +000041
Gabor Marton1f667532018-05-24 08:41:07 +000042 return std::make_tuple(D0, D1);
43 }
44
Balazs Keric7797c42018-07-11 09:37:24 +000045 // Get a pair of node pointers into the synthesized AST from the given code
46 // snippets. The same matcher is used for both snippets.
47 template <typename NodeType, typename MatcherType>
48 std::tuple<NodeType *, NodeType *> makeDecls(
49 const std::string &SrcCode0, const std::string &SrcCode1, Language Lang,
50 const MatcherType &AMatcher) {
51 return makeDecls<NodeType, MatcherType>(
52 SrcCode0, SrcCode1, Lang, AMatcher, AMatcher);
53 }
54
55 // Get a pair of Decl pointers to the synthesized declarations from the given
56 // code snippets. We search for the first NamedDecl with given name in both
57 // snippets.
58 std::tuple<NamedDecl *, NamedDecl *> makeNamedDecls(
59 const std::string &SrcCode0, const std::string &SrcCode1,
60 Language Lang, const char *const Identifier = "foo") {
61 auto Matcher = namedDecl(hasName(Identifier));
62 return makeDecls<NamedDecl>(SrcCode0, SrcCode1, Lang, Matcher);
63 }
64
Gabor Marton1f667532018-05-24 08:41:07 +000065 bool testStructuralMatch(NamedDecl *D0, NamedDecl *D1) {
66 llvm::DenseSet<std::pair<Decl *, Decl *>> NonEquivalentDecls;
67 StructuralEquivalenceContext Ctx(D0->getASTContext(), D1->getASTContext(),
68 NonEquivalentDecls, false, false);
69 return Ctx.IsStructurallyEquivalent(D0, D1);
70 }
71
72 bool testStructuralMatch(std::tuple<NamedDecl *, NamedDecl *> t) {
73 return testStructuralMatch(get<0>(t), get<1>(t));
74 }
75};
76
77TEST_F(StructuralEquivalenceTest, Int) {
78 auto Decls = makeNamedDecls("int foo;", "int foo;", Lang_CXX);
79 EXPECT_TRUE(testStructuralMatch(Decls));
80}
81
82TEST_F(StructuralEquivalenceTest, IntVsSignedInt) {
83 auto Decls = makeNamedDecls("int foo;", "signed int foo;", Lang_CXX);
84 EXPECT_TRUE(testStructuralMatch(Decls));
85}
86
87TEST_F(StructuralEquivalenceTest, Char) {
88 auto Decls = makeNamedDecls("char foo;", "char foo;", Lang_CXX);
89 EXPECT_TRUE(testStructuralMatch(Decls));
90}
91
92// This test is disabled for now.
93// FIXME Whether this is equivalent is dependendant on the target.
94TEST_F(StructuralEquivalenceTest, DISABLED_CharVsSignedChar) {
95 auto Decls = makeNamedDecls("char foo;", "signed char foo;", Lang_CXX);
96 EXPECT_FALSE(testStructuralMatch(Decls));
97}
98
99TEST_F(StructuralEquivalenceTest, ForwardRecordDecl) {
100 auto Decls = makeNamedDecls("struct foo;", "struct foo;", Lang_CXX);
101 EXPECT_TRUE(testStructuralMatch(Decls));
102}
103
104TEST_F(StructuralEquivalenceTest, IntVsSignedIntInStruct) {
105 auto Decls = makeNamedDecls("struct foo { int x; };",
106 "struct foo { signed int x; };", Lang_CXX);
107 EXPECT_TRUE(testStructuralMatch(Decls));
108}
109
110TEST_F(StructuralEquivalenceTest, CharVsSignedCharInStruct) {
111 auto Decls = makeNamedDecls("struct foo { char x; };",
112 "struct foo { signed char x; };", Lang_CXX);
113 EXPECT_FALSE(testStructuralMatch(Decls));
114}
115
116TEST_F(StructuralEquivalenceTest, IntVsSignedIntTemplateSpec) {
Balazs Keric7797c42018-07-11 09:37:24 +0000117 auto Decls = makeDecls<ClassTemplateSpecializationDecl>(
118 R"(template <class T> struct foo; template<> struct foo<int>{};)",
119 R"(template <class T> struct foo; template<> struct foo<signed int>{};)",
120 Lang_CXX,
121 classTemplateSpecializationDecl());
122 auto Spec0 = get<0>(Decls);
123 auto Spec1 = get<1>(Decls);
Gabor Marton1f667532018-05-24 08:41:07 +0000124 EXPECT_TRUE(testStructuralMatch(Spec0, Spec1));
125}
126
127TEST_F(StructuralEquivalenceTest, CharVsSignedCharTemplateSpec) {
Balazs Keric7797c42018-07-11 09:37:24 +0000128 auto Decls = makeDecls<ClassTemplateSpecializationDecl>(
129 R"(template <class T> struct foo; template<> struct foo<char>{};)",
130 R"(template <class T> struct foo; template<> struct foo<signed char>{};)",
131 Lang_CXX,
132 classTemplateSpecializationDecl());
133 auto Spec0 = get<0>(Decls);
134 auto Spec1 = get<1>(Decls);
Gabor Marton1f667532018-05-24 08:41:07 +0000135 EXPECT_FALSE(testStructuralMatch(Spec0, Spec1));
136}
137
138TEST_F(StructuralEquivalenceTest, CharVsSignedCharTemplateSpecWithInheritance) {
Balazs Keric7797c42018-07-11 09:37:24 +0000139 auto Decls = makeDecls<ClassTemplateSpecializationDecl>(
Gabor Marton1f667532018-05-24 08:41:07 +0000140 R"(
141 struct true_type{};
142 template <class T> struct foo;
143 template<> struct foo<char> : true_type {};
144 )",
145 R"(
146 struct true_type{};
147 template <class T> struct foo;
148 template<> struct foo<signed char> : true_type {};
149 )",
Balazs Keric7797c42018-07-11 09:37:24 +0000150 Lang_CXX,
151 classTemplateSpecializationDecl());
152 EXPECT_FALSE(testStructuralMatch(Decls));
Gabor Marton1f667532018-05-24 08:41:07 +0000153}
154
155// This test is disabled for now.
156// FIXME Enable it, once the check is implemented.
157TEST_F(StructuralEquivalenceTest, DISABLED_WrongOrderInNamespace) {
158 auto Code =
159 R"(
160 namespace NS {
161 template <class T> class Base {
162 int a;
163 };
164 class Derived : Base<Derived> {
165 };
166 }
167 void foo(NS::Derived &);
168 )";
169 auto Decls = makeNamedDecls(Code, Code, Lang_CXX);
170
171 NamespaceDecl *NS =
172 LastDeclMatcher<NamespaceDecl>().match(get<1>(Decls), namespaceDecl());
173 ClassTemplateDecl *TD = LastDeclMatcher<ClassTemplateDecl>().match(
174 get<1>(Decls), classTemplateDecl(hasName("Base")));
175
176 // Reorder the decls, move the TD to the last place in the DC.
177 NS->removeDecl(TD);
178 NS->addDeclInternal(TD);
179
180 EXPECT_FALSE(testStructuralMatch(Decls));
181}
182
183TEST_F(StructuralEquivalenceTest, WrongOrderOfFieldsInClass) {
184 auto Code = "class X { int a; int b; };";
185 auto Decls = makeNamedDecls(Code, Code, Lang_CXX, "X");
186
187 CXXRecordDecl *RD = FirstDeclMatcher<CXXRecordDecl>().match(
188 get<1>(Decls), cxxRecordDecl(hasName("X")));
189 FieldDecl *FD =
190 FirstDeclMatcher<FieldDecl>().match(get<1>(Decls), fieldDecl(hasName("a")));
191
192 // Reorder the FieldDecls
193 RD->removeDecl(FD);
194 RD->addDeclInternal(FD);
195
196 EXPECT_FALSE(testStructuralMatch(Decls));
197}
198
Balazs Keric7797c42018-07-11 09:37:24 +0000199struct StructuralEquivalenceFunctionTest : StructuralEquivalenceTest {
200};
201
202TEST_F(StructuralEquivalenceFunctionTest, ParamConstWithRef) {
203 auto t = makeNamedDecls("void foo(int&);",
204 "void foo(const int&);", Lang_CXX);
205 EXPECT_FALSE(testStructuralMatch(t));
206}
207
208TEST_F(StructuralEquivalenceFunctionTest, ParamConstSimple) {
209 auto t = makeNamedDecls("void foo(int);",
210 "void foo(const int);", Lang_CXX);
211 EXPECT_TRUE(testStructuralMatch(t));
212 // consider this OK
213}
214
215TEST_F(StructuralEquivalenceFunctionTest, Throw) {
216 auto t = makeNamedDecls("void foo();",
217 "void foo() throw();", Lang_CXX);
218 EXPECT_FALSE(testStructuralMatch(t));
219}
220
221TEST_F(StructuralEquivalenceFunctionTest, Noexcept) {
222 auto t = makeNamedDecls("void foo();",
223 "void foo() noexcept;", Lang_CXX11);
224 EXPECT_FALSE(testStructuralMatch(t));
225}
226
227TEST_F(StructuralEquivalenceFunctionTest, ThrowVsNoexcept) {
228 auto t = makeNamedDecls("void foo() throw();",
229 "void foo() noexcept;", Lang_CXX11);
230 EXPECT_FALSE(testStructuralMatch(t));
231}
232
233TEST_F(StructuralEquivalenceFunctionTest, ThrowVsNoexceptFalse) {
234 auto t = makeNamedDecls("void foo() throw();",
235 "void foo() noexcept(false);", Lang_CXX11);
236 EXPECT_FALSE(testStructuralMatch(t));
237}
238
239TEST_F(StructuralEquivalenceFunctionTest, ThrowVsNoexceptTrue) {
240 auto t = makeNamedDecls("void foo() throw();",
241 "void foo() noexcept(true);", Lang_CXX11);
242 EXPECT_FALSE(testStructuralMatch(t));
243}
244
245TEST_F(StructuralEquivalenceFunctionTest, DISABLED_NoexceptNonMatch) {
246 // The expression is not checked yet.
247 auto t = makeNamedDecls("void foo() noexcept(false);",
248 "void foo() noexcept(true);", Lang_CXX11);
249 EXPECT_FALSE(testStructuralMatch(t));
250}
251
252TEST_F(StructuralEquivalenceFunctionTest, NoexceptMatch) {
253 auto t = makeNamedDecls("void foo() noexcept(false);",
254 "void foo() noexcept(false);", Lang_CXX11);
255 EXPECT_TRUE(testStructuralMatch(t));
256}
257
258TEST_F(StructuralEquivalenceFunctionTest, NoexceptVsNoexceptFalse) {
259 auto t = makeNamedDecls("void foo() noexcept;",
260 "void foo() noexcept(false);", Lang_CXX11);
261 EXPECT_FALSE(testStructuralMatch(t));
262}
263
264TEST_F(StructuralEquivalenceFunctionTest, NoexceptVsNoexceptTrue) {
265 auto t = makeNamedDecls("void foo() noexcept;",
266 "void foo() noexcept(true);", Lang_CXX11);
267 EXPECT_FALSE(testStructuralMatch(t));
268}
269
270TEST_F(StructuralEquivalenceFunctionTest, ReturnType) {
271 auto t = makeNamedDecls("char foo();",
272 "int foo();", Lang_CXX);
273 EXPECT_FALSE(testStructuralMatch(t));
274}
275
276TEST_F(StructuralEquivalenceFunctionTest, ReturnConst) {
277 auto t = makeNamedDecls("char foo();",
278 "const char foo();", Lang_CXX);
279 EXPECT_FALSE(testStructuralMatch(t));
280}
281
282TEST_F(StructuralEquivalenceFunctionTest, ReturnRef) {
283 auto t = makeNamedDecls("char &foo();",
284 "char &&foo();", Lang_CXX11);
285 EXPECT_FALSE(testStructuralMatch(t));
286}
287
288TEST_F(StructuralEquivalenceFunctionTest, ParamCount) {
289 auto t = makeNamedDecls("void foo(int);",
290 "void foo(int, int);", Lang_CXX);
291 EXPECT_FALSE(testStructuralMatch(t));
292}
293
294TEST_F(StructuralEquivalenceFunctionTest, ParamType) {
295 auto t = makeNamedDecls("void foo(int);",
296 "void foo(char);", Lang_CXX);
297 EXPECT_FALSE(testStructuralMatch(t));
298}
299
300TEST_F(StructuralEquivalenceFunctionTest, ParamName) {
301 auto t = makeNamedDecls("void foo(int a);",
302 "void foo(int b);", Lang_CXX);
303 EXPECT_TRUE(testStructuralMatch(t));
304}
305
306TEST_F(StructuralEquivalenceFunctionTest, Variadic) {
307 auto t = makeNamedDecls("void foo(int x...);",
308 "void foo(int x);", Lang_CXX);
309 EXPECT_FALSE(testStructuralMatch(t));
310}
311
312TEST_F(StructuralEquivalenceFunctionTest, ParamPtr) {
313 auto t = makeNamedDecls("void foo(int *);",
314 "void foo(int);", Lang_CXX);
315 EXPECT_FALSE(testStructuralMatch(t));
316}
317
318TEST_F(StructuralEquivalenceFunctionTest, NameInParen) {
319 auto t = makeNamedDecls(
320 "void ((foo))();",
321 "void foo();",
322 Lang_CXX);
323 EXPECT_TRUE(testStructuralMatch(t));
324}
325
326TEST_F(StructuralEquivalenceFunctionTest, NameInParenWithExceptionSpec) {
327 auto t = makeNamedDecls(
328 "void (foo)() throw(int);",
329 "void (foo)() noexcept;",
330 Lang_CXX11);
331 EXPECT_FALSE(testStructuralMatch(t));
332}
333
334TEST_F(StructuralEquivalenceFunctionTest, NameInParenWithConst) {
335 auto t = makeNamedDecls(
336 "struct A { void (foo)() const; };",
337 "struct A { void (foo)(); };",
338 Lang_CXX11);
339 EXPECT_FALSE(testStructuralMatch(t));
340}
341
342struct StructuralEquivalenceCXXMethodTest : StructuralEquivalenceTest {
343};
344
345TEST_F(StructuralEquivalenceCXXMethodTest, Virtual) {
346 auto t = makeDecls<CXXMethodDecl>(
347 "struct X { void foo(); };",
348 "struct X { virtual void foo(); };", Lang_CXX,
349 cxxMethodDecl(hasName("foo")));
350 EXPECT_FALSE(testStructuralMatch(t));
351}
352
353TEST_F(StructuralEquivalenceCXXMethodTest, Pure) {
354 auto t = makeNamedDecls("struct X { virtual void foo(); };",
355 "struct X { virtual void foo() = 0; };", Lang_CXX);
356 EXPECT_FALSE(testStructuralMatch(t));
357}
358
359TEST_F(StructuralEquivalenceCXXMethodTest, DISABLED_Final) {
360 // The final-ness is not checked yet.
361 auto t = makeNamedDecls("struct X { virtual void foo(); };",
362 "struct X { virtual void foo() final; };", Lang_CXX);
363 EXPECT_FALSE(testStructuralMatch(t));
364}
365
366TEST_F(StructuralEquivalenceCXXMethodTest, Const) {
367 auto t = makeNamedDecls("struct X { void foo(); };",
368 "struct X { void foo() const; };", Lang_CXX);
369 EXPECT_FALSE(testStructuralMatch(t));
370}
371
372TEST_F(StructuralEquivalenceCXXMethodTest, Static) {
373 auto t = makeNamedDecls("struct X { void foo(); };",
374 "struct X { static void foo(); };", Lang_CXX);
375 EXPECT_FALSE(testStructuralMatch(t));
376}
377
378TEST_F(StructuralEquivalenceCXXMethodTest, Ref1) {
379 auto t = makeNamedDecls("struct X { void foo(); };",
380 "struct X { void foo() &&; };", Lang_CXX11);
381 EXPECT_FALSE(testStructuralMatch(t));
382}
383
384TEST_F(StructuralEquivalenceCXXMethodTest, Ref2) {
385 auto t = makeNamedDecls("struct X { void foo() &; };",
386 "struct X { void foo() &&; };", Lang_CXX11);
387 EXPECT_FALSE(testStructuralMatch(t));
388}
389
390TEST_F(StructuralEquivalenceCXXMethodTest, AccessSpecifier) {
391 auto t = makeDecls<CXXMethodDecl>(
392 "struct X { public: void foo(); };",
393 "struct X { private: void foo(); };", Lang_CXX,
394 cxxMethodDecl(hasName("foo")));
395 EXPECT_FALSE(testStructuralMatch(t));
396}
397
398TEST_F(StructuralEquivalenceCXXMethodTest, Delete) {
399 auto t = makeNamedDecls("struct X { void foo(); };",
400 "struct X { void foo() = delete; };", Lang_CXX11);
401 EXPECT_FALSE(testStructuralMatch(t));
402}
403
404TEST_F(StructuralEquivalenceCXXMethodTest, Constructor) {
405 auto t = makeDecls<FunctionDecl>(
406 "void foo();", "struct foo { foo(); };", Lang_CXX,
407 functionDecl(), cxxConstructorDecl());
408 EXPECT_FALSE(testStructuralMatch(t));
409}
410
411TEST_F(StructuralEquivalenceCXXMethodTest, ConstructorParam) {
412 auto t = makeDecls<CXXConstructorDecl>("struct X { X(); };",
413 "struct X { X(int); };", Lang_CXX,
414 cxxConstructorDecl());
415 EXPECT_FALSE(testStructuralMatch(t));
416}
417
418TEST_F(StructuralEquivalenceCXXMethodTest, ConstructorExplicit) {
419 auto t = makeDecls<CXXConstructorDecl>("struct X { X(int); };",
420 "struct X { explicit X(int); };",
421 Lang_CXX11,
422 cxxConstructorDecl());
423 EXPECT_FALSE(testStructuralMatch(t));
424}
425
426TEST_F(StructuralEquivalenceCXXMethodTest, ConstructorDefault) {
427 auto t = makeDecls<CXXConstructorDecl>("struct X { X(); };",
428 "struct X { X() = default; };",
429 Lang_CXX11,
430 cxxConstructorDecl());
431 EXPECT_FALSE(testStructuralMatch(t));
432}
433
434TEST_F(StructuralEquivalenceCXXMethodTest, Conversion) {
435 auto t = makeDecls<CXXConversionDecl>("struct X { operator bool(); };",
436 "struct X { operator char(); };",
437 Lang_CXX11,
438 cxxConversionDecl());
439 EXPECT_FALSE(testStructuralMatch(t));
440}
441
442TEST_F(StructuralEquivalenceCXXMethodTest, Operator) {
443 auto t = makeDecls<FunctionDecl>(
444 "struct X { int operator +(int); };",
445 "struct X { int operator -(int); };", Lang_CXX,
446 functionDecl(hasOverloadedOperatorName("+")),
447 functionDecl(hasOverloadedOperatorName("-")));
448 EXPECT_FALSE(testStructuralMatch(t));
449}
450
451TEST_F(StructuralEquivalenceCXXMethodTest, OutOfClass1) {
452 auto t = makeDecls<FunctionDecl>(
453 "struct X { virtual void f(); }; void X::f() { }",
454 "struct X { virtual void f() { }; };",
455 Lang_CXX,
456 functionDecl(allOf(hasName("f"), isDefinition())));
457 EXPECT_TRUE(testStructuralMatch(t));
458}
459
460TEST_F(StructuralEquivalenceCXXMethodTest, OutOfClass2) {
461 auto t = makeDecls<FunctionDecl>(
462 "struct X { virtual void f(); }; void X::f() { }",
463 "struct X { void f(); }; void X::f() { }",
464 Lang_CXX,
465 functionDecl(allOf(hasName("f"), isDefinition())));
466 EXPECT_FALSE(testStructuralMatch(t));
467}
468
469struct StructuralEquivalenceRecordTest : StructuralEquivalenceTest {
470};
471
472TEST_F(StructuralEquivalenceRecordTest, Name) {
473 auto t = makeDecls<CXXRecordDecl>(
474 "struct A{ };",
475 "struct B{ };",
476 Lang_CXX,
477 cxxRecordDecl());
478 EXPECT_FALSE(testStructuralMatch(t));
479}
480
481TEST_F(StructuralEquivalenceRecordTest, Fields) {
482 auto t = makeNamedDecls(
483 "struct foo{ int x; };",
484 "struct foo{ char x; };",
485 Lang_CXX);
486 EXPECT_FALSE(testStructuralMatch(t));
487}
488
489TEST_F(StructuralEquivalenceRecordTest, DISABLED_Methods) {
490 // Currently, methods of a class are not checked at class equivalence.
491 auto t = makeNamedDecls(
492 "struct foo{ int x(); };",
493 "struct foo{ char x(); };",
494 Lang_CXX);
495 EXPECT_FALSE(testStructuralMatch(t));
496}
497
498TEST_F(StructuralEquivalenceRecordTest, Bases) {
499 auto t = makeNamedDecls(
500 "struct A{ }; struct foo: A { };",
501 "struct B{ }; struct foo: B { };",
502 Lang_CXX);
503 EXPECT_FALSE(testStructuralMatch(t));
504}
505
506TEST_F(StructuralEquivalenceRecordTest, InheritanceVirtual) {
507 auto t = makeNamedDecls(
508 "struct A{ }; struct foo: A { };",
509 "struct A{ }; struct foo: virtual A { };",
510 Lang_CXX);
511 EXPECT_FALSE(testStructuralMatch(t));
512}
513
514TEST_F(StructuralEquivalenceRecordTest, DISABLED_InheritanceType) {
515 // Access specifier in inheritance is not checked yet.
516 auto t = makeNamedDecls(
517 "struct A{ }; struct foo: public A { };",
518 "struct A{ }; struct foo: private A { };",
519 Lang_CXX);
520 EXPECT_FALSE(testStructuralMatch(t));
521}
522
523TEST_F(StructuralEquivalenceRecordTest, Match) {
524 auto Code = R"(
525 struct A{ };
526 struct B{ };
527 struct foo: A, virtual B {
528 void x();
529 int a;
530 };
531 )";
532 auto t = makeNamedDecls(Code, Code, Lang_CXX);
533 EXPECT_TRUE(testStructuralMatch(t));
534}
535
536TEST_F(StructuralEquivalenceTest, CompareSameDeclWithMultiple) {
537 auto t = makeNamedDecls(
538 "struct A{ }; struct B{ }; void foo(A a, A b);",
539 "struct A{ }; struct B{ }; void foo(A a, B b);",
540 Lang_CXX);
541 EXPECT_FALSE(testStructuralMatch(t));
542}
543
Gabor Marton1f667532018-05-24 08:41:07 +0000544} // end namespace ast_matchers
545} // end namespace clang