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