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   if (!GetParam().isCXX()) {
709     // TODO: Split parts that depend on C++ into a separate test.
710     return;
711   }
712   expectTreeDumpEqual(
713       R"cpp(
714 void test(int a, int *ap, bool b) {
715   --a; ++a;
716   ~a; compl a;
717   -a;
718   +a;
719   &a;
720   *ap;
721   !b; not b;
722   __real a; __imag a;
723 }
724     )cpp",
725       R"txt(
726 *: TranslationUnit
727 `-SimpleDeclaration
728   |-void
729   |-SimpleDeclarator
730   | |-test
731   | `-ParametersAndQualifiers
732   |   |-(
733   |   |-SimpleDeclaration
734   |   | |-int
735   |   | `-SimpleDeclarator
736   |   |   `-a
737   |   |-,
738   |   |-SimpleDeclaration
739   |   | |-int
740   |   | `-SimpleDeclarator
741   |   |   |-*
742   |   |   `-ap
743   |   |-,
744   |   |-SimpleDeclaration
745   |   | |-bool
746   |   | `-SimpleDeclarator
747   |   |   `-b
748   |   `-)
749   `-CompoundStatement
750     |-{
751     |-ExpressionStatement
752     | |-PrefixUnaryOperatorExpression
753     | | |---
754     | | `-UnknownExpression
755     | |   `-a
756     | `-;
757     |-ExpressionStatement
758     | |-PrefixUnaryOperatorExpression
759     | | |-++
760     | | `-UnknownExpression
761     | |   `-a
762     | `-;
763     |-ExpressionStatement
764     | |-PrefixUnaryOperatorExpression
765     | | |-~
766     | | `-UnknownExpression
767     | |   `-a
768     | `-;
769     |-ExpressionStatement
770     | |-PrefixUnaryOperatorExpression
771     | | |-compl
772     | | `-UnknownExpression
773     | |   `-a
774     | `-;
775     |-ExpressionStatement
776     | |-PrefixUnaryOperatorExpression
777     | | |--
778     | | `-UnknownExpression
779     | |   `-a
780     | `-;
781     |-ExpressionStatement
782     | |-PrefixUnaryOperatorExpression
783     | | |-+
784     | | `-UnknownExpression
785     | |   `-a
786     | `-;
787     |-ExpressionStatement
788     | |-PrefixUnaryOperatorExpression
789     | | |-&
790     | | `-UnknownExpression
791     | |   `-a
792     | `-;
793     |-ExpressionStatement
794     | |-PrefixUnaryOperatorExpression
795     | | |-*
796     | | `-UnknownExpression
797     | |   `-ap
798     | `-;
799     |-ExpressionStatement
800     | |-PrefixUnaryOperatorExpression
801     | | |-!
802     | | `-UnknownExpression
803     | |   `-b
804     | `-;
805     |-ExpressionStatement
806     | |-PrefixUnaryOperatorExpression
807     | | |-not
808     | | `-UnknownExpression
809     | |   `-b
810     | `-;
811     |-ExpressionStatement
812     | |-PrefixUnaryOperatorExpression
813     | | |-__real
814     | | `-UnknownExpression
815     | |   `-a
816     | `-;
817     |-ExpressionStatement
818     | |-PrefixUnaryOperatorExpression
819     | | |-__imag
820     | | `-UnknownExpression
821     | |   `-a
822     | `-;
823     `-}
824 )txt");
825 }
826 
827 TEST_P(SyntaxTreeTest, BinaryOperator) {
828   if (!GetParam().isCXX()) {
829     // TODO: Split parts that depend on C++ into a separate test.
830     return;
831   }
832   expectTreeDumpEqual(
833       R"cpp(
834 void test(int a) {
835   1 - 2;
836   1 == 2;
837   a = 1;
838   a <<= 1;
839 
840   true || false;
841   true or false;
842 
843   1 & 2;
844   1 bitand 2;
845 
846   a ^= 3;
847   a xor_eq 3;
848 }
849     )cpp",
850       R"txt(
851 *: TranslationUnit
852 `-SimpleDeclaration
853   |-void
854   |-SimpleDeclarator
855   | |-test
856   | `-ParametersAndQualifiers
857   |   |-(
858   |   |-SimpleDeclaration
859   |   | |-int
860   |   | `-SimpleDeclarator
861   |   |   `-a
862   |   `-)
863   `-CompoundStatement
864     |-{
865     |-ExpressionStatement
866     | |-BinaryOperatorExpression
867     | | |-UnknownExpression
868     | | | `-1
869     | | |--
870     | | `-UnknownExpression
871     | |   `-2
872     | `-;
873     |-ExpressionStatement
874     | |-BinaryOperatorExpression
875     | | |-UnknownExpression
876     | | | `-1
877     | | |-==
878     | | `-UnknownExpression
879     | |   `-2
880     | `-;
881     |-ExpressionStatement
882     | |-BinaryOperatorExpression
883     | | |-UnknownExpression
884     | | | `-a
885     | | |-=
886     | | `-UnknownExpression
887     | |   `-1
888     | `-;
889     |-ExpressionStatement
890     | |-BinaryOperatorExpression
891     | | |-UnknownExpression
892     | | | `-a
893     | | |-<<=
894     | | `-UnknownExpression
895     | |   `-1
896     | `-;
897     |-ExpressionStatement
898     | |-BinaryOperatorExpression
899     | | |-UnknownExpression
900     | | | `-true
901     | | |-||
902     | | `-UnknownExpression
903     | |   `-false
904     | `-;
905     |-ExpressionStatement
906     | |-BinaryOperatorExpression
907     | | |-UnknownExpression
908     | | | `-true
909     | | |-or
910     | | `-UnknownExpression
911     | |   `-false
912     | `-;
913     |-ExpressionStatement
914     | |-BinaryOperatorExpression
915     | | |-UnknownExpression
916     | | | `-1
917     | | |-&
918     | | `-UnknownExpression
919     | |   `-2
920     | `-;
921     |-ExpressionStatement
922     | |-BinaryOperatorExpression
923     | | |-UnknownExpression
924     | | | `-1
925     | | |-bitand
926     | | `-UnknownExpression
927     | |   `-2
928     | `-;
929     |-ExpressionStatement
930     | |-BinaryOperatorExpression
931     | | |-UnknownExpression
932     | | | `-a
933     | | |-^=
934     | | `-UnknownExpression
935     | |   `-3
936     | `-;
937     |-ExpressionStatement
938     | |-BinaryOperatorExpression
939     | | |-UnknownExpression
940     | | | `-a
941     | | |-xor_eq
942     | | `-UnknownExpression
943     | |   `-3
944     | `-;
945     `-}
946 )txt");
947 }
948 
949 TEST_P(SyntaxTreeTest, NestedBinaryOperator) {
950   expectTreeDumpEqual(
951       R"cpp(
952 void test(int a, int b) {
953   (1 + 2) * (4 / 2);
954   a + b + 42;
955   a = b = 42;
956   a + b * 4 + 2;
957   a % 2 + b * 42;
958 }
959     )cpp",
960       R"txt(
961 *: TranslationUnit
962 `-SimpleDeclaration
963   |-void
964   |-SimpleDeclarator
965   | |-test
966   | `-ParametersAndQualifiers
967   |   |-(
968   |   |-SimpleDeclaration
969   |   | |-int
970   |   | `-SimpleDeclarator
971   |   |   `-a
972   |   |-,
973   |   |-SimpleDeclaration
974   |   | |-int
975   |   | `-SimpleDeclarator
976   |   |   `-b
977   |   `-)
978   `-CompoundStatement
979     |-{
980     |-ExpressionStatement
981     | |-BinaryOperatorExpression
982     | | |-UnknownExpression
983     | | | |-(
984     | | | |-BinaryOperatorExpression
985     | | | | |-UnknownExpression
986     | | | | | `-1
987     | | | | |-+
988     | | | | `-UnknownExpression
989     | | | |   `-2
990     | | | `-)
991     | | |-*
992     | | `-UnknownExpression
993     | |   |-(
994     | |   |-BinaryOperatorExpression
995     | |   | |-UnknownExpression
996     | |   | | `-4
997     | |   | |-/
998     | |   | `-UnknownExpression
999     | |   |   `-2
1000     | |   `-)
1001     | `-;
1002     |-ExpressionStatement
1003     | |-BinaryOperatorExpression
1004     | | |-BinaryOperatorExpression
1005     | | | |-UnknownExpression
1006     | | | | `-a
1007     | | | |-+
1008     | | | `-UnknownExpression
1009     | | |   `-b
1010     | | |-+
1011     | | `-UnknownExpression
1012     | |   `-42
1013     | `-;
1014     |-ExpressionStatement
1015     | |-BinaryOperatorExpression
1016     | | |-UnknownExpression
1017     | | | `-a
1018     | | |-=
1019     | | `-BinaryOperatorExpression
1020     | |   |-UnknownExpression
1021     | |   | `-b
1022     | |   |-=
1023     | |   `-UnknownExpression
1024     | |     `-42
1025     | `-;
1026     |-ExpressionStatement
1027     | |-BinaryOperatorExpression
1028     | | |-BinaryOperatorExpression
1029     | | | |-UnknownExpression
1030     | | | | `-a
1031     | | | |-+
1032     | | | `-BinaryOperatorExpression
1033     | | |   |-UnknownExpression
1034     | | |   | `-b
1035     | | |   |-*
1036     | | |   `-UnknownExpression
1037     | | |     `-4
1038     | | |-+
1039     | | `-UnknownExpression
1040     | |   `-2
1041     | `-;
1042     |-ExpressionStatement
1043     | |-BinaryOperatorExpression
1044     | | |-BinaryOperatorExpression
1045     | | | |-UnknownExpression
1046     | | | | `-a
1047     | | | |-%
1048     | | | `-UnknownExpression
1049     | | |   `-2
1050     | | |-+
1051     | | `-BinaryOperatorExpression
1052     | |   |-UnknownExpression
1053     | |   | `-b
1054     | |   |-*
1055     | |   `-UnknownExpression
1056     | |     `-42
1057     | `-;
1058     `-}
1059 )txt");
1060 }
1061 
1062 TEST_P(SyntaxTreeTest, UserDefinedBinaryOperator) {
1063   if (!GetParam().isCXX()) {
1064     return;
1065   }
1066   expectTreeDumpEqual(
1067       R"cpp(
1068 struct X {
1069   X& operator=(const X&);
1070   friend X operator+(X, const X&);
1071   friend bool operator<(const X&, const X&);
1072 };
1073 void test(X x, X y) {
1074   x = y;
1075   x + y;
1076   x < y;
1077 }
1078       )cpp",
1079       R"txt(
1080 *: TranslationUnit
1081 |-SimpleDeclaration
1082 | |-struct
1083 | |-X
1084 | |-{
1085 | |-SimpleDeclaration
1086 | | |-X
1087 | | |-SimpleDeclarator
1088 | | | |-&
1089 | | | |-operator
1090 | | | |-=
1091 | | | `-ParametersAndQualifiers
1092 | | |   |-(
1093 | | |   |-SimpleDeclaration
1094 | | |   | |-const
1095 | | |   | |-X
1096 | | |   | `-SimpleDeclarator
1097 | | |   |   `-&
1098 | | |   `-)
1099 | | `-;
1100 | |-UnknownDeclaration
1101 | | `-SimpleDeclaration
1102 | |   |-friend
1103 | |   |-X
1104 | |   |-SimpleDeclarator
1105 | |   | |-operator
1106 | |   | |-+
1107 | |   | `-ParametersAndQualifiers
1108 | |   |   |-(
1109 | |   |   |-SimpleDeclaration
1110 | |   |   | `-X
1111 | |   |   |-,
1112 | |   |   |-SimpleDeclaration
1113 | |   |   | |-const
1114 | |   |   | |-X
1115 | |   |   | `-SimpleDeclarator
1116 | |   |   |   `-&
1117 | |   |   `-)
1118 | |   `-;
1119 | |-UnknownDeclaration
1120 | | `-SimpleDeclaration
1121 | |   |-friend
1122 | |   |-bool
1123 | |   |-SimpleDeclarator
1124 | |   | |-operator
1125 | |   | |-<
1126 | |   | `-ParametersAndQualifiers
1127 | |   |   |-(
1128 | |   |   |-SimpleDeclaration
1129 | |   |   | |-const
1130 | |   |   | |-X
1131 | |   |   | `-SimpleDeclarator
1132 | |   |   |   `-&
1133 | |   |   |-,
1134 | |   |   |-SimpleDeclaration
1135 | |   |   | |-const
1136 | |   |   | |-X
1137 | |   |   | `-SimpleDeclarator
1138 | |   |   |   `-&
1139 | |   |   `-)
1140 | |   `-;
1141 | |-}
1142 | `-;
1143 `-SimpleDeclaration
1144   |-void
1145   |-SimpleDeclarator
1146   | |-test
1147   | `-ParametersAndQualifiers
1148   |   |-(
1149   |   |-SimpleDeclaration
1150   |   | |-X
1151   |   | `-SimpleDeclarator
1152   |   |   `-x
1153   |   |-,
1154   |   |-SimpleDeclaration
1155   |   | |-X
1156   |   | `-SimpleDeclarator
1157   |   |   `-y
1158   |   `-)
1159   `-CompoundStatement
1160     |-{
1161     |-ExpressionStatement
1162     | |-BinaryOperatorExpression
1163     | | |-UnknownExpression
1164     | | | `-x
1165     | | |-UnknownExpression
1166     | | | `-=
1167     | | `-UnknownExpression
1168     | |   `-y
1169     | `-;
1170     |-ExpressionStatement
1171     | |-BinaryOperatorExpression
1172     | | |-UnknownExpression
1173     | | | `-UnknownExpression
1174     | | |   `-x
1175     | | |-UnknownExpression
1176     | | | `-+
1177     | | `-UnknownExpression
1178     | |   `-y
1179     | `-;
1180     |-ExpressionStatement
1181     | |-BinaryOperatorExpression
1182     | | |-UnknownExpression
1183     | | | `-x
1184     | | |-UnknownExpression
1185     | | | `-<
1186     | | `-UnknownExpression
1187     | |   `-y
1188     | `-;
1189     `-}
1190 )txt");
1191 }
1192 
1193 TEST_P(SyntaxTreeTest, MultipleDeclaratorsGrouping) {
1194   expectTreeDumpEqual(
1195       R"cpp(
1196       int *a, b; int *c, d;
1197   )cpp",
1198       R"txt(
1199 *: TranslationUnit
1200 |-SimpleDeclaration
1201 | |-int
1202 | |-SimpleDeclarator
1203 | | |-*
1204 | | `-a
1205 | |-,
1206 | |-SimpleDeclarator
1207 | | `-b
1208 | `-;
1209 `-SimpleDeclaration
1210   |-int
1211   |-SimpleDeclarator
1212   | |-*
1213   | `-c
1214   |-,
1215   |-SimpleDeclarator
1216   | `-d
1217   `-;
1218   )txt");
1219 }
1220 
1221 TEST_P(SyntaxTreeTest, MultipleDeclaratorsGroupingTypedef) {
1222   expectTreeDumpEqual(
1223       R"cpp(
1224     typedef int *a, b;
1225   )cpp",
1226       R"txt(
1227 *: TranslationUnit
1228 `-SimpleDeclaration
1229   |-typedef
1230   |-int
1231   |-SimpleDeclarator
1232   | |-*
1233   | `-a
1234   |-,
1235   |-SimpleDeclarator
1236   | `-b
1237   `-;
1238   )txt");
1239 }
1240 
1241 TEST_P(SyntaxTreeTest, MultipleDeclaratorsInsideStatement) {
1242   expectTreeDumpEqual(
1243       R"cpp(
1244 void foo() {
1245       int *a, b;
1246       typedef int *ta, tb;
1247 }
1248   )cpp",
1249       R"txt(
1250 *: TranslationUnit
1251 `-SimpleDeclaration
1252   |-void
1253   |-SimpleDeclarator
1254   | |-foo
1255   | `-ParametersAndQualifiers
1256   |   |-(
1257   |   `-)
1258   `-CompoundStatement
1259     |-{
1260     |-DeclarationStatement
1261     | |-SimpleDeclaration
1262     | | |-int
1263     | | |-SimpleDeclarator
1264     | | | |-*
1265     | | | `-a
1266     | | |-,
1267     | | `-SimpleDeclarator
1268     | |   `-b
1269     | `-;
1270     |-DeclarationStatement
1271     | |-SimpleDeclaration
1272     | | |-typedef
1273     | | |-int
1274     | | |-SimpleDeclarator
1275     | | | |-*
1276     | | | `-ta
1277     | | |-,
1278     | | `-SimpleDeclarator
1279     | |   `-tb
1280     | `-;
1281     `-}
1282   )txt");
1283 }
1284 
1285 TEST_P(SyntaxTreeTest, Namespaces) {
1286   if (!GetParam().isCXX()) {
1287     return;
1288   }
1289   expectTreeDumpEqual(
1290       R"cpp(
1291 namespace a { namespace b {} }
1292 namespace a::b {}
1293 namespace {}
1294 
1295 namespace foo = a;
1296     )cpp",
1297       R"txt(
1298 *: TranslationUnit
1299 |-NamespaceDefinition
1300 | |-namespace
1301 | |-a
1302 | |-{
1303 | |-NamespaceDefinition
1304 | | |-namespace
1305 | | |-b
1306 | | |-{
1307 | | `-}
1308 | `-}
1309 |-NamespaceDefinition
1310 | |-namespace
1311 | |-a
1312 | |-::
1313 | |-b
1314 | |-{
1315 | `-}
1316 |-NamespaceDefinition
1317 | |-namespace
1318 | |-{
1319 | `-}
1320 `-NamespaceAliasDefinition
1321   |-namespace
1322   |-foo
1323   |-=
1324   |-a
1325   `-;
1326 )txt");
1327 }
1328 
1329 TEST_P(SyntaxTreeTest, UsingDirective) {
1330   if (!GetParam().isCXX()) {
1331     return;
1332   }
1333   expectTreeDumpEqual(
1334       R"cpp(
1335 namespace ns {}
1336 using namespace ::ns;
1337     )cpp",
1338       R"txt(
1339 *: TranslationUnit
1340 |-NamespaceDefinition
1341 | |-namespace
1342 | |-ns
1343 | |-{
1344 | `-}
1345 `-UsingNamespaceDirective
1346   |-using
1347   |-namespace
1348   |-::
1349   |-ns
1350   `-;
1351        )txt");
1352 }
1353 
1354 TEST_P(SyntaxTreeTest, UsingDeclaration) {
1355   if (!GetParam().isCXX()) {
1356     return;
1357   }
1358   expectTreeDumpEqual(
1359       R"cpp(
1360 namespace ns { int a; }
1361 using ns::a;
1362     )cpp",
1363       R"txt(
1364 *: TranslationUnit
1365 |-NamespaceDefinition
1366 | |-namespace
1367 | |-ns
1368 | |-{
1369 | |-SimpleDeclaration
1370 | | |-int
1371 | | |-SimpleDeclarator
1372 | | | `-a
1373 | | `-;
1374 | `-}
1375 `-UsingDeclaration
1376   |-using
1377   |-ns
1378   |-::
1379   |-a
1380   `-;
1381        )txt");
1382 }
1383 
1384 TEST_P(SyntaxTreeTest, FreeStandingClasses) {
1385   // Free-standing classes, must live inside a SimpleDeclaration.
1386   expectTreeDumpEqual(
1387       R"cpp(
1388 struct X;
1389 struct X {};
1390 
1391 struct Y *y1;
1392 struct Y {} *y2;
1393 
1394 struct {} *a1;
1395     )cpp",
1396       R"txt(
1397 *: TranslationUnit
1398 |-SimpleDeclaration
1399 | |-struct
1400 | |-X
1401 | `-;
1402 |-SimpleDeclaration
1403 | |-struct
1404 | |-X
1405 | |-{
1406 | |-}
1407 | `-;
1408 |-SimpleDeclaration
1409 | |-struct
1410 | |-Y
1411 | |-SimpleDeclarator
1412 | | |-*
1413 | | `-y1
1414 | `-;
1415 |-SimpleDeclaration
1416 | |-struct
1417 | |-Y
1418 | |-{
1419 | |-}
1420 | |-SimpleDeclarator
1421 | | |-*
1422 | | `-y2
1423 | `-;
1424 `-SimpleDeclaration
1425   |-struct
1426   |-{
1427   |-}
1428   |-SimpleDeclarator
1429   | |-*
1430   | `-a1
1431   `-;
1432 )txt");
1433 }
1434 
1435 TEST_P(SyntaxTreeTest, Templates) {
1436   if (!GetParam().isCXX()) {
1437     return;
1438   }
1439   if (GetParam().hasDelayedTemplateParsing()) {
1440     // FIXME: Make this test work on Windows by generating the expected syntax
1441     // tree when `-fdelayed-template-parsing` is active.
1442     return;
1443   }
1444   expectTreeDumpEqual(
1445       R"cpp(
1446 template <class T> struct cls {};
1447 template <class T> int var = 10;
1448 template <class T> int fun() {}
1449     )cpp",
1450       R"txt(
1451 *: TranslationUnit
1452 |-TemplateDeclaration
1453 | |-template
1454 | |-<
1455 | |-UnknownDeclaration
1456 | | |-class
1457 | | `-T
1458 | |->
1459 | `-SimpleDeclaration
1460 |   |-struct
1461 |   |-cls
1462 |   |-{
1463 |   |-}
1464 |   `-;
1465 |-TemplateDeclaration
1466 | |-template
1467 | |-<
1468 | |-UnknownDeclaration
1469 | | |-class
1470 | | `-T
1471 | |->
1472 | `-SimpleDeclaration
1473 |   |-int
1474 |   |-SimpleDeclarator
1475 |   | |-var
1476 |   | |-=
1477 |   | `-UnknownExpression
1478 |   |   `-10
1479 |   `-;
1480 `-TemplateDeclaration
1481   |-template
1482   |-<
1483   |-UnknownDeclaration
1484   | |-class
1485   | `-T
1486   |->
1487   `-SimpleDeclaration
1488     |-int
1489     |-SimpleDeclarator
1490     | |-fun
1491     | `-ParametersAndQualifiers
1492     |   |-(
1493     |   `-)
1494     `-CompoundStatement
1495       |-{
1496       `-}
1497 )txt");
1498 }
1499 
1500 TEST_P(SyntaxTreeTest, NestedTemplates) {
1501   if (!GetParam().isCXX()) {
1502     return;
1503   }
1504   expectTreeDumpEqual(
1505       R"cpp(
1506 template <class T>
1507 struct X {
1508   template <class U>
1509   U foo();
1510 };
1511     )cpp",
1512       R"txt(
1513 *: TranslationUnit
1514 `-TemplateDeclaration
1515   |-template
1516   |-<
1517   |-UnknownDeclaration
1518   | |-class
1519   | `-T
1520   |->
1521   `-SimpleDeclaration
1522     |-struct
1523     |-X
1524     |-{
1525     |-TemplateDeclaration
1526     | |-template
1527     | |-<
1528     | |-UnknownDeclaration
1529     | | |-class
1530     | | `-U
1531     | |->
1532     | `-SimpleDeclaration
1533     |   |-U
1534     |   |-SimpleDeclarator
1535     |   | |-foo
1536     |   | `-ParametersAndQualifiers
1537     |   |   |-(
1538     |   |   `-)
1539     |   `-;
1540     |-}
1541     `-;
1542 )txt");
1543 }
1544 
1545 TEST_P(SyntaxTreeTest, Templates2) {
1546   if (!GetParam().isCXX()) {
1547     return;
1548   }
1549   expectTreeDumpEqual(
1550       R"cpp(
1551 template <class T> struct X { struct Y; };
1552 template <class T> struct X<T>::Y {};
1553     )cpp",
1554       R"txt(
1555 *: TranslationUnit
1556 |-TemplateDeclaration
1557 | |-template
1558 | |-<
1559 | |-UnknownDeclaration
1560 | | |-class
1561 | | `-T
1562 | |->
1563 | `-SimpleDeclaration
1564 |   |-struct
1565 |   |-X
1566 |   |-{
1567 |   |-SimpleDeclaration
1568 |   | |-struct
1569 |   | |-Y
1570 |   | `-;
1571 |   |-}
1572 |   `-;
1573 `-TemplateDeclaration
1574   |-template
1575   |-<
1576   |-UnknownDeclaration
1577   | |-class
1578   | `-T
1579   |->
1580   `-SimpleDeclaration
1581     |-struct
1582     |-X
1583     |-<
1584     |-T
1585     |->
1586     |-::
1587     |-Y
1588     |-{
1589     |-}
1590     `-;
1591        )txt");
1592 }
1593 
1594 TEST_P(SyntaxTreeTest, TemplatesUsingUsing) {
1595   if (!GetParam().isCXX()) {
1596     return;
1597   }
1598   expectTreeDumpEqual(
1599       R"cpp(
1600 template <class T> struct X {
1601   using T::foo;
1602   using typename T::bar;
1603 };
1604     )cpp",
1605       R"txt(
1606 *: TranslationUnit
1607 `-TemplateDeclaration
1608   |-template
1609   |-<
1610   |-UnknownDeclaration
1611   | |-class
1612   | `-T
1613   |->
1614   `-SimpleDeclaration
1615     |-struct
1616     |-X
1617     |-{
1618     |-UsingDeclaration
1619     | |-using
1620     | |-T
1621     | |-::
1622     | |-foo
1623     | `-;
1624     |-UsingDeclaration
1625     | |-using
1626     | |-typename
1627     | |-T
1628     | |-::
1629     | |-bar
1630     | `-;
1631     |-}
1632     `-;
1633        )txt");
1634 }
1635 
1636 TEST_P(SyntaxTreeTest, ExplicitTemplateInstantations) {
1637   if (!GetParam().isCXX()) {
1638     return;
1639   }
1640   expectTreeDumpEqual(
1641       R"cpp(
1642 template <class T> struct X {};
1643 template <class T> struct X<T*> {};
1644 template <> struct X<int> {};
1645 
1646 template struct X<double>;
1647 extern template struct X<float>;
1648 )cpp",
1649       R"txt(
1650 *: TranslationUnit
1651 |-TemplateDeclaration
1652 | |-template
1653 | |-<
1654 | |-UnknownDeclaration
1655 | | |-class
1656 | | `-T
1657 | |->
1658 | `-SimpleDeclaration
1659 |   |-struct
1660 |   |-X
1661 |   |-{
1662 |   |-}
1663 |   `-;
1664 |-TemplateDeclaration
1665 | |-template
1666 | |-<
1667 | |-UnknownDeclaration
1668 | | |-class
1669 | | `-T
1670 | |->
1671 | `-SimpleDeclaration
1672 |   |-struct
1673 |   |-X
1674 |   |-<
1675 |   |-T
1676 |   |-*
1677 |   |->
1678 |   |-{
1679 |   |-}
1680 |   `-;
1681 |-TemplateDeclaration
1682 | |-template
1683 | |-<
1684 | |->
1685 | `-SimpleDeclaration
1686 |   |-struct
1687 |   |-X
1688 |   |-<
1689 |   |-int
1690 |   |->
1691 |   |-{
1692 |   |-}
1693 |   `-;
1694 |-ExplicitTemplateInstantiation
1695 | |-template
1696 | `-SimpleDeclaration
1697 |   |-struct
1698 |   |-X
1699 |   |-<
1700 |   |-double
1701 |   |->
1702 |   `-;
1703 `-ExplicitTemplateInstantiation
1704   |-extern
1705   |-template
1706   `-SimpleDeclaration
1707     |-struct
1708     |-X
1709     |-<
1710     |-float
1711     |->
1712     `-;
1713 )txt");
1714 }
1715 
1716 TEST_P(SyntaxTreeTest, UsingType) {
1717   if (!GetParam().isCXX()) {
1718     return;
1719   }
1720   expectTreeDumpEqual(
1721       R"cpp(
1722 using type = int;
1723     )cpp",
1724       R"txt(
1725 *: TranslationUnit
1726 `-TypeAliasDeclaration
1727   |-using
1728   |-type
1729   |-=
1730   |-int
1731   `-;
1732        )txt");
1733 }
1734 
1735 TEST_P(SyntaxTreeTest, EmptyDeclaration) {
1736   expectTreeDumpEqual(
1737       R"cpp(
1738 ;
1739     )cpp",
1740       R"txt(
1741 *: TranslationUnit
1742 `-EmptyDeclaration
1743   `-;
1744        )txt");
1745 }
1746 
1747 TEST_P(SyntaxTreeTest, StaticAssert) {
1748   if (!GetParam().isCXX11OrLater()) {
1749     return;
1750   }
1751   expectTreeDumpEqual(
1752       R"cpp(
1753 static_assert(true, "message");
1754 static_assert(true);
1755     )cpp",
1756       R"txt(
1757 *: TranslationUnit
1758 |-StaticAssertDeclaration
1759 | |-static_assert
1760 | |-(
1761 | |-UnknownExpression
1762 | | `-true
1763 | |-,
1764 | |-UnknownExpression
1765 | | `-"message"
1766 | |-)
1767 | `-;
1768 `-StaticAssertDeclaration
1769   |-static_assert
1770   |-(
1771   |-UnknownExpression
1772   | `-true
1773   |-)
1774   `-;
1775        )txt");
1776 }
1777 
1778 TEST_P(SyntaxTreeTest, ExternC) {
1779   if (!GetParam().isCXX()) {
1780     return;
1781   }
1782   expectTreeDumpEqual(
1783       R"cpp(
1784 extern "C" int a;
1785 extern "C" { int b; int c; }
1786     )cpp",
1787       R"txt(
1788 *: TranslationUnit
1789 |-LinkageSpecificationDeclaration
1790 | |-extern
1791 | |-"C"
1792 | `-SimpleDeclaration
1793 |   |-int
1794 |   |-SimpleDeclarator
1795 |   | `-a
1796 |   `-;
1797 `-LinkageSpecificationDeclaration
1798   |-extern
1799   |-"C"
1800   |-{
1801   |-SimpleDeclaration
1802   | |-int
1803   | |-SimpleDeclarator
1804   | | `-b
1805   | `-;
1806   |-SimpleDeclaration
1807   | |-int
1808   | |-SimpleDeclarator
1809   | | `-c
1810   | `-;
1811   `-}
1812        )txt");
1813 }
1814 
1815 TEST_P(SyntaxTreeTest, NonModifiableNodes) {
1816   // Some nodes are non-modifiable, they are marked with 'I:'.
1817   expectTreeDumpEqual(
1818       R"cpp(
1819 #define HALF_IF if (1+
1820 #define HALF_IF_2 1) {}
1821 void test() {
1822   HALF_IF HALF_IF_2 else {}
1823 })cpp",
1824       R"txt(
1825 *: TranslationUnit
1826 `-SimpleDeclaration
1827   |-void
1828   |-SimpleDeclarator
1829   | |-test
1830   | `-ParametersAndQualifiers
1831   |   |-(
1832   |   `-)
1833   `-CompoundStatement
1834     |-{
1835     |-IfStatement
1836     | |-I: if
1837     | |-I: (
1838     | |-I: BinaryOperatorExpression
1839     | | |-I: UnknownExpression
1840     | | | `-I: 1
1841     | | |-I: +
1842     | | `-I: UnknownExpression
1843     | |   `-I: 1
1844     | |-I: )
1845     | |-I: CompoundStatement
1846     | | |-I: {
1847     | | `-I: }
1848     | |-else
1849     | `-CompoundStatement
1850     |   |-{
1851     |   `-}
1852     `-}
1853        )txt");
1854 }
1855 
1856 TEST_P(SyntaxTreeTest, ModifiableNodes) {
1857   // All nodes can be mutated.
1858   expectTreeDumpEqual(
1859       R"cpp(
1860 #define OPEN {
1861 #define CLOSE }
1862 
1863 void test() {
1864   OPEN
1865     1;
1866   CLOSE
1867 
1868   OPEN
1869     2;
1870   }
1871 }
1872 )cpp",
1873       R"txt(
1874 *: TranslationUnit
1875 `-SimpleDeclaration
1876   |-void
1877   |-SimpleDeclarator
1878   | |-test
1879   | `-ParametersAndQualifiers
1880   |   |-(
1881   |   `-)
1882   `-CompoundStatement
1883     |-{
1884     |-CompoundStatement
1885     | |-{
1886     | |-ExpressionStatement
1887     | | |-UnknownExpression
1888     | | | `-1
1889     | | `-;
1890     | `-}
1891     |-CompoundStatement
1892     | |-{
1893     | |-ExpressionStatement
1894     | | |-UnknownExpression
1895     | | | `-2
1896     | | `-;
1897     | `-}
1898     `-}
1899        )txt");
1900 }
1901 
1902 TEST_P(SyntaxTreeTest, ArraySubscriptsInDeclarators) {
1903   expectTreeDumpEqual(
1904       R"cpp(
1905 int a[10];
1906 int b[1][2][3];
1907 int c[] = {1,2,3};
1908     )cpp",
1909       R"txt(
1910 *: TranslationUnit
1911 |-SimpleDeclaration
1912 | |-int
1913 | |-SimpleDeclarator
1914 | | |-a
1915 | | `-ArraySubscript
1916 | |   |-[
1917 | |   |-UnknownExpression
1918 | |   | `-10
1919 | |   `-]
1920 | `-;
1921 |-SimpleDeclaration
1922 | |-int
1923 | |-SimpleDeclarator
1924 | | |-b
1925 | | |-ArraySubscript
1926 | | | |-[
1927 | | | |-UnknownExpression
1928 | | | | `-1
1929 | | | `-]
1930 | | |-ArraySubscript
1931 | | | |-[
1932 | | | |-UnknownExpression
1933 | | | | `-2
1934 | | | `-]
1935 | | `-ArraySubscript
1936 | |   |-[
1937 | |   |-UnknownExpression
1938 | |   | `-3
1939 | |   `-]
1940 | `-;
1941 `-SimpleDeclaration
1942   |-int
1943   |-SimpleDeclarator
1944   | |-c
1945   | |-ArraySubscript
1946   | | |-[
1947   | | `-]
1948   | |-=
1949   | `-UnknownExpression
1950   |   `-UnknownExpression
1951   |     |-{
1952   |     |-UnknownExpression
1953   |     | `-1
1954   |     |-,
1955   |     |-UnknownExpression
1956   |     | `-2
1957   |     |-,
1958   |     |-UnknownExpression
1959   |     | `-3
1960   |     `-}
1961   `-;       )txt");
1962 }
1963 
1964 TEST_P(SyntaxTreeTest, StaticArraySubscriptsInDeclarators) {
1965   if (!GetParam().isC99OrLater()) {
1966     return;
1967   }
1968   expectTreeDumpEqual(
1969       R"cpp(
1970 void f(int xs[static 10]);
1971     )cpp",
1972       R"txt(
1973 *: TranslationUnit
1974 `-SimpleDeclaration
1975   |-void
1976   |-SimpleDeclarator
1977   | |-f
1978   | `-ParametersAndQualifiers
1979   |   |-(
1980   |   |-SimpleDeclaration
1981   |   | |-int
1982   |   | `-SimpleDeclarator
1983   |   |   |-xs
1984   |   |   `-ArraySubscript
1985   |   |     |-[
1986   |   |     |-static
1987   |   |     |-UnknownExpression
1988   |   |     | `-10
1989   |   |     `-]
1990   |   `-)
1991   `-;       )txt");
1992 }
1993 
1994 TEST_P(SyntaxTreeTest, ParameterListsInDeclarators) {
1995   if (!GetParam().isCXX()) {
1996     // TODO: Split parts that depend on C++ into a separate test.
1997     return;
1998   }
1999   expectTreeDumpEqual(
2000       R"cpp(
2001 struct Test {
2002   int a() const;
2003   int b() volatile;
2004   int c() &;
2005   int d() &&;
2006   int foo(int a, int b);
2007   int foo(const int a, volatile int b, const volatile int c, int* d,
2008           int& e, int&& f);
2009 };
2010       )cpp",
2011       R"txt(
2012 *: TranslationUnit
2013 `-SimpleDeclaration
2014   |-struct
2015   |-Test
2016   |-{
2017   |-SimpleDeclaration
2018   | |-int
2019   | |-SimpleDeclarator
2020   | | |-a
2021   | | `-ParametersAndQualifiers
2022   | |   |-(
2023   | |   |-)
2024   | |   `-const
2025   | `-;
2026   |-SimpleDeclaration
2027   | |-int
2028   | |-SimpleDeclarator
2029   | | |-b
2030   | | `-ParametersAndQualifiers
2031   | |   |-(
2032   | |   |-)
2033   | |   `-volatile
2034   | `-;
2035   |-SimpleDeclaration
2036   | |-int
2037   | |-SimpleDeclarator
2038   | | |-c
2039   | | `-ParametersAndQualifiers
2040   | |   |-(
2041   | |   |-)
2042   | |   `-&
2043   | `-;
2044   |-SimpleDeclaration
2045   | |-int
2046   | |-SimpleDeclarator
2047   | | |-d
2048   | | `-ParametersAndQualifiers
2049   | |   |-(
2050   | |   |-)
2051   | |   `-&&
2052   | `-;
2053   |-SimpleDeclaration
2054   | |-int
2055   | |-SimpleDeclarator
2056   | | |-foo
2057   | | `-ParametersAndQualifiers
2058   | |   |-(
2059   | |   |-SimpleDeclaration
2060   | |   | |-int
2061   | |   | `-SimpleDeclarator
2062   | |   |   `-a
2063   | |   |-,
2064   | |   |-SimpleDeclaration
2065   | |   | |-int
2066   | |   | `-SimpleDeclarator
2067   | |   |   `-b
2068   | |   `-)
2069   | `-;
2070   |-SimpleDeclaration
2071   | |-int
2072   | |-SimpleDeclarator
2073   | | |-foo
2074   | | `-ParametersAndQualifiers
2075   | |   |-(
2076   | |   |-SimpleDeclaration
2077   | |   | |-const
2078   | |   | |-int
2079   | |   | `-SimpleDeclarator
2080   | |   |   `-a
2081   | |   |-,
2082   | |   |-SimpleDeclaration
2083   | |   | |-volatile
2084   | |   | |-int
2085   | |   | `-SimpleDeclarator
2086   | |   |   `-b
2087   | |   |-,
2088   | |   |-SimpleDeclaration
2089   | |   | |-const
2090   | |   | |-volatile
2091   | |   | |-int
2092   | |   | `-SimpleDeclarator
2093   | |   |   `-c
2094   | |   |-,
2095   | |   |-SimpleDeclaration
2096   | |   | |-int
2097   | |   | `-SimpleDeclarator
2098   | |   |   |-*
2099   | |   |   `-d
2100   | |   |-,
2101   | |   |-SimpleDeclaration
2102   | |   | |-int
2103   | |   | `-SimpleDeclarator
2104   | |   |   |-&
2105   | |   |   `-e
2106   | |   |-,
2107   | |   |-SimpleDeclaration
2108   | |   | |-int
2109   | |   | `-SimpleDeclarator
2110   | |   |   |-&&
2111   | |   |   `-f
2112   | |   `-)
2113   | `-;
2114   |-}
2115   `-;
2116        )txt");
2117 }
2118 
2119 TEST_P(SyntaxTreeTest, TrailingConst) {
2120   if (!GetParam().isCXX()) {
2121     // TODO: Split parts that depend on C++ into a separate test.
2122     return;
2123   }
2124   expectTreeDumpEqual(
2125       R"cpp(
2126 struct X {
2127   int foo() const;
2128 };
2129     )cpp",
2130       R"txt(
2131 *: TranslationUnit
2132 `-SimpleDeclaration
2133   |-struct
2134   |-X
2135   |-{
2136   |-SimpleDeclaration
2137   | |-int
2138   | |-SimpleDeclarator
2139   | | |-foo
2140   | | `-ParametersAndQualifiers
2141   | |   |-(
2142   | |   |-)
2143   | |   `-const
2144   | `-;
2145   |-}
2146   `-;
2147     )txt");
2148 }
2149 
2150 TEST_P(SyntaxTreeTest, TrailingReturn) {
2151   if (!GetParam().isCXX11OrLater()) {
2152     return;
2153   }
2154   expectTreeDumpEqual(
2155       R"cpp(
2156 auto foo() -> int;
2157     )cpp",
2158       R"txt(
2159 *: TranslationUnit
2160 `-SimpleDeclaration
2161   |-auto
2162   |-SimpleDeclarator
2163   | |-foo
2164   | `-ParametersAndQualifiers
2165   |   |-(
2166   |   |-)
2167   |   `-TrailingReturnType
2168   |     |-->
2169   |     `-int
2170   `-;
2171        )txt");
2172 }
2173 
2174 TEST_P(SyntaxTreeTest, ExceptionSpecification) {
2175   if (!GetParam().isCXX11OrLater()) {
2176     // TODO: Split parts that depend on C++11 into a separate test.
2177     return;
2178   }
2179   expectTreeDumpEqual(
2180       R"cpp(
2181 int a() noexcept;
2182 int b() noexcept(true);
2183 int c() throw();
2184     )cpp",
2185       R"txt(
2186 *: TranslationUnit
2187 |-SimpleDeclaration
2188 | |-int
2189 | |-SimpleDeclarator
2190 | | |-a
2191 | | `-ParametersAndQualifiers
2192 | |   |-(
2193 | |   |-)
2194 | |   `-noexcept
2195 | `-;
2196 |-SimpleDeclaration
2197 | |-int
2198 | |-SimpleDeclarator
2199 | | |-b
2200 | | `-ParametersAndQualifiers
2201 | |   |-(
2202 | |   |-)
2203 | |   |-noexcept
2204 | |   |-(
2205 | |   |-UnknownExpression
2206 | |   | `-true
2207 | |   `-)
2208 | `-;
2209 `-SimpleDeclaration
2210   |-int
2211   |-SimpleDeclarator
2212   | |-c
2213   | `-ParametersAndQualifiers
2214   |   |-(
2215   |   |-)
2216   |   |-throw
2217   |   |-(
2218   |   `-)
2219   `-;
2220        )txt");
2221 }
2222 
2223 TEST_P(SyntaxTreeTest, DeclaratorsInParentheses) {
2224   expectTreeDumpEqual(
2225       R"cpp(
2226 int (a);
2227 int *(b);
2228 int (*c)(int);
2229 int *(d)(int);
2230     )cpp",
2231       R"txt(
2232 *: TranslationUnit
2233 |-SimpleDeclaration
2234 | |-int
2235 | |-SimpleDeclarator
2236 | | `-ParenDeclarator
2237 | |   |-(
2238 | |   |-a
2239 | |   `-)
2240 | `-;
2241 |-SimpleDeclaration
2242 | |-int
2243 | |-SimpleDeclarator
2244 | | |-*
2245 | | `-ParenDeclarator
2246 | |   |-(
2247 | |   |-b
2248 | |   `-)
2249 | `-;
2250 |-SimpleDeclaration
2251 | |-int
2252 | |-SimpleDeclarator
2253 | | |-ParenDeclarator
2254 | | | |-(
2255 | | | |-*
2256 | | | |-c
2257 | | | `-)
2258 | | `-ParametersAndQualifiers
2259 | |   |-(
2260 | |   |-SimpleDeclaration
2261 | |   | `-int
2262 | |   `-)
2263 | `-;
2264 `-SimpleDeclaration
2265   |-int
2266   |-SimpleDeclarator
2267   | |-*
2268   | |-ParenDeclarator
2269   | | |-(
2270   | | |-d
2271   | | `-)
2272   | `-ParametersAndQualifiers
2273   |   |-(
2274   |   |-SimpleDeclaration
2275   |   | `-int
2276   |   `-)
2277   `-;
2278        )txt");
2279 }
2280 
2281 TEST_P(SyntaxTreeTest, ConstVolatileQualifiers) {
2282   expectTreeDumpEqual(
2283       R"cpp(
2284 const int west = -1;
2285 int const east = 1;
2286 const int const universal = 0;
2287 const int const *const *volatile b;
2288     )cpp",
2289       R"txt(
2290 *: TranslationUnit
2291 |-SimpleDeclaration
2292 | |-const
2293 | |-int
2294 | |-SimpleDeclarator
2295 | | |-west
2296 | | |-=
2297 | | `-PrefixUnaryOperatorExpression
2298 | |   |--
2299 | |   `-UnknownExpression
2300 | |     `-1
2301 | `-;
2302 |-SimpleDeclaration
2303 | |-int
2304 | |-const
2305 | |-SimpleDeclarator
2306 | | |-east
2307 | | |-=
2308 | | `-UnknownExpression
2309 | |   `-1
2310 | `-;
2311 |-SimpleDeclaration
2312 | |-const
2313 | |-int
2314 | |-const
2315 | |-SimpleDeclarator
2316 | | |-universal
2317 | | |-=
2318 | | `-UnknownExpression
2319 | |   `-0
2320 | `-;
2321 `-SimpleDeclaration
2322   |-const
2323   |-int
2324   |-const
2325   |-SimpleDeclarator
2326   | |-*
2327   | |-const
2328   | |-*
2329   | |-volatile
2330   | `-b
2331   `-;
2332        )txt");
2333 }
2334 
2335 TEST_P(SyntaxTreeTest, RangesOfDeclaratorsWithTrailingReturnTypes) {
2336   if (!GetParam().isCXX11OrLater()) {
2337     return;
2338   }
2339   expectTreeDumpEqual(
2340       R"cpp(
2341 auto foo() -> auto(*)(int) -> double*;
2342     )cpp",
2343       R"txt(
2344 *: TranslationUnit
2345 `-SimpleDeclaration
2346   |-auto
2347   |-SimpleDeclarator
2348   | |-foo
2349   | `-ParametersAndQualifiers
2350   |   |-(
2351   |   |-)
2352   |   `-TrailingReturnType
2353   |     |-->
2354   |     |-auto
2355   |     `-SimpleDeclarator
2356   |       |-ParenDeclarator
2357   |       | |-(
2358   |       | |-*
2359   |       | `-)
2360   |       `-ParametersAndQualifiers
2361   |         |-(
2362   |         |-SimpleDeclaration
2363   |         | `-int
2364   |         |-)
2365   |         `-TrailingReturnType
2366   |           |-->
2367   |           |-double
2368   |           `-SimpleDeclarator
2369   |             `-*
2370   `-;
2371        )txt");
2372 }
2373 
2374 TEST_P(SyntaxTreeTest, MemberPointers) {
2375   if (!GetParam().isCXX()) {
2376     return;
2377   }
2378   expectTreeDumpEqual(
2379       R"cpp(
2380 struct X {};
2381 int X::* a;
2382 const int X::* b;
2383     )cpp",
2384       R"txt(
2385 *: TranslationUnit
2386 |-SimpleDeclaration
2387 | |-struct
2388 | |-X
2389 | |-{
2390 | |-}
2391 | `-;
2392 |-SimpleDeclaration
2393 | |-int
2394 | |-SimpleDeclarator
2395 | | |-MemberPointer
2396 | | | |-X
2397 | | | |-::
2398 | | | `-*
2399 | | `-a
2400 | `-;
2401 `-SimpleDeclaration
2402   |-const
2403   |-int
2404   |-SimpleDeclarator
2405   | |-MemberPointer
2406   | | |-X
2407   | | |-::
2408   | | `-*
2409   | `-b
2410   `-;
2411        )txt");
2412 }
2413 
2414 TEST_P(SyntaxTreeTest, ComplexDeclarator) {
2415   expectTreeDumpEqual(
2416       R"cpp(
2417 void x(char a, short (*b)(int));
2418     )cpp",
2419       R"txt(
2420 *: TranslationUnit
2421 `-SimpleDeclaration
2422   |-void
2423   |-SimpleDeclarator
2424   | |-x
2425   | `-ParametersAndQualifiers
2426   |   |-(
2427   |   |-SimpleDeclaration
2428   |   | |-char
2429   |   | `-SimpleDeclarator
2430   |   |   `-a
2431   |   |-,
2432   |   |-SimpleDeclaration
2433   |   | |-short
2434   |   | `-SimpleDeclarator
2435   |   |   |-ParenDeclarator
2436   |   |   | |-(
2437   |   |   | |-*
2438   |   |   | |-b
2439   |   |   | `-)
2440   |   |   `-ParametersAndQualifiers
2441   |   |     |-(
2442   |   |     |-SimpleDeclaration
2443   |   |     | `-int
2444   |   |     `-)
2445   |   `-)
2446   `-;
2447        )txt");
2448 }
2449 
2450 TEST_P(SyntaxTreeTest, ComplexDeclarator2) {
2451   expectTreeDumpEqual(
2452       R"cpp(
2453 void x(char a, short (*b)(int), long (**c)(long long));
2454     )cpp",
2455       R"txt(
2456 *: TranslationUnit
2457 `-SimpleDeclaration
2458   |-void
2459   |-SimpleDeclarator
2460   | |-x
2461   | `-ParametersAndQualifiers
2462   |   |-(
2463   |   |-SimpleDeclaration
2464   |   | |-char
2465   |   | `-SimpleDeclarator
2466   |   |   `-a
2467   |   |-,
2468   |   |-SimpleDeclaration
2469   |   | |-short
2470   |   | `-SimpleDeclarator
2471   |   |   |-ParenDeclarator
2472   |   |   | |-(
2473   |   |   | |-*
2474   |   |   | |-b
2475   |   |   | `-)
2476   |   |   `-ParametersAndQualifiers
2477   |   |     |-(
2478   |   |     |-SimpleDeclaration
2479   |   |     | `-int
2480   |   |     `-)
2481   |   |-,
2482   |   |-SimpleDeclaration
2483   |   | |-long
2484   |   | `-SimpleDeclarator
2485   |   |   |-ParenDeclarator
2486   |   |   | |-(
2487   |   |   | |-*
2488   |   |   | |-*
2489   |   |   | |-c
2490   |   |   | `-)
2491   |   |   `-ParametersAndQualifiers
2492   |   |     |-(
2493   |   |     |-SimpleDeclaration
2494   |   |     | |-long
2495   |   |     | `-long
2496   |   |     `-)
2497   |   `-)
2498   `-;
2499        )txt");
2500 }
2501 
2502 TEST_P(SyntaxTreeTest, Mutations) {
2503   if (!GetParam().isCXX11OrLater()) {
2504     return;
2505   }
2506 
2507   using Transformation = std::function<void(
2508       const llvm::Annotations & /*Input*/, syntax::TranslationUnit * /*Root*/)>;
2509   auto CheckTransformation = [this](std::string Input, std::string Expected,
2510                                     Transformation Transform) -> void {
2511     llvm::Annotations Source(Input);
2512     auto *Root = buildTree(Source.code(), GetParam());
2513 
2514     Transform(Source, Root);
2515 
2516     auto Replacements = syntax::computeReplacements(*Arena, *Root);
2517     auto Output = tooling::applyAllReplacements(Source.code(), Replacements);
2518     if (!Output) {
2519       ADD_FAILURE() << "could not apply replacements: "
2520                     << llvm::toString(Output.takeError());
2521       return;
2522     }
2523 
2524     EXPECT_EQ(Expected, *Output) << "input is:\n" << Input;
2525   };
2526 
2527   // Removes the selected statement. Input should have exactly one selected
2528   // range and it should correspond to a single statement.
2529   auto RemoveStatement = [this](const llvm::Annotations &Input,
2530                                 syntax::TranslationUnit *TU) {
2531     auto *S = cast<syntax::Statement>(nodeByRange(Input.range(), TU));
2532     ASSERT_TRUE(S->canModify()) << "cannot remove a statement";
2533     syntax::removeStatement(*Arena, S);
2534     EXPECT_TRUE(S->isDetached());
2535     EXPECT_FALSE(S->isOriginal())
2536         << "node removed from tree cannot be marked as original";
2537   };
2538 
2539   std::vector<std::pair<std::string /*Input*/, std::string /*Expected*/>>
2540       Cases = {
2541           {"void test() { [[100+100;]] test(); }", "void test() {  test(); }"},
2542           {"void test() { if (true) [[{}]] else {} }",
2543            "void test() { if (true) ; else {} }"},
2544           {"void test() { [[;]] }", "void test() {  }"}};
2545   for (const auto &C : Cases)
2546     CheckTransformation(C.first, C.second, RemoveStatement);
2547 }
2548 
2549 TEST_P(SyntaxTreeTest, SynthesizedNodes) {
2550   buildTree("", GetParam());
2551 
2552   auto *C = syntax::createPunctuation(*Arena, tok::comma);
2553   ASSERT_NE(C, nullptr);
2554   EXPECT_EQ(C->token()->kind(), tok::comma);
2555   EXPECT_TRUE(C->canModify());
2556   EXPECT_FALSE(C->isOriginal());
2557   EXPECT_TRUE(C->isDetached());
2558 
2559   auto *S = syntax::createEmptyStatement(*Arena);
2560   ASSERT_NE(S, nullptr);
2561   EXPECT_TRUE(S->canModify());
2562   EXPECT_FALSE(S->isOriginal());
2563   EXPECT_TRUE(S->isDetached());
2564 }
2565 
2566 INSTANTIATE_TEST_CASE_P(SyntaxTreeTests, SyntaxTreeTest,
2567                         testing::ValuesIn(TestClangConfig::allConfigs()));
2568 
2569 } // namespace
2570