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