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 // 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 65 bool testStructuralMatch(NamedDecl *D0, NamedDecl *D1) { 66 llvm::DenseSet<std::pair<Decl *, Decl *>> NonEquivalentDecls; 67 StructuralEquivalenceContext Ctx( 68 D0->getASTContext(), D1->getASTContext(), NonEquivalentDecls, 69 StructuralEquivalenceKind::Default, false, false); 70 return Ctx.IsStructurallyEquivalent(D0, D1); 71 } 72 73 bool testStructuralMatch(std::tuple<NamedDecl *, NamedDecl *> t) { 74 return testStructuralMatch(get<0>(t), get<1>(t)); 75 } 76 }; 77 78 TEST_F(StructuralEquivalenceTest, Int) { 79 auto Decls = makeNamedDecls("int foo;", "int foo;", Lang_CXX); 80 EXPECT_TRUE(testStructuralMatch(Decls)); 81 } 82 83 TEST_F(StructuralEquivalenceTest, IntVsSignedInt) { 84 auto Decls = makeNamedDecls("int foo;", "signed int foo;", Lang_CXX); 85 EXPECT_TRUE(testStructuralMatch(Decls)); 86 } 87 88 TEST_F(StructuralEquivalenceTest, Char) { 89 auto Decls = makeNamedDecls("char foo;", "char foo;", Lang_CXX); 90 EXPECT_TRUE(testStructuralMatch(Decls)); 91 } 92 93 // This test is disabled for now. 94 // FIXME Whether this is equivalent is dependendant on the target. 95 TEST_F(StructuralEquivalenceTest, DISABLED_CharVsSignedChar) { 96 auto Decls = makeNamedDecls("char foo;", "signed char foo;", Lang_CXX); 97 EXPECT_FALSE(testStructuralMatch(Decls)); 98 } 99 100 TEST_F(StructuralEquivalenceTest, ForwardRecordDecl) { 101 auto Decls = makeNamedDecls("struct foo;", "struct foo;", Lang_CXX); 102 EXPECT_TRUE(testStructuralMatch(Decls)); 103 } 104 105 TEST_F(StructuralEquivalenceTest, IntVsSignedIntInStruct) { 106 auto Decls = makeNamedDecls("struct foo { int x; };", 107 "struct foo { signed int x; };", Lang_CXX); 108 EXPECT_TRUE(testStructuralMatch(Decls)); 109 } 110 111 TEST_F(StructuralEquivalenceTest, CharVsSignedCharInStruct) { 112 auto Decls = makeNamedDecls("struct foo { char x; };", 113 "struct foo { signed char x; };", Lang_CXX); 114 EXPECT_FALSE(testStructuralMatch(Decls)); 115 } 116 117 TEST_F(StructuralEquivalenceTest, IntVsSignedIntTemplateSpec) { 118 auto Decls = makeDecls<ClassTemplateSpecializationDecl>( 119 R"(template <class T> struct foo; template<> struct foo<int>{};)", 120 R"(template <class T> struct foo; template<> struct foo<signed int>{};)", 121 Lang_CXX, 122 classTemplateSpecializationDecl()); 123 auto Spec0 = get<0>(Decls); 124 auto Spec1 = get<1>(Decls); 125 EXPECT_TRUE(testStructuralMatch(Spec0, Spec1)); 126 } 127 128 TEST_F(StructuralEquivalenceTest, CharVsSignedCharTemplateSpec) { 129 auto Decls = makeDecls<ClassTemplateSpecializationDecl>( 130 R"(template <class T> struct foo; template<> struct foo<char>{};)", 131 R"(template <class T> struct foo; template<> struct foo<signed char>{};)", 132 Lang_CXX, 133 classTemplateSpecializationDecl()); 134 auto Spec0 = get<0>(Decls); 135 auto Spec1 = get<1>(Decls); 136 EXPECT_FALSE(testStructuralMatch(Spec0, Spec1)); 137 } 138 139 TEST_F(StructuralEquivalenceTest, CharVsSignedCharTemplateSpecWithInheritance) { 140 auto Decls = makeDecls<ClassTemplateSpecializationDecl>( 141 R"( 142 struct true_type{}; 143 template <class T> struct foo; 144 template<> struct foo<char> : true_type {}; 145 )", 146 R"( 147 struct true_type{}; 148 template <class T> struct foo; 149 template<> struct foo<signed char> : true_type {}; 150 )", 151 Lang_CXX, 152 classTemplateSpecializationDecl()); 153 EXPECT_FALSE(testStructuralMatch(Decls)); 154 } 155 156 // This test is disabled for now. 157 // FIXME Enable it, once the check is implemented. 158 TEST_F(StructuralEquivalenceTest, DISABLED_WrongOrderInNamespace) { 159 auto Code = 160 R"( 161 namespace NS { 162 template <class T> class Base { 163 int a; 164 }; 165 class Derived : Base<Derived> { 166 }; 167 } 168 void foo(NS::Derived &); 169 )"; 170 auto Decls = makeNamedDecls(Code, Code, Lang_CXX); 171 172 NamespaceDecl *NS = 173 LastDeclMatcher<NamespaceDecl>().match(get<1>(Decls), namespaceDecl()); 174 ClassTemplateDecl *TD = LastDeclMatcher<ClassTemplateDecl>().match( 175 get<1>(Decls), classTemplateDecl(hasName("Base"))); 176 177 // Reorder the decls, move the TD to the last place in the DC. 178 NS->removeDecl(TD); 179 NS->addDeclInternal(TD); 180 181 EXPECT_FALSE(testStructuralMatch(Decls)); 182 } 183 184 TEST_F(StructuralEquivalenceTest, WrongOrderOfFieldsInClass) { 185 auto Code = "class X { int a; int b; };"; 186 auto Decls = makeNamedDecls(Code, Code, Lang_CXX, "X"); 187 188 CXXRecordDecl *RD = FirstDeclMatcher<CXXRecordDecl>().match( 189 get<1>(Decls), cxxRecordDecl(hasName("X"))); 190 FieldDecl *FD = 191 FirstDeclMatcher<FieldDecl>().match(get<1>(Decls), fieldDecl(hasName("a"))); 192 193 // Reorder the FieldDecls 194 RD->removeDecl(FD); 195 RD->addDeclInternal(FD); 196 197 EXPECT_FALSE(testStructuralMatch(Decls)); 198 } 199 200 struct StructuralEquivalenceFunctionTest : StructuralEquivalenceTest { 201 }; 202 203 TEST_F(StructuralEquivalenceFunctionTest, ParamConstWithRef) { 204 auto t = makeNamedDecls("void foo(int&);", 205 "void foo(const int&);", Lang_CXX); 206 EXPECT_FALSE(testStructuralMatch(t)); 207 } 208 209 TEST_F(StructuralEquivalenceFunctionTest, ParamConstSimple) { 210 auto t = makeNamedDecls("void foo(int);", 211 "void foo(const int);", Lang_CXX); 212 EXPECT_TRUE(testStructuralMatch(t)); 213 // consider this OK 214 } 215 216 TEST_F(StructuralEquivalenceFunctionTest, Throw) { 217 auto t = makeNamedDecls("void foo();", 218 "void foo() throw();", Lang_CXX); 219 EXPECT_FALSE(testStructuralMatch(t)); 220 } 221 222 TEST_F(StructuralEquivalenceFunctionTest, Noexcept) { 223 auto t = makeNamedDecls("void foo();", 224 "void foo() noexcept;", Lang_CXX11); 225 EXPECT_FALSE(testStructuralMatch(t)); 226 } 227 228 TEST_F(StructuralEquivalenceFunctionTest, ThrowVsNoexcept) { 229 auto t = makeNamedDecls("void foo() throw();", 230 "void foo() noexcept;", Lang_CXX11); 231 EXPECT_FALSE(testStructuralMatch(t)); 232 } 233 234 TEST_F(StructuralEquivalenceFunctionTest, ThrowVsNoexceptFalse) { 235 auto t = makeNamedDecls("void foo() throw();", 236 "void foo() noexcept(false);", Lang_CXX11); 237 EXPECT_FALSE(testStructuralMatch(t)); 238 } 239 240 TEST_F(StructuralEquivalenceFunctionTest, ThrowVsNoexceptTrue) { 241 auto t = makeNamedDecls("void foo() throw();", 242 "void foo() noexcept(true);", Lang_CXX11); 243 EXPECT_FALSE(testStructuralMatch(t)); 244 } 245 246 TEST_F(StructuralEquivalenceFunctionTest, DISABLED_NoexceptNonMatch) { 247 // The expression is not checked yet. 248 auto t = makeNamedDecls("void foo() noexcept(false);", 249 "void foo() noexcept(true);", Lang_CXX11); 250 EXPECT_FALSE(testStructuralMatch(t)); 251 } 252 253 TEST_F(StructuralEquivalenceFunctionTest, NoexceptMatch) { 254 auto t = makeNamedDecls("void foo() noexcept(false);", 255 "void foo() noexcept(false);", Lang_CXX11); 256 EXPECT_TRUE(testStructuralMatch(t)); 257 } 258 259 TEST_F(StructuralEquivalenceFunctionTest, NoexceptVsNoexceptFalse) { 260 auto t = makeNamedDecls("void foo() noexcept;", 261 "void foo() noexcept(false);", Lang_CXX11); 262 EXPECT_FALSE(testStructuralMatch(t)); 263 } 264 265 TEST_F(StructuralEquivalenceFunctionTest, NoexceptVsNoexceptTrue) { 266 auto t = makeNamedDecls("void foo() noexcept;", 267 "void foo() noexcept(true);", Lang_CXX11); 268 EXPECT_FALSE(testStructuralMatch(t)); 269 } 270 271 TEST_F(StructuralEquivalenceFunctionTest, ReturnType) { 272 auto t = makeNamedDecls("char foo();", 273 "int foo();", Lang_CXX); 274 EXPECT_FALSE(testStructuralMatch(t)); 275 } 276 277 TEST_F(StructuralEquivalenceFunctionTest, ReturnConst) { 278 auto t = makeNamedDecls("char foo();", 279 "const char foo();", Lang_CXX); 280 EXPECT_FALSE(testStructuralMatch(t)); 281 } 282 283 TEST_F(StructuralEquivalenceFunctionTest, ReturnRef) { 284 auto t = makeNamedDecls("char &foo();", 285 "char &&foo();", Lang_CXX11); 286 EXPECT_FALSE(testStructuralMatch(t)); 287 } 288 289 TEST_F(StructuralEquivalenceFunctionTest, ParamCount) { 290 auto t = makeNamedDecls("void foo(int);", 291 "void foo(int, int);", Lang_CXX); 292 EXPECT_FALSE(testStructuralMatch(t)); 293 } 294 295 TEST_F(StructuralEquivalenceFunctionTest, ParamType) { 296 auto t = makeNamedDecls("void foo(int);", 297 "void foo(char);", Lang_CXX); 298 EXPECT_FALSE(testStructuralMatch(t)); 299 } 300 301 TEST_F(StructuralEquivalenceFunctionTest, ParamName) { 302 auto t = makeNamedDecls("void foo(int a);", 303 "void foo(int b);", Lang_CXX); 304 EXPECT_TRUE(testStructuralMatch(t)); 305 } 306 307 TEST_F(StructuralEquivalenceFunctionTest, Variadic) { 308 auto t = makeNamedDecls("void foo(int x...);", 309 "void foo(int x);", Lang_CXX); 310 EXPECT_FALSE(testStructuralMatch(t)); 311 } 312 313 TEST_F(StructuralEquivalenceFunctionTest, ParamPtr) { 314 auto t = makeNamedDecls("void foo(int *);", 315 "void foo(int);", Lang_CXX); 316 EXPECT_FALSE(testStructuralMatch(t)); 317 } 318 319 TEST_F(StructuralEquivalenceFunctionTest, NameInParen) { 320 auto t = makeNamedDecls( 321 "void ((foo))();", 322 "void foo();", 323 Lang_CXX); 324 EXPECT_TRUE(testStructuralMatch(t)); 325 } 326 327 TEST_F(StructuralEquivalenceFunctionTest, NameInParenWithExceptionSpec) { 328 auto t = makeNamedDecls( 329 "void (foo)() throw(int);", 330 "void (foo)() noexcept;", 331 Lang_CXX11); 332 EXPECT_FALSE(testStructuralMatch(t)); 333 } 334 335 TEST_F(StructuralEquivalenceFunctionTest, NameInParenWithConst) { 336 auto t = makeNamedDecls( 337 "struct A { void (foo)() const; };", 338 "struct A { void (foo)(); };", 339 Lang_CXX11); 340 EXPECT_FALSE(testStructuralMatch(t)); 341 } 342 343 struct StructuralEquivalenceCXXMethodTest : StructuralEquivalenceTest { 344 }; 345 346 TEST_F(StructuralEquivalenceCXXMethodTest, Virtual) { 347 auto t = makeDecls<CXXMethodDecl>( 348 "struct X { void foo(); };", 349 "struct X { virtual void foo(); };", Lang_CXX, 350 cxxMethodDecl(hasName("foo"))); 351 EXPECT_FALSE(testStructuralMatch(t)); 352 } 353 354 TEST_F(StructuralEquivalenceCXXMethodTest, Pure) { 355 auto t = makeNamedDecls("struct X { virtual void foo(); };", 356 "struct X { virtual void foo() = 0; };", Lang_CXX); 357 EXPECT_FALSE(testStructuralMatch(t)); 358 } 359 360 TEST_F(StructuralEquivalenceCXXMethodTest, DISABLED_Final) { 361 // The final-ness is not checked yet. 362 auto t = makeNamedDecls("struct X { virtual void foo(); };", 363 "struct X { virtual void foo() final; };", Lang_CXX); 364 EXPECT_FALSE(testStructuralMatch(t)); 365 } 366 367 TEST_F(StructuralEquivalenceCXXMethodTest, Const) { 368 auto t = makeNamedDecls("struct X { void foo(); };", 369 "struct X { void foo() const; };", Lang_CXX); 370 EXPECT_FALSE(testStructuralMatch(t)); 371 } 372 373 TEST_F(StructuralEquivalenceCXXMethodTest, Static) { 374 auto t = makeNamedDecls("struct X { void foo(); };", 375 "struct X { static void foo(); };", Lang_CXX); 376 EXPECT_FALSE(testStructuralMatch(t)); 377 } 378 379 TEST_F(StructuralEquivalenceCXXMethodTest, Ref1) { 380 auto t = makeNamedDecls("struct X { void foo(); };", 381 "struct X { void foo() &&; };", Lang_CXX11); 382 EXPECT_FALSE(testStructuralMatch(t)); 383 } 384 385 TEST_F(StructuralEquivalenceCXXMethodTest, Ref2) { 386 auto t = makeNamedDecls("struct X { void foo() &; };", 387 "struct X { void foo() &&; };", Lang_CXX11); 388 EXPECT_FALSE(testStructuralMatch(t)); 389 } 390 391 TEST_F(StructuralEquivalenceCXXMethodTest, AccessSpecifier) { 392 auto t = makeDecls<CXXMethodDecl>( 393 "struct X { public: void foo(); };", 394 "struct X { private: void foo(); };", Lang_CXX, 395 cxxMethodDecl(hasName("foo"))); 396 EXPECT_FALSE(testStructuralMatch(t)); 397 } 398 399 TEST_F(StructuralEquivalenceCXXMethodTest, Delete) { 400 auto t = makeNamedDecls("struct X { void foo(); };", 401 "struct X { void foo() = delete; };", Lang_CXX11); 402 EXPECT_FALSE(testStructuralMatch(t)); 403 } 404 405 TEST_F(StructuralEquivalenceCXXMethodTest, Constructor) { 406 auto t = makeDecls<FunctionDecl>( 407 "void foo();", "struct foo { foo(); };", Lang_CXX, 408 functionDecl(hasName("foo")), cxxConstructorDecl(hasName("foo"))); 409 EXPECT_FALSE(testStructuralMatch(t)); 410 } 411 412 TEST_F(StructuralEquivalenceCXXMethodTest, ConstructorParam) { 413 auto t = makeDecls<CXXConstructorDecl>("struct X { X(); };", 414 "struct X { X(int); };", Lang_CXX, 415 cxxConstructorDecl(hasName("X"))); 416 EXPECT_FALSE(testStructuralMatch(t)); 417 } 418 419 TEST_F(StructuralEquivalenceCXXMethodTest, ConstructorExplicit) { 420 auto t = makeDecls<CXXConstructorDecl>("struct X { X(int); };", 421 "struct X { explicit X(int); };", 422 Lang_CXX11, 423 cxxConstructorDecl(hasName("X"))); 424 EXPECT_FALSE(testStructuralMatch(t)); 425 } 426 427 TEST_F(StructuralEquivalenceCXXMethodTest, ConstructorDefault) { 428 auto t = makeDecls<CXXConstructorDecl>("struct X { X(); };", 429 "struct X { X() = default; };", 430 Lang_CXX11, 431 cxxConstructorDecl(hasName("X"))); 432 EXPECT_FALSE(testStructuralMatch(t)); 433 } 434 435 TEST_F(StructuralEquivalenceCXXMethodTest, Conversion) { 436 auto t = makeDecls<CXXConversionDecl>("struct X { operator bool(); };", 437 "struct X { operator char(); };", 438 Lang_CXX11, 439 cxxConversionDecl()); 440 EXPECT_FALSE(testStructuralMatch(t)); 441 } 442 443 TEST_F(StructuralEquivalenceCXXMethodTest, Operator) { 444 auto t = makeDecls<FunctionDecl>( 445 "struct X { int operator +(int); };", 446 "struct X { int operator -(int); };", Lang_CXX, 447 functionDecl(hasOverloadedOperatorName("+")), 448 functionDecl(hasOverloadedOperatorName("-"))); 449 EXPECT_FALSE(testStructuralMatch(t)); 450 } 451 452 TEST_F(StructuralEquivalenceCXXMethodTest, OutOfClass1) { 453 auto t = makeDecls<FunctionDecl>( 454 "struct X { virtual void f(); }; void X::f() { }", 455 "struct X { virtual void f() { }; };", 456 Lang_CXX, 457 functionDecl(allOf(hasName("f"), isDefinition()))); 458 EXPECT_TRUE(testStructuralMatch(t)); 459 } 460 461 TEST_F(StructuralEquivalenceCXXMethodTest, OutOfClass2) { 462 auto t = makeDecls<FunctionDecl>( 463 "struct X { virtual void f(); }; void X::f() { }", 464 "struct X { void f(); }; void X::f() { }", 465 Lang_CXX, 466 functionDecl(allOf(hasName("f"), isDefinition()))); 467 EXPECT_FALSE(testStructuralMatch(t)); 468 } 469 470 struct StructuralEquivalenceRecordTest : StructuralEquivalenceTest { 471 }; 472 473 TEST_F(StructuralEquivalenceRecordTest, Name) { 474 auto t = makeDecls<CXXRecordDecl>( 475 "struct A{ };", 476 "struct B{ };", 477 Lang_CXX, 478 cxxRecordDecl(hasName("A")), 479 cxxRecordDecl(hasName("B"))); 480 EXPECT_FALSE(testStructuralMatch(t)); 481 } 482 483 TEST_F(StructuralEquivalenceRecordTest, Fields) { 484 auto t = makeNamedDecls( 485 "struct foo{ int x; };", 486 "struct foo{ char x; };", 487 Lang_CXX); 488 EXPECT_FALSE(testStructuralMatch(t)); 489 } 490 491 TEST_F(StructuralEquivalenceRecordTest, DISABLED_Methods) { 492 // Currently, methods of a class are not checked at class equivalence. 493 auto t = makeNamedDecls( 494 "struct foo{ int x(); };", 495 "struct foo{ char x(); };", 496 Lang_CXX); 497 EXPECT_FALSE(testStructuralMatch(t)); 498 } 499 500 TEST_F(StructuralEquivalenceRecordTest, Bases) { 501 auto t = makeNamedDecls( 502 "struct A{ }; struct foo: A { };", 503 "struct B{ }; struct foo: B { };", 504 Lang_CXX); 505 EXPECT_FALSE(testStructuralMatch(t)); 506 } 507 508 TEST_F(StructuralEquivalenceRecordTest, InheritanceVirtual) { 509 auto t = makeNamedDecls( 510 "struct A{ }; struct foo: A { };", 511 "struct A{ }; struct foo: virtual A { };", 512 Lang_CXX); 513 EXPECT_FALSE(testStructuralMatch(t)); 514 } 515 516 TEST_F(StructuralEquivalenceRecordTest, DISABLED_InheritanceType) { 517 // Access specifier in inheritance is not checked yet. 518 auto t = makeNamedDecls( 519 "struct A{ }; struct foo: public A { };", 520 "struct A{ }; struct foo: private A { };", 521 Lang_CXX); 522 EXPECT_FALSE(testStructuralMatch(t)); 523 } 524 525 TEST_F(StructuralEquivalenceRecordTest, Match) { 526 auto Code = R"( 527 struct A{ }; 528 struct B{ }; 529 struct foo: A, virtual B { 530 void x(); 531 int a; 532 }; 533 )"; 534 auto t = makeNamedDecls(Code, Code, Lang_CXX); 535 EXPECT_TRUE(testStructuralMatch(t)); 536 } 537 538 TEST_F(StructuralEquivalenceTest, CompareSameDeclWithMultiple) { 539 auto t = makeNamedDecls( 540 "struct A{ }; struct B{ }; void foo(A a, A b);", 541 "struct A{ }; struct B{ }; void foo(A a, B b);", 542 Lang_CXX); 543 EXPECT_FALSE(testStructuralMatch(t)); 544 } 545 546 } // end namespace ast_matchers 547 } // end namespace clang 548