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