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