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