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