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