1 #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 
12 namespace clang {
13 namespace ast_matchers {
14 
15 using std::get;
16 
17 struct StructuralEquivalenceTest : ::testing::Test {
18   std::unique_ptr<ASTUnit> AST0, AST1;
19   std::string Code0, Code1; // Buffers for SourceManager
20 
21   // 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) {
28     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 
37     NodeType *D0 = FirstDeclMatcher<NodeType>().match(
38         AST0->getASTContext().getTranslationUnitDecl(), Matcher0);
39     NodeType *D1 = FirstDeclMatcher<NodeType>().match(
40         AST1->getASTContext().getTranslationUnitDecl(), Matcher1);
41 
42     return std::make_tuple(D0, D1);
43   }
44 
45   std::tuple<TranslationUnitDecl *, TranslationUnitDecl *> makeTuDecls(
46       const std::string &SrcCode0, const std::string &SrcCode1, Language Lang) {
47     this->Code0 = SrcCode0;
48     this->Code1 = SrcCode1;
49     ArgVector Args = getBasicRunOptionsForLanguage(Lang);
50 
51     const char *const InputFileName = "input.cc";
52 
53     AST0 = tooling::buildASTFromCodeWithArgs(Code0, Args, InputFileName);
54     AST1 = tooling::buildASTFromCodeWithArgs(Code1, Args, InputFileName);
55 
56     return std::make_tuple(AST0->getASTContext().getTranslationUnitDecl(),
57                            AST1->getASTContext().getTranslationUnitDecl());
58   }
59 
60   // Get a pair of node pointers into the synthesized AST from the given code
61   // snippets. The same matcher is used for both snippets.
62   template <typename NodeType, typename MatcherType>
63   std::tuple<NodeType *, NodeType *> makeDecls(
64       const std::string &SrcCode0, const std::string &SrcCode1, Language Lang,
65       const MatcherType &AMatcher) {
66     return makeDecls<NodeType, MatcherType>(
67           SrcCode0, SrcCode1, Lang, AMatcher, AMatcher);
68   }
69 
70   // Get a pair of Decl pointers to the synthesized declarations from the given
71   // code snippets. We search for the first NamedDecl with given name in both
72   // snippets.
73   std::tuple<NamedDecl *, NamedDecl *> makeNamedDecls(
74       const std::string &SrcCode0, const std::string &SrcCode1,
75       Language Lang, const char *const Identifier = "foo") {
76     auto Matcher = namedDecl(hasName(Identifier));
77     return makeDecls<NamedDecl>(SrcCode0, SrcCode1, Lang, Matcher);
78   }
79 
80   bool testStructuralMatch(Decl *D0, Decl *D1) {
81     llvm::DenseSet<std::pair<Decl *, Decl *>> NonEquivalentDecls01;
82     llvm::DenseSet<std::pair<Decl *, Decl *>> NonEquivalentDecls10;
83     StructuralEquivalenceContext Ctx01(
84         D0->getASTContext(), D1->getASTContext(),
85         NonEquivalentDecls01, StructuralEquivalenceKind::Default, false, false);
86     StructuralEquivalenceContext Ctx10(
87         D1->getASTContext(), D0->getASTContext(),
88         NonEquivalentDecls10, StructuralEquivalenceKind::Default, false, false);
89     bool Eq01 = Ctx01.IsEquivalent(D0, D1);
90     bool Eq10 = Ctx10.IsEquivalent(D1, D0);
91     EXPECT_EQ(Eq01, Eq10);
92     return Eq01;
93   }
94 
95   bool testStructuralMatch(std::tuple<Decl *, Decl *> t) {
96     return testStructuralMatch(get<0>(t), get<1>(t));
97   }
98 };
99 
100 TEST_F(StructuralEquivalenceTest, Int) {
101   auto Decls = makeNamedDecls("int foo;", "int foo;", Lang_CXX);
102   EXPECT_TRUE(testStructuralMatch(Decls));
103 }
104 
105 TEST_F(StructuralEquivalenceTest, IntVsSignedInt) {
106   auto Decls = makeNamedDecls("int foo;", "signed int foo;", Lang_CXX);
107   EXPECT_TRUE(testStructuralMatch(Decls));
108 }
109 
110 TEST_F(StructuralEquivalenceTest, Char) {
111   auto Decls = makeNamedDecls("char foo;", "char foo;", Lang_CXX);
112   EXPECT_TRUE(testStructuralMatch(Decls));
113 }
114 
115 // This test is disabled for now.
116 // FIXME Whether this is equivalent is dependendant on the target.
117 TEST_F(StructuralEquivalenceTest, DISABLED_CharVsSignedChar) {
118   auto Decls = makeNamedDecls("char foo;", "signed char foo;", Lang_CXX);
119   EXPECT_FALSE(testStructuralMatch(Decls));
120 }
121 
122 TEST_F(StructuralEquivalenceTest, ForwardRecordDecl) {
123   auto Decls = makeNamedDecls("struct foo;", "struct foo;", Lang_CXX);
124   EXPECT_TRUE(testStructuralMatch(Decls));
125 }
126 
127 TEST_F(StructuralEquivalenceTest, IntVsSignedIntInStruct) {
128   auto Decls = makeNamedDecls("struct foo { int x; };",
129                               "struct foo { signed int x; };", Lang_CXX);
130   EXPECT_TRUE(testStructuralMatch(Decls));
131 }
132 
133 TEST_F(StructuralEquivalenceTest, CharVsSignedCharInStruct) {
134   auto Decls = makeNamedDecls("struct foo { char x; };",
135                               "struct foo { signed char x; };", Lang_CXX);
136   EXPECT_FALSE(testStructuralMatch(Decls));
137 }
138 
139 TEST_F(StructuralEquivalenceTest, IntVsSignedIntTemplateSpec) {
140   auto Decls = makeDecls<ClassTemplateSpecializationDecl>(
141       R"(template <class T> struct foo; template<> struct foo<int>{};)",
142       R"(template <class T> struct foo; template<> struct foo<signed int>{};)",
143       Lang_CXX,
144       classTemplateSpecializationDecl());
145   auto Spec0 = get<0>(Decls);
146   auto Spec1 = get<1>(Decls);
147   EXPECT_TRUE(testStructuralMatch(Spec0, Spec1));
148 }
149 
150 TEST_F(StructuralEquivalenceTest, CharVsSignedCharTemplateSpec) {
151   auto Decls = makeDecls<ClassTemplateSpecializationDecl>(
152       R"(template <class T> struct foo; template<> struct foo<char>{};)",
153       R"(template <class T> struct foo; template<> struct foo<signed char>{};)",
154       Lang_CXX,
155       classTemplateSpecializationDecl());
156   auto Spec0 = get<0>(Decls);
157   auto Spec1 = get<1>(Decls);
158   EXPECT_FALSE(testStructuralMatch(Spec0, Spec1));
159 }
160 
161 TEST_F(StructuralEquivalenceTest, CharVsSignedCharTemplateSpecWithInheritance) {
162   auto Decls = makeDecls<ClassTemplateSpecializationDecl>(
163       R"(
164       struct true_type{};
165       template <class T> struct foo;
166       template<> struct foo<char> : true_type {};
167       )",
168       R"(
169       struct true_type{};
170       template <class T> struct foo;
171       template<> struct foo<signed char> : true_type {};
172       )",
173       Lang_CXX,
174       classTemplateSpecializationDecl());
175   EXPECT_FALSE(testStructuralMatch(Decls));
176 }
177 
178 // This test is disabled for now.
179 // FIXME Enable it, once the check is implemented.
180 TEST_F(StructuralEquivalenceTest, DISABLED_WrongOrderInNamespace) {
181   auto Code =
182       R"(
183       namespace NS {
184       template <class T> class Base {
185           int a;
186       };
187       class Derived : Base<Derived> {
188       };
189       }
190       void foo(NS::Derived &);
191       )";
192   auto Decls = makeNamedDecls(Code, Code, Lang_CXX);
193 
194   NamespaceDecl *NS =
195       LastDeclMatcher<NamespaceDecl>().match(get<1>(Decls), namespaceDecl());
196   ClassTemplateDecl *TD = LastDeclMatcher<ClassTemplateDecl>().match(
197       get<1>(Decls), classTemplateDecl(hasName("Base")));
198 
199   // Reorder the decls, move the TD to the last place in the DC.
200   NS->removeDecl(TD);
201   NS->addDeclInternal(TD);
202 
203   EXPECT_FALSE(testStructuralMatch(Decls));
204 }
205 
206 TEST_F(StructuralEquivalenceTest, WrongOrderOfFieldsInClass) {
207   auto Code = "class X { int a; int b; };";
208   auto Decls = makeNamedDecls(Code, Code, Lang_CXX, "X");
209 
210   CXXRecordDecl *RD = FirstDeclMatcher<CXXRecordDecl>().match(
211       get<1>(Decls), cxxRecordDecl(hasName("X")));
212   FieldDecl *FD =
213       FirstDeclMatcher<FieldDecl>().match(get<1>(Decls), fieldDecl(hasName("a")));
214 
215   // Reorder the FieldDecls
216   RD->removeDecl(FD);
217   RD->addDeclInternal(FD);
218 
219   EXPECT_FALSE(testStructuralMatch(Decls));
220 }
221 
222 struct StructuralEquivalenceFunctionTest : StructuralEquivalenceTest {
223 };
224 
225 TEST_F(StructuralEquivalenceFunctionTest, TemplateVsNonTemplate) {
226   auto t = makeNamedDecls(
227       "void foo();",
228       "template<class T> void foo();",
229       Lang_CXX);
230   EXPECT_FALSE(testStructuralMatch(t));
231 }
232 
233 TEST_F(StructuralEquivalenceFunctionTest, ParamConstWithRef) {
234   auto t = makeNamedDecls("void foo(int&);",
235                           "void foo(const int&);", Lang_CXX);
236   EXPECT_FALSE(testStructuralMatch(t));
237 }
238 
239 TEST_F(StructuralEquivalenceFunctionTest, ParamConstSimple) {
240   auto t = makeNamedDecls("void foo(int);",
241                           "void foo(const int);", Lang_CXX);
242   EXPECT_TRUE(testStructuralMatch(t));
243   // consider this OK
244 }
245 
246 TEST_F(StructuralEquivalenceFunctionTest, Throw) {
247   auto t = makeNamedDecls("void foo();",
248                           "void foo() throw();", Lang_CXX);
249   EXPECT_FALSE(testStructuralMatch(t));
250 }
251 
252 TEST_F(StructuralEquivalenceFunctionTest, Noexcept) {
253   auto t = makeNamedDecls("void foo();",
254                           "void foo() noexcept;", Lang_CXX11);
255   EXPECT_FALSE(testStructuralMatch(t));
256 }
257 
258 TEST_F(StructuralEquivalenceFunctionTest, ThrowVsNoexcept) {
259   auto t = makeNamedDecls("void foo() throw();",
260                           "void foo() noexcept;", Lang_CXX11);
261   EXPECT_FALSE(testStructuralMatch(t));
262 }
263 
264 TEST_F(StructuralEquivalenceFunctionTest, ThrowVsNoexceptFalse) {
265   auto t = makeNamedDecls("void foo() throw();",
266                           "void foo() noexcept(false);", Lang_CXX11);
267   EXPECT_FALSE(testStructuralMatch(t));
268 }
269 
270 TEST_F(StructuralEquivalenceFunctionTest, ThrowVsNoexceptTrue) {
271   auto t = makeNamedDecls("void foo() throw();",
272                           "void foo() noexcept(true);", Lang_CXX11);
273   EXPECT_FALSE(testStructuralMatch(t));
274 }
275 
276 TEST_F(StructuralEquivalenceFunctionTest, DISABLED_NoexceptNonMatch) {
277   // The expression is not checked yet.
278   auto t = makeNamedDecls("void foo() noexcept(false);",
279                           "void foo() noexcept(true);", Lang_CXX11);
280   EXPECT_FALSE(testStructuralMatch(t));
281 }
282 
283 TEST_F(StructuralEquivalenceFunctionTest, NoexceptMatch) {
284   auto t = makeNamedDecls("void foo() noexcept(false);",
285                           "void foo() noexcept(false);", Lang_CXX11);
286   EXPECT_TRUE(testStructuralMatch(t));
287 }
288 
289 TEST_F(StructuralEquivalenceFunctionTest, NoexceptVsNoexceptFalse) {
290   auto t = makeNamedDecls("void foo() noexcept;",
291                           "void foo() noexcept(false);", Lang_CXX11);
292   EXPECT_FALSE(testStructuralMatch(t));
293 }
294 
295 TEST_F(StructuralEquivalenceFunctionTest, NoexceptVsNoexceptTrue) {
296   auto t = makeNamedDecls("void foo() noexcept;",
297                           "void foo() noexcept(true);", Lang_CXX11);
298   EXPECT_FALSE(testStructuralMatch(t));
299 }
300 
301 TEST_F(StructuralEquivalenceFunctionTest, ReturnType) {
302   auto t = makeNamedDecls("char foo();",
303                           "int foo();", Lang_CXX);
304   EXPECT_FALSE(testStructuralMatch(t));
305 }
306 
307 TEST_F(StructuralEquivalenceFunctionTest, ReturnConst) {
308   auto t = makeNamedDecls("char foo();",
309                           "const char foo();", Lang_CXX);
310   EXPECT_FALSE(testStructuralMatch(t));
311 }
312 
313 TEST_F(StructuralEquivalenceFunctionTest, ReturnRef) {
314   auto t = makeNamedDecls("char &foo();",
315                           "char &&foo();", Lang_CXX11);
316   EXPECT_FALSE(testStructuralMatch(t));
317 }
318 
319 TEST_F(StructuralEquivalenceFunctionTest, ParamCount) {
320   auto t = makeNamedDecls("void foo(int);",
321                           "void foo(int, int);", Lang_CXX);
322   EXPECT_FALSE(testStructuralMatch(t));
323 }
324 
325 TEST_F(StructuralEquivalenceFunctionTest, ParamType) {
326   auto t = makeNamedDecls("void foo(int);",
327                           "void foo(char);", Lang_CXX);
328   EXPECT_FALSE(testStructuralMatch(t));
329 }
330 
331 TEST_F(StructuralEquivalenceFunctionTest, ParamName) {
332   auto t = makeNamedDecls("void foo(int a);",
333                           "void foo(int b);", Lang_CXX);
334   EXPECT_TRUE(testStructuralMatch(t));
335 }
336 
337 TEST_F(StructuralEquivalenceFunctionTest, Variadic) {
338   auto t = makeNamedDecls("void foo(int x...);",
339                           "void foo(int x);", Lang_CXX);
340   EXPECT_FALSE(testStructuralMatch(t));
341 }
342 
343 TEST_F(StructuralEquivalenceFunctionTest, ParamPtr) {
344   auto t = makeNamedDecls("void foo(int *);",
345                           "void foo(int);", Lang_CXX);
346   EXPECT_FALSE(testStructuralMatch(t));
347 }
348 
349 TEST_F(StructuralEquivalenceFunctionTest, NameInParen) {
350   auto t = makeNamedDecls(
351       "void ((foo))();",
352       "void foo();",
353       Lang_CXX);
354   EXPECT_TRUE(testStructuralMatch(t));
355 }
356 
357 TEST_F(StructuralEquivalenceFunctionTest, NameInParenWithExceptionSpec) {
358   auto t = makeNamedDecls(
359       "void (foo)() throw(int);",
360       "void (foo)() noexcept;",
361       Lang_CXX11);
362   EXPECT_FALSE(testStructuralMatch(t));
363 }
364 
365 TEST_F(StructuralEquivalenceFunctionTest, NameInParenWithConst) {
366   auto t = makeNamedDecls(
367       "struct A { void (foo)() const; };",
368       "struct A { void (foo)(); };",
369       Lang_CXX11);
370   EXPECT_FALSE(testStructuralMatch(t));
371 }
372 
373 struct StructuralEquivalenceCXXMethodTest : StructuralEquivalenceTest {
374 };
375 
376 TEST_F(StructuralEquivalenceCXXMethodTest, Virtual) {
377   auto t = makeDecls<CXXMethodDecl>(
378       "struct X { void foo(); };",
379       "struct X { virtual void foo(); };", Lang_CXX,
380       cxxMethodDecl(hasName("foo")));
381   EXPECT_FALSE(testStructuralMatch(t));
382 }
383 
384 TEST_F(StructuralEquivalenceCXXMethodTest, Pure) {
385   auto t = makeNamedDecls("struct X { virtual void foo(); };",
386                           "struct X { virtual void foo() = 0; };", Lang_CXX);
387   EXPECT_FALSE(testStructuralMatch(t));
388 }
389 
390 TEST_F(StructuralEquivalenceCXXMethodTest, DISABLED_Final) {
391   // The final-ness is not checked yet.
392   auto t = makeNamedDecls("struct X { virtual void foo(); };",
393                           "struct X { virtual void foo() final; };", Lang_CXX);
394   EXPECT_FALSE(testStructuralMatch(t));
395 }
396 
397 TEST_F(StructuralEquivalenceCXXMethodTest, Const) {
398   auto t = makeNamedDecls("struct X { void foo(); };",
399                           "struct X { void foo() const; };", Lang_CXX);
400   EXPECT_FALSE(testStructuralMatch(t));
401 }
402 
403 TEST_F(StructuralEquivalenceCXXMethodTest, Static) {
404   auto t = makeNamedDecls("struct X { void foo(); };",
405                           "struct X { static void foo(); };", Lang_CXX);
406   EXPECT_FALSE(testStructuralMatch(t));
407 }
408 
409 TEST_F(StructuralEquivalenceCXXMethodTest, Ref1) {
410   auto t = makeNamedDecls("struct X { void foo(); };",
411                           "struct X { void foo() &&; };", Lang_CXX11);
412   EXPECT_FALSE(testStructuralMatch(t));
413 }
414 
415 TEST_F(StructuralEquivalenceCXXMethodTest, Ref2) {
416   auto t = makeNamedDecls("struct X { void foo() &; };",
417                           "struct X { void foo() &&; };", Lang_CXX11);
418   EXPECT_FALSE(testStructuralMatch(t));
419 }
420 
421 TEST_F(StructuralEquivalenceCXXMethodTest, AccessSpecifier) {
422   auto t = makeDecls<CXXMethodDecl>(
423       "struct X { public: void foo(); };",
424       "struct X { private: void foo(); };", Lang_CXX,
425       cxxMethodDecl(hasName("foo")));
426   EXPECT_FALSE(testStructuralMatch(t));
427 }
428 
429 TEST_F(StructuralEquivalenceCXXMethodTest, Delete) {
430   auto t = makeNamedDecls("struct X { void foo(); };",
431                           "struct X { void foo() = delete; };", Lang_CXX11);
432   EXPECT_FALSE(testStructuralMatch(t));
433 }
434 
435 TEST_F(StructuralEquivalenceCXXMethodTest, Constructor) {
436   auto t = makeDecls<FunctionDecl>(
437       "void foo();", "struct foo { foo(); };", Lang_CXX,
438       functionDecl(hasName("foo")), cxxConstructorDecl(hasName("foo")));
439   EXPECT_FALSE(testStructuralMatch(t));
440 }
441 
442 TEST_F(StructuralEquivalenceCXXMethodTest, ConstructorParam) {
443   auto t = makeDecls<CXXConstructorDecl>("struct X { X(); };",
444                                          "struct X { X(int); };", Lang_CXX,
445                                          cxxConstructorDecl(hasName("X")));
446   EXPECT_FALSE(testStructuralMatch(t));
447 }
448 
449 TEST_F(StructuralEquivalenceCXXMethodTest, ConstructorExplicit) {
450   auto t = makeDecls<CXXConstructorDecl>("struct X { X(int); };",
451                                          "struct X { explicit X(int); };",
452                                          Lang_CXX11,
453                                          cxxConstructorDecl(hasName("X")));
454   EXPECT_FALSE(testStructuralMatch(t));
455 }
456 
457 TEST_F(StructuralEquivalenceCXXMethodTest, ConstructorDefault) {
458   auto t = makeDecls<CXXConstructorDecl>("struct X { X(); };",
459                                          "struct X { X() = default; };",
460                                          Lang_CXX11,
461                                          cxxConstructorDecl(hasName("X")));
462   EXPECT_FALSE(testStructuralMatch(t));
463 }
464 
465 TEST_F(StructuralEquivalenceCXXMethodTest, Conversion) {
466   auto t = makeDecls<CXXConversionDecl>("struct X { operator bool(); };",
467                                         "struct X { operator char(); };",
468                                          Lang_CXX11,
469                                          cxxConversionDecl());
470   EXPECT_FALSE(testStructuralMatch(t));
471 }
472 
473 TEST_F(StructuralEquivalenceCXXMethodTest, Operator) {
474   auto t = makeDecls<FunctionDecl>(
475       "struct X { int operator +(int); };",
476       "struct X { int operator -(int); };", Lang_CXX,
477       functionDecl(hasOverloadedOperatorName("+")),
478       functionDecl(hasOverloadedOperatorName("-")));
479   EXPECT_FALSE(testStructuralMatch(t));
480 }
481 
482 TEST_F(StructuralEquivalenceCXXMethodTest, OutOfClass1) {
483   auto t = makeDecls<FunctionDecl>(
484       "struct X { virtual void f(); }; void X::f() { }",
485       "struct X { virtual void f() { }; };",
486       Lang_CXX,
487       functionDecl(allOf(hasName("f"), isDefinition())));
488   EXPECT_TRUE(testStructuralMatch(t));
489 }
490 
491 TEST_F(StructuralEquivalenceCXXMethodTest, OutOfClass2) {
492   auto t = makeDecls<FunctionDecl>(
493       "struct X { virtual void f(); }; void X::f() { }",
494       "struct X { void f(); }; void X::f() { }",
495       Lang_CXX,
496       functionDecl(allOf(hasName("f"), isDefinition())));
497   EXPECT_FALSE(testStructuralMatch(t));
498 }
499 
500 struct StructuralEquivalenceRecordTest : StructuralEquivalenceTest {
501   // FIXME Use a common getRecordDecl with ASTImporterTest.cpp!
502   RecordDecl *getRecordDecl(FieldDecl *FD) {
503     auto *ET = cast<ElaboratedType>(FD->getType().getTypePtr());
504     return cast<RecordType>(ET->getNamedType().getTypePtr())->getDecl();
505   };
506 };
507 
508 TEST_F(StructuralEquivalenceRecordTest, Name) {
509   auto t = makeDecls<CXXRecordDecl>(
510       "struct A{ };",
511       "struct B{ };",
512       Lang_CXX,
513       cxxRecordDecl(hasName("A")),
514       cxxRecordDecl(hasName("B")));
515   EXPECT_FALSE(testStructuralMatch(t));
516 }
517 
518 TEST_F(StructuralEquivalenceRecordTest, Fields) {
519   auto t = makeNamedDecls(
520       "struct foo{ int x; };",
521       "struct foo{ char x; };",
522       Lang_CXX);
523   EXPECT_FALSE(testStructuralMatch(t));
524 }
525 
526 TEST_F(StructuralEquivalenceRecordTest, DISABLED_Methods) {
527   // Currently, methods of a class are not checked at class equivalence.
528   auto t = makeNamedDecls(
529       "struct foo{ int x(); };",
530       "struct foo{ char x(); };",
531       Lang_CXX);
532   EXPECT_FALSE(testStructuralMatch(t));
533 }
534 
535 TEST_F(StructuralEquivalenceRecordTest, Bases) {
536   auto t = makeNamedDecls(
537       "struct A{ }; struct foo: A { };",
538       "struct B{ }; struct foo: B { };",
539       Lang_CXX);
540   EXPECT_FALSE(testStructuralMatch(t));
541 }
542 
543 TEST_F(StructuralEquivalenceRecordTest, InheritanceVirtual) {
544   auto t = makeNamedDecls(
545       "struct A{ }; struct foo: A { };",
546       "struct A{ }; struct foo: virtual A { };",
547       Lang_CXX);
548   EXPECT_FALSE(testStructuralMatch(t));
549 }
550 
551 TEST_F(StructuralEquivalenceRecordTest, DISABLED_InheritanceType) {
552   // Access specifier in inheritance is not checked yet.
553   auto t = makeNamedDecls(
554       "struct A{ }; struct foo: public A { };",
555       "struct A{ }; struct foo: private A { };",
556       Lang_CXX);
557   EXPECT_FALSE(testStructuralMatch(t));
558 }
559 
560 TEST_F(StructuralEquivalenceRecordTest, Match) {
561   auto Code = R"(
562       struct A{ };
563       struct B{ };
564       struct foo: A, virtual B {
565         void x();
566         int a;
567       };
568       )";
569   auto t = makeNamedDecls(Code, Code, Lang_CXX);
570   EXPECT_TRUE(testStructuralMatch(t));
571 }
572 
573 TEST_F(StructuralEquivalenceRecordTest, UnnamedRecordsShouldBeInequivalent) {
574   auto t = makeTuDecls(
575       R"(
576       struct A {
577         struct {
578           struct A *next;
579         } entry0;
580         struct {
581           struct A *next;
582         } entry1;
583       };
584       )",
585       "", Lang_C);
586   auto *TU = get<0>(t);
587   auto *Entry0 =
588       FirstDeclMatcher<FieldDecl>().match(TU, fieldDecl(hasName("entry0")));
589   auto *Entry1 =
590       FirstDeclMatcher<FieldDecl>().match(TU, fieldDecl(hasName("entry1")));
591   auto *R0 = getRecordDecl(Entry0);
592   auto *R1 = getRecordDecl(Entry1);
593 
594   ASSERT_NE(R0, R1);
595   EXPECT_TRUE(testStructuralMatch(R0, R0));
596   EXPECT_TRUE(testStructuralMatch(R1, R1));
597   EXPECT_FALSE(testStructuralMatch(R0, R1));
598 }
599 
600 TEST_F(StructuralEquivalenceRecordTest,
601        UnnamedRecordsShouldBeInequivalentEvenIfTheSecondIsBeingDefined) {
602   auto Code =
603       R"(
604       struct A {
605         struct {
606           struct A *next;
607         } entry0;
608         struct {
609           struct A *next;
610         } entry1;
611       };
612       )";
613   auto t = makeTuDecls(Code, Code, Lang_C);
614 
615   auto *FromTU = get<0>(t);
616   auto *Entry1 =
617       FirstDeclMatcher<FieldDecl>().match(FromTU, fieldDecl(hasName("entry1")));
618 
619   auto *ToTU = get<1>(t);
620   auto *Entry0 =
621       FirstDeclMatcher<FieldDecl>().match(ToTU, fieldDecl(hasName("entry0")));
622   auto *A =
623       FirstDeclMatcher<RecordDecl>().match(ToTU, recordDecl(hasName("A")));
624   A->startDefinition(); // Set isBeingDefined, getDefinition() will return a
625                         // nullptr. This may be the case during ASTImport.
626 
627   auto *R0 = getRecordDecl(Entry0);
628   auto *R1 = getRecordDecl(Entry1);
629 
630   ASSERT_NE(R0, R1);
631   EXPECT_TRUE(testStructuralMatch(R0, R0));
632   EXPECT_TRUE(testStructuralMatch(R1, R1));
633   EXPECT_FALSE(testStructuralMatch(R0, R1));
634 }
635 
636 TEST_F(StructuralEquivalenceRecordTest, TemplateVsNonTemplate) {
637   auto t = makeDecls<CXXRecordDecl>(
638       "struct A { };",
639       "template<class T> struct A { };",
640       Lang_CXX,
641       cxxRecordDecl(hasName("A")));
642   EXPECT_FALSE(testStructuralMatch(t));
643 }
644 
645 TEST_F(StructuralEquivalenceRecordTest,
646     FwdDeclRecordShouldBeEqualWithFwdDeclRecord) {
647   auto t = makeNamedDecls("class foo;", "class foo;", Lang_CXX11);
648   EXPECT_TRUE(testStructuralMatch(t));
649 }
650 
651 TEST_F(StructuralEquivalenceRecordTest,
652        FwdDeclRecordShouldBeEqualWithRecordWhichHasDefinition) {
653   auto t =
654       makeNamedDecls("class foo;", "class foo { int A; };", Lang_CXX11);
655   EXPECT_TRUE(testStructuralMatch(t));
656 }
657 
658 TEST_F(StructuralEquivalenceRecordTest,
659        RecordShouldBeEqualWithRecordWhichHasDefinition) {
660   auto t = makeNamedDecls("class foo { int A; };", "class foo { int A; };",
661                           Lang_CXX11);
662   EXPECT_TRUE(testStructuralMatch(t));
663 }
664 
665 TEST_F(StructuralEquivalenceRecordTest, RecordsWithDifferentBody) {
666   auto t = makeNamedDecls("class foo { int B; };", "class foo { int A; };",
667                           Lang_CXX11);
668   EXPECT_FALSE(testStructuralMatch(t));
669 }
670 
671 TEST_F(StructuralEquivalenceTest, CompareSameDeclWithMultiple) {
672   auto t = makeNamedDecls(
673       "struct A{ }; struct B{ }; void foo(A a, A b);",
674       "struct A{ }; struct B{ }; void foo(A a, B b);",
675       Lang_CXX);
676   EXPECT_FALSE(testStructuralMatch(t));
677 }
678 
679 struct StructuralEquivalenceEnumTest : StructuralEquivalenceTest {};
680 
681 TEST_F(StructuralEquivalenceEnumTest, FwdDeclEnumShouldBeEqualWithFwdDeclEnum) {
682   auto t = makeNamedDecls("enum class foo;", "enum class foo;", Lang_CXX11);
683   EXPECT_TRUE(testStructuralMatch(t));
684 }
685 
686 TEST_F(StructuralEquivalenceEnumTest,
687        FwdDeclEnumShouldBeEqualWithEnumWhichHasDefinition) {
688   auto t =
689       makeNamedDecls("enum class foo;", "enum class foo { A };", Lang_CXX11);
690   EXPECT_TRUE(testStructuralMatch(t));
691 }
692 
693 TEST_F(StructuralEquivalenceEnumTest,
694        EnumShouldBeEqualWithEnumWhichHasDefinition) {
695   auto t = makeNamedDecls("enum class foo { A };", "enum class foo { A };",
696                           Lang_CXX11);
697   EXPECT_TRUE(testStructuralMatch(t));
698 }
699 
700 TEST_F(StructuralEquivalenceEnumTest, EnumsWithDifferentBody) {
701   auto t = makeNamedDecls("enum class foo { B };", "enum class foo { A };",
702                           Lang_CXX11);
703   EXPECT_FALSE(testStructuralMatch(t));
704 }
705 
706 
707 } // end namespace ast_matchers
708 } // end namespace clang
709