xref: /llvm-project/clang/unittests/Tooling/Syntax/TreeTest.cpp (revision fd7300f717c18c861e77685efe6f16f12fb63ae7)
1 //===- TreeTest.cpp -------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "clang/Tooling/Syntax/Tree.h"
10 #include "clang/AST/ASTConsumer.h"
11 #include "clang/AST/Decl.h"
12 #include "clang/AST/Stmt.h"
13 #include "clang/Basic/LLVM.h"
14 #include "clang/Basic/TokenKinds.h"
15 #include "clang/Frontend/CompilerInstance.h"
16 #include "clang/Frontend/CompilerInvocation.h"
17 #include "clang/Frontend/FrontendAction.h"
18 #include "clang/Lex/PreprocessorOptions.h"
19 #include "clang/Tooling/Core/Replacement.h"
20 #include "clang/Tooling/Syntax/BuildTree.h"
21 #include "clang/Tooling/Syntax/Mutations.h"
22 #include "clang/Tooling/Syntax/Nodes.h"
23 #include "clang/Tooling/Syntax/Tokens.h"
24 #include "clang/Tooling/Tooling.h"
25 #include "llvm/ADT/ArrayRef.h"
26 #include "llvm/ADT/STLExtras.h"
27 #include "llvm/ADT/StringRef.h"
28 #include "llvm/Support/Casting.h"
29 #include "llvm/Support/Error.h"
30 #include "llvm/Testing/Support/Annotations.h"
31 #include "gmock/gmock.h"
32 #include "gtest/gtest.h"
33 #include <cstdlib>
34 
35 using namespace clang;
36 
37 namespace {
38 static llvm::ArrayRef<syntax::Token> tokens(syntax::Node *N) {
39   assert(N->isOriginal() && "tokens of modified nodes are not well-defined");
40   if (auto *L = dyn_cast<syntax::Leaf>(N))
41     return llvm::makeArrayRef(L->token(), 1);
42   auto *T = cast<syntax::Tree>(N);
43   return llvm::makeArrayRef(T->firstLeaf()->token(),
44                             T->lastLeaf()->token() + 1);
45 }
46 
47 class SyntaxTreeTest : public ::testing::Test {
48 protected:
49   // Build a syntax tree for the code.
50   syntax::TranslationUnit *buildTree(llvm::StringRef Code, StringRef Target) {
51     // FIXME: this code is almost the identical to the one in TokensTest. Share
52     //        it.
53     class BuildSyntaxTree : public ASTConsumer {
54     public:
55       BuildSyntaxTree(syntax::TranslationUnit *&Root,
56                       std::unique_ptr<syntax::Arena> &Arena,
57                       std::unique_ptr<syntax::TokenCollector> Tokens)
58           : Root(Root), Arena(Arena), Tokens(std::move(Tokens)) {
59         assert(this->Tokens);
60       }
61 
62       void HandleTranslationUnit(ASTContext &Ctx) override {
63         Arena = std::make_unique<syntax::Arena>(Ctx.getSourceManager(),
64                                                 Ctx.getLangOpts(),
65                                                 std::move(*Tokens).consume());
66         Tokens = nullptr; // make sure we fail if this gets called twice.
67         Root = syntax::buildSyntaxTree(*Arena, *Ctx.getTranslationUnitDecl());
68       }
69 
70     private:
71       syntax::TranslationUnit *&Root;
72       std::unique_ptr<syntax::Arena> &Arena;
73       std::unique_ptr<syntax::TokenCollector> Tokens;
74     };
75 
76     class BuildSyntaxTreeAction : public ASTFrontendAction {
77     public:
78       BuildSyntaxTreeAction(syntax::TranslationUnit *&Root,
79                             std::unique_ptr<syntax::Arena> &Arena)
80           : Root(Root), Arena(Arena) {}
81 
82       std::unique_ptr<ASTConsumer>
83       CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override {
84         // We start recording the tokens, ast consumer will take on the result.
85         auto Tokens =
86             std::make_unique<syntax::TokenCollector>(CI.getPreprocessor());
87         return std::make_unique<BuildSyntaxTree>(Root, Arena,
88                                                  std::move(Tokens));
89       }
90 
91     private:
92       syntax::TranslationUnit *&Root;
93       std::unique_ptr<syntax::Arena> &Arena;
94     };
95 
96     constexpr const char *FileName = "./input.cpp";
97     FS->addFile(FileName, time_t(), llvm::MemoryBuffer::getMemBufferCopy(""));
98     if (!Diags->getClient())
99       Diags->setClient(new IgnoringDiagConsumer);
100     // Prepare to run a compiler.
101     std::vector<const char *> Args = {"-target",       Target.data(),
102                                       "-fsyntax-only", "-std=c++17",
103                                       "syntax-test",   FileName};
104     Invocation = createInvocationFromCommandLine(Args, Diags, FS);
105     assert(Invocation);
106     Invocation->getFrontendOpts().DisableFree = false;
107     Invocation->getPreprocessorOpts().addRemappedFile(
108         FileName, llvm::MemoryBuffer::getMemBufferCopy(Code).release());
109     CompilerInstance Compiler;
110     Compiler.setInvocation(Invocation);
111     Compiler.setDiagnostics(Diags.get());
112     Compiler.setFileManager(FileMgr.get());
113     Compiler.setSourceManager(SourceMgr.get());
114 
115     syntax::TranslationUnit *Root = nullptr;
116     BuildSyntaxTreeAction Recorder(Root, this->Arena);
117     if (!Compiler.ExecuteAction(Recorder)) {
118       ADD_FAILURE() << "failed to run the frontend";
119       std::abort();
120     }
121     return Root;
122   }
123 
124   void expectTreeDumpEqual(StringRef Code, StringRef Tree,
125                            bool RunWithDelayedTemplateParsing = true) {
126     SCOPED_TRACE(Code);
127 
128     std::string Expected = Tree.trim().str();
129 
130     // We want to run the test with -fdelayed-template-parsing enabled and
131     // disabled, therefore we use these representative targets that differ in
132     // the default value.
133     // We are not passing -fdelayed-template-parsing directly but we are using
134     // the `-target` to improve coverage and discover differences in behavior
135     // early.
136     for (const StringRef Target :
137          {"x86_64-unknown-unknown", "x86_64-pc-win32"}) {
138       if (!RunWithDelayedTemplateParsing && Target.equals("x86_64-pc-win32")) {
139         continue;
140       }
141       auto *Root = buildTree(Code, Target);
142       std::string Actual = std::string(StringRef(Root->dump(*Arena)).trim());
143       EXPECT_EQ(Expected, Actual)
144           << "for target " << Target << " the resulting dump is:\n"
145           << Actual;
146     }
147   }
148 
149   // Adds a file to the test VFS.
150   void addFile(llvm::StringRef Path, llvm::StringRef Contents) {
151     if (!FS->addFile(Path, time_t(),
152                      llvm::MemoryBuffer::getMemBufferCopy(Contents))) {
153       ADD_FAILURE() << "could not add a file to VFS: " << Path;
154     }
155   }
156 
157   /// Finds the deepest node in the tree that covers exactly \p R.
158   /// FIXME: implement this efficiently and move to public syntax tree API.
159   syntax::Node *nodeByRange(llvm::Annotations::Range R, syntax::Node *Root) {
160     llvm::ArrayRef<syntax::Token> Toks = tokens(Root);
161 
162     if (Toks.front().location().isFileID() &&
163         Toks.back().location().isFileID() &&
164         syntax::Token::range(*SourceMgr, Toks.front(), Toks.back()) ==
165             syntax::FileRange(SourceMgr->getMainFileID(), R.Begin, R.End))
166       return Root;
167 
168     auto *T = dyn_cast<syntax::Tree>(Root);
169     if (!T)
170       return nullptr;
171     for (auto *C = T->firstChild(); C != nullptr; C = C->nextSibling()) {
172       if (auto *Result = nodeByRange(R, C))
173         return Result;
174     }
175     return nullptr;
176   }
177 
178   // Data fields.
179   llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
180       new DiagnosticsEngine(new DiagnosticIDs, new DiagnosticOptions);
181   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS =
182       new llvm::vfs::InMemoryFileSystem;
183   llvm::IntrusiveRefCntPtr<FileManager> FileMgr =
184       new FileManager(FileSystemOptions(), FS);
185   llvm::IntrusiveRefCntPtr<SourceManager> SourceMgr =
186       new SourceManager(*Diags, *FileMgr);
187   std::shared_ptr<CompilerInvocation> Invocation;
188   // Set after calling buildTree().
189   std::unique_ptr<syntax::Arena> Arena;
190 };
191 
192 TEST_F(SyntaxTreeTest, Simple) {
193   expectTreeDumpEqual(
194       R"cpp(
195 int main() {}
196 void foo() {}
197     )cpp",
198       R"txt(
199 *: TranslationUnit
200 |-SimpleDeclaration
201 | |-int
202 | |-SimpleDeclarator
203 | | |-main
204 | | `-ParametersAndQualifiers
205 | |   |-(
206 | |   `-)
207 | `-CompoundStatement
208 |   |-{
209 |   `-}
210 `-SimpleDeclaration
211   |-void
212   |-SimpleDeclarator
213   | |-foo
214   | `-ParametersAndQualifiers
215   |   |-(
216   |   `-)
217   `-CompoundStatement
218     |-{
219     `-}
220 )txt");
221 }
222 
223 TEST_F(SyntaxTreeTest, If) {
224   expectTreeDumpEqual(
225       R"cpp(
226 int main() {
227   if (true) {}
228   if (true) {} else if (false) {}
229 }
230         )cpp",
231       R"txt(
232 *: TranslationUnit
233 `-SimpleDeclaration
234   |-int
235   |-SimpleDeclarator
236   | |-main
237   | `-ParametersAndQualifiers
238   |   |-(
239   |   `-)
240   `-CompoundStatement
241     |-{
242     |-IfStatement
243     | |-if
244     | |-(
245     | |-UnknownExpression
246     | | `-true
247     | |-)
248     | `-CompoundStatement
249     |   |-{
250     |   `-}
251     |-IfStatement
252     | |-if
253     | |-(
254     | |-UnknownExpression
255     | | `-true
256     | |-)
257     | |-CompoundStatement
258     | | |-{
259     | | `-}
260     | |-else
261     | `-IfStatement
262     |   |-if
263     |   |-(
264     |   |-UnknownExpression
265     |   | `-false
266     |   |-)
267     |   `-CompoundStatement
268     |     |-{
269     |     `-}
270     `-}
271         )txt");
272 }
273 
274 TEST_F(SyntaxTreeTest, For) {
275   expectTreeDumpEqual(
276       R"cpp(
277 void test() {
278   for (;;)  {}
279 }
280 )cpp",
281       R"txt(
282 *: TranslationUnit
283 `-SimpleDeclaration
284   |-void
285   |-SimpleDeclarator
286   | |-test
287   | `-ParametersAndQualifiers
288   |   |-(
289   |   `-)
290   `-CompoundStatement
291     |-{
292     |-ForStatement
293     | |-for
294     | |-(
295     | |-;
296     | |-;
297     | |-)
298     | `-CompoundStatement
299     |   |-{
300     |   `-}
301     `-}
302         )txt");
303 }
304 
305 TEST_F(SyntaxTreeTest, RangeBasedFor) {
306   expectTreeDumpEqual(
307       R"cpp(
308 void test() {
309   int a[3];
310   for (int x : a) ;
311 }
312       )cpp",
313       R"txt(
314 *: TranslationUnit
315 `-SimpleDeclaration
316   |-void
317   |-SimpleDeclarator
318   | |-test
319   | `-ParametersAndQualifiers
320   |   |-(
321   |   `-)
322   `-CompoundStatement
323     |-{
324     |-DeclarationStatement
325     | |-SimpleDeclaration
326     | | |-int
327     | | `-SimpleDeclarator
328     | |   |-a
329     | |   `-ArraySubscript
330     | |     |-[
331     | |     |-UnknownExpression
332     | |     | `-3
333     | |     `-]
334     | `-;
335     |-RangeBasedForStatement
336     | |-for
337     | |-(
338     | |-SimpleDeclaration
339     | | |-int
340     | | |-SimpleDeclarator
341     | | | `-x
342     | | `-:
343     | |-UnknownExpression
344     | | `-a
345     | |-)
346     | `-EmptyStatement
347     |   `-;
348     `-}
349        )txt");
350 }
351 
352 TEST_F(SyntaxTreeTest, DeclarationStatement) {
353   expectTreeDumpEqual("void test() { int a = 10; }",
354                       R"txt(
355 *: TranslationUnit
356 `-SimpleDeclaration
357   |-void
358   |-SimpleDeclarator
359   | |-test
360   | `-ParametersAndQualifiers
361   |   |-(
362   |   `-)
363   `-CompoundStatement
364     |-{
365     |-DeclarationStatement
366     | |-SimpleDeclaration
367     | | |-int
368     | | `-SimpleDeclarator
369     | |   |-a
370     | |   |-=
371     | |   `-UnknownExpression
372     | |     `-10
373     | `-;
374     `-}
375 )txt");
376 }
377 
378 TEST_F(SyntaxTreeTest, Switch) {
379   expectTreeDumpEqual(
380       R"cpp(
381 void test() {
382   switch (true) {
383     case 0:
384     default:;
385   }
386 }
387 )cpp",
388       R"txt(
389 *: TranslationUnit
390 `-SimpleDeclaration
391   |-void
392   |-SimpleDeclarator
393   | |-test
394   | `-ParametersAndQualifiers
395   |   |-(
396   |   `-)
397   `-CompoundStatement
398     |-{
399     |-SwitchStatement
400     | |-switch
401     | |-(
402     | |-UnknownExpression
403     | | `-true
404     | |-)
405     | `-CompoundStatement
406     |   |-{
407     |   |-CaseStatement
408     |   | |-case
409     |   | |-UnknownExpression
410     |   | | `-0
411     |   | |-:
412     |   | `-DefaultStatement
413     |   |   |-default
414     |   |   |-:
415     |   |   `-EmptyStatement
416     |   |     `-;
417     |   `-}
418     `-}
419 )txt");
420 }
421 
422 TEST_F(SyntaxTreeTest, While) {
423   expectTreeDumpEqual(
424       R"cpp(
425 void test() {
426   while (true) { continue; break; }
427 }
428 )cpp",
429       R"txt(
430 *: TranslationUnit
431 `-SimpleDeclaration
432   |-void
433   |-SimpleDeclarator
434   | |-test
435   | `-ParametersAndQualifiers
436   |   |-(
437   |   `-)
438   `-CompoundStatement
439     |-{
440     |-WhileStatement
441     | |-while
442     | |-(
443     | |-UnknownExpression
444     | | `-true
445     | |-)
446     | `-CompoundStatement
447     |   |-{
448     |   |-ContinueStatement
449     |   | |-continue
450     |   | `-;
451     |   |-BreakStatement
452     |   | |-break
453     |   | `-;
454     |   `-}
455     `-}
456 )txt");
457 }
458 
459 TEST_F(SyntaxTreeTest, UnhandledStatement) {
460   // Unhandled statements should end up as 'unknown statement'.
461   // This example uses a 'label statement', which does not yet have a syntax
462   // counterpart.
463   expectTreeDumpEqual("void main() { foo: return 100; }",
464                       R"txt(
465 *: TranslationUnit
466 `-SimpleDeclaration
467   |-void
468   |-SimpleDeclarator
469   | |-main
470   | `-ParametersAndQualifiers
471   |   |-(
472   |   `-)
473   `-CompoundStatement
474     |-{
475     |-UnknownStatement
476     | |-foo
477     | |-:
478     | `-ReturnStatement
479     |   |-return
480     |   |-UnknownExpression
481     |   | `-100
482     |   `-;
483     `-}
484 )txt");
485 }
486 
487 TEST_F(SyntaxTreeTest, Expressions) {
488   // expressions should be wrapped in 'ExpressionStatement' when they appear
489   // in a statement position.
490   expectTreeDumpEqual(
491       R"cpp(
492 void test() {
493   test();
494   if (true) test(); else test();
495 }
496     )cpp",
497       R"txt(
498 *: TranslationUnit
499 `-SimpleDeclaration
500   |-void
501   |-SimpleDeclarator
502   | |-test
503   | `-ParametersAndQualifiers
504   |   |-(
505   |   `-)
506   `-CompoundStatement
507     |-{
508     |-ExpressionStatement
509     | |-UnknownExpression
510     | | |-test
511     | | |-(
512     | | `-)
513     | `-;
514     |-IfStatement
515     | |-if
516     | |-(
517     | |-UnknownExpression
518     | | `-true
519     | |-)
520     | |-ExpressionStatement
521     | | |-UnknownExpression
522     | | | |-test
523     | | | |-(
524     | | | `-)
525     | | `-;
526     | |-else
527     | `-ExpressionStatement
528     |   |-UnknownExpression
529     |   | |-test
530     |   | |-(
531     |   | `-)
532     |   `-;
533     `-}
534 )txt");
535 }
536 
537 TEST_F(SyntaxTreeTest, MultipleDeclaratorsGrouping) {
538   expectTreeDumpEqual(
539       R"cpp(
540       int *a, b;
541   )cpp",
542       R"txt(
543 *: TranslationUnit
544 `-SimpleDeclaration
545   |-int
546   |-SimpleDeclarator
547   | |-*
548   | `-a
549   |-,
550   |-SimpleDeclarator
551   | `-b
552   `-;
553   )txt");
554   expectTreeDumpEqual(
555       R"cpp(
556     typedef int *a, b;
557   )cpp",
558       R"txt(
559 *: TranslationUnit
560 `-SimpleDeclaration
561   |-typedef
562   |-int
563   |-SimpleDeclarator
564   | |-*
565   | `-a
566   |-,
567   |-SimpleDeclarator
568   | `-b
569   `-;
570   )txt");
571 }
572 
573 TEST_F(SyntaxTreeTest, MultipleDeclaratorsInsideStatement) {
574   expectTreeDumpEqual(
575       R"cpp(
576 void foo() {
577       int *a, b;
578       typedef int *ta, tb;
579 }
580   )cpp",
581       R"txt(
582 *: TranslationUnit
583 `-SimpleDeclaration
584   |-void
585   |-SimpleDeclarator
586   | |-foo
587   | `-ParametersAndQualifiers
588   |   |-(
589   |   `-)
590   `-CompoundStatement
591     |-{
592     |-DeclarationStatement
593     | |-SimpleDeclaration
594     | | |-int
595     | | |-SimpleDeclarator
596     | | | |-*
597     | | | `-a
598     | | |-,
599     | | `-SimpleDeclarator
600     | |   `-b
601     | `-;
602     |-DeclarationStatement
603     | |-SimpleDeclaration
604     | | |-typedef
605     | | |-int
606     | | |-SimpleDeclarator
607     | | | |-*
608     | | | `-ta
609     | | |-,
610     | | `-SimpleDeclarator
611     | |   `-tb
612     | `-;
613     `-}
614   )txt");
615 }
616 
617 TEST_F(SyntaxTreeTest, Namespaces) {
618   expectTreeDumpEqual(
619       R"cpp(
620 namespace a { namespace b {} }
621 namespace a::b {}
622 namespace {}
623 
624 namespace foo = a;
625     )cpp",
626       R"txt(
627 *: TranslationUnit
628 |-NamespaceDefinition
629 | |-namespace
630 | |-a
631 | |-{
632 | |-NamespaceDefinition
633 | | |-namespace
634 | | |-b
635 | | |-{
636 | | `-}
637 | `-}
638 |-NamespaceDefinition
639 | |-namespace
640 | |-a
641 | |-::
642 | |-b
643 | |-{
644 | `-}
645 |-NamespaceDefinition
646 | |-namespace
647 | |-{
648 | `-}
649 `-NamespaceAliasDefinition
650   |-namespace
651   |-foo
652   |-=
653   |-a
654   `-;
655 )txt");
656 }
657 
658 TEST_F(SyntaxTreeTest, UsingDirective) {
659   expectTreeDumpEqual(
660       R"cpp(
661 namespace ns {}
662 using namespace ::ns;
663     )cpp",
664       R"txt(
665 *: TranslationUnit
666 |-NamespaceDefinition
667 | |-namespace
668 | |-ns
669 | |-{
670 | `-}
671 `-UsingNamespaceDirective
672   |-using
673   |-namespace
674   |-::
675   |-ns
676   `-;
677        )txt");
678 }
679 
680 TEST_F(SyntaxTreeTest, UsingDeclaration) {
681   expectTreeDumpEqual(
682       R"cpp(
683 namespace ns { int a; }
684 using ns::a;
685     )cpp",
686       R"txt(
687 *: TranslationUnit
688 |-NamespaceDefinition
689 | |-namespace
690 | |-ns
691 | |-{
692 | |-SimpleDeclaration
693 | | |-int
694 | | |-SimpleDeclarator
695 | | | `-a
696 | | `-;
697 | `-}
698 `-UsingDeclaration
699   |-using
700   |-ns
701   |-::
702   |-a
703   `-;
704        )txt");
705 }
706 
707 TEST_F(SyntaxTreeTest, FreeStandingClasses) {
708   // Free-standing classes, must live inside a SimpleDeclaration.
709   expectTreeDumpEqual(
710       R"cpp(
711 sturct X;
712 struct X {};
713 
714 struct Y *y1;
715 struct Y {} *y2;
716 
717 struct {} *a1;
718     )cpp",
719       R"txt(
720 *: TranslationUnit
721 |-SimpleDeclaration
722 | |-sturct
723 | |-X
724 | `-;
725 |-SimpleDeclaration
726 | |-struct
727 | |-X
728 | |-{
729 | |-}
730 | `-;
731 |-SimpleDeclaration
732 | |-struct
733 | |-Y
734 | |-SimpleDeclarator
735 | | |-*
736 | | `-y1
737 | `-;
738 |-SimpleDeclaration
739 | |-struct
740 | |-Y
741 | |-{
742 | |-}
743 | |-SimpleDeclarator
744 | | |-*
745 | | `-y2
746 | `-;
747 `-SimpleDeclaration
748   |-struct
749   |-{
750   |-}
751   |-SimpleDeclarator
752   | |-*
753   | `-a1
754   `-;
755 )txt");
756 }
757 
758 TEST_F(SyntaxTreeTest, Templates) {
759   expectTreeDumpEqual(
760       R"cpp(
761 template <class T> struct cls {};
762 template <class T> int var = 10;
763 template <class T> int fun() {}
764     )cpp",
765       R"txt(
766 *: TranslationUnit
767 |-TemplateDeclaration
768 | |-template
769 | |-<
770 | |-UnknownDeclaration
771 | | |-class
772 | | `-T
773 | |->
774 | `-SimpleDeclaration
775 |   |-struct
776 |   |-cls
777 |   |-{
778 |   |-}
779 |   `-;
780 |-TemplateDeclaration
781 | |-template
782 | |-<
783 | |-UnknownDeclaration
784 | | |-class
785 | | `-T
786 | |->
787 | `-SimpleDeclaration
788 |   |-int
789 |   |-SimpleDeclarator
790 |   | |-var
791 |   | |-=
792 |   | `-UnknownExpression
793 |   |   `-10
794 |   `-;
795 `-TemplateDeclaration
796   |-template
797   |-<
798   |-UnknownDeclaration
799   | |-class
800   | `-T
801   |->
802   `-SimpleDeclaration
803     |-int
804     |-SimpleDeclarator
805     | |-fun
806     | `-ParametersAndQualifiers
807     |   |-(
808     |   `-)
809     `-CompoundStatement
810       |-{
811       `-}
812 )txt",
813       // FIXME: Make this test work on windows by generating the expected Syntax
814       // tree when -fdelayed-template-parsing is active.
815       /*RunWithDelayedTemplateParsing=*/true);
816 }
817 
818 TEST_F(SyntaxTreeTest, NestedTemplates) {
819   expectTreeDumpEqual(
820       R"cpp(
821 template <class T>
822 struct X {
823   template <class U>
824   U foo();
825 };
826     )cpp",
827       R"txt(
828 *: TranslationUnit
829 `-TemplateDeclaration
830   |-template
831   |-<
832   |-UnknownDeclaration
833   | |-class
834   | `-T
835   |->
836   `-SimpleDeclaration
837     |-struct
838     |-X
839     |-{
840     |-TemplateDeclaration
841     | |-template
842     | |-<
843     | |-UnknownDeclaration
844     | | |-class
845     | | `-U
846     | |->
847     | `-SimpleDeclaration
848     |   |-U
849     |   |-SimpleDeclarator
850     |   | |-foo
851     |   | `-ParametersAndQualifiers
852     |   |   |-(
853     |   |   `-)
854     |   `-;
855     |-}
856     `-;
857 )txt");
858 }
859 
860 TEST_F(SyntaxTreeTest, Templates2) {
861   expectTreeDumpEqual(
862       R"cpp(
863 template <class T> struct X { struct Y; };
864 template <class T> struct X<T>::Y {};
865     )cpp",
866       R"txt(
867 *: TranslationUnit
868 |-TemplateDeclaration
869 | |-template
870 | |-<
871 | |-UnknownDeclaration
872 | | |-class
873 | | `-T
874 | |->
875 | `-SimpleDeclaration
876 |   |-struct
877 |   |-X
878 |   |-{
879 |   |-SimpleDeclaration
880 |   | |-struct
881 |   | |-Y
882 |   | `-;
883 |   |-}
884 |   `-;
885 `-TemplateDeclaration
886   |-template
887   |-<
888   |-UnknownDeclaration
889   | |-class
890   | `-T
891   |->
892   `-SimpleDeclaration
893     |-struct
894     |-X
895     |-<
896     |-T
897     |->
898     |-::
899     |-Y
900     |-{
901     |-}
902     `-;
903        )txt");
904 }
905 
906 TEST_F(SyntaxTreeTest, TemplatesUsingUsing) {
907   expectTreeDumpEqual(
908       R"cpp(
909 template <class T> struct X {
910   using T::foo;
911   using typename T::bar;
912 };
913     )cpp",
914       R"txt(
915 *: TranslationUnit
916 `-TemplateDeclaration
917   |-template
918   |-<
919   |-UnknownDeclaration
920   | |-class
921   | `-T
922   |->
923   `-SimpleDeclaration
924     |-struct
925     |-X
926     |-{
927     |-UsingDeclaration
928     | |-using
929     | |-T
930     | |-::
931     | |-foo
932     | `-;
933     |-UsingDeclaration
934     | |-using
935     | |-typename
936     | |-T
937     | |-::
938     | |-bar
939     | `-;
940     |-}
941     `-;
942        )txt");
943 }
944 
945 TEST_F(SyntaxTreeTest, ExplicitTemplateInstantations) {
946   expectTreeDumpEqual(
947       R"cpp(
948 template <class T> struct X {};
949 template <class T> struct X<T*> {};
950 template <> struct X<int> {};
951 
952 template struct X<double>;
953 extern template struct X<float>;
954 )cpp",
955       R"txt(
956 *: TranslationUnit
957 |-TemplateDeclaration
958 | |-template
959 | |-<
960 | |-UnknownDeclaration
961 | | |-class
962 | | `-T
963 | |->
964 | `-SimpleDeclaration
965 |   |-struct
966 |   |-X
967 |   |-{
968 |   |-}
969 |   `-;
970 |-TemplateDeclaration
971 | |-template
972 | |-<
973 | |-UnknownDeclaration
974 | | |-class
975 | | `-T
976 | |->
977 | `-SimpleDeclaration
978 |   |-struct
979 |   |-X
980 |   |-<
981 |   |-T
982 |   |-*
983 |   |->
984 |   |-{
985 |   |-}
986 |   `-;
987 |-TemplateDeclaration
988 | |-template
989 | |-<
990 | |->
991 | `-SimpleDeclaration
992 |   |-struct
993 |   |-X
994 |   |-<
995 |   |-int
996 |   |->
997 |   |-{
998 |   |-}
999 |   `-;
1000 |-ExplicitTemplateInstantiation
1001 | |-template
1002 | `-SimpleDeclaration
1003 |   |-struct
1004 |   |-X
1005 |   |-<
1006 |   |-double
1007 |   |->
1008 |   `-;
1009 `-ExplicitTemplateInstantiation
1010   |-extern
1011   |-template
1012   `-SimpleDeclaration
1013     |-struct
1014     |-X
1015     |-<
1016     |-float
1017     |->
1018     `-;
1019 )txt");
1020 }
1021 
1022 TEST_F(SyntaxTreeTest, UsingType) {
1023   expectTreeDumpEqual(
1024       R"cpp(
1025 using type = int;
1026     )cpp",
1027       R"txt(
1028 *: TranslationUnit
1029 `-TypeAliasDeclaration
1030   |-using
1031   |-type
1032   |-=
1033   |-int
1034   `-;
1035        )txt");
1036 }
1037 
1038 TEST_F(SyntaxTreeTest, EmptyDeclaration) {
1039   expectTreeDumpEqual(
1040       R"cpp(
1041 ;
1042     )cpp",
1043       R"txt(
1044 *: TranslationUnit
1045 `-EmptyDeclaration
1046   `-;
1047        )txt");
1048 }
1049 
1050 TEST_F(SyntaxTreeTest, StaticAssert) {
1051   expectTreeDumpEqual(
1052       R"cpp(
1053 static_assert(true, "message");
1054 static_assert(true);
1055     )cpp",
1056       R"txt(
1057 *: TranslationUnit
1058 |-StaticAssertDeclaration
1059 | |-static_assert
1060 | |-(
1061 | |-UnknownExpression
1062 | | `-true
1063 | |-,
1064 | |-UnknownExpression
1065 | | `-"message"
1066 | |-)
1067 | `-;
1068 `-StaticAssertDeclaration
1069   |-static_assert
1070   |-(
1071   |-UnknownExpression
1072   | `-true
1073   |-)
1074   `-;
1075        )txt");
1076 }
1077 
1078 TEST_F(SyntaxTreeTest, ExternC) {
1079   expectTreeDumpEqual(
1080       R"cpp(
1081 extern "C" int a;
1082 extern "C" { int b; int c; }
1083     )cpp",
1084       R"txt(
1085 *: TranslationUnit
1086 |-LinkageSpecificationDeclaration
1087 | |-extern
1088 | |-"C"
1089 | `-SimpleDeclaration
1090 |   |-int
1091 |   |-SimpleDeclarator
1092 |   | `-a
1093 |   `-;
1094 `-LinkageSpecificationDeclaration
1095   |-extern
1096   |-"C"
1097   |-{
1098   |-SimpleDeclaration
1099   | |-int
1100   | |-SimpleDeclarator
1101   | | `-b
1102   | `-;
1103   |-SimpleDeclaration
1104   | |-int
1105   | |-SimpleDeclarator
1106   | | `-c
1107   | `-;
1108   `-}
1109        )txt");
1110 }
1111 
1112 TEST_F(SyntaxTreeTest, NonModifiableNodes) {
1113   // Some nodes are non-modifiable, they are marked with 'I:'.
1114   expectTreeDumpEqual(
1115       R"cpp(
1116 #define HALF_IF if (1+
1117 #define HALF_IF_2 1) {}
1118 void test() {
1119   HALF_IF HALF_IF_2 else {}
1120 })cpp",
1121       R"txt(
1122 *: TranslationUnit
1123 `-SimpleDeclaration
1124   |-void
1125   |-SimpleDeclarator
1126   | |-test
1127   | `-ParametersAndQualifiers
1128   |   |-(
1129   |   `-)
1130   `-CompoundStatement
1131     |-{
1132     |-IfStatement
1133     | |-I: if
1134     | |-I: (
1135     | |-I: UnknownExpression
1136     | | |-I: 1
1137     | | |-I: +
1138     | | `-I: 1
1139     | |-I: )
1140     | |-I: CompoundStatement
1141     | | |-I: {
1142     | | `-I: }
1143     | |-else
1144     | `-CompoundStatement
1145     |   |-{
1146     |   `-}
1147     `-}
1148        )txt");
1149   // All nodes can be mutated.
1150   expectTreeDumpEqual(
1151       R"cpp(
1152 #define OPEN {
1153 #define CLOSE }
1154 
1155 void test() {
1156   OPEN
1157     1;
1158   CLOSE
1159 
1160   OPEN
1161     2;
1162   }
1163 }
1164 )cpp",
1165       R"txt(
1166 *: TranslationUnit
1167 `-SimpleDeclaration
1168   |-void
1169   |-SimpleDeclarator
1170   | |-test
1171   | `-ParametersAndQualifiers
1172   |   |-(
1173   |   `-)
1174   `-CompoundStatement
1175     |-{
1176     |-CompoundStatement
1177     | |-{
1178     | |-ExpressionStatement
1179     | | |-UnknownExpression
1180     | | | `-1
1181     | | `-;
1182     | `-}
1183     |-CompoundStatement
1184     | |-{
1185     | |-ExpressionStatement
1186     | | |-UnknownExpression
1187     | | | `-2
1188     | | `-;
1189     | `-}
1190     `-}
1191        )txt");
1192 }
1193 
1194 TEST_F(SyntaxTreeTest, ArraySubscriptsInDeclarators) {
1195   expectTreeDumpEqual(
1196       R"cpp(
1197 int a[10];
1198 int b[1][2][3];
1199 int c[] = {1,2,3};
1200 void f(int xs[static 10]);
1201     )cpp",
1202       R"txt(
1203 *: TranslationUnit
1204 |-SimpleDeclaration
1205 | |-int
1206 | |-SimpleDeclarator
1207 | | |-a
1208 | | `-ArraySubscript
1209 | |   |-[
1210 | |   |-UnknownExpression
1211 | |   | `-10
1212 | |   `-]
1213 | `-;
1214 |-SimpleDeclaration
1215 | |-int
1216 | |-SimpleDeclarator
1217 | | |-b
1218 | | |-ArraySubscript
1219 | | | |-[
1220 | | | |-UnknownExpression
1221 | | | | `-1
1222 | | | `-]
1223 | | |-ArraySubscript
1224 | | | |-[
1225 | | | |-UnknownExpression
1226 | | | | `-2
1227 | | | `-]
1228 | | `-ArraySubscript
1229 | |   |-[
1230 | |   |-UnknownExpression
1231 | |   | `-3
1232 | |   `-]
1233 | `-;
1234 |-SimpleDeclaration
1235 | |-int
1236 | |-SimpleDeclarator
1237 | | |-c
1238 | | |-ArraySubscript
1239 | | | |-[
1240 | | | `-]
1241 | | |-=
1242 | | `-UnknownExpression
1243 | |   |-{
1244 | |   |-1
1245 | |   |-,
1246 | |   |-2
1247 | |   |-,
1248 | |   |-3
1249 | |   `-}
1250 | `-;
1251 `-SimpleDeclaration
1252   |-void
1253   |-SimpleDeclarator
1254   | |-f
1255   | `-ParametersAndQualifiers
1256   |   |-(
1257   |   |-SimpleDeclaration
1258   |   | |-int
1259   |   | `-SimpleDeclarator
1260   |   |   |-xs
1261   |   |   `-ArraySubscript
1262   |   |     |-[
1263   |   |     |-static
1264   |   |     |-UnknownExpression
1265   |   |     | `-10
1266   |   |     `-]
1267   |   `-)
1268   `-;
1269        )txt");
1270 }
1271 
1272 TEST_F(SyntaxTreeTest, ParameterListsInDeclarators) {
1273   expectTreeDumpEqual(
1274       R"cpp(
1275 int a() const;
1276 int b() volatile;
1277 int c() &;
1278 int d() &&;
1279 int foo(int a, int b);
1280 int foo(
1281   const int a,
1282   volatile int b,
1283   const volatile int c,
1284   int* d,
1285   int& e,
1286   int&& f
1287 );
1288     )cpp",
1289       R"txt(
1290 *: TranslationUnit
1291 |-SimpleDeclaration
1292 | |-int
1293 | |-SimpleDeclarator
1294 | | |-a
1295 | | `-ParametersAndQualifiers
1296 | |   |-(
1297 | |   |-)
1298 | |   `-const
1299 | `-;
1300 |-SimpleDeclaration
1301 | |-int
1302 | |-SimpleDeclarator
1303 | | |-b
1304 | | `-ParametersAndQualifiers
1305 | |   |-(
1306 | |   |-)
1307 | |   `-volatile
1308 | `-;
1309 |-SimpleDeclaration
1310 | |-int
1311 | |-SimpleDeclarator
1312 | | |-c
1313 | | `-ParametersAndQualifiers
1314 | |   |-(
1315 | |   |-)
1316 | |   `-&
1317 | `-;
1318 |-SimpleDeclaration
1319 | |-int
1320 | |-SimpleDeclarator
1321 | | |-d
1322 | | `-ParametersAndQualifiers
1323 | |   |-(
1324 | |   |-)
1325 | |   `-&&
1326 | `-;
1327 |-SimpleDeclaration
1328 | |-int
1329 | |-SimpleDeclarator
1330 | | |-foo
1331 | | `-ParametersAndQualifiers
1332 | |   |-(
1333 | |   |-SimpleDeclaration
1334 | |   | |-int
1335 | |   | `-SimpleDeclarator
1336 | |   |   `-a
1337 | |   |-,
1338 | |   |-SimpleDeclaration
1339 | |   | |-int
1340 | |   | `-SimpleDeclarator
1341 | |   |   `-b
1342 | |   `-)
1343 | `-;
1344 `-SimpleDeclaration
1345   |-int
1346   |-SimpleDeclarator
1347   | |-foo
1348   | `-ParametersAndQualifiers
1349   |   |-(
1350   |   |-SimpleDeclaration
1351   |   | |-const
1352   |   | |-int
1353   |   | `-SimpleDeclarator
1354   |   |   `-a
1355   |   |-,
1356   |   |-SimpleDeclaration
1357   |   | |-volatile
1358   |   | |-int
1359   |   | `-SimpleDeclarator
1360   |   |   `-b
1361   |   |-,
1362   |   |-SimpleDeclaration
1363   |   | |-const
1364   |   | |-volatile
1365   |   | |-int
1366   |   | `-SimpleDeclarator
1367   |   |   `-c
1368   |   |-,
1369   |   |-SimpleDeclaration
1370   |   | |-int
1371   |   | `-SimpleDeclarator
1372   |   |   |-*
1373   |   |   `-d
1374   |   |-,
1375   |   |-SimpleDeclaration
1376   |   | |-int
1377   |   | `-SimpleDeclarator
1378   |   |   |-&
1379   |   |   `-e
1380   |   |-,
1381   |   |-SimpleDeclaration
1382   |   | |-int
1383   |   | `-SimpleDeclarator
1384   |   |   |-&&
1385   |   |   `-f
1386   |   `-)
1387   `-;
1388        )txt");
1389 }
1390 
1391 TEST_F(SyntaxTreeTest, TrailingConst) {
1392   expectTreeDumpEqual(
1393       R"cpp(
1394 struct X {
1395   int foo() const;
1396 }
1397     )cpp",
1398       R"txt(
1399 *: TranslationUnit
1400 `-SimpleDeclaration
1401   |-struct
1402   |-X
1403   |-{
1404   |-SimpleDeclaration
1405   | |-int
1406   | |-SimpleDeclarator
1407   | | |-foo
1408   | | `-ParametersAndQualifiers
1409   | |   |-(
1410   | |   |-)
1411   | |   `-const
1412   | `-;
1413   `-}
1414     )txt");
1415 }
1416 
1417 TEST_F(SyntaxTreeTest, TrailingReturn) {
1418   expectTreeDumpEqual(
1419       R"cpp(
1420 auto foo() -> int;
1421     )cpp",
1422       R"txt(
1423 *: TranslationUnit
1424 `-SimpleDeclaration
1425   |-auto
1426   |-SimpleDeclarator
1427   | |-foo
1428   | `-ParametersAndQualifiers
1429   |   |-(
1430   |   |-)
1431   |   `-TrailingReturnType
1432   |     |-->
1433   |     `-int
1434   `-;
1435        )txt");
1436 }
1437 
1438 TEST_F(SyntaxTreeTest, ExceptionSpecification) {
1439   expectTreeDumpEqual(
1440       R"cpp(
1441 int a() noexcept;
1442 int b() noexcept(true);
1443 int c() throw();
1444     )cpp",
1445       R"txt(
1446 *: TranslationUnit
1447 |-SimpleDeclaration
1448 | |-int
1449 | |-SimpleDeclarator
1450 | | |-a
1451 | | `-ParametersAndQualifiers
1452 | |   |-(
1453 | |   |-)
1454 | |   `-noexcept
1455 | `-;
1456 |-SimpleDeclaration
1457 | |-int
1458 | |-SimpleDeclarator
1459 | | |-b
1460 | | `-ParametersAndQualifiers
1461 | |   |-(
1462 | |   |-)
1463 | |   |-noexcept
1464 | |   |-(
1465 | |   |-UnknownExpression
1466 | |   | `-true
1467 | |   `-)
1468 | `-;
1469 `-SimpleDeclaration
1470   |-int
1471   |-SimpleDeclarator
1472   | |-c
1473   | `-ParametersAndQualifiers
1474   |   |-(
1475   |   |-)
1476   |   |-throw
1477   |   |-(
1478   |   `-)
1479   `-;
1480        )txt");
1481 }
1482 
1483 TEST_F(SyntaxTreeTest, DeclaratorsInParentheses) {
1484   expectTreeDumpEqual(
1485       R"cpp(
1486 int (a);
1487 int *(b);
1488 int (*c)(int);
1489 int *(d)(int);
1490     )cpp",
1491       R"txt(
1492 *: TranslationUnit
1493 |-SimpleDeclaration
1494 | |-int
1495 | |-SimpleDeclarator
1496 | | `-ParenDeclarator
1497 | |   |-(
1498 | |   |-a
1499 | |   `-)
1500 | `-;
1501 |-SimpleDeclaration
1502 | |-int
1503 | |-SimpleDeclarator
1504 | | |-*
1505 | | `-ParenDeclarator
1506 | |   |-(
1507 | |   |-b
1508 | |   `-)
1509 | `-;
1510 |-SimpleDeclaration
1511 | |-int
1512 | |-SimpleDeclarator
1513 | | |-ParenDeclarator
1514 | | | |-(
1515 | | | |-*
1516 | | | |-c
1517 | | | `-)
1518 | | `-ParametersAndQualifiers
1519 | |   |-(
1520 | |   |-SimpleDeclaration
1521 | |   | `-int
1522 | |   `-)
1523 | `-;
1524 `-SimpleDeclaration
1525   |-int
1526   |-SimpleDeclarator
1527   | |-*
1528   | |-ParenDeclarator
1529   | | |-(
1530   | | |-d
1531   | | `-)
1532   | `-ParametersAndQualifiers
1533   |   |-(
1534   |   |-SimpleDeclaration
1535   |   | `-int
1536   |   `-)
1537   `-;
1538        )txt");
1539 }
1540 
1541 TEST_F(SyntaxTreeTest, ConstVolatileQualifiers) {
1542   expectTreeDumpEqual(
1543       R"cpp(
1544 const int west = -1;
1545 int const east = 1;
1546 const int const universal = 0;
1547 const int const *const *volatile b;
1548     )cpp",
1549       R"txt(
1550 *: TranslationUnit
1551 |-SimpleDeclaration
1552 | |-const
1553 | |-int
1554 | |-SimpleDeclarator
1555 | | |-west
1556 | | |-=
1557 | | `-UnknownExpression
1558 | |   |--
1559 | |   `-1
1560 | `-;
1561 |-SimpleDeclaration
1562 | |-int
1563 | |-const
1564 | |-SimpleDeclarator
1565 | | |-east
1566 | | |-=
1567 | | `-UnknownExpression
1568 | |   `-1
1569 | `-;
1570 |-SimpleDeclaration
1571 | |-const
1572 | |-int
1573 | |-const
1574 | |-SimpleDeclarator
1575 | | |-universal
1576 | | |-=
1577 | | `-UnknownExpression
1578 | |   `-0
1579 | `-;
1580 `-SimpleDeclaration
1581   |-const
1582   |-int
1583   |-const
1584   |-SimpleDeclarator
1585   | |-*
1586   | |-const
1587   | |-*
1588   | |-volatile
1589   | `-b
1590   `-;
1591        )txt");
1592 }
1593 
1594 TEST_F(SyntaxTreeTest, RangesOfDeclaratorsWithTrailingReturnTypes) {
1595   expectTreeDumpEqual(
1596       R"cpp(
1597 auto foo() -> auto(*)(int) -> double*;
1598     )cpp",
1599       R"txt(
1600 *: TranslationUnit
1601 `-SimpleDeclaration
1602   |-auto
1603   |-SimpleDeclarator
1604   | |-foo
1605   | `-ParametersAndQualifiers
1606   |   |-(
1607   |   |-)
1608   |   `-TrailingReturnType
1609   |     |-->
1610   |     |-auto
1611   |     `-SimpleDeclarator
1612   |       |-ParenDeclarator
1613   |       | |-(
1614   |       | |-*
1615   |       | `-)
1616   |       `-ParametersAndQualifiers
1617   |         |-(
1618   |         |-SimpleDeclaration
1619   |         | `-int
1620   |         |-)
1621   |         `-TrailingReturnType
1622   |           |-->
1623   |           |-double
1624   |           `-SimpleDeclarator
1625   |             `-*
1626   `-;
1627        )txt");
1628 }
1629 
1630 TEST_F(SyntaxTreeTest, MemberPointers) {
1631   expectTreeDumpEqual(
1632       R"cpp(
1633 struct X {};
1634 int X::* a;
1635 const int X::* b;
1636     )cpp",
1637       R"txt(
1638 *: TranslationUnit
1639 |-SimpleDeclaration
1640 | |-struct
1641 | |-X
1642 | |-{
1643 | |-}
1644 | `-;
1645 |-SimpleDeclaration
1646 | |-int
1647 | |-SimpleDeclarator
1648 | | |-MemberPointer
1649 | | | |-X
1650 | | | |-::
1651 | | | `-*
1652 | | `-a
1653 | `-;
1654 `-SimpleDeclaration
1655   |-const
1656   |-int
1657   |-SimpleDeclarator
1658   | |-MemberPointer
1659   | | |-X
1660   | | |-::
1661   | | `-*
1662   | `-b
1663   `-;
1664        )txt");
1665 }
1666 
1667 TEST_F(SyntaxTreeTest, ComplexDeclarator) {
1668   expectTreeDumpEqual(
1669       R"cpp(
1670 void x(char a, short (*b)(int));
1671     )cpp",
1672       R"txt(
1673 *: TranslationUnit
1674 `-SimpleDeclaration
1675   |-void
1676   |-SimpleDeclarator
1677   | |-x
1678   | `-ParametersAndQualifiers
1679   |   |-(
1680   |   |-SimpleDeclaration
1681   |   | |-char
1682   |   | `-SimpleDeclarator
1683   |   |   `-a
1684   |   |-,
1685   |   |-SimpleDeclaration
1686   |   | |-short
1687   |   | `-SimpleDeclarator
1688   |   |   |-ParenDeclarator
1689   |   |   | |-(
1690   |   |   | |-*
1691   |   |   | |-b
1692   |   |   | `-)
1693   |   |   `-ParametersAndQualifiers
1694   |   |     |-(
1695   |   |     |-SimpleDeclaration
1696   |   |     | `-int
1697   |   |     `-)
1698   |   `-)
1699   `-;
1700        )txt");
1701 }
1702 
1703 TEST_F(SyntaxTreeTest, ComplexDeclarator2) {
1704   expectTreeDumpEqual(
1705       R"cpp(
1706 void x(char a, short (*b)(int), long (**c)(long long));
1707     )cpp",
1708       R"txt(
1709 *: TranslationUnit
1710 `-SimpleDeclaration
1711   |-void
1712   |-SimpleDeclarator
1713   | |-x
1714   | `-ParametersAndQualifiers
1715   |   |-(
1716   |   |-SimpleDeclaration
1717   |   | |-char
1718   |   | `-SimpleDeclarator
1719   |   |   `-a
1720   |   |-,
1721   |   |-SimpleDeclaration
1722   |   | |-short
1723   |   | `-SimpleDeclarator
1724   |   |   |-ParenDeclarator
1725   |   |   | |-(
1726   |   |   | |-*
1727   |   |   | |-b
1728   |   |   | `-)
1729   |   |   `-ParametersAndQualifiers
1730   |   |     |-(
1731   |   |     |-SimpleDeclaration
1732   |   |     | `-int
1733   |   |     `-)
1734   |   |-,
1735   |   |-SimpleDeclaration
1736   |   | |-long
1737   |   | `-SimpleDeclarator
1738   |   |   |-ParenDeclarator
1739   |   |   | |-(
1740   |   |   | |-*
1741   |   |   | |-*
1742   |   |   | |-c
1743   |   |   | `-)
1744   |   |   `-ParametersAndQualifiers
1745   |   |     |-(
1746   |   |     |-SimpleDeclaration
1747   |   |     | |-long
1748   |   |     | `-long
1749   |   |     `-)
1750   |   `-)
1751   `-;
1752        )txt");
1753 }
1754 
1755 TEST_F(SyntaxTreeTest, Mutations) {
1756   using Transformation = std::function<void(
1757       const llvm::Annotations & /*Input*/, syntax::TranslationUnit * /*Root*/)>;
1758   auto CheckTransformation = [this](std::string Input, std::string Expected,
1759                                     Transformation Transform) -> void {
1760     llvm::Annotations Source(Input);
1761     auto *Root = buildTree(Source.code(), "x86_64-unknown-unknown");
1762 
1763     Transform(Source, Root);
1764 
1765     auto Replacements = syntax::computeReplacements(*Arena, *Root);
1766     auto Output = tooling::applyAllReplacements(Source.code(), Replacements);
1767     if (!Output) {
1768       ADD_FAILURE() << "could not apply replacements: "
1769                     << llvm::toString(Output.takeError());
1770       return;
1771     }
1772 
1773     EXPECT_EQ(Expected, *Output) << "input is:\n" << Input;
1774   };
1775 
1776   // Removes the selected statement. Input should have exactly one selected
1777   // range and it should correspond to a single statement.
1778   auto RemoveStatement = [this](const llvm::Annotations &Input,
1779                                 syntax::TranslationUnit *TU) {
1780     auto *S = cast<syntax::Statement>(nodeByRange(Input.range(), TU));
1781     ASSERT_TRUE(S->canModify()) << "cannot remove a statement";
1782     syntax::removeStatement(*Arena, S);
1783     EXPECT_TRUE(S->isDetached());
1784     EXPECT_FALSE(S->isOriginal())
1785         << "node removed from tree cannot be marked as original";
1786   };
1787 
1788   std::vector<std::pair<std::string /*Input*/, std::string /*Expected*/>>
1789       Cases = {
1790           {"void test() { [[100+100;]] test(); }", "void test() {  test(); }"},
1791           {"void test() { if (true) [[{}]] else {} }",
1792            "void test() { if (true) ; else {} }"},
1793           {"void test() { [[;]] }", "void test() {  }"}};
1794   for (const auto &C : Cases)
1795     CheckTransformation(C.first, C.second, RemoveStatement);
1796 }
1797 
1798 TEST_F(SyntaxTreeTest, SynthesizedNodes) {
1799   buildTree("", "x86_64-unknown-unknown");
1800 
1801   auto *C = syntax::createPunctuation(*Arena, tok::comma);
1802   ASSERT_NE(C, nullptr);
1803   EXPECT_EQ(C->token()->kind(), tok::comma);
1804   EXPECT_TRUE(C->canModify());
1805   EXPECT_FALSE(C->isOriginal());
1806   EXPECT_TRUE(C->isDetached());
1807 
1808   auto *S = syntax::createEmptyStatement(*Arena);
1809   ASSERT_NE(S, nullptr);
1810   EXPECT_TRUE(S->canModify());
1811   EXPECT_FALSE(S->isOriginal());
1812   EXPECT_TRUE(S->isDetached());
1813 }
1814 
1815 } // namespace
1816