1 //===- TreeTest.cpp -------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "clang/Tooling/Syntax/Tree.h" 10 #include "clang/AST/ASTConsumer.h" 11 #include "clang/AST/Decl.h" 12 #include "clang/AST/Stmt.h" 13 #include "clang/Basic/LLVM.h" 14 #include "clang/Basic/TokenKinds.h" 15 #include "clang/Frontend/CompilerInstance.h" 16 #include "clang/Frontend/CompilerInvocation.h" 17 #include "clang/Frontend/FrontendAction.h" 18 #include "clang/Frontend/TextDiagnosticPrinter.h" 19 #include "clang/Lex/PreprocessorOptions.h" 20 #include "clang/Tooling/Core/Replacement.h" 21 #include "clang/Tooling/Syntax/BuildTree.h" 22 #include "clang/Tooling/Syntax/Mutations.h" 23 #include "clang/Tooling/Syntax/Nodes.h" 24 #include "clang/Tooling/Syntax/Tokens.h" 25 #include "clang/Tooling/Tooling.h" 26 #include "llvm/ADT/ArrayRef.h" 27 #include "llvm/ADT/STLExtras.h" 28 #include "llvm/ADT/StringRef.h" 29 #include "llvm/Support/Casting.h" 30 #include "llvm/Support/Error.h" 31 #include "llvm/Testing/Support/Annotations.h" 32 #include "gmock/gmock.h" 33 #include "gtest/gtest.h" 34 #include <cstdlib> 35 36 using namespace clang; 37 38 namespace { 39 static llvm::ArrayRef<syntax::Token> tokens(syntax::Node *N) { 40 assert(N->isOriginal() && "tokens of modified nodes are not well-defined"); 41 if (auto *L = dyn_cast<syntax::Leaf>(N)) 42 return llvm::makeArrayRef(L->token(), 1); 43 auto *T = cast<syntax::Tree>(N); 44 return llvm::makeArrayRef(T->firstLeaf()->token(), 45 T->lastLeaf()->token() + 1); 46 } 47 48 class SyntaxTreeTest : public ::testing::Test { 49 protected: 50 // Build a syntax tree for the code. 51 syntax::TranslationUnit * 52 buildTree(llvm::StringRef Code, 53 const std::string &Target = "x86_64-pc-linux-gnu") { 54 // FIXME: this code is almost the identical to the one in TokensTest. Share 55 // it. 56 class BuildSyntaxTree : public ASTConsumer { 57 public: 58 BuildSyntaxTree(syntax::TranslationUnit *&Root, 59 std::unique_ptr<syntax::Arena> &Arena, 60 std::unique_ptr<syntax::TokenCollector> Tokens) 61 : Root(Root), Arena(Arena), Tokens(std::move(Tokens)) { 62 assert(this->Tokens); 63 } 64 65 void HandleTranslationUnit(ASTContext &Ctx) override { 66 Arena = std::make_unique<syntax::Arena>(Ctx.getSourceManager(), 67 Ctx.getLangOpts(), 68 std::move(*Tokens).consume()); 69 Tokens = nullptr; // make sure we fail if this gets called twice. 70 Root = syntax::buildSyntaxTree(*Arena, *Ctx.getTranslationUnitDecl()); 71 } 72 73 private: 74 syntax::TranslationUnit *&Root; 75 std::unique_ptr<syntax::Arena> &Arena; 76 std::unique_ptr<syntax::TokenCollector> Tokens; 77 }; 78 79 class BuildSyntaxTreeAction : public ASTFrontendAction { 80 public: 81 BuildSyntaxTreeAction(syntax::TranslationUnit *&Root, 82 std::unique_ptr<syntax::Arena> &Arena) 83 : Root(Root), Arena(Arena) {} 84 85 std::unique_ptr<ASTConsumer> 86 CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override { 87 // We start recording the tokens, ast consumer will take on the result. 88 auto Tokens = 89 std::make_unique<syntax::TokenCollector>(CI.getPreprocessor()); 90 return std::make_unique<BuildSyntaxTree>(Root, Arena, 91 std::move(Tokens)); 92 } 93 94 private: 95 syntax::TranslationUnit *&Root; 96 std::unique_ptr<syntax::Arena> &Arena; 97 }; 98 99 constexpr const char *FileName = "./input.cpp"; 100 FS->addFile(FileName, time_t(), llvm::MemoryBuffer::getMemBufferCopy("")); 101 102 if (!Diags->getClient()) 103 Diags->setClient(new TextDiagnosticPrinter(llvm::errs(), DiagOpts.get())); 104 Diags->setSeverityForGroup(diag::Flavor::WarningOrError, "unused-value", 105 diag::Severity::Ignored, SourceLocation()); 106 107 // Prepare to run a compiler. 108 std::vector<const char *> Args = { 109 "syntax-test", "-target", Target.c_str(), 110 FileName, "-fsyntax-only", "-std=c++17", 111 }; 112 Invocation = createInvocationFromCommandLine(Args, Diags, FS); 113 assert(Invocation); 114 Invocation->getFrontendOpts().DisableFree = false; 115 Invocation->getPreprocessorOpts().addRemappedFile( 116 FileName, llvm::MemoryBuffer::getMemBufferCopy(Code).release()); 117 CompilerInstance Compiler; 118 Compiler.setInvocation(Invocation); 119 Compiler.setDiagnostics(Diags.get()); 120 Compiler.setFileManager(FileMgr.get()); 121 Compiler.setSourceManager(SourceMgr.get()); 122 123 syntax::TranslationUnit *Root = nullptr; 124 BuildSyntaxTreeAction Recorder(Root, this->Arena); 125 126 // Action could not be executed but the frontend didn't identify any errors 127 // in the code ==> problem in setting up the action. 128 if (!Compiler.ExecuteAction(Recorder) && 129 Diags->getClient()->getNumErrors() == 0) { 130 ADD_FAILURE() << "failed to run the frontend"; 131 std::abort(); 132 } 133 return Root; 134 } 135 136 void expectTreeDumpEqual(StringRef Code, StringRef Tree, 137 bool RunWithDelayedTemplateParsing = true) { 138 SCOPED_TRACE(Code); 139 140 std::string Expected = Tree.trim().str(); 141 142 // We want to run the test with -fdelayed-template-parsing enabled and 143 // disabled, therefore we use these representative targets that differ in 144 // the default value. 145 // We are not passing -fdelayed-template-parsing directly but we are using 146 // the `-target` to improve coverage and discover differences in behavior 147 // early. 148 for (const std::string Target : 149 {"x86_64-pc-linux-gnu", "x86_64-pc-win32-msvc"}) { 150 if (!RunWithDelayedTemplateParsing && 151 Target == "x86_64-pc-win32-msvc") { 152 continue; 153 } 154 auto *Root = buildTree(Code, Target); 155 EXPECT_EQ(Diags->getClient()->getNumErrors(), 0u) 156 << "Source file has syntax errors, they were printed to the test log"; 157 std::string Actual = std::string(StringRef(Root->dump(*Arena)).trim()); 158 EXPECT_EQ(Expected, Actual) 159 << "for target " << Target << " the resulting dump is:\n" 160 << Actual; 161 } 162 } 163 164 // Adds a file to the test VFS. 165 void addFile(llvm::StringRef Path, llvm::StringRef Contents) { 166 if (!FS->addFile(Path, time_t(), 167 llvm::MemoryBuffer::getMemBufferCopy(Contents))) { 168 ADD_FAILURE() << "could not add a file to VFS: " << Path; 169 } 170 } 171 172 /// Finds the deepest node in the tree that covers exactly \p R. 173 /// FIXME: implement this efficiently and move to public syntax tree API. 174 syntax::Node *nodeByRange(llvm::Annotations::Range R, syntax::Node *Root) { 175 llvm::ArrayRef<syntax::Token> Toks = tokens(Root); 176 177 if (Toks.front().location().isFileID() && 178 Toks.back().location().isFileID() && 179 syntax::Token::range(*SourceMgr, Toks.front(), Toks.back()) == 180 syntax::FileRange(SourceMgr->getMainFileID(), R.Begin, R.End)) 181 return Root; 182 183 auto *T = dyn_cast<syntax::Tree>(Root); 184 if (!T) 185 return nullptr; 186 for (auto *C = T->firstChild(); C != nullptr; C = C->nextSibling()) { 187 if (auto *Result = nodeByRange(R, C)) 188 return Result; 189 } 190 return nullptr; 191 } 192 193 // Data fields. 194 llvm::IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = 195 new DiagnosticOptions(); 196 llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags = 197 new DiagnosticsEngine(new DiagnosticIDs, DiagOpts.get()); 198 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS = 199 new llvm::vfs::InMemoryFileSystem; 200 llvm::IntrusiveRefCntPtr<FileManager> FileMgr = 201 new FileManager(FileSystemOptions(), FS); 202 llvm::IntrusiveRefCntPtr<SourceManager> SourceMgr = 203 new SourceManager(*Diags, *FileMgr); 204 std::shared_ptr<CompilerInvocation> Invocation; 205 // Set after calling buildTree(). 206 std::unique_ptr<syntax::Arena> Arena; 207 }; 208 209 TEST_F(SyntaxTreeTest, Simple) { 210 expectTreeDumpEqual( 211 R"cpp( 212 int main() {} 213 void foo() {} 214 )cpp", 215 R"txt( 216 *: TranslationUnit 217 |-SimpleDeclaration 218 | |-int 219 | |-SimpleDeclarator 220 | | |-main 221 | | `-ParametersAndQualifiers 222 | | |-( 223 | | `-) 224 | `-CompoundStatement 225 | |-{ 226 | `-} 227 `-SimpleDeclaration 228 |-void 229 |-SimpleDeclarator 230 | |-foo 231 | `-ParametersAndQualifiers 232 | |-( 233 | `-) 234 `-CompoundStatement 235 |-{ 236 `-} 237 )txt"); 238 } 239 240 TEST_F(SyntaxTreeTest, SimpleVariable) { 241 expectTreeDumpEqual( 242 R"cpp( 243 int a; 244 int b = 42; 245 )cpp", 246 R"txt( 247 *: TranslationUnit 248 |-SimpleDeclaration 249 | |-int 250 | |-SimpleDeclarator 251 | | `-a 252 | `-; 253 `-SimpleDeclaration 254 |-int 255 |-SimpleDeclarator 256 | |-b 257 | |-= 258 | `-UnknownExpression 259 | `-42 260 `-; 261 )txt"); 262 } 263 264 TEST_F(SyntaxTreeTest, SimpleFunction) { 265 expectTreeDumpEqual( 266 R"cpp( 267 void foo(int a, int b) {} 268 )cpp", 269 R"txt( 270 *: TranslationUnit 271 `-SimpleDeclaration 272 |-void 273 |-SimpleDeclarator 274 | |-foo 275 | `-ParametersAndQualifiers 276 | |-( 277 | |-SimpleDeclaration 278 | | |-int 279 | | `-SimpleDeclarator 280 | | `-a 281 | |-, 282 | |-SimpleDeclaration 283 | | |-int 284 | | `-SimpleDeclarator 285 | | `-b 286 | `-) 287 `-CompoundStatement 288 |-{ 289 `-} 290 )txt"); 291 } 292 293 TEST_F(SyntaxTreeTest, If) { 294 expectTreeDumpEqual( 295 R"cpp( 296 int main() { 297 if (true) {} 298 if (true) {} else if (false) {} 299 } 300 )cpp", 301 R"txt( 302 *: TranslationUnit 303 `-SimpleDeclaration 304 |-int 305 |-SimpleDeclarator 306 | |-main 307 | `-ParametersAndQualifiers 308 | |-( 309 | `-) 310 `-CompoundStatement 311 |-{ 312 |-IfStatement 313 | |-if 314 | |-( 315 | |-UnknownExpression 316 | | `-true 317 | |-) 318 | `-CompoundStatement 319 | |-{ 320 | `-} 321 |-IfStatement 322 | |-if 323 | |-( 324 | |-UnknownExpression 325 | | `-true 326 | |-) 327 | |-CompoundStatement 328 | | |-{ 329 | | `-} 330 | |-else 331 | `-IfStatement 332 | |-if 333 | |-( 334 | |-UnknownExpression 335 | | `-false 336 | |-) 337 | `-CompoundStatement 338 | |-{ 339 | `-} 340 `-} 341 )txt"); 342 } 343 344 TEST_F(SyntaxTreeTest, For) { 345 expectTreeDumpEqual( 346 R"cpp( 347 void test() { 348 for (;;) {} 349 } 350 )cpp", 351 R"txt( 352 *: TranslationUnit 353 `-SimpleDeclaration 354 |-void 355 |-SimpleDeclarator 356 | |-test 357 | `-ParametersAndQualifiers 358 | |-( 359 | `-) 360 `-CompoundStatement 361 |-{ 362 |-ForStatement 363 | |-for 364 | |-( 365 | |-; 366 | |-; 367 | |-) 368 | `-CompoundStatement 369 | |-{ 370 | `-} 371 `-} 372 )txt"); 373 } 374 375 TEST_F(SyntaxTreeTest, RangeBasedFor) { 376 expectTreeDumpEqual( 377 R"cpp( 378 void test() { 379 int a[3]; 380 for (int x : a) ; 381 } 382 )cpp", 383 R"txt( 384 *: TranslationUnit 385 `-SimpleDeclaration 386 |-void 387 |-SimpleDeclarator 388 | |-test 389 | `-ParametersAndQualifiers 390 | |-( 391 | `-) 392 `-CompoundStatement 393 |-{ 394 |-DeclarationStatement 395 | |-SimpleDeclaration 396 | | |-int 397 | | `-SimpleDeclarator 398 | | |-a 399 | | `-ArraySubscript 400 | | |-[ 401 | | |-UnknownExpression 402 | | | `-3 403 | | `-] 404 | `-; 405 |-RangeBasedForStatement 406 | |-for 407 | |-( 408 | |-SimpleDeclaration 409 | | |-int 410 | | |-SimpleDeclarator 411 | | | `-x 412 | | `-: 413 | |-UnknownExpression 414 | | `-a 415 | |-) 416 | `-EmptyStatement 417 | `-; 418 `-} 419 )txt"); 420 } 421 422 TEST_F(SyntaxTreeTest, DeclarationStatement) { 423 expectTreeDumpEqual("void test() { int a = 10; }", 424 R"txt( 425 *: TranslationUnit 426 `-SimpleDeclaration 427 |-void 428 |-SimpleDeclarator 429 | |-test 430 | `-ParametersAndQualifiers 431 | |-( 432 | `-) 433 `-CompoundStatement 434 |-{ 435 |-DeclarationStatement 436 | |-SimpleDeclaration 437 | | |-int 438 | | `-SimpleDeclarator 439 | | |-a 440 | | |-= 441 | | `-UnknownExpression 442 | | `-10 443 | `-; 444 `-} 445 )txt"); 446 } 447 448 TEST_F(SyntaxTreeTest, Switch) { 449 expectTreeDumpEqual( 450 R"cpp( 451 void test() { 452 switch (true) { 453 case 0: 454 default:; 455 } 456 } 457 )cpp", 458 R"txt( 459 *: TranslationUnit 460 `-SimpleDeclaration 461 |-void 462 |-SimpleDeclarator 463 | |-test 464 | `-ParametersAndQualifiers 465 | |-( 466 | `-) 467 `-CompoundStatement 468 |-{ 469 |-SwitchStatement 470 | |-switch 471 | |-( 472 | |-UnknownExpression 473 | | `-true 474 | |-) 475 | `-CompoundStatement 476 | |-{ 477 | |-CaseStatement 478 | | |-case 479 | | |-UnknownExpression 480 | | | `-0 481 | | |-: 482 | | `-DefaultStatement 483 | | |-default 484 | | |-: 485 | | `-EmptyStatement 486 | | `-; 487 | `-} 488 `-} 489 )txt"); 490 } 491 492 TEST_F(SyntaxTreeTest, While) { 493 expectTreeDumpEqual( 494 R"cpp( 495 void test() { 496 while (true) { continue; break; } 497 } 498 )cpp", 499 R"txt( 500 *: TranslationUnit 501 `-SimpleDeclaration 502 |-void 503 |-SimpleDeclarator 504 | |-test 505 | `-ParametersAndQualifiers 506 | |-( 507 | `-) 508 `-CompoundStatement 509 |-{ 510 |-WhileStatement 511 | |-while 512 | |-( 513 | |-UnknownExpression 514 | | `-true 515 | |-) 516 | `-CompoundStatement 517 | |-{ 518 | |-ContinueStatement 519 | | |-continue 520 | | `-; 521 | |-BreakStatement 522 | | |-break 523 | | `-; 524 | `-} 525 `-} 526 )txt"); 527 } 528 529 TEST_F(SyntaxTreeTest, UnhandledStatement) { 530 // Unhandled statements should end up as 'unknown statement'. 531 // This example uses a 'label statement', which does not yet have a syntax 532 // counterpart. 533 expectTreeDumpEqual("int main() { foo: return 100; }", 534 R"txt( 535 *: TranslationUnit 536 `-SimpleDeclaration 537 |-int 538 |-SimpleDeclarator 539 | |-main 540 | `-ParametersAndQualifiers 541 | |-( 542 | `-) 543 `-CompoundStatement 544 |-{ 545 |-UnknownStatement 546 | |-foo 547 | |-: 548 | `-ReturnStatement 549 | |-return 550 | |-UnknownExpression 551 | | `-100 552 | `-; 553 `-} 554 )txt"); 555 } 556 557 TEST_F(SyntaxTreeTest, Expressions) { 558 // expressions should be wrapped in 'ExpressionStatement' when they appear 559 // in a statement position. 560 expectTreeDumpEqual( 561 R"cpp( 562 void test() { 563 test(); 564 if (true) test(); else test(); 565 } 566 )cpp", 567 R"txt( 568 *: TranslationUnit 569 `-SimpleDeclaration 570 |-void 571 |-SimpleDeclarator 572 | |-test 573 | `-ParametersAndQualifiers 574 | |-( 575 | `-) 576 `-CompoundStatement 577 |-{ 578 |-ExpressionStatement 579 | |-UnknownExpression 580 | | |-UnknownExpression 581 | | | `-test 582 | | |-( 583 | | `-) 584 | `-; 585 |-IfStatement 586 | |-if 587 | |-( 588 | |-UnknownExpression 589 | | `-true 590 | |-) 591 | |-ExpressionStatement 592 | | |-UnknownExpression 593 | | | |-UnknownExpression 594 | | | | `-test 595 | | | |-( 596 | | | `-) 597 | | `-; 598 | |-else 599 | `-ExpressionStatement 600 | |-UnknownExpression 601 | | |-UnknownExpression 602 | | | `-test 603 | | |-( 604 | | `-) 605 | `-; 606 `-} 607 )txt"); 608 } 609 610 TEST_F(SyntaxTreeTest, PostfixUnaryOperator) { 611 expectTreeDumpEqual( 612 R"cpp( 613 void test(int a) { 614 a++; 615 a--; 616 } 617 )cpp", 618 R"txt( 619 *: TranslationUnit 620 `-SimpleDeclaration 621 |-void 622 |-SimpleDeclarator 623 | |-test 624 | `-ParametersAndQualifiers 625 | |-( 626 | |-SimpleDeclaration 627 | | |-int 628 | | `-SimpleDeclarator 629 | | `-a 630 | `-) 631 `-CompoundStatement 632 |-{ 633 |-ExpressionStatement 634 | |-PostfixUnaryOperatorExpression 635 | | |-UnknownExpression 636 | | | `-a 637 | | `-++ 638 | `-; 639 |-ExpressionStatement 640 | |-PostfixUnaryOperatorExpression 641 | | |-UnknownExpression 642 | | | `-a 643 | | `--- 644 | `-; 645 `-} 646 )txt"); 647 } 648 649 TEST_F(SyntaxTreeTest, PrefixUnaryOperator) { 650 expectTreeDumpEqual( 651 R"cpp( 652 void test(int a, int *ap, bool b) { 653 --a; ++a; 654 ~a; compl a; 655 -a; 656 +a; 657 &a; 658 *ap; 659 !b; not b; 660 __real a; __imag a; 661 } 662 )cpp", 663 R"txt( 664 *: TranslationUnit 665 `-SimpleDeclaration 666 |-void 667 |-SimpleDeclarator 668 | |-test 669 | `-ParametersAndQualifiers 670 | |-( 671 | |-SimpleDeclaration 672 | | |-int 673 | | `-SimpleDeclarator 674 | | `-a 675 | |-, 676 | |-SimpleDeclaration 677 | | |-int 678 | | `-SimpleDeclarator 679 | | |-* 680 | | `-ap 681 | |-, 682 | |-SimpleDeclaration 683 | | |-bool 684 | | `-SimpleDeclarator 685 | | `-b 686 | `-) 687 `-CompoundStatement 688 |-{ 689 |-ExpressionStatement 690 | |-PrefixUnaryOperatorExpression 691 | | |--- 692 | | `-UnknownExpression 693 | | `-a 694 | `-; 695 |-ExpressionStatement 696 | |-PrefixUnaryOperatorExpression 697 | | |-++ 698 | | `-UnknownExpression 699 | | `-a 700 | `-; 701 |-ExpressionStatement 702 | |-PrefixUnaryOperatorExpression 703 | | |-~ 704 | | `-UnknownExpression 705 | | `-a 706 | `-; 707 |-ExpressionStatement 708 | |-PrefixUnaryOperatorExpression 709 | | |-compl 710 | | `-UnknownExpression 711 | | `-a 712 | `-; 713 |-ExpressionStatement 714 | |-PrefixUnaryOperatorExpression 715 | | |-- 716 | | `-UnknownExpression 717 | | `-a 718 | `-; 719 |-ExpressionStatement 720 | |-PrefixUnaryOperatorExpression 721 | | |-+ 722 | | `-UnknownExpression 723 | | `-a 724 | `-; 725 |-ExpressionStatement 726 | |-PrefixUnaryOperatorExpression 727 | | |-& 728 | | `-UnknownExpression 729 | | `-a 730 | `-; 731 |-ExpressionStatement 732 | |-PrefixUnaryOperatorExpression 733 | | |-* 734 | | `-UnknownExpression 735 | | `-ap 736 | `-; 737 |-ExpressionStatement 738 | |-PrefixUnaryOperatorExpression 739 | | |-! 740 | | `-UnknownExpression 741 | | `-b 742 | `-; 743 |-ExpressionStatement 744 | |-PrefixUnaryOperatorExpression 745 | | |-not 746 | | `-UnknownExpression 747 | | `-b 748 | `-; 749 |-ExpressionStatement 750 | |-PrefixUnaryOperatorExpression 751 | | |-__real 752 | | `-UnknownExpression 753 | | `-a 754 | `-; 755 |-ExpressionStatement 756 | |-PrefixUnaryOperatorExpression 757 | | |-__imag 758 | | `-UnknownExpression 759 | | `-a 760 | `-; 761 `-} 762 )txt"); 763 } 764 765 TEST_F(SyntaxTreeTest, BinaryOperator) { 766 expectTreeDumpEqual( 767 R"cpp( 768 void test(int a) { 769 1 - 2; 770 1 == 2; 771 a = 1; 772 a <<= 1; 773 774 true || false; 775 true or false; 776 777 1 & 2; 778 1 bitand 2; 779 780 a ^= 3; 781 a xor_eq 3; 782 } 783 )cpp", 784 R"txt( 785 *: TranslationUnit 786 `-SimpleDeclaration 787 |-void 788 |-SimpleDeclarator 789 | |-test 790 | `-ParametersAndQualifiers 791 | |-( 792 | |-SimpleDeclaration 793 | | |-int 794 | | `-SimpleDeclarator 795 | | `-a 796 | `-) 797 `-CompoundStatement 798 |-{ 799 |-ExpressionStatement 800 | |-BinaryOperatorExpression 801 | | |-UnknownExpression 802 | | | `-1 803 | | |-- 804 | | `-UnknownExpression 805 | | `-2 806 | `-; 807 |-ExpressionStatement 808 | |-BinaryOperatorExpression 809 | | |-UnknownExpression 810 | | | `-1 811 | | |-== 812 | | `-UnknownExpression 813 | | `-2 814 | `-; 815 |-ExpressionStatement 816 | |-BinaryOperatorExpression 817 | | |-UnknownExpression 818 | | | `-a 819 | | |-= 820 | | `-UnknownExpression 821 | | `-1 822 | `-; 823 |-ExpressionStatement 824 | |-BinaryOperatorExpression 825 | | |-UnknownExpression 826 | | | `-a 827 | | |-<<= 828 | | `-UnknownExpression 829 | | `-1 830 | `-; 831 |-ExpressionStatement 832 | |-BinaryOperatorExpression 833 | | |-UnknownExpression 834 | | | `-true 835 | | |-|| 836 | | `-UnknownExpression 837 | | `-false 838 | `-; 839 |-ExpressionStatement 840 | |-BinaryOperatorExpression 841 | | |-UnknownExpression 842 | | | `-true 843 | | |-or 844 | | `-UnknownExpression 845 | | `-false 846 | `-; 847 |-ExpressionStatement 848 | |-BinaryOperatorExpression 849 | | |-UnknownExpression 850 | | | `-1 851 | | |-& 852 | | `-UnknownExpression 853 | | `-2 854 | `-; 855 |-ExpressionStatement 856 | |-BinaryOperatorExpression 857 | | |-UnknownExpression 858 | | | `-1 859 | | |-bitand 860 | | `-UnknownExpression 861 | | `-2 862 | `-; 863 |-ExpressionStatement 864 | |-BinaryOperatorExpression 865 | | |-UnknownExpression 866 | | | `-a 867 | | |-^= 868 | | `-UnknownExpression 869 | | `-3 870 | `-; 871 |-ExpressionStatement 872 | |-BinaryOperatorExpression 873 | | |-UnknownExpression 874 | | | `-a 875 | | |-xor_eq 876 | | `-UnknownExpression 877 | | `-3 878 | `-; 879 `-} 880 )txt"); 881 } 882 883 TEST_F(SyntaxTreeTest, NestedBinaryOperator) { 884 expectTreeDumpEqual( 885 R"cpp( 886 void test(int a, int b) { 887 (1 + 2) * (4 / 2); 888 a + b + 42; 889 a = b = 42; 890 a + b * 4 + 2; 891 a % 2 + b * 42; 892 } 893 )cpp", 894 R"txt( 895 *: TranslationUnit 896 `-SimpleDeclaration 897 |-void 898 |-SimpleDeclarator 899 | |-test 900 | `-ParametersAndQualifiers 901 | |-( 902 | |-SimpleDeclaration 903 | | |-int 904 | | `-SimpleDeclarator 905 | | `-a 906 | |-, 907 | |-SimpleDeclaration 908 | | |-int 909 | | `-SimpleDeclarator 910 | | `-b 911 | `-) 912 `-CompoundStatement 913 |-{ 914 |-ExpressionStatement 915 | |-BinaryOperatorExpression 916 | | |-UnknownExpression 917 | | | |-( 918 | | | |-BinaryOperatorExpression 919 | | | | |-UnknownExpression 920 | | | | | `-1 921 | | | | |-+ 922 | | | | `-UnknownExpression 923 | | | | `-2 924 | | | `-) 925 | | |-* 926 | | `-UnknownExpression 927 | | |-( 928 | | |-BinaryOperatorExpression 929 | | | |-UnknownExpression 930 | | | | `-4 931 | | | |-/ 932 | | | `-UnknownExpression 933 | | | `-2 934 | | `-) 935 | `-; 936 |-ExpressionStatement 937 | |-BinaryOperatorExpression 938 | | |-BinaryOperatorExpression 939 | | | |-UnknownExpression 940 | | | | `-a 941 | | | |-+ 942 | | | `-UnknownExpression 943 | | | `-b 944 | | |-+ 945 | | `-UnknownExpression 946 | | `-42 947 | `-; 948 |-ExpressionStatement 949 | |-BinaryOperatorExpression 950 | | |-UnknownExpression 951 | | | `-a 952 | | |-= 953 | | `-BinaryOperatorExpression 954 | | |-UnknownExpression 955 | | | `-b 956 | | |-= 957 | | `-UnknownExpression 958 | | `-42 959 | `-; 960 |-ExpressionStatement 961 | |-BinaryOperatorExpression 962 | | |-BinaryOperatorExpression 963 | | | |-UnknownExpression 964 | | | | `-a 965 | | | |-+ 966 | | | `-BinaryOperatorExpression 967 | | | |-UnknownExpression 968 | | | | `-b 969 | | | |-* 970 | | | `-UnknownExpression 971 | | | `-4 972 | | |-+ 973 | | `-UnknownExpression 974 | | `-2 975 | `-; 976 |-ExpressionStatement 977 | |-BinaryOperatorExpression 978 | | |-BinaryOperatorExpression 979 | | | |-UnknownExpression 980 | | | | `-a 981 | | | |-% 982 | | | `-UnknownExpression 983 | | | `-2 984 | | |-+ 985 | | `-BinaryOperatorExpression 986 | | |-UnknownExpression 987 | | | `-b 988 | | |-* 989 | | `-UnknownExpression 990 | | `-42 991 | `-; 992 `-} 993 )txt"); 994 } 995 996 TEST_F(SyntaxTreeTest, UserDefinedBinaryOperator) { 997 expectTreeDumpEqual( 998 R"cpp( 999 struct X { 1000 X& operator=(const X&); 1001 friend X operator+(X, const X&); 1002 friend bool operator<(const X&, const X&); 1003 }; 1004 void test(X x, X y) { 1005 x = y; 1006 x + y; 1007 x < y; 1008 } 1009 )cpp", 1010 R"txt( 1011 *: TranslationUnit 1012 |-SimpleDeclaration 1013 | |-struct 1014 | |-X 1015 | |-{ 1016 | |-SimpleDeclaration 1017 | | |-X 1018 | | |-SimpleDeclarator 1019 | | | |-& 1020 | | | |-operator 1021 | | | |-= 1022 | | | `-ParametersAndQualifiers 1023 | | | |-( 1024 | | | |-SimpleDeclaration 1025 | | | | |-const 1026 | | | | |-X 1027 | | | | `-SimpleDeclarator 1028 | | | | `-& 1029 | | | `-) 1030 | | `-; 1031 | |-UnknownDeclaration 1032 | | `-SimpleDeclaration 1033 | | |-friend 1034 | | |-X 1035 | | |-SimpleDeclarator 1036 | | | |-operator 1037 | | | |-+ 1038 | | | `-ParametersAndQualifiers 1039 | | | |-( 1040 | | | |-SimpleDeclaration 1041 | | | | `-X 1042 | | | |-, 1043 | | | |-SimpleDeclaration 1044 | | | | |-const 1045 | | | | |-X 1046 | | | | `-SimpleDeclarator 1047 | | | | `-& 1048 | | | `-) 1049 | | `-; 1050 | |-UnknownDeclaration 1051 | | `-SimpleDeclaration 1052 | | |-friend 1053 | | |-bool 1054 | | |-SimpleDeclarator 1055 | | | |-operator 1056 | | | |-< 1057 | | | `-ParametersAndQualifiers 1058 | | | |-( 1059 | | | |-SimpleDeclaration 1060 | | | | |-const 1061 | | | | |-X 1062 | | | | `-SimpleDeclarator 1063 | | | | `-& 1064 | | | |-, 1065 | | | |-SimpleDeclaration 1066 | | | | |-const 1067 | | | | |-X 1068 | | | | `-SimpleDeclarator 1069 | | | | `-& 1070 | | | `-) 1071 | | `-; 1072 | |-} 1073 | `-; 1074 `-SimpleDeclaration 1075 |-void 1076 |-SimpleDeclarator 1077 | |-test 1078 | `-ParametersAndQualifiers 1079 | |-( 1080 | |-SimpleDeclaration 1081 | | |-X 1082 | | `-SimpleDeclarator 1083 | | `-x 1084 | |-, 1085 | |-SimpleDeclaration 1086 | | |-X 1087 | | `-SimpleDeclarator 1088 | | `-y 1089 | `-) 1090 `-CompoundStatement 1091 |-{ 1092 |-ExpressionStatement 1093 | |-BinaryOperatorExpression 1094 | | |-UnknownExpression 1095 | | | `-x 1096 | | |-UnknownExpression 1097 | | | `-= 1098 | | `-UnknownExpression 1099 | | `-y 1100 | `-; 1101 |-ExpressionStatement 1102 | |-BinaryOperatorExpression 1103 | | |-UnknownExpression 1104 | | | `-UnknownExpression 1105 | | | `-x 1106 | | |-UnknownExpression 1107 | | | `-+ 1108 | | `-UnknownExpression 1109 | | `-y 1110 | `-; 1111 |-ExpressionStatement 1112 | |-BinaryOperatorExpression 1113 | | |-UnknownExpression 1114 | | | `-x 1115 | | |-UnknownExpression 1116 | | | `-< 1117 | | `-UnknownExpression 1118 | | `-y 1119 | `-; 1120 `-} 1121 )txt"); 1122 } 1123 1124 TEST_F(SyntaxTreeTest, MultipleDeclaratorsGrouping) { 1125 expectTreeDumpEqual( 1126 R"cpp( 1127 int *a, b; int *c, d; 1128 )cpp", 1129 R"txt( 1130 *: TranslationUnit 1131 |-SimpleDeclaration 1132 | |-int 1133 | |-SimpleDeclarator 1134 | | |-* 1135 | | `-a 1136 | |-, 1137 | |-SimpleDeclarator 1138 | | `-b 1139 | `-; 1140 `-SimpleDeclaration 1141 |-int 1142 |-SimpleDeclarator 1143 | |-* 1144 | `-c 1145 |-, 1146 |-SimpleDeclarator 1147 | `-d 1148 `-; 1149 )txt"); 1150 } 1151 1152 TEST_F(SyntaxTreeTest, MultipleDeclaratorsGroupingTypedef) { 1153 expectTreeDumpEqual( 1154 R"cpp( 1155 typedef int *a, b; 1156 )cpp", 1157 R"txt( 1158 *: TranslationUnit 1159 `-SimpleDeclaration 1160 |-typedef 1161 |-int 1162 |-SimpleDeclarator 1163 | |-* 1164 | `-a 1165 |-, 1166 |-SimpleDeclarator 1167 | `-b 1168 `-; 1169 )txt"); 1170 } 1171 1172 TEST_F(SyntaxTreeTest, MultipleDeclaratorsInsideStatement) { 1173 expectTreeDumpEqual( 1174 R"cpp( 1175 void foo() { 1176 int *a, b; 1177 typedef int *ta, tb; 1178 } 1179 )cpp", 1180 R"txt( 1181 *: TranslationUnit 1182 `-SimpleDeclaration 1183 |-void 1184 |-SimpleDeclarator 1185 | |-foo 1186 | `-ParametersAndQualifiers 1187 | |-( 1188 | `-) 1189 `-CompoundStatement 1190 |-{ 1191 |-DeclarationStatement 1192 | |-SimpleDeclaration 1193 | | |-int 1194 | | |-SimpleDeclarator 1195 | | | |-* 1196 | | | `-a 1197 | | |-, 1198 | | `-SimpleDeclarator 1199 | | `-b 1200 | `-; 1201 |-DeclarationStatement 1202 | |-SimpleDeclaration 1203 | | |-typedef 1204 | | |-int 1205 | | |-SimpleDeclarator 1206 | | | |-* 1207 | | | `-ta 1208 | | |-, 1209 | | `-SimpleDeclarator 1210 | | `-tb 1211 | `-; 1212 `-} 1213 )txt"); 1214 } 1215 1216 TEST_F(SyntaxTreeTest, Namespaces) { 1217 expectTreeDumpEqual( 1218 R"cpp( 1219 namespace a { namespace b {} } 1220 namespace a::b {} 1221 namespace {} 1222 1223 namespace foo = a; 1224 )cpp", 1225 R"txt( 1226 *: TranslationUnit 1227 |-NamespaceDefinition 1228 | |-namespace 1229 | |-a 1230 | |-{ 1231 | |-NamespaceDefinition 1232 | | |-namespace 1233 | | |-b 1234 | | |-{ 1235 | | `-} 1236 | `-} 1237 |-NamespaceDefinition 1238 | |-namespace 1239 | |-a 1240 | |-:: 1241 | |-b 1242 | |-{ 1243 | `-} 1244 |-NamespaceDefinition 1245 | |-namespace 1246 | |-{ 1247 | `-} 1248 `-NamespaceAliasDefinition 1249 |-namespace 1250 |-foo 1251 |-= 1252 |-a 1253 `-; 1254 )txt"); 1255 } 1256 1257 TEST_F(SyntaxTreeTest, UsingDirective) { 1258 expectTreeDumpEqual( 1259 R"cpp( 1260 namespace ns {} 1261 using namespace ::ns; 1262 )cpp", 1263 R"txt( 1264 *: TranslationUnit 1265 |-NamespaceDefinition 1266 | |-namespace 1267 | |-ns 1268 | |-{ 1269 | `-} 1270 `-UsingNamespaceDirective 1271 |-using 1272 |-namespace 1273 |-:: 1274 |-ns 1275 `-; 1276 )txt"); 1277 } 1278 1279 TEST_F(SyntaxTreeTest, UsingDeclaration) { 1280 expectTreeDumpEqual( 1281 R"cpp( 1282 namespace ns { int a; } 1283 using ns::a; 1284 )cpp", 1285 R"txt( 1286 *: TranslationUnit 1287 |-NamespaceDefinition 1288 | |-namespace 1289 | |-ns 1290 | |-{ 1291 | |-SimpleDeclaration 1292 | | |-int 1293 | | |-SimpleDeclarator 1294 | | | `-a 1295 | | `-; 1296 | `-} 1297 `-UsingDeclaration 1298 |-using 1299 |-ns 1300 |-:: 1301 |-a 1302 `-; 1303 )txt"); 1304 } 1305 1306 TEST_F(SyntaxTreeTest, FreeStandingClasses) { 1307 // Free-standing classes, must live inside a SimpleDeclaration. 1308 expectTreeDumpEqual( 1309 R"cpp( 1310 struct X; 1311 struct X {}; 1312 1313 struct Y *y1; 1314 struct Y {} *y2; 1315 1316 struct {} *a1; 1317 )cpp", 1318 R"txt( 1319 *: TranslationUnit 1320 |-SimpleDeclaration 1321 | |-struct 1322 | |-X 1323 | `-; 1324 |-SimpleDeclaration 1325 | |-struct 1326 | |-X 1327 | |-{ 1328 | |-} 1329 | `-; 1330 |-SimpleDeclaration 1331 | |-struct 1332 | |-Y 1333 | |-SimpleDeclarator 1334 | | |-* 1335 | | `-y1 1336 | `-; 1337 |-SimpleDeclaration 1338 | |-struct 1339 | |-Y 1340 | |-{ 1341 | |-} 1342 | |-SimpleDeclarator 1343 | | |-* 1344 | | `-y2 1345 | `-; 1346 `-SimpleDeclaration 1347 |-struct 1348 |-{ 1349 |-} 1350 |-SimpleDeclarator 1351 | |-* 1352 | `-a1 1353 `-; 1354 )txt"); 1355 } 1356 1357 TEST_F(SyntaxTreeTest, Templates) { 1358 expectTreeDumpEqual( 1359 R"cpp( 1360 template <class T> struct cls {}; 1361 template <class T> int var = 10; 1362 template <class T> int fun() {} 1363 )cpp", 1364 R"txt( 1365 *: TranslationUnit 1366 |-TemplateDeclaration 1367 | |-template 1368 | |-< 1369 | |-UnknownDeclaration 1370 | | |-class 1371 | | `-T 1372 | |-> 1373 | `-SimpleDeclaration 1374 | |-struct 1375 | |-cls 1376 | |-{ 1377 | |-} 1378 | `-; 1379 |-TemplateDeclaration 1380 | |-template 1381 | |-< 1382 | |-UnknownDeclaration 1383 | | |-class 1384 | | `-T 1385 | |-> 1386 | `-SimpleDeclaration 1387 | |-int 1388 | |-SimpleDeclarator 1389 | | |-var 1390 | | |-= 1391 | | `-UnknownExpression 1392 | | `-10 1393 | `-; 1394 `-TemplateDeclaration 1395 |-template 1396 |-< 1397 |-UnknownDeclaration 1398 | |-class 1399 | `-T 1400 |-> 1401 `-SimpleDeclaration 1402 |-int 1403 |-SimpleDeclarator 1404 | |-fun 1405 | `-ParametersAndQualifiers 1406 | |-( 1407 | `-) 1408 `-CompoundStatement 1409 |-{ 1410 `-} 1411 )txt", 1412 // FIXME: Make this test work on windows by generating the expected Syntax 1413 // tree when -fdelayed-template-parsing is active. 1414 /*RunWithDelayedTemplateParsing=*/false); 1415 } 1416 1417 TEST_F(SyntaxTreeTest, NestedTemplates) { 1418 expectTreeDumpEqual( 1419 R"cpp( 1420 template <class T> 1421 struct X { 1422 template <class U> 1423 U foo(); 1424 }; 1425 )cpp", 1426 R"txt( 1427 *: TranslationUnit 1428 `-TemplateDeclaration 1429 |-template 1430 |-< 1431 |-UnknownDeclaration 1432 | |-class 1433 | `-T 1434 |-> 1435 `-SimpleDeclaration 1436 |-struct 1437 |-X 1438 |-{ 1439 |-TemplateDeclaration 1440 | |-template 1441 | |-< 1442 | |-UnknownDeclaration 1443 | | |-class 1444 | | `-U 1445 | |-> 1446 | `-SimpleDeclaration 1447 | |-U 1448 | |-SimpleDeclarator 1449 | | |-foo 1450 | | `-ParametersAndQualifiers 1451 | | |-( 1452 | | `-) 1453 | `-; 1454 |-} 1455 `-; 1456 )txt"); 1457 } 1458 1459 TEST_F(SyntaxTreeTest, Templates2) { 1460 expectTreeDumpEqual( 1461 R"cpp( 1462 template <class T> struct X { struct Y; }; 1463 template <class T> struct X<T>::Y {}; 1464 )cpp", 1465 R"txt( 1466 *: TranslationUnit 1467 |-TemplateDeclaration 1468 | |-template 1469 | |-< 1470 | |-UnknownDeclaration 1471 | | |-class 1472 | | `-T 1473 | |-> 1474 | `-SimpleDeclaration 1475 | |-struct 1476 | |-X 1477 | |-{ 1478 | |-SimpleDeclaration 1479 | | |-struct 1480 | | |-Y 1481 | | `-; 1482 | |-} 1483 | `-; 1484 `-TemplateDeclaration 1485 |-template 1486 |-< 1487 |-UnknownDeclaration 1488 | |-class 1489 | `-T 1490 |-> 1491 `-SimpleDeclaration 1492 |-struct 1493 |-X 1494 |-< 1495 |-T 1496 |-> 1497 |-:: 1498 |-Y 1499 |-{ 1500 |-} 1501 `-; 1502 )txt"); 1503 } 1504 1505 TEST_F(SyntaxTreeTest, TemplatesUsingUsing) { 1506 expectTreeDumpEqual( 1507 R"cpp( 1508 template <class T> struct X { 1509 using T::foo; 1510 using typename T::bar; 1511 }; 1512 )cpp", 1513 R"txt( 1514 *: TranslationUnit 1515 `-TemplateDeclaration 1516 |-template 1517 |-< 1518 |-UnknownDeclaration 1519 | |-class 1520 | `-T 1521 |-> 1522 `-SimpleDeclaration 1523 |-struct 1524 |-X 1525 |-{ 1526 |-UsingDeclaration 1527 | |-using 1528 | |-T 1529 | |-:: 1530 | |-foo 1531 | `-; 1532 |-UsingDeclaration 1533 | |-using 1534 | |-typename 1535 | |-T 1536 | |-:: 1537 | |-bar 1538 | `-; 1539 |-} 1540 `-; 1541 )txt"); 1542 } 1543 1544 TEST_F(SyntaxTreeTest, ExplicitTemplateInstantations) { 1545 expectTreeDumpEqual( 1546 R"cpp( 1547 template <class T> struct X {}; 1548 template <class T> struct X<T*> {}; 1549 template <> struct X<int> {}; 1550 1551 template struct X<double>; 1552 extern template struct X<float>; 1553 )cpp", 1554 R"txt( 1555 *: TranslationUnit 1556 |-TemplateDeclaration 1557 | |-template 1558 | |-< 1559 | |-UnknownDeclaration 1560 | | |-class 1561 | | `-T 1562 | |-> 1563 | `-SimpleDeclaration 1564 | |-struct 1565 | |-X 1566 | |-{ 1567 | |-} 1568 | `-; 1569 |-TemplateDeclaration 1570 | |-template 1571 | |-< 1572 | |-UnknownDeclaration 1573 | | |-class 1574 | | `-T 1575 | |-> 1576 | `-SimpleDeclaration 1577 | |-struct 1578 | |-X 1579 | |-< 1580 | |-T 1581 | |-* 1582 | |-> 1583 | |-{ 1584 | |-} 1585 | `-; 1586 |-TemplateDeclaration 1587 | |-template 1588 | |-< 1589 | |-> 1590 | `-SimpleDeclaration 1591 | |-struct 1592 | |-X 1593 | |-< 1594 | |-int 1595 | |-> 1596 | |-{ 1597 | |-} 1598 | `-; 1599 |-ExplicitTemplateInstantiation 1600 | |-template 1601 | `-SimpleDeclaration 1602 | |-struct 1603 | |-X 1604 | |-< 1605 | |-double 1606 | |-> 1607 | `-; 1608 `-ExplicitTemplateInstantiation 1609 |-extern 1610 |-template 1611 `-SimpleDeclaration 1612 |-struct 1613 |-X 1614 |-< 1615 |-float 1616 |-> 1617 `-; 1618 )txt"); 1619 } 1620 1621 TEST_F(SyntaxTreeTest, UsingType) { 1622 expectTreeDumpEqual( 1623 R"cpp( 1624 using type = int; 1625 )cpp", 1626 R"txt( 1627 *: TranslationUnit 1628 `-TypeAliasDeclaration 1629 |-using 1630 |-type 1631 |-= 1632 |-int 1633 `-; 1634 )txt"); 1635 } 1636 1637 TEST_F(SyntaxTreeTest, EmptyDeclaration) { 1638 expectTreeDumpEqual( 1639 R"cpp( 1640 ; 1641 )cpp", 1642 R"txt( 1643 *: TranslationUnit 1644 `-EmptyDeclaration 1645 `-; 1646 )txt"); 1647 } 1648 1649 TEST_F(SyntaxTreeTest, StaticAssert) { 1650 expectTreeDumpEqual( 1651 R"cpp( 1652 static_assert(true, "message"); 1653 static_assert(true); 1654 )cpp", 1655 R"txt( 1656 *: TranslationUnit 1657 |-StaticAssertDeclaration 1658 | |-static_assert 1659 | |-( 1660 | |-UnknownExpression 1661 | | `-true 1662 | |-, 1663 | |-UnknownExpression 1664 | | `-"message" 1665 | |-) 1666 | `-; 1667 `-StaticAssertDeclaration 1668 |-static_assert 1669 |-( 1670 |-UnknownExpression 1671 | `-true 1672 |-) 1673 `-; 1674 )txt"); 1675 } 1676 1677 TEST_F(SyntaxTreeTest, ExternC) { 1678 expectTreeDumpEqual( 1679 R"cpp( 1680 extern "C" int a; 1681 extern "C" { int b; int c; } 1682 )cpp", 1683 R"txt( 1684 *: TranslationUnit 1685 |-LinkageSpecificationDeclaration 1686 | |-extern 1687 | |-"C" 1688 | `-SimpleDeclaration 1689 | |-int 1690 | |-SimpleDeclarator 1691 | | `-a 1692 | `-; 1693 `-LinkageSpecificationDeclaration 1694 |-extern 1695 |-"C" 1696 |-{ 1697 |-SimpleDeclaration 1698 | |-int 1699 | |-SimpleDeclarator 1700 | | `-b 1701 | `-; 1702 |-SimpleDeclaration 1703 | |-int 1704 | |-SimpleDeclarator 1705 | | `-c 1706 | `-; 1707 `-} 1708 )txt"); 1709 } 1710 1711 TEST_F(SyntaxTreeTest, NonModifiableNodes) { 1712 // Some nodes are non-modifiable, they are marked with 'I:'. 1713 expectTreeDumpEqual( 1714 R"cpp( 1715 #define HALF_IF if (1+ 1716 #define HALF_IF_2 1) {} 1717 void test() { 1718 HALF_IF HALF_IF_2 else {} 1719 })cpp", 1720 R"txt( 1721 *: TranslationUnit 1722 `-SimpleDeclaration 1723 |-void 1724 |-SimpleDeclarator 1725 | |-test 1726 | `-ParametersAndQualifiers 1727 | |-( 1728 | `-) 1729 `-CompoundStatement 1730 |-{ 1731 |-IfStatement 1732 | |-I: if 1733 | |-I: ( 1734 | |-I: BinaryOperatorExpression 1735 | | |-I: UnknownExpression 1736 | | | `-I: 1 1737 | | |-I: + 1738 | | `-I: UnknownExpression 1739 | | `-I: 1 1740 | |-I: ) 1741 | |-I: CompoundStatement 1742 | | |-I: { 1743 | | `-I: } 1744 | |-else 1745 | `-CompoundStatement 1746 | |-{ 1747 | `-} 1748 `-} 1749 )txt"); 1750 } 1751 1752 TEST_F(SyntaxTreeTest, ModifiableNodes) { 1753 // All nodes can be mutated. 1754 expectTreeDumpEqual( 1755 R"cpp( 1756 #define OPEN { 1757 #define CLOSE } 1758 1759 void test() { 1760 OPEN 1761 1; 1762 CLOSE 1763 1764 OPEN 1765 2; 1766 } 1767 } 1768 )cpp", 1769 R"txt( 1770 *: TranslationUnit 1771 `-SimpleDeclaration 1772 |-void 1773 |-SimpleDeclarator 1774 | |-test 1775 | `-ParametersAndQualifiers 1776 | |-( 1777 | `-) 1778 `-CompoundStatement 1779 |-{ 1780 |-CompoundStatement 1781 | |-{ 1782 | |-ExpressionStatement 1783 | | |-UnknownExpression 1784 | | | `-1 1785 | | `-; 1786 | `-} 1787 |-CompoundStatement 1788 | |-{ 1789 | |-ExpressionStatement 1790 | | |-UnknownExpression 1791 | | | `-2 1792 | | `-; 1793 | `-} 1794 `-} 1795 )txt"); 1796 } 1797 1798 TEST_F(SyntaxTreeTest, ArraySubscriptsInDeclarators) { 1799 expectTreeDumpEqual( 1800 R"cpp( 1801 int a[10]; 1802 int b[1][2][3]; 1803 int c[] = {1,2,3}; 1804 // void f(int xs[static 10]); 1805 )cpp", 1806 R"txt( 1807 *: TranslationUnit 1808 |-SimpleDeclaration 1809 | |-int 1810 | |-SimpleDeclarator 1811 | | |-a 1812 | | `-ArraySubscript 1813 | | |-[ 1814 | | |-UnknownExpression 1815 | | | `-10 1816 | | `-] 1817 | `-; 1818 |-SimpleDeclaration 1819 | |-int 1820 | |-SimpleDeclarator 1821 | | |-b 1822 | | |-ArraySubscript 1823 | | | |-[ 1824 | | | |-UnknownExpression 1825 | | | | `-1 1826 | | | `-] 1827 | | |-ArraySubscript 1828 | | | |-[ 1829 | | | |-UnknownExpression 1830 | | | | `-2 1831 | | | `-] 1832 | | `-ArraySubscript 1833 | | |-[ 1834 | | |-UnknownExpression 1835 | | | `-3 1836 | | `-] 1837 | `-; 1838 `-SimpleDeclaration 1839 |-int 1840 |-SimpleDeclarator 1841 | |-c 1842 | |-ArraySubscript 1843 | | |-[ 1844 | | `-] 1845 | |-= 1846 | `-UnknownExpression 1847 | `-UnknownExpression 1848 | |-{ 1849 | |-UnknownExpression 1850 | | `-1 1851 | |-, 1852 | |-UnknownExpression 1853 | | `-2 1854 | |-, 1855 | |-UnknownExpression 1856 | | `-3 1857 | `-} 1858 `-; )txt"); 1859 } 1860 1861 TEST_F(SyntaxTreeTest, ParameterListsInDeclarators) { 1862 expectTreeDumpEqual( 1863 R"cpp( 1864 struct Test { 1865 int a() const; 1866 int b() volatile; 1867 int c() &; 1868 int d() &&; 1869 int foo(int a, int b); 1870 int foo(const int a, volatile int b, const volatile int c, int* d, 1871 int& e, int&& f); 1872 }; 1873 )cpp", 1874 R"txt( 1875 *: TranslationUnit 1876 `-SimpleDeclaration 1877 |-struct 1878 |-Test 1879 |-{ 1880 |-SimpleDeclaration 1881 | |-int 1882 | |-SimpleDeclarator 1883 | | |-a 1884 | | `-ParametersAndQualifiers 1885 | | |-( 1886 | | |-) 1887 | | `-const 1888 | `-; 1889 |-SimpleDeclaration 1890 | |-int 1891 | |-SimpleDeclarator 1892 | | |-b 1893 | | `-ParametersAndQualifiers 1894 | | |-( 1895 | | |-) 1896 | | `-volatile 1897 | `-; 1898 |-SimpleDeclaration 1899 | |-int 1900 | |-SimpleDeclarator 1901 | | |-c 1902 | | `-ParametersAndQualifiers 1903 | | |-( 1904 | | |-) 1905 | | `-& 1906 | `-; 1907 |-SimpleDeclaration 1908 | |-int 1909 | |-SimpleDeclarator 1910 | | |-d 1911 | | `-ParametersAndQualifiers 1912 | | |-( 1913 | | |-) 1914 | | `-&& 1915 | `-; 1916 |-SimpleDeclaration 1917 | |-int 1918 | |-SimpleDeclarator 1919 | | |-foo 1920 | | `-ParametersAndQualifiers 1921 | | |-( 1922 | | |-SimpleDeclaration 1923 | | | |-int 1924 | | | `-SimpleDeclarator 1925 | | | `-a 1926 | | |-, 1927 | | |-SimpleDeclaration 1928 | | | |-int 1929 | | | `-SimpleDeclarator 1930 | | | `-b 1931 | | `-) 1932 | `-; 1933 |-SimpleDeclaration 1934 | |-int 1935 | |-SimpleDeclarator 1936 | | |-foo 1937 | | `-ParametersAndQualifiers 1938 | | |-( 1939 | | |-SimpleDeclaration 1940 | | | |-const 1941 | | | |-int 1942 | | | `-SimpleDeclarator 1943 | | | `-a 1944 | | |-, 1945 | | |-SimpleDeclaration 1946 | | | |-volatile 1947 | | | |-int 1948 | | | `-SimpleDeclarator 1949 | | | `-b 1950 | | |-, 1951 | | |-SimpleDeclaration 1952 | | | |-const 1953 | | | |-volatile 1954 | | | |-int 1955 | | | `-SimpleDeclarator 1956 | | | `-c 1957 | | |-, 1958 | | |-SimpleDeclaration 1959 | | | |-int 1960 | | | `-SimpleDeclarator 1961 | | | |-* 1962 | | | `-d 1963 | | |-, 1964 | | |-SimpleDeclaration 1965 | | | |-int 1966 | | | `-SimpleDeclarator 1967 | | | |-& 1968 | | | `-e 1969 | | |-, 1970 | | |-SimpleDeclaration 1971 | | | |-int 1972 | | | `-SimpleDeclarator 1973 | | | |-&& 1974 | | | `-f 1975 | | `-) 1976 | `-; 1977 |-} 1978 `-; 1979 )txt"); 1980 } 1981 1982 TEST_F(SyntaxTreeTest, TrailingConst) { 1983 expectTreeDumpEqual( 1984 R"cpp( 1985 struct X { 1986 int foo() const; 1987 }; 1988 )cpp", 1989 R"txt( 1990 *: TranslationUnit 1991 `-SimpleDeclaration 1992 |-struct 1993 |-X 1994 |-{ 1995 |-SimpleDeclaration 1996 | |-int 1997 | |-SimpleDeclarator 1998 | | |-foo 1999 | | `-ParametersAndQualifiers 2000 | | |-( 2001 | | |-) 2002 | | `-const 2003 | `-; 2004 |-} 2005 `-; 2006 )txt"); 2007 } 2008 2009 TEST_F(SyntaxTreeTest, TrailingReturn) { 2010 expectTreeDumpEqual( 2011 R"cpp( 2012 auto foo() -> int; 2013 )cpp", 2014 R"txt( 2015 *: TranslationUnit 2016 `-SimpleDeclaration 2017 |-auto 2018 |-SimpleDeclarator 2019 | |-foo 2020 | `-ParametersAndQualifiers 2021 | |-( 2022 | |-) 2023 | `-TrailingReturnType 2024 | |--> 2025 | `-int 2026 `-; 2027 )txt"); 2028 } 2029 2030 TEST_F(SyntaxTreeTest, ExceptionSpecification) { 2031 expectTreeDumpEqual( 2032 R"cpp( 2033 int a() noexcept; 2034 int b() noexcept(true); 2035 int c() throw(); 2036 )cpp", 2037 R"txt( 2038 *: TranslationUnit 2039 |-SimpleDeclaration 2040 | |-int 2041 | |-SimpleDeclarator 2042 | | |-a 2043 | | `-ParametersAndQualifiers 2044 | | |-( 2045 | | |-) 2046 | | `-noexcept 2047 | `-; 2048 |-SimpleDeclaration 2049 | |-int 2050 | |-SimpleDeclarator 2051 | | |-b 2052 | | `-ParametersAndQualifiers 2053 | | |-( 2054 | | |-) 2055 | | |-noexcept 2056 | | |-( 2057 | | |-UnknownExpression 2058 | | | `-true 2059 | | `-) 2060 | `-; 2061 `-SimpleDeclaration 2062 |-int 2063 |-SimpleDeclarator 2064 | |-c 2065 | `-ParametersAndQualifiers 2066 | |-( 2067 | |-) 2068 | |-throw 2069 | |-( 2070 | `-) 2071 `-; 2072 )txt"); 2073 } 2074 2075 TEST_F(SyntaxTreeTest, DeclaratorsInParentheses) { 2076 expectTreeDumpEqual( 2077 R"cpp( 2078 int (a); 2079 int *(b); 2080 int (*c)(int); 2081 int *(d)(int); 2082 )cpp", 2083 R"txt( 2084 *: TranslationUnit 2085 |-SimpleDeclaration 2086 | |-int 2087 | |-SimpleDeclarator 2088 | | `-ParenDeclarator 2089 | | |-( 2090 | | |-a 2091 | | `-) 2092 | `-; 2093 |-SimpleDeclaration 2094 | |-int 2095 | |-SimpleDeclarator 2096 | | |-* 2097 | | `-ParenDeclarator 2098 | | |-( 2099 | | |-b 2100 | | `-) 2101 | `-; 2102 |-SimpleDeclaration 2103 | |-int 2104 | |-SimpleDeclarator 2105 | | |-ParenDeclarator 2106 | | | |-( 2107 | | | |-* 2108 | | | |-c 2109 | | | `-) 2110 | | `-ParametersAndQualifiers 2111 | | |-( 2112 | | |-SimpleDeclaration 2113 | | | `-int 2114 | | `-) 2115 | `-; 2116 `-SimpleDeclaration 2117 |-int 2118 |-SimpleDeclarator 2119 | |-* 2120 | |-ParenDeclarator 2121 | | |-( 2122 | | |-d 2123 | | `-) 2124 | `-ParametersAndQualifiers 2125 | |-( 2126 | |-SimpleDeclaration 2127 | | `-int 2128 | `-) 2129 `-; 2130 )txt"); 2131 } 2132 2133 TEST_F(SyntaxTreeTest, ConstVolatileQualifiers) { 2134 expectTreeDumpEqual( 2135 R"cpp( 2136 const int west = -1; 2137 int const east = 1; 2138 const int const universal = 0; 2139 const int const *const *volatile b; 2140 )cpp", 2141 R"txt( 2142 *: TranslationUnit 2143 |-SimpleDeclaration 2144 | |-const 2145 | |-int 2146 | |-SimpleDeclarator 2147 | | |-west 2148 | | |-= 2149 | | `-PrefixUnaryOperatorExpression 2150 | | |-- 2151 | | `-UnknownExpression 2152 | | `-1 2153 | `-; 2154 |-SimpleDeclaration 2155 | |-int 2156 | |-const 2157 | |-SimpleDeclarator 2158 | | |-east 2159 | | |-= 2160 | | `-UnknownExpression 2161 | | `-1 2162 | `-; 2163 |-SimpleDeclaration 2164 | |-const 2165 | |-int 2166 | |-const 2167 | |-SimpleDeclarator 2168 | | |-universal 2169 | | |-= 2170 | | `-UnknownExpression 2171 | | `-0 2172 | `-; 2173 `-SimpleDeclaration 2174 |-const 2175 |-int 2176 |-const 2177 |-SimpleDeclarator 2178 | |-* 2179 | |-const 2180 | |-* 2181 | |-volatile 2182 | `-b 2183 `-; 2184 )txt"); 2185 } 2186 2187 TEST_F(SyntaxTreeTest, RangesOfDeclaratorsWithTrailingReturnTypes) { 2188 expectTreeDumpEqual( 2189 R"cpp( 2190 auto foo() -> auto(*)(int) -> double*; 2191 )cpp", 2192 R"txt( 2193 *: TranslationUnit 2194 `-SimpleDeclaration 2195 |-auto 2196 |-SimpleDeclarator 2197 | |-foo 2198 | `-ParametersAndQualifiers 2199 | |-( 2200 | |-) 2201 | `-TrailingReturnType 2202 | |--> 2203 | |-auto 2204 | `-SimpleDeclarator 2205 | |-ParenDeclarator 2206 | | |-( 2207 | | |-* 2208 | | `-) 2209 | `-ParametersAndQualifiers 2210 | |-( 2211 | |-SimpleDeclaration 2212 | | `-int 2213 | |-) 2214 | `-TrailingReturnType 2215 | |--> 2216 | |-double 2217 | `-SimpleDeclarator 2218 | `-* 2219 `-; 2220 )txt"); 2221 } 2222 2223 TEST_F(SyntaxTreeTest, MemberPointers) { 2224 expectTreeDumpEqual( 2225 R"cpp( 2226 struct X {}; 2227 int X::* a; 2228 const int X::* b; 2229 )cpp", 2230 R"txt( 2231 *: TranslationUnit 2232 |-SimpleDeclaration 2233 | |-struct 2234 | |-X 2235 | |-{ 2236 | |-} 2237 | `-; 2238 |-SimpleDeclaration 2239 | |-int 2240 | |-SimpleDeclarator 2241 | | |-MemberPointer 2242 | | | |-X 2243 | | | |-:: 2244 | | | `-* 2245 | | `-a 2246 | `-; 2247 `-SimpleDeclaration 2248 |-const 2249 |-int 2250 |-SimpleDeclarator 2251 | |-MemberPointer 2252 | | |-X 2253 | | |-:: 2254 | | `-* 2255 | `-b 2256 `-; 2257 )txt"); 2258 } 2259 2260 TEST_F(SyntaxTreeTest, ComplexDeclarator) { 2261 expectTreeDumpEqual( 2262 R"cpp( 2263 void x(char a, short (*b)(int)); 2264 )cpp", 2265 R"txt( 2266 *: TranslationUnit 2267 `-SimpleDeclaration 2268 |-void 2269 |-SimpleDeclarator 2270 | |-x 2271 | `-ParametersAndQualifiers 2272 | |-( 2273 | |-SimpleDeclaration 2274 | | |-char 2275 | | `-SimpleDeclarator 2276 | | `-a 2277 | |-, 2278 | |-SimpleDeclaration 2279 | | |-short 2280 | | `-SimpleDeclarator 2281 | | |-ParenDeclarator 2282 | | | |-( 2283 | | | |-* 2284 | | | |-b 2285 | | | `-) 2286 | | `-ParametersAndQualifiers 2287 | | |-( 2288 | | |-SimpleDeclaration 2289 | | | `-int 2290 | | `-) 2291 | `-) 2292 `-; 2293 )txt"); 2294 } 2295 2296 TEST_F(SyntaxTreeTest, ComplexDeclarator2) { 2297 expectTreeDumpEqual( 2298 R"cpp( 2299 void x(char a, short (*b)(int), long (**c)(long long)); 2300 )cpp", 2301 R"txt( 2302 *: TranslationUnit 2303 `-SimpleDeclaration 2304 |-void 2305 |-SimpleDeclarator 2306 | |-x 2307 | `-ParametersAndQualifiers 2308 | |-( 2309 | |-SimpleDeclaration 2310 | | |-char 2311 | | `-SimpleDeclarator 2312 | | `-a 2313 | |-, 2314 | |-SimpleDeclaration 2315 | | |-short 2316 | | `-SimpleDeclarator 2317 | | |-ParenDeclarator 2318 | | | |-( 2319 | | | |-* 2320 | | | |-b 2321 | | | `-) 2322 | | `-ParametersAndQualifiers 2323 | | |-( 2324 | | |-SimpleDeclaration 2325 | | | `-int 2326 | | `-) 2327 | |-, 2328 | |-SimpleDeclaration 2329 | | |-long 2330 | | `-SimpleDeclarator 2331 | | |-ParenDeclarator 2332 | | | |-( 2333 | | | |-* 2334 | | | |-* 2335 | | | |-c 2336 | | | `-) 2337 | | `-ParametersAndQualifiers 2338 | | |-( 2339 | | |-SimpleDeclaration 2340 | | | |-long 2341 | | | `-long 2342 | | `-) 2343 | `-) 2344 `-; 2345 )txt"); 2346 } 2347 2348 TEST_F(SyntaxTreeTest, Mutations) { 2349 using Transformation = std::function<void( 2350 const llvm::Annotations & /*Input*/, syntax::TranslationUnit * /*Root*/)>; 2351 auto CheckTransformation = [this](std::string Input, std::string Expected, 2352 Transformation Transform) -> void { 2353 llvm::Annotations Source(Input); 2354 auto *Root = buildTree(Source.code()); 2355 2356 Transform(Source, Root); 2357 2358 auto Replacements = syntax::computeReplacements(*Arena, *Root); 2359 auto Output = tooling::applyAllReplacements(Source.code(), Replacements); 2360 if (!Output) { 2361 ADD_FAILURE() << "could not apply replacements: " 2362 << llvm::toString(Output.takeError()); 2363 return; 2364 } 2365 2366 EXPECT_EQ(Expected, *Output) << "input is:\n" << Input; 2367 }; 2368 2369 // Removes the selected statement. Input should have exactly one selected 2370 // range and it should correspond to a single statement. 2371 auto RemoveStatement = [this](const llvm::Annotations &Input, 2372 syntax::TranslationUnit *TU) { 2373 auto *S = cast<syntax::Statement>(nodeByRange(Input.range(), TU)); 2374 ASSERT_TRUE(S->canModify()) << "cannot remove a statement"; 2375 syntax::removeStatement(*Arena, S); 2376 EXPECT_TRUE(S->isDetached()); 2377 EXPECT_FALSE(S->isOriginal()) 2378 << "node removed from tree cannot be marked as original"; 2379 }; 2380 2381 std::vector<std::pair<std::string /*Input*/, std::string /*Expected*/>> 2382 Cases = { 2383 {"void test() { [[100+100;]] test(); }", "void test() { test(); }"}, 2384 {"void test() { if (true) [[{}]] else {} }", 2385 "void test() { if (true) ; else {} }"}, 2386 {"void test() { [[;]] }", "void test() { }"}}; 2387 for (const auto &C : Cases) 2388 CheckTransformation(C.first, C.second, RemoveStatement); 2389 } 2390 2391 TEST_F(SyntaxTreeTest, SynthesizedNodes) { 2392 buildTree(""); 2393 2394 auto *C = syntax::createPunctuation(*Arena, tok::comma); 2395 ASSERT_NE(C, nullptr); 2396 EXPECT_EQ(C->token()->kind(), tok::comma); 2397 EXPECT_TRUE(C->canModify()); 2398 EXPECT_FALSE(C->isOriginal()); 2399 EXPECT_TRUE(C->isDetached()); 2400 2401 auto *S = syntax::createEmptyStatement(*Arena); 2402 ASSERT_NE(S, nullptr); 2403 EXPECT_TRUE(S->canModify()); 2404 EXPECT_FALSE(S->isOriginal()); 2405 EXPECT_TRUE(S->isDetached()); 2406 } 2407 2408 } // namespace 2409