xref: /llvm-project/clang/unittests/Tooling/Syntax/TreeTest.cpp (revision cdce2fe561eb6e63d77d1d589e521a8e2afb1eef)
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, SimpleVariable) {
228   expectTreeDumpEqual(
229       R"cpp(
230 int a;
231 int b = 42;
232     )cpp",
233       R"txt(
234 *: TranslationUnit
235 |-SimpleDeclaration
236 | |-int
237 | |-SimpleDeclarator
238 | | `-a
239 | `-;
240 `-SimpleDeclaration
241   |-int
242   |-SimpleDeclarator
243   | |-b
244   | |-=
245   | `-UnknownExpression
246   |   `-42
247   `-;
248 )txt");
249 }
250 
251 TEST_F(SyntaxTreeTest, SimpleFunction) {
252   expectTreeDumpEqual(
253       R"cpp(
254 void foo(int a, int b) {}
255     )cpp",
256       R"txt(
257 *: TranslationUnit
258 `-SimpleDeclaration
259   |-void
260   |-SimpleDeclarator
261   | |-foo
262   | `-ParametersAndQualifiers
263   |   |-(
264   |   |-SimpleDeclaration
265   |   | |-int
266   |   | `-SimpleDeclarator
267   |   |   `-a
268   |   |-,
269   |   |-SimpleDeclaration
270   |   | |-int
271   |   | `-SimpleDeclarator
272   |   |   `-b
273   |   `-)
274   `-CompoundStatement
275     |-{
276     `-}
277 )txt");
278 }
279 
280 TEST_F(SyntaxTreeTest, If) {
281   expectTreeDumpEqual(
282       R"cpp(
283 int main() {
284   if (true) {}
285   if (true) {} else if (false) {}
286 }
287         )cpp",
288       R"txt(
289 *: TranslationUnit
290 `-SimpleDeclaration
291   |-int
292   |-SimpleDeclarator
293   | |-main
294   | `-ParametersAndQualifiers
295   |   |-(
296   |   `-)
297   `-CompoundStatement
298     |-{
299     |-IfStatement
300     | |-if
301     | |-(
302     | |-UnknownExpression
303     | | `-true
304     | |-)
305     | `-CompoundStatement
306     |   |-{
307     |   `-}
308     |-IfStatement
309     | |-if
310     | |-(
311     | |-UnknownExpression
312     | | `-true
313     | |-)
314     | |-CompoundStatement
315     | | |-{
316     | | `-}
317     | |-else
318     | `-IfStatement
319     |   |-if
320     |   |-(
321     |   |-UnknownExpression
322     |   | `-false
323     |   |-)
324     |   `-CompoundStatement
325     |     |-{
326     |     `-}
327     `-}
328         )txt");
329 }
330 
331 TEST_F(SyntaxTreeTest, For) {
332   expectTreeDumpEqual(
333       R"cpp(
334 void test() {
335   for (;;)  {}
336 }
337 )cpp",
338       R"txt(
339 *: TranslationUnit
340 `-SimpleDeclaration
341   |-void
342   |-SimpleDeclarator
343   | |-test
344   | `-ParametersAndQualifiers
345   |   |-(
346   |   `-)
347   `-CompoundStatement
348     |-{
349     |-ForStatement
350     | |-for
351     | |-(
352     | |-;
353     | |-;
354     | |-)
355     | `-CompoundStatement
356     |   |-{
357     |   `-}
358     `-}
359         )txt");
360 }
361 
362 TEST_F(SyntaxTreeTest, RangeBasedFor) {
363   expectTreeDumpEqual(
364       R"cpp(
365 void test() {
366   int a[3];
367   for (int x : a) ;
368 }
369       )cpp",
370       R"txt(
371 *: TranslationUnit
372 `-SimpleDeclaration
373   |-void
374   |-SimpleDeclarator
375   | |-test
376   | `-ParametersAndQualifiers
377   |   |-(
378   |   `-)
379   `-CompoundStatement
380     |-{
381     |-DeclarationStatement
382     | |-SimpleDeclaration
383     | | |-int
384     | | `-SimpleDeclarator
385     | |   |-a
386     | |   `-ArraySubscript
387     | |     |-[
388     | |     |-UnknownExpression
389     | |     | `-3
390     | |     `-]
391     | `-;
392     |-RangeBasedForStatement
393     | |-for
394     | |-(
395     | |-SimpleDeclaration
396     | | |-int
397     | | |-SimpleDeclarator
398     | | | `-x
399     | | `-:
400     | |-UnknownExpression
401     | | `-a
402     | |-)
403     | `-EmptyStatement
404     |   `-;
405     `-}
406        )txt");
407 }
408 
409 TEST_F(SyntaxTreeTest, DeclarationStatement) {
410   expectTreeDumpEqual("void test() { int a = 10; }",
411                       R"txt(
412 *: TranslationUnit
413 `-SimpleDeclaration
414   |-void
415   |-SimpleDeclarator
416   | |-test
417   | `-ParametersAndQualifiers
418   |   |-(
419   |   `-)
420   `-CompoundStatement
421     |-{
422     |-DeclarationStatement
423     | |-SimpleDeclaration
424     | | |-int
425     | | `-SimpleDeclarator
426     | |   |-a
427     | |   |-=
428     | |   `-UnknownExpression
429     | |     `-10
430     | `-;
431     `-}
432 )txt");
433 }
434 
435 TEST_F(SyntaxTreeTest, Switch) {
436   expectTreeDumpEqual(
437       R"cpp(
438 void test() {
439   switch (true) {
440     case 0:
441     default:;
442   }
443 }
444 )cpp",
445       R"txt(
446 *: TranslationUnit
447 `-SimpleDeclaration
448   |-void
449   |-SimpleDeclarator
450   | |-test
451   | `-ParametersAndQualifiers
452   |   |-(
453   |   `-)
454   `-CompoundStatement
455     |-{
456     |-SwitchStatement
457     | |-switch
458     | |-(
459     | |-UnknownExpression
460     | | `-true
461     | |-)
462     | `-CompoundStatement
463     |   |-{
464     |   |-CaseStatement
465     |   | |-case
466     |   | |-UnknownExpression
467     |   | | `-0
468     |   | |-:
469     |   | `-DefaultStatement
470     |   |   |-default
471     |   |   |-:
472     |   |   `-EmptyStatement
473     |   |     `-;
474     |   `-}
475     `-}
476 )txt");
477 }
478 
479 TEST_F(SyntaxTreeTest, While) {
480   expectTreeDumpEqual(
481       R"cpp(
482 void test() {
483   while (true) { continue; break; }
484 }
485 )cpp",
486       R"txt(
487 *: TranslationUnit
488 `-SimpleDeclaration
489   |-void
490   |-SimpleDeclarator
491   | |-test
492   | `-ParametersAndQualifiers
493   |   |-(
494   |   `-)
495   `-CompoundStatement
496     |-{
497     |-WhileStatement
498     | |-while
499     | |-(
500     | |-UnknownExpression
501     | | `-true
502     | |-)
503     | `-CompoundStatement
504     |   |-{
505     |   |-ContinueStatement
506     |   | |-continue
507     |   | `-;
508     |   |-BreakStatement
509     |   | |-break
510     |   | `-;
511     |   `-}
512     `-}
513 )txt");
514 }
515 
516 TEST_F(SyntaxTreeTest, UnhandledStatement) {
517   // Unhandled statements should end up as 'unknown statement'.
518   // This example uses a 'label statement', which does not yet have a syntax
519   // counterpart.
520   expectTreeDumpEqual("void main() { foo: return 100; }",
521                       R"txt(
522 *: TranslationUnit
523 `-SimpleDeclaration
524   |-void
525   |-SimpleDeclarator
526   | |-main
527   | `-ParametersAndQualifiers
528   |   |-(
529   |   `-)
530   `-CompoundStatement
531     |-{
532     |-UnknownStatement
533     | |-foo
534     | |-:
535     | `-ReturnStatement
536     |   |-return
537     |   |-UnknownExpression
538     |   | `-100
539     |   `-;
540     `-}
541 )txt");
542 }
543 
544 TEST_F(SyntaxTreeTest, Expressions) {
545   // expressions should be wrapped in 'ExpressionStatement' when they appear
546   // in a statement position.
547   expectTreeDumpEqual(
548       R"cpp(
549 void test() {
550   test();
551   if (true) test(); else test();
552 }
553     )cpp",
554       R"txt(
555 *: TranslationUnit
556 `-SimpleDeclaration
557   |-void
558   |-SimpleDeclarator
559   | |-test
560   | `-ParametersAndQualifiers
561   |   |-(
562   |   `-)
563   `-CompoundStatement
564     |-{
565     |-ExpressionStatement
566     | |-UnknownExpression
567     | | |-test
568     | | |-(
569     | | `-)
570     | `-;
571     |-IfStatement
572     | |-if
573     | |-(
574     | |-UnknownExpression
575     | | `-true
576     | |-)
577     | |-ExpressionStatement
578     | | |-UnknownExpression
579     | | | |-test
580     | | | |-(
581     | | | `-)
582     | | `-;
583     | |-else
584     | `-ExpressionStatement
585     |   |-UnknownExpression
586     |   | |-test
587     |   | |-(
588     |   | `-)
589     |   `-;
590     `-}
591 )txt");
592 }
593 
594 TEST_F(SyntaxTreeTest, MultipleDeclaratorsGrouping) {
595   expectTreeDumpEqual(
596       R"cpp(
597       int *a, b; int *c, d;
598   )cpp",
599       R"txt(
600 *: TranslationUnit
601 |-SimpleDeclaration
602 | |-int
603 | |-SimpleDeclarator
604 | | |-*
605 | | `-a
606 | |-,
607 | |-SimpleDeclarator
608 | | `-b
609 | `-;
610 `-SimpleDeclaration
611   |-int
612   |-SimpleDeclarator
613   | |-*
614   | `-c
615   |-,
616   |-SimpleDeclarator
617   | `-d
618   `-;
619   )txt");
620 }
621 
622 TEST_F(SyntaxTreeTest, MultipleDeclaratorsGroupingTypedef) {
623   expectTreeDumpEqual(
624       R"cpp(
625     typedef int *a, b;
626   )cpp",
627       R"txt(
628 *: TranslationUnit
629 `-SimpleDeclaration
630   |-typedef
631   |-int
632   |-SimpleDeclarator
633   | |-*
634   | `-a
635   |-,
636   |-SimpleDeclarator
637   | `-b
638   `-;
639   )txt");
640 }
641 
642 TEST_F(SyntaxTreeTest, MultipleDeclaratorsInsideStatement) {
643   expectTreeDumpEqual(
644       R"cpp(
645 void foo() {
646       int *a, b;
647       typedef int *ta, tb;
648 }
649   )cpp",
650       R"txt(
651 *: TranslationUnit
652 `-SimpleDeclaration
653   |-void
654   |-SimpleDeclarator
655   | |-foo
656   | `-ParametersAndQualifiers
657   |   |-(
658   |   `-)
659   `-CompoundStatement
660     |-{
661     |-DeclarationStatement
662     | |-SimpleDeclaration
663     | | |-int
664     | | |-SimpleDeclarator
665     | | | |-*
666     | | | `-a
667     | | |-,
668     | | `-SimpleDeclarator
669     | |   `-b
670     | `-;
671     |-DeclarationStatement
672     | |-SimpleDeclaration
673     | | |-typedef
674     | | |-int
675     | | |-SimpleDeclarator
676     | | | |-*
677     | | | `-ta
678     | | |-,
679     | | `-SimpleDeclarator
680     | |   `-tb
681     | `-;
682     `-}
683   )txt");
684 }
685 
686 TEST_F(SyntaxTreeTest, Namespaces) {
687   expectTreeDumpEqual(
688       R"cpp(
689 namespace a { namespace b {} }
690 namespace a::b {}
691 namespace {}
692 
693 namespace foo = a;
694     )cpp",
695       R"txt(
696 *: TranslationUnit
697 |-NamespaceDefinition
698 | |-namespace
699 | |-a
700 | |-{
701 | |-NamespaceDefinition
702 | | |-namespace
703 | | |-b
704 | | |-{
705 | | `-}
706 | `-}
707 |-NamespaceDefinition
708 | |-namespace
709 | |-a
710 | |-::
711 | |-b
712 | |-{
713 | `-}
714 |-NamespaceDefinition
715 | |-namespace
716 | |-{
717 | `-}
718 `-NamespaceAliasDefinition
719   |-namespace
720   |-foo
721   |-=
722   |-a
723   `-;
724 )txt");
725 }
726 
727 TEST_F(SyntaxTreeTest, UsingDirective) {
728   expectTreeDumpEqual(
729       R"cpp(
730 namespace ns {}
731 using namespace ::ns;
732     )cpp",
733       R"txt(
734 *: TranslationUnit
735 |-NamespaceDefinition
736 | |-namespace
737 | |-ns
738 | |-{
739 | `-}
740 `-UsingNamespaceDirective
741   |-using
742   |-namespace
743   |-::
744   |-ns
745   `-;
746        )txt");
747 }
748 
749 TEST_F(SyntaxTreeTest, UsingDeclaration) {
750   expectTreeDumpEqual(
751       R"cpp(
752 namespace ns { int a; }
753 using ns::a;
754     )cpp",
755       R"txt(
756 *: TranslationUnit
757 |-NamespaceDefinition
758 | |-namespace
759 | |-ns
760 | |-{
761 | |-SimpleDeclaration
762 | | |-int
763 | | |-SimpleDeclarator
764 | | | `-a
765 | | `-;
766 | `-}
767 `-UsingDeclaration
768   |-using
769   |-ns
770   |-::
771   |-a
772   `-;
773        )txt");
774 }
775 
776 TEST_F(SyntaxTreeTest, FreeStandingClasses) {
777   // Free-standing classes, must live inside a SimpleDeclaration.
778   expectTreeDumpEqual(
779       R"cpp(
780 sturct X;
781 struct X {};
782 
783 struct Y *y1;
784 struct Y {} *y2;
785 
786 struct {} *a1;
787     )cpp",
788       R"txt(
789 *: TranslationUnit
790 |-SimpleDeclaration
791 | |-sturct
792 | |-X
793 | `-;
794 |-SimpleDeclaration
795 | |-struct
796 | |-X
797 | |-{
798 | |-}
799 | `-;
800 |-SimpleDeclaration
801 | |-struct
802 | |-Y
803 | |-SimpleDeclarator
804 | | |-*
805 | | `-y1
806 | `-;
807 |-SimpleDeclaration
808 | |-struct
809 | |-Y
810 | |-{
811 | |-}
812 | |-SimpleDeclarator
813 | | |-*
814 | | `-y2
815 | `-;
816 `-SimpleDeclaration
817   |-struct
818   |-{
819   |-}
820   |-SimpleDeclarator
821   | |-*
822   | `-a1
823   `-;
824 )txt");
825 }
826 
827 TEST_F(SyntaxTreeTest, Templates) {
828   expectTreeDumpEqual(
829       R"cpp(
830 template <class T> struct cls {};
831 template <class T> int var = 10;
832 template <class T> int fun() {}
833     )cpp",
834       R"txt(
835 *: TranslationUnit
836 |-TemplateDeclaration
837 | |-template
838 | |-<
839 | |-UnknownDeclaration
840 | | |-class
841 | | `-T
842 | |->
843 | `-SimpleDeclaration
844 |   |-struct
845 |   |-cls
846 |   |-{
847 |   |-}
848 |   `-;
849 |-TemplateDeclaration
850 | |-template
851 | |-<
852 | |-UnknownDeclaration
853 | | |-class
854 | | `-T
855 | |->
856 | `-SimpleDeclaration
857 |   |-int
858 |   |-SimpleDeclarator
859 |   | |-var
860 |   | |-=
861 |   | `-UnknownExpression
862 |   |   `-10
863 |   `-;
864 `-TemplateDeclaration
865   |-template
866   |-<
867   |-UnknownDeclaration
868   | |-class
869   | `-T
870   |->
871   `-SimpleDeclaration
872     |-int
873     |-SimpleDeclarator
874     | |-fun
875     | `-ParametersAndQualifiers
876     |   |-(
877     |   `-)
878     `-CompoundStatement
879       |-{
880       `-}
881 )txt",
882       // FIXME: Make this test work on windows by generating the expected Syntax
883       // tree when -fdelayed-template-parsing is active.
884       /*RunWithDelayedTemplateParsing=*/false);
885 }
886 
887 TEST_F(SyntaxTreeTest, NestedTemplates) {
888   expectTreeDumpEqual(
889       R"cpp(
890 template <class T>
891 struct X {
892   template <class U>
893   U foo();
894 };
895     )cpp",
896       R"txt(
897 *: TranslationUnit
898 `-TemplateDeclaration
899   |-template
900   |-<
901   |-UnknownDeclaration
902   | |-class
903   | `-T
904   |->
905   `-SimpleDeclaration
906     |-struct
907     |-X
908     |-{
909     |-TemplateDeclaration
910     | |-template
911     | |-<
912     | |-UnknownDeclaration
913     | | |-class
914     | | `-U
915     | |->
916     | `-SimpleDeclaration
917     |   |-U
918     |   |-SimpleDeclarator
919     |   | |-foo
920     |   | `-ParametersAndQualifiers
921     |   |   |-(
922     |   |   `-)
923     |   `-;
924     |-}
925     `-;
926 )txt");
927 }
928 
929 TEST_F(SyntaxTreeTest, Templates2) {
930   expectTreeDumpEqual(
931       R"cpp(
932 template <class T> struct X { struct Y; };
933 template <class T> struct X<T>::Y {};
934     )cpp",
935       R"txt(
936 *: TranslationUnit
937 |-TemplateDeclaration
938 | |-template
939 | |-<
940 | |-UnknownDeclaration
941 | | |-class
942 | | `-T
943 | |->
944 | `-SimpleDeclaration
945 |   |-struct
946 |   |-X
947 |   |-{
948 |   |-SimpleDeclaration
949 |   | |-struct
950 |   | |-Y
951 |   | `-;
952 |   |-}
953 |   `-;
954 `-TemplateDeclaration
955   |-template
956   |-<
957   |-UnknownDeclaration
958   | |-class
959   | `-T
960   |->
961   `-SimpleDeclaration
962     |-struct
963     |-X
964     |-<
965     |-T
966     |->
967     |-::
968     |-Y
969     |-{
970     |-}
971     `-;
972        )txt");
973 }
974 
975 TEST_F(SyntaxTreeTest, TemplatesUsingUsing) {
976   expectTreeDumpEqual(
977       R"cpp(
978 template <class T> struct X {
979   using T::foo;
980   using typename T::bar;
981 };
982     )cpp",
983       R"txt(
984 *: TranslationUnit
985 `-TemplateDeclaration
986   |-template
987   |-<
988   |-UnknownDeclaration
989   | |-class
990   | `-T
991   |->
992   `-SimpleDeclaration
993     |-struct
994     |-X
995     |-{
996     |-UsingDeclaration
997     | |-using
998     | |-T
999     | |-::
1000     | |-foo
1001     | `-;
1002     |-UsingDeclaration
1003     | |-using
1004     | |-typename
1005     | |-T
1006     | |-::
1007     | |-bar
1008     | `-;
1009     |-}
1010     `-;
1011        )txt");
1012 }
1013 
1014 TEST_F(SyntaxTreeTest, ExplicitTemplateInstantations) {
1015   expectTreeDumpEqual(
1016       R"cpp(
1017 template <class T> struct X {};
1018 template <class T> struct X<T*> {};
1019 template <> struct X<int> {};
1020 
1021 template struct X<double>;
1022 extern template struct X<float>;
1023 )cpp",
1024       R"txt(
1025 *: TranslationUnit
1026 |-TemplateDeclaration
1027 | |-template
1028 | |-<
1029 | |-UnknownDeclaration
1030 | | |-class
1031 | | `-T
1032 | |->
1033 | `-SimpleDeclaration
1034 |   |-struct
1035 |   |-X
1036 |   |-{
1037 |   |-}
1038 |   `-;
1039 |-TemplateDeclaration
1040 | |-template
1041 | |-<
1042 | |-UnknownDeclaration
1043 | | |-class
1044 | | `-T
1045 | |->
1046 | `-SimpleDeclaration
1047 |   |-struct
1048 |   |-X
1049 |   |-<
1050 |   |-T
1051 |   |-*
1052 |   |->
1053 |   |-{
1054 |   |-}
1055 |   `-;
1056 |-TemplateDeclaration
1057 | |-template
1058 | |-<
1059 | |->
1060 | `-SimpleDeclaration
1061 |   |-struct
1062 |   |-X
1063 |   |-<
1064 |   |-int
1065 |   |->
1066 |   |-{
1067 |   |-}
1068 |   `-;
1069 |-ExplicitTemplateInstantiation
1070 | |-template
1071 | `-SimpleDeclaration
1072 |   |-struct
1073 |   |-X
1074 |   |-<
1075 |   |-double
1076 |   |->
1077 |   `-;
1078 `-ExplicitTemplateInstantiation
1079   |-extern
1080   |-template
1081   `-SimpleDeclaration
1082     |-struct
1083     |-X
1084     |-<
1085     |-float
1086     |->
1087     `-;
1088 )txt");
1089 }
1090 
1091 TEST_F(SyntaxTreeTest, UsingType) {
1092   expectTreeDumpEqual(
1093       R"cpp(
1094 using type = int;
1095     )cpp",
1096       R"txt(
1097 *: TranslationUnit
1098 `-TypeAliasDeclaration
1099   |-using
1100   |-type
1101   |-=
1102   |-int
1103   `-;
1104        )txt");
1105 }
1106 
1107 TEST_F(SyntaxTreeTest, EmptyDeclaration) {
1108   expectTreeDumpEqual(
1109       R"cpp(
1110 ;
1111     )cpp",
1112       R"txt(
1113 *: TranslationUnit
1114 `-EmptyDeclaration
1115   `-;
1116        )txt");
1117 }
1118 
1119 TEST_F(SyntaxTreeTest, StaticAssert) {
1120   expectTreeDumpEqual(
1121       R"cpp(
1122 static_assert(true, "message");
1123 static_assert(true);
1124     )cpp",
1125       R"txt(
1126 *: TranslationUnit
1127 |-StaticAssertDeclaration
1128 | |-static_assert
1129 | |-(
1130 | |-UnknownExpression
1131 | | `-true
1132 | |-,
1133 | |-UnknownExpression
1134 | | `-"message"
1135 | |-)
1136 | `-;
1137 `-StaticAssertDeclaration
1138   |-static_assert
1139   |-(
1140   |-UnknownExpression
1141   | `-true
1142   |-)
1143   `-;
1144        )txt");
1145 }
1146 
1147 TEST_F(SyntaxTreeTest, ExternC) {
1148   expectTreeDumpEqual(
1149       R"cpp(
1150 extern "C" int a;
1151 extern "C" { int b; int c; }
1152     )cpp",
1153       R"txt(
1154 *: TranslationUnit
1155 |-LinkageSpecificationDeclaration
1156 | |-extern
1157 | |-"C"
1158 | `-SimpleDeclaration
1159 |   |-int
1160 |   |-SimpleDeclarator
1161 |   | `-a
1162 |   `-;
1163 `-LinkageSpecificationDeclaration
1164   |-extern
1165   |-"C"
1166   |-{
1167   |-SimpleDeclaration
1168   | |-int
1169   | |-SimpleDeclarator
1170   | | `-b
1171   | `-;
1172   |-SimpleDeclaration
1173   | |-int
1174   | |-SimpleDeclarator
1175   | | `-c
1176   | `-;
1177   `-}
1178        )txt");
1179 }
1180 
1181 TEST_F(SyntaxTreeTest, NonModifiableNodes) {
1182   // Some nodes are non-modifiable, they are marked with 'I:'.
1183   expectTreeDumpEqual(
1184       R"cpp(
1185 #define HALF_IF if (1+
1186 #define HALF_IF_2 1) {}
1187 void test() {
1188   HALF_IF HALF_IF_2 else {}
1189 })cpp",
1190       R"txt(
1191 *: TranslationUnit
1192 `-SimpleDeclaration
1193   |-void
1194   |-SimpleDeclarator
1195   | |-test
1196   | `-ParametersAndQualifiers
1197   |   |-(
1198   |   `-)
1199   `-CompoundStatement
1200     |-{
1201     |-IfStatement
1202     | |-I: if
1203     | |-I: (
1204     | |-I: UnknownExpression
1205     | | |-I: 1
1206     | | |-I: +
1207     | | `-I: 1
1208     | |-I: )
1209     | |-I: CompoundStatement
1210     | | |-I: {
1211     | | `-I: }
1212     | |-else
1213     | `-CompoundStatement
1214     |   |-{
1215     |   `-}
1216     `-}
1217        )txt");
1218   // All nodes can be mutated.
1219   expectTreeDumpEqual(
1220       R"cpp(
1221 #define OPEN {
1222 #define CLOSE }
1223 
1224 void test() {
1225   OPEN
1226     1;
1227   CLOSE
1228 
1229   OPEN
1230     2;
1231   }
1232 }
1233 )cpp",
1234       R"txt(
1235 *: TranslationUnit
1236 `-SimpleDeclaration
1237   |-void
1238   |-SimpleDeclarator
1239   | |-test
1240   | `-ParametersAndQualifiers
1241   |   |-(
1242   |   `-)
1243   `-CompoundStatement
1244     |-{
1245     |-CompoundStatement
1246     | |-{
1247     | |-ExpressionStatement
1248     | | |-UnknownExpression
1249     | | | `-1
1250     | | `-;
1251     | `-}
1252     |-CompoundStatement
1253     | |-{
1254     | |-ExpressionStatement
1255     | | |-UnknownExpression
1256     | | | `-2
1257     | | `-;
1258     | `-}
1259     `-}
1260        )txt");
1261 }
1262 
1263 TEST_F(SyntaxTreeTest, ArraySubscriptsInDeclarators) {
1264   expectTreeDumpEqual(
1265       R"cpp(
1266 int a[10];
1267 int b[1][2][3];
1268 int c[] = {1,2,3};
1269 void f(int xs[static 10]);
1270     )cpp",
1271       R"txt(
1272 *: TranslationUnit
1273 |-SimpleDeclaration
1274 | |-int
1275 | |-SimpleDeclarator
1276 | | |-a
1277 | | `-ArraySubscript
1278 | |   |-[
1279 | |   |-UnknownExpression
1280 | |   | `-10
1281 | |   `-]
1282 | `-;
1283 |-SimpleDeclaration
1284 | |-int
1285 | |-SimpleDeclarator
1286 | | |-b
1287 | | |-ArraySubscript
1288 | | | |-[
1289 | | | |-UnknownExpression
1290 | | | | `-1
1291 | | | `-]
1292 | | |-ArraySubscript
1293 | | | |-[
1294 | | | |-UnknownExpression
1295 | | | | `-2
1296 | | | `-]
1297 | | `-ArraySubscript
1298 | |   |-[
1299 | |   |-UnknownExpression
1300 | |   | `-3
1301 | |   `-]
1302 | `-;
1303 |-SimpleDeclaration
1304 | |-int
1305 | |-SimpleDeclarator
1306 | | |-c
1307 | | |-ArraySubscript
1308 | | | |-[
1309 | | | `-]
1310 | | |-=
1311 | | `-UnknownExpression
1312 | |   |-{
1313 | |   |-1
1314 | |   |-,
1315 | |   |-2
1316 | |   |-,
1317 | |   |-3
1318 | |   `-}
1319 | `-;
1320 `-SimpleDeclaration
1321   |-void
1322   |-SimpleDeclarator
1323   | |-f
1324   | `-ParametersAndQualifiers
1325   |   |-(
1326   |   |-SimpleDeclaration
1327   |   | |-int
1328   |   | `-SimpleDeclarator
1329   |   |   |-xs
1330   |   |   `-ArraySubscript
1331   |   |     |-[
1332   |   |     |-static
1333   |   |     |-UnknownExpression
1334   |   |     | `-10
1335   |   |     `-]
1336   |   `-)
1337   `-;
1338        )txt");
1339 }
1340 
1341 TEST_F(SyntaxTreeTest, ParameterListsInDeclarators) {
1342   expectTreeDumpEqual(
1343       R"cpp(
1344 int a() const;
1345 int b() volatile;
1346 int c() &;
1347 int d() &&;
1348 int foo(int a, int b);
1349 int foo(
1350   const int a,
1351   volatile int b,
1352   const volatile int c,
1353   int* d,
1354   int& e,
1355   int&& f
1356 );
1357     )cpp",
1358       R"txt(
1359 *: TranslationUnit
1360 |-SimpleDeclaration
1361 | |-int
1362 | |-SimpleDeclarator
1363 | | |-a
1364 | | `-ParametersAndQualifiers
1365 | |   |-(
1366 | |   |-)
1367 | |   `-const
1368 | `-;
1369 |-SimpleDeclaration
1370 | |-int
1371 | |-SimpleDeclarator
1372 | | |-b
1373 | | `-ParametersAndQualifiers
1374 | |   |-(
1375 | |   |-)
1376 | |   `-volatile
1377 | `-;
1378 |-SimpleDeclaration
1379 | |-int
1380 | |-SimpleDeclarator
1381 | | |-c
1382 | | `-ParametersAndQualifiers
1383 | |   |-(
1384 | |   |-)
1385 | |   `-&
1386 | `-;
1387 |-SimpleDeclaration
1388 | |-int
1389 | |-SimpleDeclarator
1390 | | |-d
1391 | | `-ParametersAndQualifiers
1392 | |   |-(
1393 | |   |-)
1394 | |   `-&&
1395 | `-;
1396 |-SimpleDeclaration
1397 | |-int
1398 | |-SimpleDeclarator
1399 | | |-foo
1400 | | `-ParametersAndQualifiers
1401 | |   |-(
1402 | |   |-SimpleDeclaration
1403 | |   | |-int
1404 | |   | `-SimpleDeclarator
1405 | |   |   `-a
1406 | |   |-,
1407 | |   |-SimpleDeclaration
1408 | |   | |-int
1409 | |   | `-SimpleDeclarator
1410 | |   |   `-b
1411 | |   `-)
1412 | `-;
1413 `-SimpleDeclaration
1414   |-int
1415   |-SimpleDeclarator
1416   | |-foo
1417   | `-ParametersAndQualifiers
1418   |   |-(
1419   |   |-SimpleDeclaration
1420   |   | |-const
1421   |   | |-int
1422   |   | `-SimpleDeclarator
1423   |   |   `-a
1424   |   |-,
1425   |   |-SimpleDeclaration
1426   |   | |-volatile
1427   |   | |-int
1428   |   | `-SimpleDeclarator
1429   |   |   `-b
1430   |   |-,
1431   |   |-SimpleDeclaration
1432   |   | |-const
1433   |   | |-volatile
1434   |   | |-int
1435   |   | `-SimpleDeclarator
1436   |   |   `-c
1437   |   |-,
1438   |   |-SimpleDeclaration
1439   |   | |-int
1440   |   | `-SimpleDeclarator
1441   |   |   |-*
1442   |   |   `-d
1443   |   |-,
1444   |   |-SimpleDeclaration
1445   |   | |-int
1446   |   | `-SimpleDeclarator
1447   |   |   |-&
1448   |   |   `-e
1449   |   |-,
1450   |   |-SimpleDeclaration
1451   |   | |-int
1452   |   | `-SimpleDeclarator
1453   |   |   |-&&
1454   |   |   `-f
1455   |   `-)
1456   `-;
1457        )txt");
1458 }
1459 
1460 TEST_F(SyntaxTreeTest, TrailingConst) {
1461   expectTreeDumpEqual(
1462       R"cpp(
1463 struct X {
1464   int foo() const;
1465 }
1466     )cpp",
1467       R"txt(
1468 *: TranslationUnit
1469 `-SimpleDeclaration
1470   |-struct
1471   |-X
1472   |-{
1473   |-SimpleDeclaration
1474   | |-int
1475   | |-SimpleDeclarator
1476   | | |-foo
1477   | | `-ParametersAndQualifiers
1478   | |   |-(
1479   | |   |-)
1480   | |   `-const
1481   | `-;
1482   `-}
1483     )txt");
1484 }
1485 
1486 TEST_F(SyntaxTreeTest, TrailingReturn) {
1487   expectTreeDumpEqual(
1488       R"cpp(
1489 auto foo() -> int;
1490     )cpp",
1491       R"txt(
1492 *: TranslationUnit
1493 `-SimpleDeclaration
1494   |-auto
1495   |-SimpleDeclarator
1496   | |-foo
1497   | `-ParametersAndQualifiers
1498   |   |-(
1499   |   |-)
1500   |   `-TrailingReturnType
1501   |     |-->
1502   |     `-int
1503   `-;
1504        )txt");
1505 }
1506 
1507 TEST_F(SyntaxTreeTest, ExceptionSpecification) {
1508   expectTreeDumpEqual(
1509       R"cpp(
1510 int a() noexcept;
1511 int b() noexcept(true);
1512 int c() throw();
1513     )cpp",
1514       R"txt(
1515 *: TranslationUnit
1516 |-SimpleDeclaration
1517 | |-int
1518 | |-SimpleDeclarator
1519 | | |-a
1520 | | `-ParametersAndQualifiers
1521 | |   |-(
1522 | |   |-)
1523 | |   `-noexcept
1524 | `-;
1525 |-SimpleDeclaration
1526 | |-int
1527 | |-SimpleDeclarator
1528 | | |-b
1529 | | `-ParametersAndQualifiers
1530 | |   |-(
1531 | |   |-)
1532 | |   |-noexcept
1533 | |   |-(
1534 | |   |-UnknownExpression
1535 | |   | `-true
1536 | |   `-)
1537 | `-;
1538 `-SimpleDeclaration
1539   |-int
1540   |-SimpleDeclarator
1541   | |-c
1542   | `-ParametersAndQualifiers
1543   |   |-(
1544   |   |-)
1545   |   |-throw
1546   |   |-(
1547   |   `-)
1548   `-;
1549        )txt");
1550 }
1551 
1552 TEST_F(SyntaxTreeTest, DeclaratorsInParentheses) {
1553   expectTreeDumpEqual(
1554       R"cpp(
1555 int (a);
1556 int *(b);
1557 int (*c)(int);
1558 int *(d)(int);
1559     )cpp",
1560       R"txt(
1561 *: TranslationUnit
1562 |-SimpleDeclaration
1563 | |-int
1564 | |-SimpleDeclarator
1565 | | `-ParenDeclarator
1566 | |   |-(
1567 | |   |-a
1568 | |   `-)
1569 | `-;
1570 |-SimpleDeclaration
1571 | |-int
1572 | |-SimpleDeclarator
1573 | | |-*
1574 | | `-ParenDeclarator
1575 | |   |-(
1576 | |   |-b
1577 | |   `-)
1578 | `-;
1579 |-SimpleDeclaration
1580 | |-int
1581 | |-SimpleDeclarator
1582 | | |-ParenDeclarator
1583 | | | |-(
1584 | | | |-*
1585 | | | |-c
1586 | | | `-)
1587 | | `-ParametersAndQualifiers
1588 | |   |-(
1589 | |   |-SimpleDeclaration
1590 | |   | `-int
1591 | |   `-)
1592 | `-;
1593 `-SimpleDeclaration
1594   |-int
1595   |-SimpleDeclarator
1596   | |-*
1597   | |-ParenDeclarator
1598   | | |-(
1599   | | |-d
1600   | | `-)
1601   | `-ParametersAndQualifiers
1602   |   |-(
1603   |   |-SimpleDeclaration
1604   |   | `-int
1605   |   `-)
1606   `-;
1607        )txt");
1608 }
1609 
1610 TEST_F(SyntaxTreeTest, ConstVolatileQualifiers) {
1611   expectTreeDumpEqual(
1612       R"cpp(
1613 const int west = -1;
1614 int const east = 1;
1615 const int const universal = 0;
1616 const int const *const *volatile b;
1617     )cpp",
1618       R"txt(
1619 *: TranslationUnit
1620 |-SimpleDeclaration
1621 | |-const
1622 | |-int
1623 | |-SimpleDeclarator
1624 | | |-west
1625 | | |-=
1626 | | `-UnknownExpression
1627 | |   |--
1628 | |   `-1
1629 | `-;
1630 |-SimpleDeclaration
1631 | |-int
1632 | |-const
1633 | |-SimpleDeclarator
1634 | | |-east
1635 | | |-=
1636 | | `-UnknownExpression
1637 | |   `-1
1638 | `-;
1639 |-SimpleDeclaration
1640 | |-const
1641 | |-int
1642 | |-const
1643 | |-SimpleDeclarator
1644 | | |-universal
1645 | | |-=
1646 | | `-UnknownExpression
1647 | |   `-0
1648 | `-;
1649 `-SimpleDeclaration
1650   |-const
1651   |-int
1652   |-const
1653   |-SimpleDeclarator
1654   | |-*
1655   | |-const
1656   | |-*
1657   | |-volatile
1658   | `-b
1659   `-;
1660        )txt");
1661 }
1662 
1663 TEST_F(SyntaxTreeTest, RangesOfDeclaratorsWithTrailingReturnTypes) {
1664   expectTreeDumpEqual(
1665       R"cpp(
1666 auto foo() -> auto(*)(int) -> double*;
1667     )cpp",
1668       R"txt(
1669 *: TranslationUnit
1670 `-SimpleDeclaration
1671   |-auto
1672   |-SimpleDeclarator
1673   | |-foo
1674   | `-ParametersAndQualifiers
1675   |   |-(
1676   |   |-)
1677   |   `-TrailingReturnType
1678   |     |-->
1679   |     |-auto
1680   |     `-SimpleDeclarator
1681   |       |-ParenDeclarator
1682   |       | |-(
1683   |       | |-*
1684   |       | `-)
1685   |       `-ParametersAndQualifiers
1686   |         |-(
1687   |         |-SimpleDeclaration
1688   |         | `-int
1689   |         |-)
1690   |         `-TrailingReturnType
1691   |           |-->
1692   |           |-double
1693   |           `-SimpleDeclarator
1694   |             `-*
1695   `-;
1696        )txt");
1697 }
1698 
1699 TEST_F(SyntaxTreeTest, MemberPointers) {
1700   expectTreeDumpEqual(
1701       R"cpp(
1702 struct X {};
1703 int X::* a;
1704 const int X::* b;
1705     )cpp",
1706       R"txt(
1707 *: TranslationUnit
1708 |-SimpleDeclaration
1709 | |-struct
1710 | |-X
1711 | |-{
1712 | |-}
1713 | `-;
1714 |-SimpleDeclaration
1715 | |-int
1716 | |-SimpleDeclarator
1717 | | |-MemberPointer
1718 | | | |-X
1719 | | | |-::
1720 | | | `-*
1721 | | `-a
1722 | `-;
1723 `-SimpleDeclaration
1724   |-const
1725   |-int
1726   |-SimpleDeclarator
1727   | |-MemberPointer
1728   | | |-X
1729   | | |-::
1730   | | `-*
1731   | `-b
1732   `-;
1733        )txt");
1734 }
1735 
1736 TEST_F(SyntaxTreeTest, ComplexDeclarator) {
1737   expectTreeDumpEqual(
1738       R"cpp(
1739 void x(char a, short (*b)(int));
1740     )cpp",
1741       R"txt(
1742 *: TranslationUnit
1743 `-SimpleDeclaration
1744   |-void
1745   |-SimpleDeclarator
1746   | |-x
1747   | `-ParametersAndQualifiers
1748   |   |-(
1749   |   |-SimpleDeclaration
1750   |   | |-char
1751   |   | `-SimpleDeclarator
1752   |   |   `-a
1753   |   |-,
1754   |   |-SimpleDeclaration
1755   |   | |-short
1756   |   | `-SimpleDeclarator
1757   |   |   |-ParenDeclarator
1758   |   |   | |-(
1759   |   |   | |-*
1760   |   |   | |-b
1761   |   |   | `-)
1762   |   |   `-ParametersAndQualifiers
1763   |   |     |-(
1764   |   |     |-SimpleDeclaration
1765   |   |     | `-int
1766   |   |     `-)
1767   |   `-)
1768   `-;
1769        )txt");
1770 }
1771 
1772 TEST_F(SyntaxTreeTest, ComplexDeclarator2) {
1773   expectTreeDumpEqual(
1774       R"cpp(
1775 void x(char a, short (*b)(int), long (**c)(long long));
1776     )cpp",
1777       R"txt(
1778 *: TranslationUnit
1779 `-SimpleDeclaration
1780   |-void
1781   |-SimpleDeclarator
1782   | |-x
1783   | `-ParametersAndQualifiers
1784   |   |-(
1785   |   |-SimpleDeclaration
1786   |   | |-char
1787   |   | `-SimpleDeclarator
1788   |   |   `-a
1789   |   |-,
1790   |   |-SimpleDeclaration
1791   |   | |-short
1792   |   | `-SimpleDeclarator
1793   |   |   |-ParenDeclarator
1794   |   |   | |-(
1795   |   |   | |-*
1796   |   |   | |-b
1797   |   |   | `-)
1798   |   |   `-ParametersAndQualifiers
1799   |   |     |-(
1800   |   |     |-SimpleDeclaration
1801   |   |     | `-int
1802   |   |     `-)
1803   |   |-,
1804   |   |-SimpleDeclaration
1805   |   | |-long
1806   |   | `-SimpleDeclarator
1807   |   |   |-ParenDeclarator
1808   |   |   | |-(
1809   |   |   | |-*
1810   |   |   | |-*
1811   |   |   | |-c
1812   |   |   | `-)
1813   |   |   `-ParametersAndQualifiers
1814   |   |     |-(
1815   |   |     |-SimpleDeclaration
1816   |   |     | |-long
1817   |   |     | `-long
1818   |   |     `-)
1819   |   `-)
1820   `-;
1821        )txt");
1822 }
1823 
1824 TEST_F(SyntaxTreeTest, Mutations) {
1825   using Transformation = std::function<void(
1826       const llvm::Annotations & /*Input*/, syntax::TranslationUnit * /*Root*/)>;
1827   auto CheckTransformation = [this](std::string Input, std::string Expected,
1828                                     Transformation Transform) -> void {
1829     llvm::Annotations Source(Input);
1830     auto *Root = buildTree(Source.code());
1831 
1832     Transform(Source, Root);
1833 
1834     auto Replacements = syntax::computeReplacements(*Arena, *Root);
1835     auto Output = tooling::applyAllReplacements(Source.code(), Replacements);
1836     if (!Output) {
1837       ADD_FAILURE() << "could not apply replacements: "
1838                     << llvm::toString(Output.takeError());
1839       return;
1840     }
1841 
1842     EXPECT_EQ(Expected, *Output) << "input is:\n" << Input;
1843   };
1844 
1845   // Removes the selected statement. Input should have exactly one selected
1846   // range and it should correspond to a single statement.
1847   auto RemoveStatement = [this](const llvm::Annotations &Input,
1848                                 syntax::TranslationUnit *TU) {
1849     auto *S = cast<syntax::Statement>(nodeByRange(Input.range(), TU));
1850     ASSERT_TRUE(S->canModify()) << "cannot remove a statement";
1851     syntax::removeStatement(*Arena, S);
1852     EXPECT_TRUE(S->isDetached());
1853     EXPECT_FALSE(S->isOriginal())
1854         << "node removed from tree cannot be marked as original";
1855   };
1856 
1857   std::vector<std::pair<std::string /*Input*/, std::string /*Expected*/>>
1858       Cases = {
1859           {"void test() { [[100+100;]] test(); }", "void test() {  test(); }"},
1860           {"void test() { if (true) [[{}]] else {} }",
1861            "void test() { if (true) ; else {} }"},
1862           {"void test() { [[;]] }", "void test() {  }"}};
1863   for (const auto &C : Cases)
1864     CheckTransformation(C.first, C.second, RemoveStatement);
1865 }
1866 
1867 TEST_F(SyntaxTreeTest, SynthesizedNodes) {
1868   buildTree("");
1869 
1870   auto *C = syntax::createPunctuation(*Arena, tok::comma);
1871   ASSERT_NE(C, nullptr);
1872   EXPECT_EQ(C->token()->kind(), tok::comma);
1873   EXPECT_TRUE(C->canModify());
1874   EXPECT_FALSE(C->isOriginal());
1875   EXPECT_TRUE(C->isDetached());
1876 
1877   auto *S = syntax::createEmptyStatement(*Arena);
1878   ASSERT_NE(S, nullptr);
1879   EXPECT_TRUE(S->canModify());
1880   EXPECT_FALSE(S->isOriginal());
1881   EXPECT_TRUE(S->isDetached());
1882 }
1883 
1884 } // namespace
1885