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/Lex/PreprocessorOptions.h" 19 #include "clang/Tooling/Core/Replacement.h" 20 #include "clang/Tooling/Syntax/BuildTree.h" 21 #include "clang/Tooling/Syntax/Mutations.h" 22 #include "clang/Tooling/Syntax/Nodes.h" 23 #include "clang/Tooling/Syntax/Tokens.h" 24 #include "clang/Tooling/Tooling.h" 25 #include "llvm/ADT/ArrayRef.h" 26 #include "llvm/ADT/STLExtras.h" 27 #include "llvm/ADT/StringRef.h" 28 #include "llvm/Support/Casting.h" 29 #include "llvm/Support/Error.h" 30 #include "llvm/Testing/Support/Annotations.h" 31 #include "gmock/gmock.h" 32 #include "gtest/gtest.h" 33 #include <cstdlib> 34 35 using namespace clang; 36 37 namespace { 38 static llvm::ArrayRef<syntax::Token> tokens(syntax::Node *N) { 39 assert(N->isOriginal() && "tokens of modified nodes are not well-defined"); 40 if (auto *L = dyn_cast<syntax::Leaf>(N)) 41 return llvm::makeArrayRef(L->token(), 1); 42 auto *T = cast<syntax::Tree>(N); 43 return llvm::makeArrayRef(T->firstLeaf()->token(), 44 T->lastLeaf()->token() + 1); 45 } 46 47 class SyntaxTreeTest : public ::testing::Test { 48 protected: 49 // Build a syntax tree for the code. 50 syntax::TranslationUnit *buildTree(llvm::StringRef Code, StringRef Target) { 51 // FIXME: this code is almost the identical to the one in TokensTest. Share 52 // it. 53 class BuildSyntaxTree : public ASTConsumer { 54 public: 55 BuildSyntaxTree(syntax::TranslationUnit *&Root, 56 std::unique_ptr<syntax::Arena> &Arena, 57 std::unique_ptr<syntax::TokenCollector> Tokens) 58 : Root(Root), Arena(Arena), Tokens(std::move(Tokens)) { 59 assert(this->Tokens); 60 } 61 62 void HandleTranslationUnit(ASTContext &Ctx) override { 63 Arena = std::make_unique<syntax::Arena>(Ctx.getSourceManager(), 64 Ctx.getLangOpts(), 65 std::move(*Tokens).consume()); 66 Tokens = nullptr; // make sure we fail if this gets called twice. 67 Root = syntax::buildSyntaxTree(*Arena, *Ctx.getTranslationUnitDecl()); 68 } 69 70 private: 71 syntax::TranslationUnit *&Root; 72 std::unique_ptr<syntax::Arena> &Arena; 73 std::unique_ptr<syntax::TokenCollector> Tokens; 74 }; 75 76 class BuildSyntaxTreeAction : public ASTFrontendAction { 77 public: 78 BuildSyntaxTreeAction(syntax::TranslationUnit *&Root, 79 std::unique_ptr<syntax::Arena> &Arena) 80 : Root(Root), Arena(Arena) {} 81 82 std::unique_ptr<ASTConsumer> 83 CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override { 84 // We start recording the tokens, ast consumer will take on the result. 85 auto Tokens = 86 std::make_unique<syntax::TokenCollector>(CI.getPreprocessor()); 87 return std::make_unique<BuildSyntaxTree>(Root, Arena, 88 std::move(Tokens)); 89 } 90 91 private: 92 syntax::TranslationUnit *&Root; 93 std::unique_ptr<syntax::Arena> &Arena; 94 }; 95 96 constexpr const char *FileName = "./input.cpp"; 97 FS->addFile(FileName, time_t(), llvm::MemoryBuffer::getMemBufferCopy("")); 98 if (!Diags->getClient()) 99 Diags->setClient(new IgnoringDiagConsumer); 100 // Prepare to run a compiler. 101 std::vector<const char *> Args = {"-target", Target.data(), 102 "-fsyntax-only", "-std=c++17", 103 "syntax-test", FileName}; 104 Invocation = createInvocationFromCommandLine(Args, Diags, FS); 105 assert(Invocation); 106 Invocation->getFrontendOpts().DisableFree = false; 107 Invocation->getPreprocessorOpts().addRemappedFile( 108 FileName, llvm::MemoryBuffer::getMemBufferCopy(Code).release()); 109 CompilerInstance Compiler; 110 Compiler.setInvocation(Invocation); 111 Compiler.setDiagnostics(Diags.get()); 112 Compiler.setFileManager(FileMgr.get()); 113 Compiler.setSourceManager(SourceMgr.get()); 114 115 syntax::TranslationUnit *Root = nullptr; 116 BuildSyntaxTreeAction Recorder(Root, this->Arena); 117 if (!Compiler.ExecuteAction(Recorder)) { 118 ADD_FAILURE() << "failed to run the frontend"; 119 std::abort(); 120 } 121 return Root; 122 } 123 124 void expectTreeDumpEqual(StringRef Code, StringRef Tree, 125 bool RunWithDelayedTemplateParsing = true) { 126 SCOPED_TRACE(Code); 127 128 std::string Expected = Tree.trim().str(); 129 130 // We want to run the test with -fdelayed-template-parsing enabled and 131 // disabled, therefore we use these representative targets that differ in 132 // the default value. 133 // We are not passing -fdelayed-template-parsing directly but we are using 134 // the `-target` to improve coverage and discover differences in behavior 135 // early. 136 for (const StringRef Target : 137 {"x86_64-unknown-unknown", "x86_64-pc-win32"}) { 138 if (!RunWithDelayedTemplateParsing && Target.equals("x86_64-pc-win32")) { 139 continue; 140 } 141 auto *Root = buildTree(Code, Target); 142 std::string Actual = std::string(StringRef(Root->dump(*Arena)).trim()); 143 EXPECT_EQ(Expected, Actual) 144 << "for target " << Target << " the resulting dump is:\n" 145 << Actual; 146 } 147 } 148 149 // Adds a file to the test VFS. 150 void addFile(llvm::StringRef Path, llvm::StringRef Contents) { 151 if (!FS->addFile(Path, time_t(), 152 llvm::MemoryBuffer::getMemBufferCopy(Contents))) { 153 ADD_FAILURE() << "could not add a file to VFS: " << Path; 154 } 155 } 156 157 /// Finds the deepest node in the tree that covers exactly \p R. 158 /// FIXME: implement this efficiently and move to public syntax tree API. 159 syntax::Node *nodeByRange(llvm::Annotations::Range R, syntax::Node *Root) { 160 llvm::ArrayRef<syntax::Token> Toks = tokens(Root); 161 162 if (Toks.front().location().isFileID() && 163 Toks.back().location().isFileID() && 164 syntax::Token::range(*SourceMgr, Toks.front(), Toks.back()) == 165 syntax::FileRange(SourceMgr->getMainFileID(), R.Begin, R.End)) 166 return Root; 167 168 auto *T = dyn_cast<syntax::Tree>(Root); 169 if (!T) 170 return nullptr; 171 for (auto *C = T->firstChild(); C != nullptr; C = C->nextSibling()) { 172 if (auto *Result = nodeByRange(R, C)) 173 return Result; 174 } 175 return nullptr; 176 } 177 178 // Data fields. 179 llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags = 180 new DiagnosticsEngine(new DiagnosticIDs, new DiagnosticOptions); 181 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS = 182 new llvm::vfs::InMemoryFileSystem; 183 llvm::IntrusiveRefCntPtr<FileManager> FileMgr = 184 new FileManager(FileSystemOptions(), FS); 185 llvm::IntrusiveRefCntPtr<SourceManager> SourceMgr = 186 new SourceManager(*Diags, *FileMgr); 187 std::shared_ptr<CompilerInvocation> Invocation; 188 // Set after calling buildTree(). 189 std::unique_ptr<syntax::Arena> Arena; 190 }; 191 192 TEST_F(SyntaxTreeTest, Simple) { 193 expectTreeDumpEqual( 194 R"cpp( 195 int main() {} 196 void foo() {} 197 )cpp", 198 R"txt( 199 *: TranslationUnit 200 |-SimpleDeclaration 201 | |-int 202 | |-SimpleDeclarator 203 | | |-main 204 | | `-ParametersAndQualifiers 205 | | |-( 206 | | `-) 207 | `-CompoundStatement 208 | |-{ 209 | `-} 210 `-SimpleDeclaration 211 |-void 212 |-SimpleDeclarator 213 | |-foo 214 | `-ParametersAndQualifiers 215 | |-( 216 | `-) 217 `-CompoundStatement 218 |-{ 219 `-} 220 )txt"); 221 } 222 223 TEST_F(SyntaxTreeTest, If) { 224 expectTreeDumpEqual( 225 R"cpp( 226 int main() { 227 if (true) {} 228 if (true) {} else if (false) {} 229 } 230 )cpp", 231 R"txt( 232 *: TranslationUnit 233 `-SimpleDeclaration 234 |-int 235 |-SimpleDeclarator 236 | |-main 237 | `-ParametersAndQualifiers 238 | |-( 239 | `-) 240 `-CompoundStatement 241 |-{ 242 |-IfStatement 243 | |-if 244 | |-( 245 | |-UnknownExpression 246 | | `-true 247 | |-) 248 | `-CompoundStatement 249 | |-{ 250 | `-} 251 |-IfStatement 252 | |-if 253 | |-( 254 | |-UnknownExpression 255 | | `-true 256 | |-) 257 | |-CompoundStatement 258 | | |-{ 259 | | `-} 260 | |-else 261 | `-IfStatement 262 | |-if 263 | |-( 264 | |-UnknownExpression 265 | | `-false 266 | |-) 267 | `-CompoundStatement 268 | |-{ 269 | `-} 270 `-} 271 )txt"); 272 } 273 274 TEST_F(SyntaxTreeTest, For) { 275 expectTreeDumpEqual( 276 R"cpp( 277 void test() { 278 for (;;) {} 279 } 280 )cpp", 281 R"txt( 282 *: TranslationUnit 283 `-SimpleDeclaration 284 |-void 285 |-SimpleDeclarator 286 | |-test 287 | `-ParametersAndQualifiers 288 | |-( 289 | `-) 290 `-CompoundStatement 291 |-{ 292 |-ForStatement 293 | |-for 294 | |-( 295 | |-; 296 | |-; 297 | |-) 298 | `-CompoundStatement 299 | |-{ 300 | `-} 301 `-} 302 )txt"); 303 } 304 305 TEST_F(SyntaxTreeTest, RangeBasedFor) { 306 expectTreeDumpEqual( 307 R"cpp( 308 void test() { 309 int a[3]; 310 for (int x : a) ; 311 } 312 )cpp", 313 R"txt( 314 *: TranslationUnit 315 `-SimpleDeclaration 316 |-void 317 |-SimpleDeclarator 318 | |-test 319 | `-ParametersAndQualifiers 320 | |-( 321 | `-) 322 `-CompoundStatement 323 |-{ 324 |-DeclarationStatement 325 | |-SimpleDeclaration 326 | | |-int 327 | | `-SimpleDeclarator 328 | | |-a 329 | | `-ArraySubscript 330 | | |-[ 331 | | |-UnknownExpression 332 | | | `-3 333 | | `-] 334 | `-; 335 |-RangeBasedForStatement 336 | |-for 337 | |-( 338 | |-SimpleDeclaration 339 | | |-int 340 | | |-SimpleDeclarator 341 | | | `-x 342 | | `-: 343 | |-UnknownExpression 344 | | `-a 345 | |-) 346 | `-EmptyStatement 347 | `-; 348 `-} 349 )txt"); 350 } 351 352 TEST_F(SyntaxTreeTest, DeclarationStatement) { 353 expectTreeDumpEqual("void test() { int a = 10; }", 354 R"txt( 355 *: TranslationUnit 356 `-SimpleDeclaration 357 |-void 358 |-SimpleDeclarator 359 | |-test 360 | `-ParametersAndQualifiers 361 | |-( 362 | `-) 363 `-CompoundStatement 364 |-{ 365 |-DeclarationStatement 366 | |-SimpleDeclaration 367 | | |-int 368 | | `-SimpleDeclarator 369 | | |-a 370 | | |-= 371 | | `-UnknownExpression 372 | | `-10 373 | `-; 374 `-} 375 )txt"); 376 } 377 378 TEST_F(SyntaxTreeTest, Switch) { 379 expectTreeDumpEqual( 380 R"cpp( 381 void test() { 382 switch (true) { 383 case 0: 384 default:; 385 } 386 } 387 )cpp", 388 R"txt( 389 *: TranslationUnit 390 `-SimpleDeclaration 391 |-void 392 |-SimpleDeclarator 393 | |-test 394 | `-ParametersAndQualifiers 395 | |-( 396 | `-) 397 `-CompoundStatement 398 |-{ 399 |-SwitchStatement 400 | |-switch 401 | |-( 402 | |-UnknownExpression 403 | | `-true 404 | |-) 405 | `-CompoundStatement 406 | |-{ 407 | |-CaseStatement 408 | | |-case 409 | | |-UnknownExpression 410 | | | `-0 411 | | |-: 412 | | `-DefaultStatement 413 | | |-default 414 | | |-: 415 | | `-EmptyStatement 416 | | `-; 417 | `-} 418 `-} 419 )txt"); 420 } 421 422 TEST_F(SyntaxTreeTest, While) { 423 expectTreeDumpEqual( 424 R"cpp( 425 void test() { 426 while (true) { continue; break; } 427 } 428 )cpp", 429 R"txt( 430 *: TranslationUnit 431 `-SimpleDeclaration 432 |-void 433 |-SimpleDeclarator 434 | |-test 435 | `-ParametersAndQualifiers 436 | |-( 437 | `-) 438 `-CompoundStatement 439 |-{ 440 |-WhileStatement 441 | |-while 442 | |-( 443 | |-UnknownExpression 444 | | `-true 445 | |-) 446 | `-CompoundStatement 447 | |-{ 448 | |-ContinueStatement 449 | | |-continue 450 | | `-; 451 | |-BreakStatement 452 | | |-break 453 | | `-; 454 | `-} 455 `-} 456 )txt"); 457 } 458 459 TEST_F(SyntaxTreeTest, UnhandledStatement) { 460 // Unhandled statements should end up as 'unknown statement'. 461 // This example uses a 'label statement', which does not yet have a syntax 462 // counterpart. 463 expectTreeDumpEqual("void main() { foo: return 100; }", 464 R"txt( 465 *: TranslationUnit 466 `-SimpleDeclaration 467 |-void 468 |-SimpleDeclarator 469 | |-main 470 | `-ParametersAndQualifiers 471 | |-( 472 | `-) 473 `-CompoundStatement 474 |-{ 475 |-UnknownStatement 476 | |-foo 477 | |-: 478 | `-ReturnStatement 479 | |-return 480 | |-UnknownExpression 481 | | `-100 482 | `-; 483 `-} 484 )txt"); 485 } 486 487 TEST_F(SyntaxTreeTest, Expressions) { 488 // expressions should be wrapped in 'ExpressionStatement' when they appear 489 // in a statement position. 490 expectTreeDumpEqual( 491 R"cpp( 492 void test() { 493 test(); 494 if (true) test(); else test(); 495 } 496 )cpp", 497 R"txt( 498 *: TranslationUnit 499 `-SimpleDeclaration 500 |-void 501 |-SimpleDeclarator 502 | |-test 503 | `-ParametersAndQualifiers 504 | |-( 505 | `-) 506 `-CompoundStatement 507 |-{ 508 |-ExpressionStatement 509 | |-UnknownExpression 510 | | |-test 511 | | |-( 512 | | `-) 513 | `-; 514 |-IfStatement 515 | |-if 516 | |-( 517 | |-UnknownExpression 518 | | `-true 519 | |-) 520 | |-ExpressionStatement 521 | | |-UnknownExpression 522 | | | |-test 523 | | | |-( 524 | | | `-) 525 | | `-; 526 | |-else 527 | `-ExpressionStatement 528 | |-UnknownExpression 529 | | |-test 530 | | |-( 531 | | `-) 532 | `-; 533 `-} 534 )txt"); 535 } 536 537 TEST_F(SyntaxTreeTest, MultipleDeclaratorsGrouping) { 538 expectTreeDumpEqual( 539 R"cpp( 540 int *a, b; 541 )cpp", 542 R"txt( 543 *: TranslationUnit 544 `-SimpleDeclaration 545 |-int 546 |-SimpleDeclarator 547 | |-* 548 | `-a 549 |-, 550 |-SimpleDeclarator 551 | `-b 552 `-; 553 )txt"); 554 expectTreeDumpEqual( 555 R"cpp( 556 typedef int *a, b; 557 )cpp", 558 R"txt( 559 *: TranslationUnit 560 `-SimpleDeclaration 561 |-typedef 562 |-int 563 |-SimpleDeclarator 564 | |-* 565 | `-a 566 |-, 567 |-SimpleDeclarator 568 | `-b 569 `-; 570 )txt"); 571 } 572 573 TEST_F(SyntaxTreeTest, MultipleDeclaratorsInsideStatement) { 574 expectTreeDumpEqual( 575 R"cpp( 576 void foo() { 577 int *a, b; 578 typedef int *ta, tb; 579 } 580 )cpp", 581 R"txt( 582 *: TranslationUnit 583 `-SimpleDeclaration 584 |-void 585 |-SimpleDeclarator 586 | |-foo 587 | `-ParametersAndQualifiers 588 | |-( 589 | `-) 590 `-CompoundStatement 591 |-{ 592 |-DeclarationStatement 593 | |-SimpleDeclaration 594 | | |-int 595 | | |-SimpleDeclarator 596 | | | |-* 597 | | | `-a 598 | | |-, 599 | | `-SimpleDeclarator 600 | | `-b 601 | `-; 602 |-DeclarationStatement 603 | |-SimpleDeclaration 604 | | |-typedef 605 | | |-int 606 | | |-SimpleDeclarator 607 | | | |-* 608 | | | `-ta 609 | | |-, 610 | | `-SimpleDeclarator 611 | | `-tb 612 | `-; 613 `-} 614 )txt"); 615 } 616 617 TEST_F(SyntaxTreeTest, Namespaces) { 618 expectTreeDumpEqual( 619 R"cpp( 620 namespace a { namespace b {} } 621 namespace a::b {} 622 namespace {} 623 624 namespace foo = a; 625 )cpp", 626 R"txt( 627 *: TranslationUnit 628 |-NamespaceDefinition 629 | |-namespace 630 | |-a 631 | |-{ 632 | |-NamespaceDefinition 633 | | |-namespace 634 | | |-b 635 | | |-{ 636 | | `-} 637 | `-} 638 |-NamespaceDefinition 639 | |-namespace 640 | |-a 641 | |-:: 642 | |-b 643 | |-{ 644 | `-} 645 |-NamespaceDefinition 646 | |-namespace 647 | |-{ 648 | `-} 649 `-NamespaceAliasDefinition 650 |-namespace 651 |-foo 652 |-= 653 |-a 654 `-; 655 )txt"); 656 } 657 658 TEST_F(SyntaxTreeTest, UsingDirective) { 659 expectTreeDumpEqual( 660 R"cpp( 661 namespace ns {} 662 using namespace ::ns; 663 )cpp", 664 R"txt( 665 *: TranslationUnit 666 |-NamespaceDefinition 667 | |-namespace 668 | |-ns 669 | |-{ 670 | `-} 671 `-UsingNamespaceDirective 672 |-using 673 |-namespace 674 |-:: 675 |-ns 676 `-; 677 )txt"); 678 } 679 680 TEST_F(SyntaxTreeTest, UsingDeclaration) { 681 expectTreeDumpEqual( 682 R"cpp( 683 namespace ns { int a; } 684 using ns::a; 685 )cpp", 686 R"txt( 687 *: TranslationUnit 688 |-NamespaceDefinition 689 | |-namespace 690 | |-ns 691 | |-{ 692 | |-SimpleDeclaration 693 | | |-int 694 | | |-SimpleDeclarator 695 | | | `-a 696 | | `-; 697 | `-} 698 `-UsingDeclaration 699 |-using 700 |-ns 701 |-:: 702 |-a 703 `-; 704 )txt"); 705 } 706 707 TEST_F(SyntaxTreeTest, FreeStandingClasses) { 708 // Free-standing classes, must live inside a SimpleDeclaration. 709 expectTreeDumpEqual( 710 R"cpp( 711 sturct X; 712 struct X {}; 713 714 struct Y *y1; 715 struct Y {} *y2; 716 717 struct {} *a1; 718 )cpp", 719 R"txt( 720 *: TranslationUnit 721 |-SimpleDeclaration 722 | |-sturct 723 | |-X 724 | `-; 725 |-SimpleDeclaration 726 | |-struct 727 | |-X 728 | |-{ 729 | |-} 730 | `-; 731 |-SimpleDeclaration 732 | |-struct 733 | |-Y 734 | |-SimpleDeclarator 735 | | |-* 736 | | `-y1 737 | `-; 738 |-SimpleDeclaration 739 | |-struct 740 | |-Y 741 | |-{ 742 | |-} 743 | |-SimpleDeclarator 744 | | |-* 745 | | `-y2 746 | `-; 747 `-SimpleDeclaration 748 |-struct 749 |-{ 750 |-} 751 |-SimpleDeclarator 752 | |-* 753 | `-a1 754 `-; 755 )txt"); 756 } 757 758 TEST_F(SyntaxTreeTest, Templates) { 759 expectTreeDumpEqual( 760 R"cpp( 761 template <class T> struct cls {}; 762 template <class T> int var = 10; 763 template <class T> int fun() {} 764 )cpp", 765 R"txt( 766 *: TranslationUnit 767 |-TemplateDeclaration 768 | |-template 769 | |-< 770 | |-UnknownDeclaration 771 | | |-class 772 | | `-T 773 | |-> 774 | `-SimpleDeclaration 775 | |-struct 776 | |-cls 777 | |-{ 778 | |-} 779 | `-; 780 |-TemplateDeclaration 781 | |-template 782 | |-< 783 | |-UnknownDeclaration 784 | | |-class 785 | | `-T 786 | |-> 787 | `-SimpleDeclaration 788 | |-int 789 | |-SimpleDeclarator 790 | | |-var 791 | | |-= 792 | | `-UnknownExpression 793 | | `-10 794 | `-; 795 `-TemplateDeclaration 796 |-template 797 |-< 798 |-UnknownDeclaration 799 | |-class 800 | `-T 801 |-> 802 `-SimpleDeclaration 803 |-int 804 |-SimpleDeclarator 805 | |-fun 806 | `-ParametersAndQualifiers 807 | |-( 808 | `-) 809 `-CompoundStatement 810 |-{ 811 `-} 812 )txt", 813 // FIXME: Make this test work on windows by generating the expected Syntax 814 // tree when -fdelayed-template-parsing is active. 815 /*RunWithDelayedTemplateParsing=*/true); 816 } 817 818 TEST_F(SyntaxTreeTest, NestedTemplates) { 819 expectTreeDumpEqual( 820 R"cpp( 821 template <class T> 822 struct X { 823 template <class U> 824 U foo(); 825 }; 826 )cpp", 827 R"txt( 828 *: TranslationUnit 829 `-TemplateDeclaration 830 |-template 831 |-< 832 |-UnknownDeclaration 833 | |-class 834 | `-T 835 |-> 836 `-SimpleDeclaration 837 |-struct 838 |-X 839 |-{ 840 |-TemplateDeclaration 841 | |-template 842 | |-< 843 | |-UnknownDeclaration 844 | | |-class 845 | | `-U 846 | |-> 847 | `-SimpleDeclaration 848 | |-U 849 | |-SimpleDeclarator 850 | | |-foo 851 | | `-ParametersAndQualifiers 852 | | |-( 853 | | `-) 854 | `-; 855 |-} 856 `-; 857 )txt"); 858 } 859 860 TEST_F(SyntaxTreeTest, Templates2) { 861 expectTreeDumpEqual( 862 R"cpp( 863 template <class T> struct X { struct Y; }; 864 template <class T> struct X<T>::Y {}; 865 )cpp", 866 R"txt( 867 *: TranslationUnit 868 |-TemplateDeclaration 869 | |-template 870 | |-< 871 | |-UnknownDeclaration 872 | | |-class 873 | | `-T 874 | |-> 875 | `-SimpleDeclaration 876 | |-struct 877 | |-X 878 | |-{ 879 | |-SimpleDeclaration 880 | | |-struct 881 | | |-Y 882 | | `-; 883 | |-} 884 | `-; 885 `-TemplateDeclaration 886 |-template 887 |-< 888 |-UnknownDeclaration 889 | |-class 890 | `-T 891 |-> 892 `-SimpleDeclaration 893 |-struct 894 |-X 895 |-< 896 |-T 897 |-> 898 |-:: 899 |-Y 900 |-{ 901 |-} 902 `-; 903 )txt"); 904 } 905 906 TEST_F(SyntaxTreeTest, TemplatesUsingUsing) { 907 expectTreeDumpEqual( 908 R"cpp( 909 template <class T> struct X { 910 using T::foo; 911 using typename T::bar; 912 }; 913 )cpp", 914 R"txt( 915 *: TranslationUnit 916 `-TemplateDeclaration 917 |-template 918 |-< 919 |-UnknownDeclaration 920 | |-class 921 | `-T 922 |-> 923 `-SimpleDeclaration 924 |-struct 925 |-X 926 |-{ 927 |-UsingDeclaration 928 | |-using 929 | |-T 930 | |-:: 931 | |-foo 932 | `-; 933 |-UsingDeclaration 934 | |-using 935 | |-typename 936 | |-T 937 | |-:: 938 | |-bar 939 | `-; 940 |-} 941 `-; 942 )txt"); 943 } 944 945 TEST_F(SyntaxTreeTest, ExplicitTemplateInstantations) { 946 expectTreeDumpEqual( 947 R"cpp( 948 template <class T> struct X {}; 949 template <class T> struct X<T*> {}; 950 template <> struct X<int> {}; 951 952 template struct X<double>; 953 extern template struct X<float>; 954 )cpp", 955 R"txt( 956 *: TranslationUnit 957 |-TemplateDeclaration 958 | |-template 959 | |-< 960 | |-UnknownDeclaration 961 | | |-class 962 | | `-T 963 | |-> 964 | `-SimpleDeclaration 965 | |-struct 966 | |-X 967 | |-{ 968 | |-} 969 | `-; 970 |-TemplateDeclaration 971 | |-template 972 | |-< 973 | |-UnknownDeclaration 974 | | |-class 975 | | `-T 976 | |-> 977 | `-SimpleDeclaration 978 | |-struct 979 | |-X 980 | |-< 981 | |-T 982 | |-* 983 | |-> 984 | |-{ 985 | |-} 986 | `-; 987 |-TemplateDeclaration 988 | |-template 989 | |-< 990 | |-> 991 | `-SimpleDeclaration 992 | |-struct 993 | |-X 994 | |-< 995 | |-int 996 | |-> 997 | |-{ 998 | |-} 999 | `-; 1000 |-ExplicitTemplateInstantiation 1001 | |-template 1002 | `-SimpleDeclaration 1003 | |-struct 1004 | |-X 1005 | |-< 1006 | |-double 1007 | |-> 1008 | `-; 1009 `-ExplicitTemplateInstantiation 1010 |-extern 1011 |-template 1012 `-SimpleDeclaration 1013 |-struct 1014 |-X 1015 |-< 1016 |-float 1017 |-> 1018 `-; 1019 )txt"); 1020 } 1021 1022 TEST_F(SyntaxTreeTest, UsingType) { 1023 expectTreeDumpEqual( 1024 R"cpp( 1025 using type = int; 1026 )cpp", 1027 R"txt( 1028 *: TranslationUnit 1029 `-TypeAliasDeclaration 1030 |-using 1031 |-type 1032 |-= 1033 |-int 1034 `-; 1035 )txt"); 1036 } 1037 1038 TEST_F(SyntaxTreeTest, EmptyDeclaration) { 1039 expectTreeDumpEqual( 1040 R"cpp( 1041 ; 1042 )cpp", 1043 R"txt( 1044 *: TranslationUnit 1045 `-EmptyDeclaration 1046 `-; 1047 )txt"); 1048 } 1049 1050 TEST_F(SyntaxTreeTest, StaticAssert) { 1051 expectTreeDumpEqual( 1052 R"cpp( 1053 static_assert(true, "message"); 1054 static_assert(true); 1055 )cpp", 1056 R"txt( 1057 *: TranslationUnit 1058 |-StaticAssertDeclaration 1059 | |-static_assert 1060 | |-( 1061 | |-UnknownExpression 1062 | | `-true 1063 | |-, 1064 | |-UnknownExpression 1065 | | `-"message" 1066 | |-) 1067 | `-; 1068 `-StaticAssertDeclaration 1069 |-static_assert 1070 |-( 1071 |-UnknownExpression 1072 | `-true 1073 |-) 1074 `-; 1075 )txt"); 1076 } 1077 1078 TEST_F(SyntaxTreeTest, ExternC) { 1079 expectTreeDumpEqual( 1080 R"cpp( 1081 extern "C" int a; 1082 extern "C" { int b; int c; } 1083 )cpp", 1084 R"txt( 1085 *: TranslationUnit 1086 |-LinkageSpecificationDeclaration 1087 | |-extern 1088 | |-"C" 1089 | `-SimpleDeclaration 1090 | |-int 1091 | |-SimpleDeclarator 1092 | | `-a 1093 | `-; 1094 `-LinkageSpecificationDeclaration 1095 |-extern 1096 |-"C" 1097 |-{ 1098 |-SimpleDeclaration 1099 | |-int 1100 | |-SimpleDeclarator 1101 | | `-b 1102 | `-; 1103 |-SimpleDeclaration 1104 | |-int 1105 | |-SimpleDeclarator 1106 | | `-c 1107 | `-; 1108 `-} 1109 )txt"); 1110 } 1111 1112 TEST_F(SyntaxTreeTest, NonModifiableNodes) { 1113 // Some nodes are non-modifiable, they are marked with 'I:'. 1114 expectTreeDumpEqual( 1115 R"cpp( 1116 #define HALF_IF if (1+ 1117 #define HALF_IF_2 1) {} 1118 void test() { 1119 HALF_IF HALF_IF_2 else {} 1120 })cpp", 1121 R"txt( 1122 *: TranslationUnit 1123 `-SimpleDeclaration 1124 |-void 1125 |-SimpleDeclarator 1126 | |-test 1127 | `-ParametersAndQualifiers 1128 | |-( 1129 | `-) 1130 `-CompoundStatement 1131 |-{ 1132 |-IfStatement 1133 | |-I: if 1134 | |-I: ( 1135 | |-I: UnknownExpression 1136 | | |-I: 1 1137 | | |-I: + 1138 | | `-I: 1 1139 | |-I: ) 1140 | |-I: CompoundStatement 1141 | | |-I: { 1142 | | `-I: } 1143 | |-else 1144 | `-CompoundStatement 1145 | |-{ 1146 | `-} 1147 `-} 1148 )txt"); 1149 // All nodes can be mutated. 1150 expectTreeDumpEqual( 1151 R"cpp( 1152 #define OPEN { 1153 #define CLOSE } 1154 1155 void test() { 1156 OPEN 1157 1; 1158 CLOSE 1159 1160 OPEN 1161 2; 1162 } 1163 } 1164 )cpp", 1165 R"txt( 1166 *: TranslationUnit 1167 `-SimpleDeclaration 1168 |-void 1169 |-SimpleDeclarator 1170 | |-test 1171 | `-ParametersAndQualifiers 1172 | |-( 1173 | `-) 1174 `-CompoundStatement 1175 |-{ 1176 |-CompoundStatement 1177 | |-{ 1178 | |-ExpressionStatement 1179 | | |-UnknownExpression 1180 | | | `-1 1181 | | `-; 1182 | `-} 1183 |-CompoundStatement 1184 | |-{ 1185 | |-ExpressionStatement 1186 | | |-UnknownExpression 1187 | | | `-2 1188 | | `-; 1189 | `-} 1190 `-} 1191 )txt"); 1192 } 1193 1194 TEST_F(SyntaxTreeTest, ArraySubscriptsInDeclarators) { 1195 expectTreeDumpEqual( 1196 R"cpp( 1197 int a[10]; 1198 int b[1][2][3]; 1199 int c[] = {1,2,3}; 1200 void f(int xs[static 10]); 1201 )cpp", 1202 R"txt( 1203 *: TranslationUnit 1204 |-SimpleDeclaration 1205 | |-int 1206 | |-SimpleDeclarator 1207 | | |-a 1208 | | `-ArraySubscript 1209 | | |-[ 1210 | | |-UnknownExpression 1211 | | | `-10 1212 | | `-] 1213 | `-; 1214 |-SimpleDeclaration 1215 | |-int 1216 | |-SimpleDeclarator 1217 | | |-b 1218 | | |-ArraySubscript 1219 | | | |-[ 1220 | | | |-UnknownExpression 1221 | | | | `-1 1222 | | | `-] 1223 | | |-ArraySubscript 1224 | | | |-[ 1225 | | | |-UnknownExpression 1226 | | | | `-2 1227 | | | `-] 1228 | | `-ArraySubscript 1229 | | |-[ 1230 | | |-UnknownExpression 1231 | | | `-3 1232 | | `-] 1233 | `-; 1234 |-SimpleDeclaration 1235 | |-int 1236 | |-SimpleDeclarator 1237 | | |-c 1238 | | |-ArraySubscript 1239 | | | |-[ 1240 | | | `-] 1241 | | |-= 1242 | | `-UnknownExpression 1243 | | |-{ 1244 | | |-1 1245 | | |-, 1246 | | |-2 1247 | | |-, 1248 | | |-3 1249 | | `-} 1250 | `-; 1251 `-SimpleDeclaration 1252 |-void 1253 |-SimpleDeclarator 1254 | |-f 1255 | `-ParametersAndQualifiers 1256 | |-( 1257 | |-SimpleDeclaration 1258 | | |-int 1259 | | `-SimpleDeclarator 1260 | | |-xs 1261 | | `-ArraySubscript 1262 | | |-[ 1263 | | |-static 1264 | | |-UnknownExpression 1265 | | | `-10 1266 | | `-] 1267 | `-) 1268 `-; 1269 )txt"); 1270 } 1271 1272 TEST_F(SyntaxTreeTest, ParameterListsInDeclarators) { 1273 expectTreeDumpEqual( 1274 R"cpp( 1275 int a() const; 1276 int b() volatile; 1277 int c() &; 1278 int d() &&; 1279 int foo(int a, int b); 1280 int foo( 1281 const int a, 1282 volatile int b, 1283 const volatile int c, 1284 int* d, 1285 int& e, 1286 int&& f 1287 ); 1288 )cpp", 1289 R"txt( 1290 *: TranslationUnit 1291 |-SimpleDeclaration 1292 | |-int 1293 | |-SimpleDeclarator 1294 | | |-a 1295 | | `-ParametersAndQualifiers 1296 | | |-( 1297 | | |-) 1298 | | `-const 1299 | `-; 1300 |-SimpleDeclaration 1301 | |-int 1302 | |-SimpleDeclarator 1303 | | |-b 1304 | | `-ParametersAndQualifiers 1305 | | |-( 1306 | | |-) 1307 | | `-volatile 1308 | `-; 1309 |-SimpleDeclaration 1310 | |-int 1311 | |-SimpleDeclarator 1312 | | |-c 1313 | | `-ParametersAndQualifiers 1314 | | |-( 1315 | | |-) 1316 | | `-& 1317 | `-; 1318 |-SimpleDeclaration 1319 | |-int 1320 | |-SimpleDeclarator 1321 | | |-d 1322 | | `-ParametersAndQualifiers 1323 | | |-( 1324 | | |-) 1325 | | `-&& 1326 | `-; 1327 |-SimpleDeclaration 1328 | |-int 1329 | |-SimpleDeclarator 1330 | | |-foo 1331 | | `-ParametersAndQualifiers 1332 | | |-( 1333 | | |-SimpleDeclaration 1334 | | | |-int 1335 | | | `-SimpleDeclarator 1336 | | | `-a 1337 | | |-, 1338 | | |-SimpleDeclaration 1339 | | | |-int 1340 | | | `-SimpleDeclarator 1341 | | | `-b 1342 | | `-) 1343 | `-; 1344 `-SimpleDeclaration 1345 |-int 1346 |-SimpleDeclarator 1347 | |-foo 1348 | `-ParametersAndQualifiers 1349 | |-( 1350 | |-SimpleDeclaration 1351 | | |-const 1352 | | |-int 1353 | | `-SimpleDeclarator 1354 | | `-a 1355 | |-, 1356 | |-SimpleDeclaration 1357 | | |-volatile 1358 | | |-int 1359 | | `-SimpleDeclarator 1360 | | `-b 1361 | |-, 1362 | |-SimpleDeclaration 1363 | | |-const 1364 | | |-volatile 1365 | | |-int 1366 | | `-SimpleDeclarator 1367 | | `-c 1368 | |-, 1369 | |-SimpleDeclaration 1370 | | |-int 1371 | | `-SimpleDeclarator 1372 | | |-* 1373 | | `-d 1374 | |-, 1375 | |-SimpleDeclaration 1376 | | |-int 1377 | | `-SimpleDeclarator 1378 | | |-& 1379 | | `-e 1380 | |-, 1381 | |-SimpleDeclaration 1382 | | |-int 1383 | | `-SimpleDeclarator 1384 | | |-&& 1385 | | `-f 1386 | `-) 1387 `-; 1388 )txt"); 1389 } 1390 1391 TEST_F(SyntaxTreeTest, TrailingConst) { 1392 expectTreeDumpEqual( 1393 R"cpp( 1394 struct X { 1395 int foo() const; 1396 } 1397 )cpp", 1398 R"txt( 1399 *: TranslationUnit 1400 `-SimpleDeclaration 1401 |-struct 1402 |-X 1403 |-{ 1404 |-SimpleDeclaration 1405 | |-int 1406 | |-SimpleDeclarator 1407 | | |-foo 1408 | | `-ParametersAndQualifiers 1409 | | |-( 1410 | | |-) 1411 | | `-const 1412 | `-; 1413 `-} 1414 )txt"); 1415 } 1416 1417 TEST_F(SyntaxTreeTest, TrailingReturn) { 1418 expectTreeDumpEqual( 1419 R"cpp( 1420 auto foo() -> int; 1421 )cpp", 1422 R"txt( 1423 *: TranslationUnit 1424 `-SimpleDeclaration 1425 |-auto 1426 |-SimpleDeclarator 1427 | |-foo 1428 | `-ParametersAndQualifiers 1429 | |-( 1430 | |-) 1431 | `-TrailingReturnType 1432 | |--> 1433 | `-int 1434 `-; 1435 )txt"); 1436 } 1437 1438 TEST_F(SyntaxTreeTest, ExceptionSpecification) { 1439 expectTreeDumpEqual( 1440 R"cpp( 1441 int a() noexcept; 1442 int b() noexcept(true); 1443 int c() throw(); 1444 )cpp", 1445 R"txt( 1446 *: TranslationUnit 1447 |-SimpleDeclaration 1448 | |-int 1449 | |-SimpleDeclarator 1450 | | |-a 1451 | | `-ParametersAndQualifiers 1452 | | |-( 1453 | | |-) 1454 | | `-noexcept 1455 | `-; 1456 |-SimpleDeclaration 1457 | |-int 1458 | |-SimpleDeclarator 1459 | | |-b 1460 | | `-ParametersAndQualifiers 1461 | | |-( 1462 | | |-) 1463 | | |-noexcept 1464 | | |-( 1465 | | |-UnknownExpression 1466 | | | `-true 1467 | | `-) 1468 | `-; 1469 `-SimpleDeclaration 1470 |-int 1471 |-SimpleDeclarator 1472 | |-c 1473 | `-ParametersAndQualifiers 1474 | |-( 1475 | |-) 1476 | |-throw 1477 | |-( 1478 | `-) 1479 `-; 1480 )txt"); 1481 } 1482 1483 TEST_F(SyntaxTreeTest, DeclaratorsInParentheses) { 1484 expectTreeDumpEqual( 1485 R"cpp( 1486 int (a); 1487 int *(b); 1488 int (*c)(int); 1489 int *(d)(int); 1490 )cpp", 1491 R"txt( 1492 *: TranslationUnit 1493 |-SimpleDeclaration 1494 | |-int 1495 | |-SimpleDeclarator 1496 | | `-ParenDeclarator 1497 | | |-( 1498 | | |-a 1499 | | `-) 1500 | `-; 1501 |-SimpleDeclaration 1502 | |-int 1503 | |-SimpleDeclarator 1504 | | |-* 1505 | | `-ParenDeclarator 1506 | | |-( 1507 | | |-b 1508 | | `-) 1509 | `-; 1510 |-SimpleDeclaration 1511 | |-int 1512 | |-SimpleDeclarator 1513 | | |-ParenDeclarator 1514 | | | |-( 1515 | | | |-* 1516 | | | |-c 1517 | | | `-) 1518 | | `-ParametersAndQualifiers 1519 | | |-( 1520 | | |-SimpleDeclaration 1521 | | | `-int 1522 | | `-) 1523 | `-; 1524 `-SimpleDeclaration 1525 |-int 1526 |-SimpleDeclarator 1527 | |-* 1528 | |-ParenDeclarator 1529 | | |-( 1530 | | |-d 1531 | | `-) 1532 | `-ParametersAndQualifiers 1533 | |-( 1534 | |-SimpleDeclaration 1535 | | `-int 1536 | `-) 1537 `-; 1538 )txt"); 1539 } 1540 1541 TEST_F(SyntaxTreeTest, ConstVolatileQualifiers) { 1542 expectTreeDumpEqual( 1543 R"cpp( 1544 const int west = -1; 1545 int const east = 1; 1546 const int const universal = 0; 1547 const int const *const *volatile b; 1548 )cpp", 1549 R"txt( 1550 *: TranslationUnit 1551 |-SimpleDeclaration 1552 | |-const 1553 | |-int 1554 | |-SimpleDeclarator 1555 | | |-west 1556 | | |-= 1557 | | `-UnknownExpression 1558 | | |-- 1559 | | `-1 1560 | `-; 1561 |-SimpleDeclaration 1562 | |-int 1563 | |-const 1564 | |-SimpleDeclarator 1565 | | |-east 1566 | | |-= 1567 | | `-UnknownExpression 1568 | | `-1 1569 | `-; 1570 |-SimpleDeclaration 1571 | |-const 1572 | |-int 1573 | |-const 1574 | |-SimpleDeclarator 1575 | | |-universal 1576 | | |-= 1577 | | `-UnknownExpression 1578 | | `-0 1579 | `-; 1580 `-SimpleDeclaration 1581 |-const 1582 |-int 1583 |-const 1584 |-SimpleDeclarator 1585 | |-* 1586 | |-const 1587 | |-* 1588 | |-volatile 1589 | `-b 1590 `-; 1591 )txt"); 1592 } 1593 1594 TEST_F(SyntaxTreeTest, RangesOfDeclaratorsWithTrailingReturnTypes) { 1595 expectTreeDumpEqual( 1596 R"cpp( 1597 auto foo() -> auto(*)(int) -> double*; 1598 )cpp", 1599 R"txt( 1600 *: TranslationUnit 1601 `-SimpleDeclaration 1602 |-auto 1603 |-SimpleDeclarator 1604 | |-foo 1605 | `-ParametersAndQualifiers 1606 | |-( 1607 | |-) 1608 | `-TrailingReturnType 1609 | |--> 1610 | |-auto 1611 | `-SimpleDeclarator 1612 | |-ParenDeclarator 1613 | | |-( 1614 | | |-* 1615 | | `-) 1616 | `-ParametersAndQualifiers 1617 | |-( 1618 | |-SimpleDeclaration 1619 | | `-int 1620 | |-) 1621 | `-TrailingReturnType 1622 | |--> 1623 | |-double 1624 | `-SimpleDeclarator 1625 | `-* 1626 `-; 1627 )txt"); 1628 } 1629 1630 TEST_F(SyntaxTreeTest, MemberPointers) { 1631 expectTreeDumpEqual( 1632 R"cpp( 1633 struct X {}; 1634 int X::* a; 1635 const int X::* b; 1636 )cpp", 1637 R"txt( 1638 *: TranslationUnit 1639 |-SimpleDeclaration 1640 | |-struct 1641 | |-X 1642 | |-{ 1643 | |-} 1644 | `-; 1645 |-SimpleDeclaration 1646 | |-int 1647 | |-SimpleDeclarator 1648 | | |-MemberPointer 1649 | | | |-X 1650 | | | |-:: 1651 | | | `-* 1652 | | `-a 1653 | `-; 1654 `-SimpleDeclaration 1655 |-const 1656 |-int 1657 |-SimpleDeclarator 1658 | |-MemberPointer 1659 | | |-X 1660 | | |-:: 1661 | | `-* 1662 | `-b 1663 `-; 1664 )txt"); 1665 } 1666 1667 TEST_F(SyntaxTreeTest, ComplexDeclarator) { 1668 expectTreeDumpEqual( 1669 R"cpp( 1670 void x(char a, short (*b)(int)); 1671 )cpp", 1672 R"txt( 1673 *: TranslationUnit 1674 `-SimpleDeclaration 1675 |-void 1676 |-SimpleDeclarator 1677 | |-x 1678 | `-ParametersAndQualifiers 1679 | |-( 1680 | |-SimpleDeclaration 1681 | | |-char 1682 | | `-SimpleDeclarator 1683 | | `-a 1684 | |-, 1685 | |-SimpleDeclaration 1686 | | |-short 1687 | | `-SimpleDeclarator 1688 | | |-ParenDeclarator 1689 | | | |-( 1690 | | | |-* 1691 | | | |-b 1692 | | | `-) 1693 | | `-ParametersAndQualifiers 1694 | | |-( 1695 | | |-SimpleDeclaration 1696 | | | `-int 1697 | | `-) 1698 | `-) 1699 `-; 1700 )txt"); 1701 } 1702 1703 TEST_F(SyntaxTreeTest, ComplexDeclarator2) { 1704 expectTreeDumpEqual( 1705 R"cpp( 1706 void x(char a, short (*b)(int), long (**c)(long long)); 1707 )cpp", 1708 R"txt( 1709 *: TranslationUnit 1710 `-SimpleDeclaration 1711 |-void 1712 |-SimpleDeclarator 1713 | |-x 1714 | `-ParametersAndQualifiers 1715 | |-( 1716 | |-SimpleDeclaration 1717 | | |-char 1718 | | `-SimpleDeclarator 1719 | | `-a 1720 | |-, 1721 | |-SimpleDeclaration 1722 | | |-short 1723 | | `-SimpleDeclarator 1724 | | |-ParenDeclarator 1725 | | | |-( 1726 | | | |-* 1727 | | | |-b 1728 | | | `-) 1729 | | `-ParametersAndQualifiers 1730 | | |-( 1731 | | |-SimpleDeclaration 1732 | | | `-int 1733 | | `-) 1734 | |-, 1735 | |-SimpleDeclaration 1736 | | |-long 1737 | | `-SimpleDeclarator 1738 | | |-ParenDeclarator 1739 | | | |-( 1740 | | | |-* 1741 | | | |-* 1742 | | | |-c 1743 | | | `-) 1744 | | `-ParametersAndQualifiers 1745 | | |-( 1746 | | |-SimpleDeclaration 1747 | | | |-long 1748 | | | `-long 1749 | | `-) 1750 | `-) 1751 `-; 1752 )txt"); 1753 } 1754 1755 TEST_F(SyntaxTreeTest, Mutations) { 1756 using Transformation = std::function<void( 1757 const llvm::Annotations & /*Input*/, syntax::TranslationUnit * /*Root*/)>; 1758 auto CheckTransformation = [this](std::string Input, std::string Expected, 1759 Transformation Transform) -> void { 1760 llvm::Annotations Source(Input); 1761 auto *Root = buildTree(Source.code(), "x86_64-unknown-unknown"); 1762 1763 Transform(Source, Root); 1764 1765 auto Replacements = syntax::computeReplacements(*Arena, *Root); 1766 auto Output = tooling::applyAllReplacements(Source.code(), Replacements); 1767 if (!Output) { 1768 ADD_FAILURE() << "could not apply replacements: " 1769 << llvm::toString(Output.takeError()); 1770 return; 1771 } 1772 1773 EXPECT_EQ(Expected, *Output) << "input is:\n" << Input; 1774 }; 1775 1776 // Removes the selected statement. Input should have exactly one selected 1777 // range and it should correspond to a single statement. 1778 auto RemoveStatement = [this](const llvm::Annotations &Input, 1779 syntax::TranslationUnit *TU) { 1780 auto *S = cast<syntax::Statement>(nodeByRange(Input.range(), TU)); 1781 ASSERT_TRUE(S->canModify()) << "cannot remove a statement"; 1782 syntax::removeStatement(*Arena, S); 1783 EXPECT_TRUE(S->isDetached()); 1784 EXPECT_FALSE(S->isOriginal()) 1785 << "node removed from tree cannot be marked as original"; 1786 }; 1787 1788 std::vector<std::pair<std::string /*Input*/, std::string /*Expected*/>> 1789 Cases = { 1790 {"void test() { [[100+100;]] test(); }", "void test() { test(); }"}, 1791 {"void test() { if (true) [[{}]] else {} }", 1792 "void test() { if (true) ; else {} }"}, 1793 {"void test() { [[;]] }", "void test() { }"}}; 1794 for (const auto &C : Cases) 1795 CheckTransformation(C.first, C.second, RemoveStatement); 1796 } 1797 1798 TEST_F(SyntaxTreeTest, SynthesizedNodes) { 1799 buildTree("", "x86_64-unknown-unknown"); 1800 1801 auto *C = syntax::createPunctuation(*Arena, tok::comma); 1802 ASSERT_NE(C, nullptr); 1803 EXPECT_EQ(C->token()->kind(), tok::comma); 1804 EXPECT_TRUE(C->canModify()); 1805 EXPECT_FALSE(C->isOriginal()); 1806 EXPECT_TRUE(C->isDetached()); 1807 1808 auto *S = syntax::createEmptyStatement(*Arena); 1809 ASSERT_NE(S, nullptr); 1810 EXPECT_TRUE(S->canModify()); 1811 EXPECT_FALSE(S->isOriginal()); 1812 EXPECT_TRUE(S->isDetached()); 1813 } 1814 1815 } // namespace 1816