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 // All nodes can be mutated. 1219 expectTreeDumpEqual( 1220 R"cpp( 1221 #define OPEN { 1222 #define CLOSE } 1223 1224 void test() { 1225 OPEN 1226 1; 1227 CLOSE 1228 1229 OPEN 1230 2; 1231 } 1232 } 1233 )cpp", 1234 R"txt( 1235 *: TranslationUnit 1236 `-SimpleDeclaration 1237 |-void 1238 |-SimpleDeclarator 1239 | |-test 1240 | `-ParametersAndQualifiers 1241 | |-( 1242 | `-) 1243 `-CompoundStatement 1244 |-{ 1245 |-CompoundStatement 1246 | |-{ 1247 | |-ExpressionStatement 1248 | | |-UnknownExpression 1249 | | | `-1 1250 | | `-; 1251 | `-} 1252 |-CompoundStatement 1253 | |-{ 1254 | |-ExpressionStatement 1255 | | |-UnknownExpression 1256 | | | `-2 1257 | | `-; 1258 | `-} 1259 `-} 1260 )txt"); 1261 } 1262 1263 TEST_F(SyntaxTreeTest, ArraySubscriptsInDeclarators) { 1264 expectTreeDumpEqual( 1265 R"cpp( 1266 int a[10]; 1267 int b[1][2][3]; 1268 int c[] = {1,2,3}; 1269 void f(int xs[static 10]); 1270 )cpp", 1271 R"txt( 1272 *: TranslationUnit 1273 |-SimpleDeclaration 1274 | |-int 1275 | |-SimpleDeclarator 1276 | | |-a 1277 | | `-ArraySubscript 1278 | | |-[ 1279 | | |-UnknownExpression 1280 | | | `-10 1281 | | `-] 1282 | `-; 1283 |-SimpleDeclaration 1284 | |-int 1285 | |-SimpleDeclarator 1286 | | |-b 1287 | | |-ArraySubscript 1288 | | | |-[ 1289 | | | |-UnknownExpression 1290 | | | | `-1 1291 | | | `-] 1292 | | |-ArraySubscript 1293 | | | |-[ 1294 | | | |-UnknownExpression 1295 | | | | `-2 1296 | | | `-] 1297 | | `-ArraySubscript 1298 | | |-[ 1299 | | |-UnknownExpression 1300 | | | `-3 1301 | | `-] 1302 | `-; 1303 |-SimpleDeclaration 1304 | |-int 1305 | |-SimpleDeclarator 1306 | | |-c 1307 | | |-ArraySubscript 1308 | | | |-[ 1309 | | | `-] 1310 | | |-= 1311 | | `-UnknownExpression 1312 | | |-{ 1313 | | |-1 1314 | | |-, 1315 | | |-2 1316 | | |-, 1317 | | |-3 1318 | | `-} 1319 | `-; 1320 `-SimpleDeclaration 1321 |-void 1322 |-SimpleDeclarator 1323 | |-f 1324 | `-ParametersAndQualifiers 1325 | |-( 1326 | |-SimpleDeclaration 1327 | | |-int 1328 | | `-SimpleDeclarator 1329 | | |-xs 1330 | | `-ArraySubscript 1331 | | |-[ 1332 | | |-static 1333 | | |-UnknownExpression 1334 | | | `-10 1335 | | `-] 1336 | `-) 1337 `-; 1338 )txt"); 1339 } 1340 1341 TEST_F(SyntaxTreeTest, ParameterListsInDeclarators) { 1342 expectTreeDumpEqual( 1343 R"cpp( 1344 int a() const; 1345 int b() volatile; 1346 int c() &; 1347 int d() &&; 1348 int foo(int a, int b); 1349 int foo( 1350 const int a, 1351 volatile int b, 1352 const volatile int c, 1353 int* d, 1354 int& e, 1355 int&& f 1356 ); 1357 )cpp", 1358 R"txt( 1359 *: TranslationUnit 1360 |-SimpleDeclaration 1361 | |-int 1362 | |-SimpleDeclarator 1363 | | |-a 1364 | | `-ParametersAndQualifiers 1365 | | |-( 1366 | | |-) 1367 | | `-const 1368 | `-; 1369 |-SimpleDeclaration 1370 | |-int 1371 | |-SimpleDeclarator 1372 | | |-b 1373 | | `-ParametersAndQualifiers 1374 | | |-( 1375 | | |-) 1376 | | `-volatile 1377 | `-; 1378 |-SimpleDeclaration 1379 | |-int 1380 | |-SimpleDeclarator 1381 | | |-c 1382 | | `-ParametersAndQualifiers 1383 | | |-( 1384 | | |-) 1385 | | `-& 1386 | `-; 1387 |-SimpleDeclaration 1388 | |-int 1389 | |-SimpleDeclarator 1390 | | |-d 1391 | | `-ParametersAndQualifiers 1392 | | |-( 1393 | | |-) 1394 | | `-&& 1395 | `-; 1396 |-SimpleDeclaration 1397 | |-int 1398 | |-SimpleDeclarator 1399 | | |-foo 1400 | | `-ParametersAndQualifiers 1401 | | |-( 1402 | | |-SimpleDeclaration 1403 | | | |-int 1404 | | | `-SimpleDeclarator 1405 | | | `-a 1406 | | |-, 1407 | | |-SimpleDeclaration 1408 | | | |-int 1409 | | | `-SimpleDeclarator 1410 | | | `-b 1411 | | `-) 1412 | `-; 1413 `-SimpleDeclaration 1414 |-int 1415 |-SimpleDeclarator 1416 | |-foo 1417 | `-ParametersAndQualifiers 1418 | |-( 1419 | |-SimpleDeclaration 1420 | | |-const 1421 | | |-int 1422 | | `-SimpleDeclarator 1423 | | `-a 1424 | |-, 1425 | |-SimpleDeclaration 1426 | | |-volatile 1427 | | |-int 1428 | | `-SimpleDeclarator 1429 | | `-b 1430 | |-, 1431 | |-SimpleDeclaration 1432 | | |-const 1433 | | |-volatile 1434 | | |-int 1435 | | `-SimpleDeclarator 1436 | | `-c 1437 | |-, 1438 | |-SimpleDeclaration 1439 | | |-int 1440 | | `-SimpleDeclarator 1441 | | |-* 1442 | | `-d 1443 | |-, 1444 | |-SimpleDeclaration 1445 | | |-int 1446 | | `-SimpleDeclarator 1447 | | |-& 1448 | | `-e 1449 | |-, 1450 | |-SimpleDeclaration 1451 | | |-int 1452 | | `-SimpleDeclarator 1453 | | |-&& 1454 | | `-f 1455 | `-) 1456 `-; 1457 )txt"); 1458 } 1459 1460 TEST_F(SyntaxTreeTest, TrailingConst) { 1461 expectTreeDumpEqual( 1462 R"cpp( 1463 struct X { 1464 int foo() const; 1465 } 1466 )cpp", 1467 R"txt( 1468 *: TranslationUnit 1469 `-SimpleDeclaration 1470 |-struct 1471 |-X 1472 |-{ 1473 |-SimpleDeclaration 1474 | |-int 1475 | |-SimpleDeclarator 1476 | | |-foo 1477 | | `-ParametersAndQualifiers 1478 | | |-( 1479 | | |-) 1480 | | `-const 1481 | `-; 1482 `-} 1483 )txt"); 1484 } 1485 1486 TEST_F(SyntaxTreeTest, TrailingReturn) { 1487 expectTreeDumpEqual( 1488 R"cpp( 1489 auto foo() -> int; 1490 )cpp", 1491 R"txt( 1492 *: TranslationUnit 1493 `-SimpleDeclaration 1494 |-auto 1495 |-SimpleDeclarator 1496 | |-foo 1497 | `-ParametersAndQualifiers 1498 | |-( 1499 | |-) 1500 | `-TrailingReturnType 1501 | |--> 1502 | `-int 1503 `-; 1504 )txt"); 1505 } 1506 1507 TEST_F(SyntaxTreeTest, ExceptionSpecification) { 1508 expectTreeDumpEqual( 1509 R"cpp( 1510 int a() noexcept; 1511 int b() noexcept(true); 1512 int c() throw(); 1513 )cpp", 1514 R"txt( 1515 *: TranslationUnit 1516 |-SimpleDeclaration 1517 | |-int 1518 | |-SimpleDeclarator 1519 | | |-a 1520 | | `-ParametersAndQualifiers 1521 | | |-( 1522 | | |-) 1523 | | `-noexcept 1524 | `-; 1525 |-SimpleDeclaration 1526 | |-int 1527 | |-SimpleDeclarator 1528 | | |-b 1529 | | `-ParametersAndQualifiers 1530 | | |-( 1531 | | |-) 1532 | | |-noexcept 1533 | | |-( 1534 | | |-UnknownExpression 1535 | | | `-true 1536 | | `-) 1537 | `-; 1538 `-SimpleDeclaration 1539 |-int 1540 |-SimpleDeclarator 1541 | |-c 1542 | `-ParametersAndQualifiers 1543 | |-( 1544 | |-) 1545 | |-throw 1546 | |-( 1547 | `-) 1548 `-; 1549 )txt"); 1550 } 1551 1552 TEST_F(SyntaxTreeTest, DeclaratorsInParentheses) { 1553 expectTreeDumpEqual( 1554 R"cpp( 1555 int (a); 1556 int *(b); 1557 int (*c)(int); 1558 int *(d)(int); 1559 )cpp", 1560 R"txt( 1561 *: TranslationUnit 1562 |-SimpleDeclaration 1563 | |-int 1564 | |-SimpleDeclarator 1565 | | `-ParenDeclarator 1566 | | |-( 1567 | | |-a 1568 | | `-) 1569 | `-; 1570 |-SimpleDeclaration 1571 | |-int 1572 | |-SimpleDeclarator 1573 | | |-* 1574 | | `-ParenDeclarator 1575 | | |-( 1576 | | |-b 1577 | | `-) 1578 | `-; 1579 |-SimpleDeclaration 1580 | |-int 1581 | |-SimpleDeclarator 1582 | | |-ParenDeclarator 1583 | | | |-( 1584 | | | |-* 1585 | | | |-c 1586 | | | `-) 1587 | | `-ParametersAndQualifiers 1588 | | |-( 1589 | | |-SimpleDeclaration 1590 | | | `-int 1591 | | `-) 1592 | `-; 1593 `-SimpleDeclaration 1594 |-int 1595 |-SimpleDeclarator 1596 | |-* 1597 | |-ParenDeclarator 1598 | | |-( 1599 | | |-d 1600 | | `-) 1601 | `-ParametersAndQualifiers 1602 | |-( 1603 | |-SimpleDeclaration 1604 | | `-int 1605 | `-) 1606 `-; 1607 )txt"); 1608 } 1609 1610 TEST_F(SyntaxTreeTest, ConstVolatileQualifiers) { 1611 expectTreeDumpEqual( 1612 R"cpp( 1613 const int west = -1; 1614 int const east = 1; 1615 const int const universal = 0; 1616 const int const *const *volatile b; 1617 )cpp", 1618 R"txt( 1619 *: TranslationUnit 1620 |-SimpleDeclaration 1621 | |-const 1622 | |-int 1623 | |-SimpleDeclarator 1624 | | |-west 1625 | | |-= 1626 | | `-UnknownExpression 1627 | | |-- 1628 | | `-1 1629 | `-; 1630 |-SimpleDeclaration 1631 | |-int 1632 | |-const 1633 | |-SimpleDeclarator 1634 | | |-east 1635 | | |-= 1636 | | `-UnknownExpression 1637 | | `-1 1638 | `-; 1639 |-SimpleDeclaration 1640 | |-const 1641 | |-int 1642 | |-const 1643 | |-SimpleDeclarator 1644 | | |-universal 1645 | | |-= 1646 | | `-UnknownExpression 1647 | | `-0 1648 | `-; 1649 `-SimpleDeclaration 1650 |-const 1651 |-int 1652 |-const 1653 |-SimpleDeclarator 1654 | |-* 1655 | |-const 1656 | |-* 1657 | |-volatile 1658 | `-b 1659 `-; 1660 )txt"); 1661 } 1662 1663 TEST_F(SyntaxTreeTest, RangesOfDeclaratorsWithTrailingReturnTypes) { 1664 expectTreeDumpEqual( 1665 R"cpp( 1666 auto foo() -> auto(*)(int) -> double*; 1667 )cpp", 1668 R"txt( 1669 *: TranslationUnit 1670 `-SimpleDeclaration 1671 |-auto 1672 |-SimpleDeclarator 1673 | |-foo 1674 | `-ParametersAndQualifiers 1675 | |-( 1676 | |-) 1677 | `-TrailingReturnType 1678 | |--> 1679 | |-auto 1680 | `-SimpleDeclarator 1681 | |-ParenDeclarator 1682 | | |-( 1683 | | |-* 1684 | | `-) 1685 | `-ParametersAndQualifiers 1686 | |-( 1687 | |-SimpleDeclaration 1688 | | `-int 1689 | |-) 1690 | `-TrailingReturnType 1691 | |--> 1692 | |-double 1693 | `-SimpleDeclarator 1694 | `-* 1695 `-; 1696 )txt"); 1697 } 1698 1699 TEST_F(SyntaxTreeTest, MemberPointers) { 1700 expectTreeDumpEqual( 1701 R"cpp( 1702 struct X {}; 1703 int X::* a; 1704 const int X::* b; 1705 )cpp", 1706 R"txt( 1707 *: TranslationUnit 1708 |-SimpleDeclaration 1709 | |-struct 1710 | |-X 1711 | |-{ 1712 | |-} 1713 | `-; 1714 |-SimpleDeclaration 1715 | |-int 1716 | |-SimpleDeclarator 1717 | | |-MemberPointer 1718 | | | |-X 1719 | | | |-:: 1720 | | | `-* 1721 | | `-a 1722 | `-; 1723 `-SimpleDeclaration 1724 |-const 1725 |-int 1726 |-SimpleDeclarator 1727 | |-MemberPointer 1728 | | |-X 1729 | | |-:: 1730 | | `-* 1731 | `-b 1732 `-; 1733 )txt"); 1734 } 1735 1736 TEST_F(SyntaxTreeTest, ComplexDeclarator) { 1737 expectTreeDumpEqual( 1738 R"cpp( 1739 void x(char a, short (*b)(int)); 1740 )cpp", 1741 R"txt( 1742 *: TranslationUnit 1743 `-SimpleDeclaration 1744 |-void 1745 |-SimpleDeclarator 1746 | |-x 1747 | `-ParametersAndQualifiers 1748 | |-( 1749 | |-SimpleDeclaration 1750 | | |-char 1751 | | `-SimpleDeclarator 1752 | | `-a 1753 | |-, 1754 | |-SimpleDeclaration 1755 | | |-short 1756 | | `-SimpleDeclarator 1757 | | |-ParenDeclarator 1758 | | | |-( 1759 | | | |-* 1760 | | | |-b 1761 | | | `-) 1762 | | `-ParametersAndQualifiers 1763 | | |-( 1764 | | |-SimpleDeclaration 1765 | | | `-int 1766 | | `-) 1767 | `-) 1768 `-; 1769 )txt"); 1770 } 1771 1772 TEST_F(SyntaxTreeTest, ComplexDeclarator2) { 1773 expectTreeDumpEqual( 1774 R"cpp( 1775 void x(char a, short (*b)(int), long (**c)(long long)); 1776 )cpp", 1777 R"txt( 1778 *: TranslationUnit 1779 `-SimpleDeclaration 1780 |-void 1781 |-SimpleDeclarator 1782 | |-x 1783 | `-ParametersAndQualifiers 1784 | |-( 1785 | |-SimpleDeclaration 1786 | | |-char 1787 | | `-SimpleDeclarator 1788 | | `-a 1789 | |-, 1790 | |-SimpleDeclaration 1791 | | |-short 1792 | | `-SimpleDeclarator 1793 | | |-ParenDeclarator 1794 | | | |-( 1795 | | | |-* 1796 | | | |-b 1797 | | | `-) 1798 | | `-ParametersAndQualifiers 1799 | | |-( 1800 | | |-SimpleDeclaration 1801 | | | `-int 1802 | | `-) 1803 | |-, 1804 | |-SimpleDeclaration 1805 | | |-long 1806 | | `-SimpleDeclarator 1807 | | |-ParenDeclarator 1808 | | | |-( 1809 | | | |-* 1810 | | | |-* 1811 | | | |-c 1812 | | | `-) 1813 | | `-ParametersAndQualifiers 1814 | | |-( 1815 | | |-SimpleDeclaration 1816 | | | |-long 1817 | | | `-long 1818 | | `-) 1819 | `-) 1820 `-; 1821 )txt"); 1822 } 1823 1824 TEST_F(SyntaxTreeTest, Mutations) { 1825 using Transformation = std::function<void( 1826 const llvm::Annotations & /*Input*/, syntax::TranslationUnit * /*Root*/)>; 1827 auto CheckTransformation = [this](std::string Input, std::string Expected, 1828 Transformation Transform) -> void { 1829 llvm::Annotations Source(Input); 1830 auto *Root = buildTree(Source.code()); 1831 1832 Transform(Source, Root); 1833 1834 auto Replacements = syntax::computeReplacements(*Arena, *Root); 1835 auto Output = tooling::applyAllReplacements(Source.code(), Replacements); 1836 if (!Output) { 1837 ADD_FAILURE() << "could not apply replacements: " 1838 << llvm::toString(Output.takeError()); 1839 return; 1840 } 1841 1842 EXPECT_EQ(Expected, *Output) << "input is:\n" << Input; 1843 }; 1844 1845 // Removes the selected statement. Input should have exactly one selected 1846 // range and it should correspond to a single statement. 1847 auto RemoveStatement = [this](const llvm::Annotations &Input, 1848 syntax::TranslationUnit *TU) { 1849 auto *S = cast<syntax::Statement>(nodeByRange(Input.range(), TU)); 1850 ASSERT_TRUE(S->canModify()) << "cannot remove a statement"; 1851 syntax::removeStatement(*Arena, S); 1852 EXPECT_TRUE(S->isDetached()); 1853 EXPECT_FALSE(S->isOriginal()) 1854 << "node removed from tree cannot be marked as original"; 1855 }; 1856 1857 std::vector<std::pair<std::string /*Input*/, std::string /*Expected*/>> 1858 Cases = { 1859 {"void test() { [[100+100;]] test(); }", "void test() { test(); }"}, 1860 {"void test() { if (true) [[{}]] else {} }", 1861 "void test() { if (true) ; else {} }"}, 1862 {"void test() { [[;]] }", "void test() { }"}}; 1863 for (const auto &C : Cases) 1864 CheckTransformation(C.first, C.second, RemoveStatement); 1865 } 1866 1867 TEST_F(SyntaxTreeTest, SynthesizedNodes) { 1868 buildTree(""); 1869 1870 auto *C = syntax::createPunctuation(*Arena, tok::comma); 1871 ASSERT_NE(C, nullptr); 1872 EXPECT_EQ(C->token()->kind(), tok::comma); 1873 EXPECT_TRUE(C->canModify()); 1874 EXPECT_FALSE(C->isOriginal()); 1875 EXPECT_TRUE(C->isDetached()); 1876 1877 auto *S = syntax::createEmptyStatement(*Arena); 1878 ASSERT_NE(S, nullptr); 1879 EXPECT_TRUE(S->canModify()); 1880 EXPECT_FALSE(S->isOriginal()); 1881 EXPECT_TRUE(S->isDetached()); 1882 } 1883 1884 } // namespace 1885