Clang Project

clang_source_code/unittests/AST/StructuralEquivalenceTest.cpp
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
12namespace clang {
13namespace ast_matchers {
14
15using std::get;
16
17struct StructuralEquivalenceTest : ::testing::Test {
18  std::unique_ptr<ASTUnit> AST0AST1;
19  std::string Code0Code1// 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 &SrcCode0const std::string &SrcCode1Language Lang,
27      const MatcherType &Matcher0const 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(D0D1);
43  }
44
45  std::tuple<TranslationUnitDecl *, TranslationUnitDecl *> makeTuDecls(
46      const std::string &SrcCode0const std::string &SrcCode1Language 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 &SrcCode0const std::string &SrcCode1Language Lang,
65      const MatcherType &AMatcher) {
66    return makeDecls<NodeType, MatcherType>(
67          SrcCode0SrcCode1LangAMatcherAMatcher);
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 &SrcCode0const std::string &SrcCode1,
75      Language Langconst char *const Identifier = "foo") {
76    auto Matcher = namedDecl(hasName(Identifier));
77    return makeDecls<NamedDecl>(SrcCode0, SrcCode1, Lang, Matcher);
78  }
79
80  bool testStructuralMatch(Decl *D0Decl *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, falsefalse);
86    StructuralEquivalenceContext Ctx10(
87        D1->getASTContext(), D0->getASTContext(),
88        NonEquivalentDecls10, StructuralEquivalenceKind::Default, falsefalse);
89    bool Eq01 = Ctx01.IsEquivalent(D0D1);
90    bool Eq10 = Ctx10.IsEquivalent(D1D0);
91    EXPECT_EQ(Eq01Eq10);
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
100TEST_F(StructuralEquivalenceTest, Int) {
101  auto Decls = makeNamedDecls("int foo;""int foo;"Lang_CXX);
102  EXPECT_TRUE(testStructuralMatch(Decls));
103}
104
105TEST_F(StructuralEquivalenceTest, IntVsSignedInt) {
106  auto Decls = makeNamedDecls("int foo;""signed int foo;"Lang_CXX);
107  EXPECT_TRUE(testStructuralMatch(Decls));
108}
109
110TEST_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.
117TEST_F(StructuralEquivalenceTest, DISABLED_CharVsSignedChar) {
118  auto Decls = makeNamedDecls("char foo;""signed char foo;"Lang_CXX);
119  EXPECT_FALSE(testStructuralMatch(Decls));
120}
121
122TEST_F(StructuralEquivalenceTest, ForwardRecordDecl) {
123  auto Decls = makeNamedDecls("struct foo;""struct foo;"Lang_CXX);
124  EXPECT_TRUE(testStructuralMatch(Decls));
125}
126
127TEST_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
133TEST_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
139TEST_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
150TEST_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
161TEST_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.
180TEST_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(CodeCodeLang_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
206TEST_F(StructuralEquivalenceTest, WrongOrderOfFieldsInClass) {
207  auto Code = "class X { int a; int b; };";
208  auto Decls = makeNamedDecls(CodeCodeLang_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
222struct StructuralEquivalenceFunctionTest : StructuralEquivalenceTest {
223};
224
225TEST_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
233TEST_F(StructuralEquivalenceFunctionTest, DifferentOperators) {
234  auto t = makeDecls<FunctionDecl>(
235      "struct X{}; bool operator<(X, X);",
236      "struct X{}; bool operator==(X, X);", Lang_CXX,
237      functionDecl(hasOverloadedOperatorName("<")),
238      functionDecl(hasOverloadedOperatorName("==")));
239  EXPECT_FALSE(testStructuralMatch(t));
240}
241
242TEST_F(StructuralEquivalenceFunctionTest, SameOperators) {
243  auto t = makeDecls<FunctionDecl>(
244      "struct X{}; bool operator<(X, X);",
245      "struct X{}; bool operator<(X, X);", Lang_CXX,
246      functionDecl(hasOverloadedOperatorName("<")),
247      functionDecl(hasOverloadedOperatorName("<")));
248  EXPECT_TRUE(testStructuralMatch(t));
249}
250
251TEST_F(StructuralEquivalenceFunctionTest, CtorVsDtor) {
252  auto t = makeDecls<FunctionDecl>(
253      "struct X{ X(); };",
254      "struct X{ ~X(); };", Lang_CXX,
255      cxxConstructorDecl(),
256      cxxDestructorDecl());
257  EXPECT_FALSE(testStructuralMatch(t));
258}
259
260TEST_F(StructuralEquivalenceFunctionTest, ParamConstWithRef) {
261  auto t = makeNamedDecls("void foo(int&);",
262                          "void foo(const int&);"Lang_CXX);
263  EXPECT_FALSE(testStructuralMatch(t));
264}
265
266TEST_F(StructuralEquivalenceFunctionTest, ParamConstSimple) {
267  auto t = makeNamedDecls("void foo(int);",
268                          "void foo(const int);"Lang_CXX);
269  EXPECT_TRUE(testStructuralMatch(t));
270  // consider this OK
271}
272
273TEST_F(StructuralEquivalenceFunctionTest, Throw) {
274  auto t = makeNamedDecls("void foo();",
275                          "void foo() throw();"Lang_CXX);
276  EXPECT_FALSE(testStructuralMatch(t));
277}
278
279TEST_F(StructuralEquivalenceFunctionTest, Noexcept) {
280  auto t = makeNamedDecls("void foo();",
281                          "void foo() noexcept;"Lang_CXX11);
282  EXPECT_FALSE(testStructuralMatch(t));
283}
284
285TEST_F(StructuralEquivalenceFunctionTest, ThrowVsNoexcept) {
286  auto t = makeNamedDecls("void foo() throw();",
287                          "void foo() noexcept;"Lang_CXX11);
288  EXPECT_FALSE(testStructuralMatch(t));
289}
290
291TEST_F(StructuralEquivalenceFunctionTest, ThrowVsNoexceptFalse) {
292  auto t = makeNamedDecls("void foo() throw();",
293                          "void foo() noexcept(false);"Lang_CXX11);
294  EXPECT_FALSE(testStructuralMatch(t));
295}
296
297TEST_F(StructuralEquivalenceFunctionTest, ThrowVsNoexceptTrue) {
298  auto t = makeNamedDecls("void foo() throw();",
299                          "void foo() noexcept(true);"Lang_CXX11);
300  EXPECT_FALSE(testStructuralMatch(t));
301}
302
303TEST_F(StructuralEquivalenceFunctionTest, DISABLED_NoexceptNonMatch) {
304  // The expression is not checked yet.
305  auto t = makeNamedDecls("void foo() noexcept(false);",
306                          "void foo() noexcept(true);"Lang_CXX11);
307  EXPECT_FALSE(testStructuralMatch(t));
308}
309
310TEST_F(StructuralEquivalenceFunctionTest, NoexceptMatch) {
311  auto t = makeNamedDecls("void foo() noexcept(false);",
312                          "void foo() noexcept(false);"Lang_CXX11);
313  EXPECT_TRUE(testStructuralMatch(t));
314}
315
316TEST_F(StructuralEquivalenceFunctionTest, NoexceptVsNoexceptFalse) {
317  auto t = makeNamedDecls("void foo() noexcept;",
318                          "void foo() noexcept(false);"Lang_CXX11);
319  EXPECT_FALSE(testStructuralMatch(t));
320}
321
322TEST_F(StructuralEquivalenceFunctionTest, NoexceptVsNoexceptTrue) {
323  auto t = makeNamedDecls("void foo() noexcept;",
324                          "void foo() noexcept(true);"Lang_CXX11);
325  EXPECT_FALSE(testStructuralMatch(t));
326}
327
328TEST_F(StructuralEquivalenceFunctionTest, ReturnType) {
329  auto t = makeNamedDecls("char foo();",
330                          "int foo();"Lang_CXX);
331  EXPECT_FALSE(testStructuralMatch(t));
332}
333
334TEST_F(StructuralEquivalenceFunctionTest, ReturnConst) {
335  auto t = makeNamedDecls("char foo();",
336                          "const char foo();"Lang_CXX);
337  EXPECT_FALSE(testStructuralMatch(t));
338}
339
340TEST_F(StructuralEquivalenceFunctionTest, ReturnRef) {
341  auto t = makeNamedDecls("char &foo();",
342                          "char &&foo();"Lang_CXX11);
343  EXPECT_FALSE(testStructuralMatch(t));
344}
345
346TEST_F(StructuralEquivalenceFunctionTest, ParamCount) {
347  auto t = makeNamedDecls("void foo(int);",
348                          "void foo(int, int);"Lang_CXX);
349  EXPECT_FALSE(testStructuralMatch(t));
350}
351
352TEST_F(StructuralEquivalenceFunctionTest, ParamType) {
353  auto t = makeNamedDecls("void foo(int);",
354                          "void foo(char);"Lang_CXX);
355  EXPECT_FALSE(testStructuralMatch(t));
356}
357
358TEST_F(StructuralEquivalenceFunctionTest, ParamName) {
359  auto t = makeNamedDecls("void foo(int a);",
360                          "void foo(int b);"Lang_CXX);
361  EXPECT_TRUE(testStructuralMatch(t));
362}
363
364TEST_F(StructuralEquivalenceFunctionTest, Variadic) {
365  auto t = makeNamedDecls("void foo(int x...);",
366                          "void foo(int x);"Lang_CXX);
367  EXPECT_FALSE(testStructuralMatch(t));
368}
369
370TEST_F(StructuralEquivalenceFunctionTest, ParamPtr) {
371  auto t = makeNamedDecls("void foo(int *);",
372                          "void foo(int);"Lang_CXX);
373  EXPECT_FALSE(testStructuralMatch(t));
374}
375
376TEST_F(StructuralEquivalenceFunctionTest, NameInParen) {
377  auto t = makeNamedDecls(
378      "void ((foo))();",
379      "void foo();",
380      Lang_CXX);
381  EXPECT_TRUE(testStructuralMatch(t));
382}
383
384TEST_F(StructuralEquivalenceFunctionTest, NameInParenWithExceptionSpec) {
385  auto t = makeNamedDecls(
386      "void (foo)() throw(int);",
387      "void (foo)() noexcept;",
388      Lang_CXX11);
389  EXPECT_FALSE(testStructuralMatch(t));
390}
391
392TEST_F(StructuralEquivalenceFunctionTest, NameInParenWithConst) {
393  auto t = makeNamedDecls(
394      "struct A { void (foo)() const; };",
395      "struct A { void (foo)(); };",
396      Lang_CXX11);
397  EXPECT_FALSE(testStructuralMatch(t));
398}
399
400TEST_F(StructuralEquivalenceFunctionTest, FunctionsWithDifferentNoreturnAttr) {
401  auto t = makeNamedDecls(
402      "__attribute__((noreturn)) void foo();",
403      "                          void foo();",
404      Lang_C);
405  EXPECT_TRUE(testStructuralMatch(t));
406}
407
408TEST_F(StructuralEquivalenceFunctionTest,
409    FunctionsWithDifferentCallingConventions) {
410  // These attributes may not be available on certain platforms.
411  if (llvm::Triple(llvm::sys::getDefaultTargetTriple()).getArch() !=
412      llvm::Triple::x86_64)
413    return;
414  auto t = makeNamedDecls(
415      "__attribute__((preserve_all)) void foo();",
416      "__attribute__((ms_abi))   void foo();",
417      Lang_C);
418  EXPECT_FALSE(testStructuralMatch(t));
419}
420
421TEST_F(StructuralEquivalenceFunctionTest, FunctionsWithDifferentSavedRegsAttr) {
422  if (llvm::Triple(llvm::sys::getDefaultTargetTriple()).getArch() !=
423      llvm::Triple::x86_64)
424    return;
425  auto t = makeNamedDecls(
426      "__attribute__((no_caller_saved_registers)) void foo();",
427      "                                           void foo();",
428      Lang_C);
429  EXPECT_FALSE(testStructuralMatch(t));
430}
431
432struct StructuralEquivalenceCXXMethodTest : StructuralEquivalenceTest {
433};
434
435TEST_F(StructuralEquivalenceCXXMethodTest, Virtual) {
436  auto t = makeDecls<CXXMethodDecl>(
437      "struct X { void foo(); };",
438      "struct X { virtual void foo(); };", Lang_CXX,
439      cxxMethodDecl(hasName("foo")));
440  EXPECT_FALSE(testStructuralMatch(t));
441}
442
443TEST_F(StructuralEquivalenceCXXMethodTest, Pure) {
444  auto t = makeNamedDecls("struct X { virtual void foo(); };",
445                          "struct X { virtual void foo() = 0; };"Lang_CXX);
446  EXPECT_FALSE(testStructuralMatch(t));
447}
448
449TEST_F(StructuralEquivalenceCXXMethodTest, DISABLED_Final) {
450  // The final-ness is not checked yet.
451  auto t = makeNamedDecls("struct X { virtual void foo(); };",
452                          "struct X { virtual void foo() final; };"Lang_CXX);
453  EXPECT_FALSE(testStructuralMatch(t));
454}
455
456TEST_F(StructuralEquivalenceCXXMethodTest, Const) {
457  auto t = makeNamedDecls("struct X { void foo(); };",
458                          "struct X { void foo() const; };"Lang_CXX);
459  EXPECT_FALSE(testStructuralMatch(t));
460}
461
462TEST_F(StructuralEquivalenceCXXMethodTest, Static) {
463  auto t = makeNamedDecls("struct X { void foo(); };",
464                          "struct X { static void foo(); };"Lang_CXX);
465  EXPECT_FALSE(testStructuralMatch(t));
466}
467
468TEST_F(StructuralEquivalenceCXXMethodTest, Ref1) {
469  auto t = makeNamedDecls("struct X { void foo(); };",
470                          "struct X { void foo() &&; };"Lang_CXX11);
471  EXPECT_FALSE(testStructuralMatch(t));
472}
473
474TEST_F(StructuralEquivalenceCXXMethodTest, Ref2) {
475  auto t = makeNamedDecls("struct X { void foo() &; };",
476                          "struct X { void foo() &&; };"Lang_CXX11);
477  EXPECT_FALSE(testStructuralMatch(t));
478}
479
480TEST_F(StructuralEquivalenceCXXMethodTest, AccessSpecifier) {
481  auto t = makeDecls<CXXMethodDecl>(
482      "struct X { public: void foo(); };",
483      "struct X { private: void foo(); };", Lang_CXX,
484      cxxMethodDecl(hasName("foo")));
485  EXPECT_FALSE(testStructuralMatch(t));
486}
487
488TEST_F(StructuralEquivalenceCXXMethodTest, Delete) {
489  auto t = makeNamedDecls("struct X { void foo(); };",
490                          "struct X { void foo() = delete; };"Lang_CXX11);
491  EXPECT_FALSE(testStructuralMatch(t));
492}
493
494TEST_F(StructuralEquivalenceCXXMethodTest, Constructor) {
495  auto t = makeDecls<FunctionDecl>(
496      "void foo();""struct foo { foo(); };", Lang_CXX,
497      functionDecl(hasName("foo")), cxxConstructorDecl(hasName("foo")));
498  EXPECT_FALSE(testStructuralMatch(t));
499}
500
501TEST_F(StructuralEquivalenceCXXMethodTest, ConstructorParam) {
502  auto t = makeDecls<CXXConstructorDecl>("struct X { X(); };",
503                                         "struct X { X(int); };", Lang_CXX,
504                                         cxxConstructorDecl(hasName("X")));
505  EXPECT_FALSE(testStructuralMatch(t));
506}
507
508TEST_F(StructuralEquivalenceCXXMethodTest, ConstructorExplicit) {
509  auto t = makeDecls<CXXConstructorDecl>("struct X { X(int); };",
510                                         "struct X { explicit X(int); };",
511                                         Lang_CXX11,
512                                         cxxConstructorDecl(hasName("X")));
513  EXPECT_FALSE(testStructuralMatch(t));
514}
515
516TEST_F(StructuralEquivalenceCXXMethodTest, ConstructorDefault) {
517  auto t = makeDecls<CXXConstructorDecl>("struct X { X(); };",
518                                         "struct X { X() = default; };",
519                                         Lang_CXX11,
520                                         cxxConstructorDecl(hasName("X")));
521  EXPECT_FALSE(testStructuralMatch(t));
522}
523
524TEST_F(StructuralEquivalenceCXXMethodTest, Conversion) {
525  auto t = makeDecls<CXXConversionDecl>("struct X { operator bool(); };",
526                                        "struct X { operator char(); };",
527                                         Lang_CXX11,
528                                         cxxConversionDecl());
529  EXPECT_FALSE(testStructuralMatch(t));
530}
531
532TEST_F(StructuralEquivalenceCXXMethodTest, Operator) {
533  auto t = makeDecls<FunctionDecl>(
534      "struct X { int operator +(int); };",
535      "struct X { int operator -(int); };", Lang_CXX,
536      functionDecl(hasOverloadedOperatorName("+")),
537      functionDecl(hasOverloadedOperatorName("-")));
538  EXPECT_FALSE(testStructuralMatch(t));
539}
540
541TEST_F(StructuralEquivalenceCXXMethodTest, OutOfClass1) {
542  auto t = makeDecls<FunctionDecl>(
543      "struct X { virtual void f(); }; void X::f() { }",
544      "struct X { virtual void f() { }; };",
545      Lang_CXX,
546      functionDecl(allOf(hasName("f"), isDefinition())));
547  EXPECT_TRUE(testStructuralMatch(t));
548}
549
550TEST_F(StructuralEquivalenceCXXMethodTest, OutOfClass2) {
551  auto t = makeDecls<FunctionDecl>(
552      "struct X { virtual void f(); }; void X::f() { }",
553      "struct X { void f(); }; void X::f() { }",
554      Lang_CXX,
555      functionDecl(allOf(hasName("f"), isDefinition())));
556  EXPECT_FALSE(testStructuralMatch(t));
557}
558
559struct StructuralEquivalenceRecordTest : StructuralEquivalenceTest {
560  // FIXME Use a common getRecordDecl with ASTImporterTest.cpp!
561  RecordDecl *getRecordDecl(FieldDecl *FD) {
562    auto *ET = cast<ElaboratedType>(FD->getType().getTypePtr());
563    return cast<RecordType>(ET->getNamedType().getTypePtr())->getDecl();
564  };
565};
566
567TEST_F(StructuralEquivalenceRecordTest, Name) {
568  auto t = makeDecls<CXXRecordDecl>(
569      "struct A{ };",
570      "struct B{ };",
571      Lang_CXX,
572      cxxRecordDecl(hasName("A")),
573      cxxRecordDecl(hasName("B")));
574  EXPECT_FALSE(testStructuralMatch(t));
575}
576
577TEST_F(StructuralEquivalenceRecordTest, Fields) {
578  auto t = makeNamedDecls(
579      "struct foo{ int x; };",
580      "struct foo{ char x; };",
581      Lang_CXX);
582  EXPECT_FALSE(testStructuralMatch(t));
583}
584
585TEST_F(StructuralEquivalenceRecordTest, DISABLED_Methods) {
586  // Currently, methods of a class are not checked at class equivalence.
587  auto t = makeNamedDecls(
588      "struct foo{ int x(); };",
589      "struct foo{ char x(); };",
590      Lang_CXX);
591  EXPECT_FALSE(testStructuralMatch(t));
592}
593
594TEST_F(StructuralEquivalenceRecordTest, Bases) {
595  auto t = makeNamedDecls(
596      "struct A{ }; struct foo: A { };",
597      "struct B{ }; struct foo: B { };",
598      Lang_CXX);
599  EXPECT_FALSE(testStructuralMatch(t));
600}
601
602TEST_F(StructuralEquivalenceRecordTest, InheritanceVirtual) {
603  auto t = makeNamedDecls(
604      "struct A{ }; struct foo: A { };",
605      "struct A{ }; struct foo: virtual A { };",
606      Lang_CXX);
607  EXPECT_FALSE(testStructuralMatch(t));
608}
609
610TEST_F(StructuralEquivalenceRecordTest, DISABLED_InheritanceType) {
611  // Access specifier in inheritance is not checked yet.
612  auto t = makeNamedDecls(
613      "struct A{ }; struct foo: public A { };",
614      "struct A{ }; struct foo: private A { };",
615      Lang_CXX);
616  EXPECT_FALSE(testStructuralMatch(t));
617}
618
619TEST_F(StructuralEquivalenceRecordTest, Match) {
620  auto Code = R"(
621      struct A{ };
622      struct B{ };
623      struct foo: A, virtual B {
624        void x();
625        int a;
626      };
627      )";
628  auto t = makeNamedDecls(CodeCodeLang_CXX);
629  EXPECT_TRUE(testStructuralMatch(t));
630}
631
632TEST_F(StructuralEquivalenceRecordTest, UnnamedRecordsShouldBeInequivalent) {
633  auto t = makeTuDecls(
634      R"(
635      struct A {
636        struct {
637          struct A *next;
638        } entry0;
639        struct {
640          struct A *next;
641        } entry1;
642      };
643      )",
644      ""Lang_C);
645  auto *TU = get<0>(t);
646  auto *Entry0 =
647      FirstDeclMatcher<FieldDecl>().match(TU, fieldDecl(hasName("entry0")));
648  auto *Entry1 =
649      FirstDeclMatcher<FieldDecl>().match(TU, fieldDecl(hasName("entry1")));
650  auto *R0 = getRecordDecl(Entry0);
651  auto *R1 = getRecordDecl(Entry1);
652
653  ASSERT_NE(R0, R1);
654  EXPECT_TRUE(testStructuralMatch(R0, R0));
655  EXPECT_TRUE(testStructuralMatch(R1, R1));
656  EXPECT_FALSE(testStructuralMatch(R0, R1));
657}
658
659TEST_F(StructuralEquivalenceRecordTest, AnonymousRecordsShouldBeInequivalent) {
660  auto t = makeTuDecls(
661      R"(
662      struct X {
663        struct {
664          int a;
665        };
666        struct {
667          int b;
668        };
669      };
670      )",
671      ""Lang_C);
672  auto *TU = get<0>(t);
673  auto *A = FirstDeclMatcher<IndirectFieldDecl>().match(
674      TU, indirectFieldDecl(hasName("a")));
675  auto *FA = cast<FieldDecl>(A->chain().front());
676  RecordDecl *RA = cast<RecordType>(FA->getType().getTypePtr())->getDecl();
677  auto *B = FirstDeclMatcher<IndirectFieldDecl>().match(
678      TU, indirectFieldDecl(hasName("b")));
679  auto *FB = cast<FieldDecl>(B->chain().front());
680  RecordDecl *RB = cast<RecordType>(FB->getType().getTypePtr())->getDecl();
681
682  ASSERT_NE(RARB);
683  EXPECT_TRUE(testStructuralMatch(RARA));
684  EXPECT_TRUE(testStructuralMatch(RBRB));
685  EXPECT_FALSE(testStructuralMatch(RARB));
686}
687
688TEST_F(StructuralEquivalenceRecordTest,
689       RecordsAreInequivalentIfOrderOfAnonRecordsIsDifferent) {
690  auto t = makeTuDecls(
691      R"(
692      struct X {
693        struct { int a; };
694        struct { int b; };
695      };
696      )",
697      R"(
698      struct X { // The order is reversed.
699        struct { int b; };
700        struct { int a; };
701      };
702      )",
703      Lang_C);
704
705  auto *TU = get<0>(t);
706  auto *A = FirstDeclMatcher<IndirectFieldDecl>().match(
707      TU, indirectFieldDecl(hasName("a")));
708  auto *FA = cast<FieldDecl>(A->chain().front());
709  RecordDecl *RA = cast<RecordType>(FA->getType().getTypePtr())->getDecl();
710
711  auto *TU1 = get<1>(t);
712  auto *A1 = FirstDeclMatcher<IndirectFieldDecl>().match(
713      TU1, indirectFieldDecl(hasName("a")));
714  auto *FA1 = cast<FieldDecl>(A1->chain().front());
715  RecordDecl *RA1 = cast<RecordType>(FA1->getType().getTypePtr())->getDecl();
716
717  RecordDecl *X =
718      FirstDeclMatcher<RecordDecl>().match(TU, recordDecl(hasName("X")));
719  RecordDecl *X1 =
720      FirstDeclMatcher<RecordDecl>().match(TU1, recordDecl(hasName("X")));
721  ASSERT_NE(XX1);
722  EXPECT_FALSE(testStructuralMatch(XX1));
723
724  ASSERT_NE(RARA1);
725  EXPECT_TRUE(testStructuralMatch(RARA));
726  EXPECT_TRUE(testStructuralMatch(RA1RA1));
727  EXPECT_FALSE(testStructuralMatch(RA1RA));
728}
729
730TEST_F(StructuralEquivalenceRecordTest,
731       UnnamedRecordsShouldBeInequivalentEvenIfTheSecondIsBeingDefined) {
732  auto Code =
733      R"(
734      struct A {
735        struct {
736          struct A *next;
737        } entry0;
738        struct {
739          struct A *next;
740        } entry1;
741      };
742      )";
743  auto t = makeTuDecls(CodeCodeLang_C);
744
745  auto *FromTU = get<0>(t);
746  auto *Entry1 =
747      FirstDeclMatcher<FieldDecl>().match(FromTU, fieldDecl(hasName("entry1")));
748
749  auto *ToTU = get<1>(t);
750  auto *Entry0 =
751      FirstDeclMatcher<FieldDecl>().match(ToTU, fieldDecl(hasName("entry0")));
752  auto *A =
753      FirstDeclMatcher<RecordDecl>().match(ToTU, recordDecl(hasName("A")));
754  A->startDefinition(); // Set isBeingDefined, getDefinition() will return a
755                        // nullptr. This may be the case during ASTImport.
756
757  auto *R0 = getRecordDecl(Entry0);
758  auto *R1 = getRecordDecl(Entry1);
759
760  ASSERT_NE(R0, R1);
761  EXPECT_TRUE(testStructuralMatch(R0, R0));
762  EXPECT_TRUE(testStructuralMatch(R1, R1));
763  EXPECT_FALSE(testStructuralMatch(R0, R1));
764}
765
766TEST_F(StructuralEquivalenceRecordTest, TemplateVsNonTemplate) {
767  auto t = makeDecls<CXXRecordDecl>(
768      "struct A { };",
769      "template<class T> struct A { };",
770      Lang_CXX,
771      cxxRecordDecl(hasName("A")));
772  EXPECT_FALSE(testStructuralMatch(t));
773}
774
775TEST_F(StructuralEquivalenceRecordTest,
776    FwdDeclRecordShouldBeEqualWithFwdDeclRecord) {
777  auto t = makeNamedDecls("class foo;""class foo;"Lang_CXX11);
778  EXPECT_TRUE(testStructuralMatch(t));
779}
780
781TEST_F(StructuralEquivalenceRecordTest,
782       FwdDeclRecordShouldBeEqualWithRecordWhichHasDefinition) {
783  auto t =
784      makeNamedDecls("class foo;""class foo { int A; };"Lang_CXX11);
785  EXPECT_TRUE(testStructuralMatch(t));
786}
787
788TEST_F(StructuralEquivalenceRecordTest,
789       RecordShouldBeEqualWithRecordWhichHasDefinition) {
790  auto t = makeNamedDecls("class foo { int A; };""class foo { int A; };",
791                          Lang_CXX11);
792  EXPECT_TRUE(testStructuralMatch(t));
793}
794
795TEST_F(StructuralEquivalenceRecordTest, RecordsWithDifferentBody) {
796  auto t = makeNamedDecls("class foo { int B; };""class foo { int A; };",
797                          Lang_CXX11);
798  EXPECT_FALSE(testStructuralMatch(t));
799}
800
801TEST_F(StructuralEquivalenceTest, CompareSameDeclWithMultiple) {
802  auto t = makeNamedDecls(
803      "struct A{ }; struct B{ }; void foo(A a, A b);",
804      "struct A{ }; struct B{ }; void foo(A a, B b);",
805      Lang_CXX);
806  EXPECT_FALSE(testStructuralMatch(t));
807}
808
809struct StructuralEquivalenceEnumTest : StructuralEquivalenceTest {};
810
811TEST_F(StructuralEquivalenceEnumTest, FwdDeclEnumShouldBeEqualWithFwdDeclEnum) {
812  auto t = makeNamedDecls("enum class foo;""enum class foo;"Lang_CXX11);
813  EXPECT_TRUE(testStructuralMatch(t));
814}
815
816TEST_F(StructuralEquivalenceEnumTest,
817       FwdDeclEnumShouldBeEqualWithEnumWhichHasDefinition) {
818  auto t =
819      makeNamedDecls("enum class foo;""enum class foo { A };"Lang_CXX11);
820  EXPECT_TRUE(testStructuralMatch(t));
821}
822
823TEST_F(StructuralEquivalenceEnumTest,
824       EnumShouldBeEqualWithEnumWhichHasDefinition) {
825  auto t = makeNamedDecls("enum class foo { A };""enum class foo { A };",
826                          Lang_CXX11);
827  EXPECT_TRUE(testStructuralMatch(t));
828}
829
830TEST_F(StructuralEquivalenceEnumTest, EnumsWithDifferentBody) {
831  auto t = makeNamedDecls("enum class foo { B };""enum class foo { A };",
832                          Lang_CXX11);
833  EXPECT_FALSE(testStructuralMatch(t));
834}
835
836struct StructuralEquivalenceTemplateTest : StructuralEquivalenceTest {};
837
838TEST_F(StructuralEquivalenceTemplateTest, ExactlySameTemplates) {
839  auto t = makeNamedDecls("template <class T> struct foo;",
840                          "template <class T> struct foo;"Lang_CXX);
841  EXPECT_TRUE(testStructuralMatch(t));
842}
843
844TEST_F(StructuralEquivalenceTemplateTest, DifferentTemplateArgName) {
845  auto t = makeNamedDecls("template <class T> struct foo;",
846                          "template <class U> struct foo;"Lang_CXX);
847  EXPECT_TRUE(testStructuralMatch(t));
848}
849
850TEST_F(StructuralEquivalenceTemplateTest, DifferentTemplateArgKind) {
851  auto t = makeNamedDecls("template <class T> struct foo;",
852                          "template <int T> struct foo;"Lang_CXX);
853  EXPECT_FALSE(testStructuralMatch(t));
854}
855
856// end namespace ast_matchers
857// end namespace clang
858