xref: /llvm-project/clang/unittests/Tooling/Syntax/TreeTest.cpp (revision 7f7f8564808b51aa62744edf75c07c0df102056a)
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 isCXX14OrLater() const {
68     return Language == Lang_CXX14 || Language == Lang_CXX17 ||
69            Language == Lang_CXX20;
70   }
71 
72   bool hasBoolType() const {
73     return Language == Lang_C89 || Language == Lang_C99;
74   }
75 
76   bool supportsCXXDynamicExceptionSpecification() const {
77     return Language == Lang_CXX03 || Language == Lang_CXX11 ||
78            Language == Lang_CXX14;
79   }
80 
81   bool hasDelayedTemplateParsing() const {
82     return Target == "x86_64-pc-win32-msvc";
83   }
84 
85   std::vector<std::string> getCommandLineArgs() const {
86     std::vector<std::string> Result = getCommandLineArgsForTesting(Language);
87     Result.push_back("-target");
88     Result.push_back(Target);
89     return Result;
90   }
91 
92   std::string toString() const {
93     std::string Result;
94     llvm::raw_string_ostream OS(Result);
95     OS << "{ Language=" << Language << ", Target=" << Target << " }";
96     return OS.str();
97   }
98 
99   friend std::ostream &operator<<(std::ostream &OS,
100                                   const TestClangConfig &ClangConfig) {
101     return OS << ClangConfig.toString();
102   }
103 
104   static std::vector<TestClangConfig> &allConfigs() {
105     static std::vector<TestClangConfig> all_configs = []() {
106       std::vector<TestClangConfig> all_configs;
107       for (TestLanguage lang : {Lang_C89, Lang_C99, Lang_CXX03, Lang_CXX11,
108                                 Lang_CXX14, Lang_CXX17, Lang_CXX20}) {
109         TestClangConfig config;
110         config.Language = lang;
111         config.Target = "x86_64-pc-linux-gnu";
112         all_configs.push_back(config);
113 
114         // Windows target is interesting to test because it enables
115         // `-fdelayed-template-parsing`.
116         config.Target = "x86_64-pc-win32-msvc";
117         all_configs.push_back(config);
118       }
119       return all_configs;
120     }();
121     return all_configs;
122   }
123 };
124 
125 class SyntaxTreeTest : public ::testing::Test,
126                        public ::testing::WithParamInterface<TestClangConfig> {
127 protected:
128   // Build a syntax tree for the code.
129   syntax::TranslationUnit *buildTree(llvm::StringRef Code,
130                                      const TestClangConfig &ClangConfig) {
131     // FIXME: this code is almost the identical to the one in TokensTest. Share
132     //        it.
133     class BuildSyntaxTree : public ASTConsumer {
134     public:
135       BuildSyntaxTree(syntax::TranslationUnit *&Root,
136                       std::unique_ptr<syntax::Arena> &Arena,
137                       std::unique_ptr<syntax::TokenCollector> Tokens)
138           : Root(Root), Arena(Arena), Tokens(std::move(Tokens)) {
139         assert(this->Tokens);
140       }
141 
142       void HandleTranslationUnit(ASTContext &Ctx) override {
143         Arena = std::make_unique<syntax::Arena>(Ctx.getSourceManager(),
144                                                 Ctx.getLangOpts(),
145                                                 std::move(*Tokens).consume());
146         Tokens = nullptr; // make sure we fail if this gets called twice.
147         Root = syntax::buildSyntaxTree(*Arena, *Ctx.getTranslationUnitDecl());
148       }
149 
150     private:
151       syntax::TranslationUnit *&Root;
152       std::unique_ptr<syntax::Arena> &Arena;
153       std::unique_ptr<syntax::TokenCollector> Tokens;
154     };
155 
156     class BuildSyntaxTreeAction : public ASTFrontendAction {
157     public:
158       BuildSyntaxTreeAction(syntax::TranslationUnit *&Root,
159                             std::unique_ptr<syntax::Arena> &Arena)
160           : Root(Root), Arena(Arena) {}
161 
162       std::unique_ptr<ASTConsumer>
163       CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override {
164         // We start recording the tokens, ast consumer will take on the result.
165         auto Tokens =
166             std::make_unique<syntax::TokenCollector>(CI.getPreprocessor());
167         return std::make_unique<BuildSyntaxTree>(Root, Arena,
168                                                  std::move(Tokens));
169       }
170 
171     private:
172       syntax::TranslationUnit *&Root;
173       std::unique_ptr<syntax::Arena> &Arena;
174     };
175 
176     constexpr const char *FileName = "./input.cpp";
177     FS->addFile(FileName, time_t(), llvm::MemoryBuffer::getMemBufferCopy(""));
178 
179     if (!Diags->getClient())
180       Diags->setClient(new TextDiagnosticPrinter(llvm::errs(), DiagOpts.get()));
181     Diags->setSeverityForGroup(diag::Flavor::WarningOrError, "unused-value",
182                                diag::Severity::Ignored, SourceLocation());
183 
184     // Prepare to run a compiler.
185     std::vector<std::string> Args = {
186         "syntax-test",
187         "-fsyntax-only",
188     };
189     llvm::copy(ClangConfig.getCommandLineArgs(), std::back_inserter(Args));
190     Args.push_back(FileName);
191 
192     std::vector<const char *> ArgsCStr;
193     for (const std::string &arg : Args) {
194       ArgsCStr.push_back(arg.c_str());
195     }
196 
197     Invocation = createInvocationFromCommandLine(ArgsCStr, Diags, FS);
198     assert(Invocation);
199     Invocation->getFrontendOpts().DisableFree = false;
200     Invocation->getPreprocessorOpts().addRemappedFile(
201         FileName, llvm::MemoryBuffer::getMemBufferCopy(Code).release());
202     CompilerInstance Compiler;
203     Compiler.setInvocation(Invocation);
204     Compiler.setDiagnostics(Diags.get());
205     Compiler.setFileManager(FileMgr.get());
206     Compiler.setSourceManager(SourceMgr.get());
207 
208     syntax::TranslationUnit *Root = nullptr;
209     BuildSyntaxTreeAction Recorder(Root, this->Arena);
210 
211     // Action could not be executed but the frontend didn't identify any errors
212     // in the code ==> problem in setting up the action.
213     if (!Compiler.ExecuteAction(Recorder) &&
214         Diags->getClient()->getNumErrors() == 0) {
215       ADD_FAILURE() << "failed to run the frontend";
216       std::abort();
217     }
218     return Root;
219   }
220 
221   ::testing::AssertionResult treeDumpEqual(StringRef Code, StringRef Tree) {
222     SCOPED_TRACE(llvm::join(GetParam().getCommandLineArgs(), " "));
223 
224     auto *Root = buildTree(Code, GetParam());
225     if (Diags->getClient()->getNumErrors() != 0) {
226       return ::testing::AssertionFailure()
227              << "Source file has syntax errors, they were printed to the test "
228                 "log";
229     }
230     std::string Actual = std::string(StringRef(Root->dump(*Arena)).trim());
231     // EXPECT_EQ shows the diff between the two strings if they are different.
232     EXPECT_EQ(Tree.trim().str(), Actual);
233     if (Actual != Tree.trim().str()) {
234       return ::testing::AssertionFailure();
235     }
236     return ::testing::AssertionSuccess();
237   }
238 
239   // Adds a file to the test VFS.
240   void addFile(llvm::StringRef Path, llvm::StringRef Contents) {
241     if (!FS->addFile(Path, time_t(),
242                      llvm::MemoryBuffer::getMemBufferCopy(Contents))) {
243       ADD_FAILURE() << "could not add a file to VFS: " << Path;
244     }
245   }
246 
247   /// Finds the deepest node in the tree that covers exactly \p R.
248   /// FIXME: implement this efficiently and move to public syntax tree API.
249   syntax::Node *nodeByRange(llvm::Annotations::Range R, syntax::Node *Root) {
250     llvm::ArrayRef<syntax::Token> Toks = tokens(Root);
251 
252     if (Toks.front().location().isFileID() &&
253         Toks.back().location().isFileID() &&
254         syntax::Token::range(*SourceMgr, Toks.front(), Toks.back()) ==
255             syntax::FileRange(SourceMgr->getMainFileID(), R.Begin, R.End))
256       return Root;
257 
258     auto *T = dyn_cast<syntax::Tree>(Root);
259     if (!T)
260       return nullptr;
261     for (auto *C = T->firstChild(); C != nullptr; C = C->nextSibling()) {
262       if (auto *Result = nodeByRange(R, C))
263         return Result;
264     }
265     return nullptr;
266   }
267 
268   // Data fields.
269   llvm::IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts =
270       new DiagnosticOptions();
271   llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
272       new DiagnosticsEngine(new DiagnosticIDs, DiagOpts.get());
273   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS =
274       new llvm::vfs::InMemoryFileSystem;
275   llvm::IntrusiveRefCntPtr<FileManager> FileMgr =
276       new FileManager(FileSystemOptions(), FS);
277   llvm::IntrusiveRefCntPtr<SourceManager> SourceMgr =
278       new SourceManager(*Diags, *FileMgr);
279   std::shared_ptr<CompilerInvocation> Invocation;
280   // Set after calling buildTree().
281   std::unique_ptr<syntax::Arena> Arena;
282 };
283 
284 TEST_P(SyntaxTreeTest, Simple) {
285   EXPECT_TRUE(treeDumpEqual(
286       R"cpp(
287 int main() {}
288 void foo() {}
289 )cpp",
290       R"txt(
291 *: TranslationUnit
292 |-SimpleDeclaration
293 | |-int
294 | |-SimpleDeclarator
295 | | |-main
296 | | `-ParametersAndQualifiers
297 | |   |-(
298 | |   `-)
299 | `-CompoundStatement
300 |   |-{
301 |   `-}
302 `-SimpleDeclaration
303   |-void
304   |-SimpleDeclarator
305   | |-foo
306   | `-ParametersAndQualifiers
307   |   |-(
308   |   `-)
309   `-CompoundStatement
310     |-{
311     `-}
312 )txt"));
313 }
314 
315 TEST_P(SyntaxTreeTest, SimpleVariable) {
316   EXPECT_TRUE(treeDumpEqual(
317       R"cpp(
318 int a;
319 int b = 42;
320 )cpp",
321       R"txt(
322 *: TranslationUnit
323 |-SimpleDeclaration
324 | |-int
325 | |-SimpleDeclarator
326 | | `-a
327 | `-;
328 `-SimpleDeclaration
329   |-int
330   |-SimpleDeclarator
331   | |-b
332   | |-=
333   | `-IntegerLiteralExpression
334   |   `-42
335   `-;
336 )txt"));
337 }
338 
339 TEST_P(SyntaxTreeTest, SimpleFunction) {
340   EXPECT_TRUE(treeDumpEqual(
341       R"cpp(
342 void foo(int a, int b) {}
343 )cpp",
344       R"txt(
345 *: TranslationUnit
346 `-SimpleDeclaration
347   |-void
348   |-SimpleDeclarator
349   | |-foo
350   | `-ParametersAndQualifiers
351   |   |-(
352   |   |-SimpleDeclaration
353   |   | |-int
354   |   | `-SimpleDeclarator
355   |   |   `-a
356   |   |-,
357   |   |-SimpleDeclaration
358   |   | |-int
359   |   | `-SimpleDeclarator
360   |   |   `-b
361   |   `-)
362   `-CompoundStatement
363     |-{
364     `-}
365 )txt"));
366 }
367 
368 TEST_P(SyntaxTreeTest, If) {
369   EXPECT_TRUE(treeDumpEqual(
370       R"cpp(
371 int main() {
372   if (1) {}
373   if (1) {} else if (0) {}
374 }
375 )cpp",
376       R"txt(
377 *: TranslationUnit
378 `-SimpleDeclaration
379   |-int
380   |-SimpleDeclarator
381   | |-main
382   | `-ParametersAndQualifiers
383   |   |-(
384   |   `-)
385   `-CompoundStatement
386     |-{
387     |-IfStatement
388     | |-if
389     | |-(
390     | |-IntegerLiteralExpression
391     | | `-1
392     | |-)
393     | `-CompoundStatement
394     |   |-{
395     |   `-}
396     |-IfStatement
397     | |-if
398     | |-(
399     | |-IntegerLiteralExpression
400     | | `-1
401     | |-)
402     | |-CompoundStatement
403     | | |-{
404     | | `-}
405     | |-else
406     | `-IfStatement
407     |   |-if
408     |   |-(
409     |   |-IntegerLiteralExpression
410     |   | `-0
411     |   |-)
412     |   `-CompoundStatement
413     |     |-{
414     |     `-}
415     `-}
416 )txt"));
417 }
418 
419 TEST_P(SyntaxTreeTest, For) {
420   EXPECT_TRUE(treeDumpEqual(
421       R"cpp(
422 void test() {
423   for (;;)  {}
424 }
425 )cpp",
426       R"txt(
427 *: TranslationUnit
428 `-SimpleDeclaration
429   |-void
430   |-SimpleDeclarator
431   | |-test
432   | `-ParametersAndQualifiers
433   |   |-(
434   |   `-)
435   `-CompoundStatement
436     |-{
437     |-ForStatement
438     | |-for
439     | |-(
440     | |-;
441     | |-;
442     | |-)
443     | `-CompoundStatement
444     |   |-{
445     |   `-}
446     `-}
447 )txt"));
448 }
449 
450 TEST_P(SyntaxTreeTest, RangeBasedFor) {
451   if (!GetParam().isCXX11OrLater()) {
452     return;
453   }
454   EXPECT_TRUE(treeDumpEqual(
455       R"cpp(
456 void test() {
457   int a[3];
458   for (int x : a)
459     ;
460 }
461 )cpp",
462       R"txt(
463 *: TranslationUnit
464 `-SimpleDeclaration
465   |-void
466   |-SimpleDeclarator
467   | |-test
468   | `-ParametersAndQualifiers
469   |   |-(
470   |   `-)
471   `-CompoundStatement
472     |-{
473     |-DeclarationStatement
474     | |-SimpleDeclaration
475     | | |-int
476     | | `-SimpleDeclarator
477     | |   |-a
478     | |   `-ArraySubscript
479     | |     |-[
480     | |     |-IntegerLiteralExpression
481     | |     | `-3
482     | |     `-]
483     | `-;
484     |-RangeBasedForStatement
485     | |-for
486     | |-(
487     | |-SimpleDeclaration
488     | | |-int
489     | | |-SimpleDeclarator
490     | | | `-x
491     | | `-:
492     | |-IdExpression
493     | | `-UnqualifiedId
494     | |   `-a
495     | |-)
496     | `-EmptyStatement
497     |   `-;
498     `-}
499 )txt"));
500 }
501 
502 TEST_P(SyntaxTreeTest, DeclarationStatement) {
503   EXPECT_TRUE(treeDumpEqual(
504       R"cpp(
505 void test() {
506   int a = 10;
507 }
508 )cpp",
509       R"txt(
510 *: TranslationUnit
511 `-SimpleDeclaration
512   |-void
513   |-SimpleDeclarator
514   | |-test
515   | `-ParametersAndQualifiers
516   |   |-(
517   |   `-)
518   `-CompoundStatement
519     |-{
520     |-DeclarationStatement
521     | |-SimpleDeclaration
522     | | |-int
523     | | `-SimpleDeclarator
524     | |   |-a
525     | |   |-=
526     | |   `-IntegerLiteralExpression
527     | |     `-10
528     | `-;
529     `-}
530 )txt"));
531 }
532 
533 TEST_P(SyntaxTreeTest, Switch) {
534   EXPECT_TRUE(treeDumpEqual(
535       R"cpp(
536 void test() {
537   switch (1) {
538     case 0:
539     default:;
540   }
541 }
542 )cpp",
543       R"txt(
544 *: TranslationUnit
545 `-SimpleDeclaration
546   |-void
547   |-SimpleDeclarator
548   | |-test
549   | `-ParametersAndQualifiers
550   |   |-(
551   |   `-)
552   `-CompoundStatement
553     |-{
554     |-SwitchStatement
555     | |-switch
556     | |-(
557     | |-IntegerLiteralExpression
558     | | `-1
559     | |-)
560     | `-CompoundStatement
561     |   |-{
562     |   |-CaseStatement
563     |   | |-case
564     |   | |-IntegerLiteralExpression
565     |   | | `-0
566     |   | |-:
567     |   | `-DefaultStatement
568     |   |   |-default
569     |   |   |-:
570     |   |   `-EmptyStatement
571     |   |     `-;
572     |   `-}
573     `-}
574 )txt"));
575 }
576 
577 TEST_P(SyntaxTreeTest, While) {
578   EXPECT_TRUE(treeDumpEqual(
579       R"cpp(
580 void test() {
581   while (1) { continue; break; }
582 }
583 )cpp",
584       R"txt(
585 *: TranslationUnit
586 `-SimpleDeclaration
587   |-void
588   |-SimpleDeclarator
589   | |-test
590   | `-ParametersAndQualifiers
591   |   |-(
592   |   `-)
593   `-CompoundStatement
594     |-{
595     |-WhileStatement
596     | |-while
597     | |-(
598     | |-IntegerLiteralExpression
599     | | `-1
600     | |-)
601     | `-CompoundStatement
602     |   |-{
603     |   |-ContinueStatement
604     |   | |-continue
605     |   | `-;
606     |   |-BreakStatement
607     |   | |-break
608     |   | `-;
609     |   `-}
610     `-}
611 )txt"));
612 }
613 
614 TEST_P(SyntaxTreeTest, UnhandledStatement) {
615   // Unhandled statements should end up as 'unknown statement'.
616   // This example uses a 'label statement', which does not yet have a syntax
617   // counterpart.
618   EXPECT_TRUE(treeDumpEqual(
619       R"cpp(
620 int main() {
621   foo: return 100;
622 }
623 )cpp",
624       R"txt(
625 *: TranslationUnit
626 `-SimpleDeclaration
627   |-int
628   |-SimpleDeclarator
629   | |-main
630   | `-ParametersAndQualifiers
631   |   |-(
632   |   `-)
633   `-CompoundStatement
634     |-{
635     |-UnknownStatement
636     | |-foo
637     | |-:
638     | `-ReturnStatement
639     |   |-return
640     |   |-IntegerLiteralExpression
641     |   | `-100
642     |   `-;
643     `-}
644 )txt"));
645 }
646 
647 TEST_P(SyntaxTreeTest, Expressions) {
648   // expressions should be wrapped in 'ExpressionStatement' when they appear
649   // in a statement position.
650   EXPECT_TRUE(treeDumpEqual(
651       R"cpp(
652 void test() {
653   test();
654   if (1) test(); else test();
655 }
656 )cpp",
657       R"txt(
658 *: TranslationUnit
659 `-SimpleDeclaration
660   |-void
661   |-SimpleDeclarator
662   | |-test
663   | `-ParametersAndQualifiers
664   |   |-(
665   |   `-)
666   `-CompoundStatement
667     |-{
668     |-ExpressionStatement
669     | |-UnknownExpression
670     | | |-IdExpression
671     | | | `-UnqualifiedId
672     | | |   `-test
673     | | |-(
674     | | `-)
675     | `-;
676     |-IfStatement
677     | |-if
678     | |-(
679     | |-IntegerLiteralExpression
680     | | `-1
681     | |-)
682     | |-ExpressionStatement
683     | | |-UnknownExpression
684     | | | |-IdExpression
685     | | | | `-UnqualifiedId
686     | | | |   `-test
687     | | | |-(
688     | | | `-)
689     | | `-;
690     | |-else
691     | `-ExpressionStatement
692     |   |-UnknownExpression
693     |   | |-IdExpression
694     |   | | `-UnqualifiedId
695     |   | |   `-test
696     |   | |-(
697     |   | `-)
698     |   `-;
699     `-}
700 )txt"));
701 }
702 
703 TEST_P(SyntaxTreeTest, UnqualifiedId) {
704   if (!GetParam().isCXX()) {
705     return;
706   }
707   EXPECT_TRUE(treeDumpEqual(
708       R"cpp(
709 struct X {
710   // TODO: Expose `id-expression` from `Declarator`
711   friend X operator+(const X&, const X&);
712   operator int();
713 };
714 template<typename T>
715 void f(T&);
716 void test(X x) {
717   x;                      // identifier
718   operator+(x, x);        // operator-function-id
719   f<X>(x);                // template-id
720   // TODO: Expose `id-expression` from `MemberExpr`
721   x.operator int();       // conversion-funtion-id
722   x.~X();                 // ~type-name
723 }
724 )cpp",
725       R"txt(
726 *: TranslationUnit
727 |-SimpleDeclaration
728 | |-struct
729 | |-X
730 | |-{
731 | |-UnknownDeclaration
732 | | `-SimpleDeclaration
733 | |   |-friend
734 | |   |-X
735 | |   |-SimpleDeclarator
736 | |   | |-operator
737 | |   | |-+
738 | |   | `-ParametersAndQualifiers
739 | |   |   |-(
740 | |   |   |-SimpleDeclaration
741 | |   |   | |-const
742 | |   |   | |-X
743 | |   |   | `-SimpleDeclarator
744 | |   |   |   `-&
745 | |   |   |-,
746 | |   |   |-SimpleDeclaration
747 | |   |   | |-const
748 | |   |   | |-X
749 | |   |   | `-SimpleDeclarator
750 | |   |   |   `-&
751 | |   |   `-)
752 | |   `-;
753 | |-SimpleDeclaration
754 | | |-SimpleDeclarator
755 | | | |-operator
756 | | | |-int
757 | | | `-ParametersAndQualifiers
758 | | |   |-(
759 | | |   `-)
760 | | `-;
761 | |-}
762 | `-;
763 |-TemplateDeclaration
764 | |-template
765 | |-<
766 | |-UnknownDeclaration
767 | | |-typename
768 | | `-T
769 | |->
770 | `-SimpleDeclaration
771 |   |-void
772 |   |-SimpleDeclarator
773 |   | |-f
774 |   | `-ParametersAndQualifiers
775 |   |   |-(
776 |   |   |-SimpleDeclaration
777 |   |   | |-T
778 |   |   | `-SimpleDeclarator
779 |   |   |   `-&
780 |   |   `-)
781 |   `-;
782 `-SimpleDeclaration
783   |-void
784   |-SimpleDeclarator
785   | |-test
786   | `-ParametersAndQualifiers
787   |   |-(
788   |   |-SimpleDeclaration
789   |   | |-X
790   |   | `-SimpleDeclarator
791   |   |   `-x
792   |   `-)
793   `-CompoundStatement
794     |-{
795     |-ExpressionStatement
796     | |-IdExpression
797     | | `-UnqualifiedId
798     | |   `-x
799     | `-;
800     |-ExpressionStatement
801     | |-UnknownExpression
802     | | |-IdExpression
803     | | | `-UnqualifiedId
804     | | |   |-operator
805     | | |   `-+
806     | | |-(
807     | | |-IdExpression
808     | | | `-UnqualifiedId
809     | | |   `-x
810     | | |-,
811     | | |-IdExpression
812     | | | `-UnqualifiedId
813     | | |   `-x
814     | | `-)
815     | `-;
816     |-ExpressionStatement
817     | |-UnknownExpression
818     | | |-IdExpression
819     | | | `-UnqualifiedId
820     | | |   |-f
821     | | |   |-<
822     | | |   |-X
823     | | |   `->
824     | | |-(
825     | | |-IdExpression
826     | | | `-UnqualifiedId
827     | | |   `-x
828     | | `-)
829     | `-;
830     |-ExpressionStatement
831     | |-UnknownExpression
832     | | |-UnknownExpression
833     | | | |-IdExpression
834     | | | | `-UnqualifiedId
835     | | | |   `-x
836     | | | |-.
837     | | | |-operator
838     | | | `-int
839     | | |-(
840     | | `-)
841     | `-;
842     |-ExpressionStatement
843     | |-UnknownExpression
844     | | |-UnknownExpression
845     | | | |-IdExpression
846     | | | | `-UnqualifiedId
847     | | | |   `-x
848     | | | |-.
849     | | | |-~
850     | | | `-X
851     | | |-(
852     | | `-)
853     | `-;
854     `-}
855 )txt"));
856 }
857 
858 TEST_P(SyntaxTreeTest, UnqualifiedIdCxx11OrLater) {
859   if (!GetParam().isCXX11OrLater()) {
860     return;
861   }
862   EXPECT_TRUE(treeDumpEqual(
863       R"cpp(
864 struct X { };
865 unsigned operator "" _w(long long unsigned);
866 void test(X x) {
867   operator "" _w(1llu);   // literal-operator-id
868   // TODO: Expose `id-expression` from `MemberExpr`
869   x.~decltype(x)();       // ~decltype-specifier
870 }
871 )cpp",
872       R"txt(
873 *: TranslationUnit
874 |-SimpleDeclaration
875 | |-struct
876 | |-X
877 | |-{
878 | |-}
879 | `-;
880 |-SimpleDeclaration
881 | |-unsigned
882 | |-SimpleDeclarator
883 | | |-operator
884 | | |-""
885 | | |-_w
886 | | `-ParametersAndQualifiers
887 | |   |-(
888 | |   |-SimpleDeclaration
889 | |   | |-long
890 | |   | |-long
891 | |   | `-unsigned
892 | |   `-)
893 | `-;
894 `-SimpleDeclaration
895   |-void
896   |-SimpleDeclarator
897   | |-test
898   | `-ParametersAndQualifiers
899   |   |-(
900   |   |-SimpleDeclaration
901   |   | |-X
902   |   | `-SimpleDeclarator
903   |   |   `-x
904   |   `-)
905   `-CompoundStatement
906     |-{
907     |-ExpressionStatement
908     | |-UnknownExpression
909     | | |-IdExpression
910     | | | `-UnqualifiedId
911     | | |   |-operator
912     | | |   |-""
913     | | |   `-_w
914     | | |-(
915     | | |-IntegerLiteralExpression
916     | | | `-1llu
917     | | `-)
918     | `-;
919     |-ExpressionStatement
920     | |-UnknownExpression
921     | | |-UnknownExpression
922     | | | |-IdExpression
923     | | | | `-UnqualifiedId
924     | | | |   `-x
925     | | | |-.
926     | | | `-~
927     | | |-decltype
928     | | |-(
929     | | |-x
930     | | |-)
931     | | |-(
932     | | `-)
933     | `-;
934     `-}
935 )txt"));
936 }
937 
938 TEST_P(SyntaxTreeTest, QualifiedId) {
939   if (!GetParam().isCXX()) {
940     return;
941   }
942   EXPECT_TRUE(treeDumpEqual(
943       R"cpp(
944 namespace a {
945   struct S {
946     template<typename T>
947     static T f(){}
948   };
949 }
950 void test() {
951   ::              // global-namespace-specifier
952   a::             // namespace-specifier
953   S::             // type-name-specifier
954   f<int>();
955 }
956 )cpp",
957       R"txt(
958 *: TranslationUnit
959 |-NamespaceDefinition
960 | |-namespace
961 | |-a
962 | |-{
963 | |-SimpleDeclaration
964 | | |-struct
965 | | |-S
966 | | |-{
967 | | |-TemplateDeclaration
968 | | | |-template
969 | | | |-<
970 | | | |-UnknownDeclaration
971 | | | | |-typename
972 | | | | `-T
973 | | | |->
974 | | | `-SimpleDeclaration
975 | | |   |-static
976 | | |   |-T
977 | | |   |-SimpleDeclarator
978 | | |   | |-f
979 | | |   | `-ParametersAndQualifiers
980 | | |   |   |-(
981 | | |   |   `-)
982 | | |   `-CompoundStatement
983 | | |     |-{
984 | | |     `-}
985 | | |-}
986 | | `-;
987 | `-}
988 `-SimpleDeclaration
989   |-void
990   |-SimpleDeclarator
991   | |-test
992   | `-ParametersAndQualifiers
993   |   |-(
994   |   `-)
995   `-CompoundStatement
996     |-{
997     |-ExpressionStatement
998     | |-UnknownExpression
999     | | |-IdExpression
1000     | | | |-NestedNameSpecifier
1001     | | | | |-NameSpecifier
1002     | | | | | `-::
1003     | | | | |-NameSpecifier
1004     | | | | | |-a
1005     | | | | | `-::
1006     | | | | `-NameSpecifier
1007     | | | |   |-S
1008     | | | |   `-::
1009     | | | `-UnqualifiedId
1010     | | |   |-f
1011     | | |   |-<
1012     | | |   |-int
1013     | | |   `->
1014     | | |-(
1015     | | `-)
1016     | `-;
1017     `-}
1018 )txt"));
1019 }
1020 
1021 TEST_P(SyntaxTreeTest, QualifiedIdWithTemplateKeyword) {
1022   if (!GetParam().isCXX()) {
1023     return;
1024   }
1025   if (GetParam().hasDelayedTemplateParsing()) {
1026     // FIXME: Make this test work on Windows by generating the expected syntax
1027     // tree when `-fdelayed-template-parsing` is active.
1028     return;
1029   }
1030   EXPECT_TRUE(treeDumpEqual(
1031       R"cpp(
1032 struct X {
1033   template<int> static void f();
1034   template<int>
1035   struct Y {
1036     static void f();
1037   };
1038 };
1039 template<typename T> void test() {
1040   // TODO: Expose `id-expression` from `DependentScopeDeclRefExpr`
1041   T::template f<0>();     // nested-name-specifier template unqualified-id
1042   T::template Y<0>::f();  // nested-name-specifier template :: unqualified-id
1043 }
1044 )cpp",
1045       R"txt(
1046 *: TranslationUnit
1047 |-SimpleDeclaration
1048 | |-struct
1049 | |-X
1050 | |-{
1051 | |-TemplateDeclaration
1052 | | |-template
1053 | | |-<
1054 | | |-SimpleDeclaration
1055 | | | `-int
1056 | | |->
1057 | | `-SimpleDeclaration
1058 | |   |-static
1059 | |   |-void
1060 | |   |-SimpleDeclarator
1061 | |   | |-f
1062 | |   | `-ParametersAndQualifiers
1063 | |   |   |-(
1064 | |   |   `-)
1065 | |   `-;
1066 | |-TemplateDeclaration
1067 | | |-template
1068 | | |-<
1069 | | |-SimpleDeclaration
1070 | | | `-int
1071 | | |->
1072 | | `-SimpleDeclaration
1073 | |   |-struct
1074 | |   |-Y
1075 | |   |-{
1076 | |   |-SimpleDeclaration
1077 | |   | |-static
1078 | |   | |-void
1079 | |   | |-SimpleDeclarator
1080 | |   | | |-f
1081 | |   | | `-ParametersAndQualifiers
1082 | |   | |   |-(
1083 | |   | |   `-)
1084 | |   | `-;
1085 | |   |-}
1086 | |   `-;
1087 | |-}
1088 | `-;
1089 `-TemplateDeclaration
1090   |-template
1091   |-<
1092   |-UnknownDeclaration
1093   | |-typename
1094   | `-T
1095   |->
1096   `-SimpleDeclaration
1097     |-void
1098     |-SimpleDeclarator
1099     | |-test
1100     | `-ParametersAndQualifiers
1101     |   |-(
1102     |   `-)
1103     `-CompoundStatement
1104       |-{
1105       |-ExpressionStatement
1106       | |-UnknownExpression
1107       | | |-UnknownExpression
1108       | | | |-T
1109       | | | |-::
1110       | | | |-template
1111       | | | |-f
1112       | | | |-<
1113       | | | |-IntegerLiteralExpression
1114       | | | | `-0
1115       | | | `->
1116       | | |-(
1117       | | `-)
1118       | `-;
1119       |-ExpressionStatement
1120       | |-UnknownExpression
1121       | | |-UnknownExpression
1122       | | | |-T
1123       | | | |-::
1124       | | | |-template
1125       | | | |-Y
1126       | | | |-<
1127       | | | |-IntegerLiteralExpression
1128       | | | | `-0
1129       | | | |->
1130       | | | |-::
1131       | | | `-f
1132       | | |-(
1133       | | `-)
1134       | `-;
1135       `-}
1136 )txt"));
1137 }
1138 
1139 TEST_P(SyntaxTreeTest, QualifiedIdDecltype) {
1140   if (!GetParam().isCXX11OrLater()) {
1141     return;
1142   }
1143   EXPECT_TRUE(treeDumpEqual(
1144       R"cpp(
1145 struct S {
1146   static void f(){}
1147 };
1148 void test(S s) {
1149   decltype(s)::   // decltype-specifier
1150       f();
1151 }
1152 )cpp",
1153       R"txt(
1154 *: TranslationUnit
1155 |-SimpleDeclaration
1156 | |-struct
1157 | |-S
1158 | |-{
1159 | |-SimpleDeclaration
1160 | | |-static
1161 | | |-void
1162 | | |-SimpleDeclarator
1163 | | | |-f
1164 | | | `-ParametersAndQualifiers
1165 | | |   |-(
1166 | | |   `-)
1167 | | `-CompoundStatement
1168 | |   |-{
1169 | |   `-}
1170 | |-}
1171 | `-;
1172 `-SimpleDeclaration
1173   |-void
1174   |-SimpleDeclarator
1175   | |-test
1176   | `-ParametersAndQualifiers
1177   |   |-(
1178   |   |-SimpleDeclaration
1179   |   | |-S
1180   |   | `-SimpleDeclarator
1181   |   |   `-s
1182   |   `-)
1183   `-CompoundStatement
1184     |-{
1185     |-ExpressionStatement
1186     | |-UnknownExpression
1187     | | |-IdExpression
1188     | | | |-NestedNameSpecifier
1189     | | | | `-NameSpecifier
1190     | | | |   |-decltype
1191     | | | |   |-(
1192     | | | |   |-IdExpression
1193     | | | |   | `-UnqualifiedId
1194     | | | |   |   `-s
1195     | | | |   |-)
1196     | | | |   `-::
1197     | | | `-UnqualifiedId
1198     | | |   `-f
1199     | | |-(
1200     | | `-)
1201     | `-;
1202     `-}
1203 )txt"));
1204 }
1205 
1206 TEST_P(SyntaxTreeTest, CxxNullPtrLiteral) {
1207   if (!GetParam().isCXX11OrLater()) {
1208     return;
1209   }
1210   EXPECT_TRUE(treeDumpEqual(
1211       R"cpp(
1212 void test() {
1213   nullptr;
1214 }
1215 )cpp",
1216       R"txt(
1217 *: TranslationUnit
1218 `-SimpleDeclaration
1219   |-void
1220   |-SimpleDeclarator
1221   | |-test
1222   | `-ParametersAndQualifiers
1223   |   |-(
1224   |   `-)
1225   `-CompoundStatement
1226     |-{
1227     |-ExpressionStatement
1228     | |-CxxNullPtrExpression
1229     | | `-nullptr
1230     | `-;
1231     `-}
1232 )txt"));
1233 }
1234 
1235 TEST_P(SyntaxTreeTest, BoolLiteral) {
1236   if (GetParam().hasBoolType()) {
1237     return;
1238   }
1239   EXPECT_TRUE(treeDumpEqual(
1240       R"cpp(
1241 void test() {
1242   true;
1243   false;
1244 }
1245 )cpp",
1246       R"txt(
1247 *: TranslationUnit
1248 `-SimpleDeclaration
1249   |-void
1250   |-SimpleDeclarator
1251   | |-test
1252   | `-ParametersAndQualifiers
1253   |   |-(
1254   |   `-)
1255   `-CompoundStatement
1256     |-{
1257     |-ExpressionStatement
1258     | |-BoolLiteralExpression
1259     | | `-true
1260     | `-;
1261     |-ExpressionStatement
1262     | |-BoolLiteralExpression
1263     | | `-false
1264     | `-;
1265     `-}
1266 )txt"));
1267 }
1268 
1269 TEST_P(SyntaxTreeTest, IntegerLiteral) {
1270   EXPECT_TRUE(treeDumpEqual(
1271       R"cpp(
1272 void test() {
1273   12;
1274   12u;
1275   12l;
1276   12ul;
1277   014;
1278   0XC;
1279 }
1280 )cpp",
1281       R"txt(
1282 *: TranslationUnit
1283 `-SimpleDeclaration
1284   |-void
1285   |-SimpleDeclarator
1286   | |-test
1287   | `-ParametersAndQualifiers
1288   |   |-(
1289   |   `-)
1290   `-CompoundStatement
1291     |-{
1292     |-ExpressionStatement
1293     | |-IntegerLiteralExpression
1294     | | `-12
1295     | `-;
1296     |-ExpressionStatement
1297     | |-IntegerLiteralExpression
1298     | | `-12u
1299     | `-;
1300     |-ExpressionStatement
1301     | |-IntegerLiteralExpression
1302     | | `-12l
1303     | `-;
1304     |-ExpressionStatement
1305     | |-IntegerLiteralExpression
1306     | | `-12ul
1307     | `-;
1308     |-ExpressionStatement
1309     | |-IntegerLiteralExpression
1310     | | `-014
1311     | `-;
1312     |-ExpressionStatement
1313     | |-IntegerLiteralExpression
1314     | | `-0XC
1315     | `-;
1316     `-}
1317 )txt"));
1318 }
1319 
1320 TEST_P(SyntaxTreeTest, IntegerLiteralLongLong) {
1321   if (!GetParam().isCXX11OrLater()) {
1322     return;
1323   }
1324   EXPECT_TRUE(treeDumpEqual(
1325       R"cpp(
1326 void test() {
1327   12ll;
1328   12ull;
1329 }
1330 )cpp",
1331       R"txt(
1332 *: TranslationUnit
1333 `-SimpleDeclaration
1334   |-void
1335   |-SimpleDeclarator
1336   | |-test
1337   | `-ParametersAndQualifiers
1338   |   |-(
1339   |   `-)
1340   `-CompoundStatement
1341     |-{
1342     |-ExpressionStatement
1343     | |-IntegerLiteralExpression
1344     | | `-12ll
1345     | `-;
1346     |-ExpressionStatement
1347     | |-IntegerLiteralExpression
1348     | | `-12ull
1349     | `-;
1350     `-}
1351 )txt"));
1352 }
1353 
1354 TEST_P(SyntaxTreeTest, IntegerLiteralBinary) {
1355   if (!GetParam().isCXX14OrLater()) {
1356     return;
1357   }
1358   EXPECT_TRUE(treeDumpEqual(
1359       R"cpp(
1360 void test() {
1361   0b1100;
1362 }
1363 )cpp",
1364       R"txt(
1365 *: TranslationUnit
1366 `-SimpleDeclaration
1367   |-void
1368   |-SimpleDeclarator
1369   | |-test
1370   | `-ParametersAndQualifiers
1371   |   |-(
1372   |   `-)
1373   `-CompoundStatement
1374     |-{
1375     |-ExpressionStatement
1376     | |-IntegerLiteralExpression
1377     | | `-0b1100
1378     | `-;
1379     `-}
1380 )txt"));
1381 }
1382 
1383 TEST_P(SyntaxTreeTest, IntegerLiteralWithDigitSeparators) {
1384   if (!GetParam().isCXX14OrLater()) {
1385     return;
1386   }
1387   EXPECT_TRUE(treeDumpEqual(
1388       R"cpp(
1389 void test() {
1390   1'2'0ull;
1391 }
1392 )cpp",
1393       R"txt(
1394 *: TranslationUnit
1395 `-SimpleDeclaration
1396   |-void
1397   |-SimpleDeclarator
1398   | |-test
1399   | `-ParametersAndQualifiers
1400   |   |-(
1401   |   `-)
1402   `-CompoundStatement
1403     |-{
1404     |-ExpressionStatement
1405     | |-IntegerLiteralExpression
1406     | | `-1'2'0ull
1407     | `-;
1408     `-}
1409 )txt"));
1410 }
1411 
1412 TEST_P(SyntaxTreeTest, PostfixUnaryOperator) {
1413   EXPECT_TRUE(treeDumpEqual(
1414       R"cpp(
1415 void test(int a) {
1416   a++;
1417   a--;
1418 }
1419 )cpp",
1420       R"txt(
1421 *: TranslationUnit
1422 `-SimpleDeclaration
1423   |-void
1424   |-SimpleDeclarator
1425   | |-test
1426   | `-ParametersAndQualifiers
1427   |   |-(
1428   |   |-SimpleDeclaration
1429   |   | |-int
1430   |   | `-SimpleDeclarator
1431   |   |   `-a
1432   |   `-)
1433   `-CompoundStatement
1434     |-{
1435     |-ExpressionStatement
1436     | |-PostfixUnaryOperatorExpression
1437     | | |-IdExpression
1438     | | | `-UnqualifiedId
1439     | | |   `-a
1440     | | `-++
1441     | `-;
1442     |-ExpressionStatement
1443     | |-PostfixUnaryOperatorExpression
1444     | | |-IdExpression
1445     | | | `-UnqualifiedId
1446     | | |   `-a
1447     | | `---
1448     | `-;
1449     `-}
1450 )txt"));
1451 }
1452 
1453 TEST_P(SyntaxTreeTest, PrefixUnaryOperator) {
1454   EXPECT_TRUE(treeDumpEqual(
1455       R"cpp(
1456 void test(int a, int *ap) {
1457   --a; ++a;
1458   ~a;
1459   -a;
1460   +a;
1461   &a;
1462   *ap;
1463   !a;
1464   __real a; __imag a;
1465 }
1466 )cpp",
1467       R"txt(
1468 *: TranslationUnit
1469 `-SimpleDeclaration
1470   |-void
1471   |-SimpleDeclarator
1472   | |-test
1473   | `-ParametersAndQualifiers
1474   |   |-(
1475   |   |-SimpleDeclaration
1476   |   | |-int
1477   |   | `-SimpleDeclarator
1478   |   |   `-a
1479   |   |-,
1480   |   |-SimpleDeclaration
1481   |   | |-int
1482   |   | `-SimpleDeclarator
1483   |   |   |-*
1484   |   |   `-ap
1485   |   `-)
1486   `-CompoundStatement
1487     |-{
1488     |-ExpressionStatement
1489     | |-PrefixUnaryOperatorExpression
1490     | | |---
1491     | | `-IdExpression
1492     | |   `-UnqualifiedId
1493     | |     `-a
1494     | `-;
1495     |-ExpressionStatement
1496     | |-PrefixUnaryOperatorExpression
1497     | | |-++
1498     | | `-IdExpression
1499     | |   `-UnqualifiedId
1500     | |     `-a
1501     | `-;
1502     |-ExpressionStatement
1503     | |-PrefixUnaryOperatorExpression
1504     | | |-~
1505     | | `-IdExpression
1506     | |   `-UnqualifiedId
1507     | |     `-a
1508     | `-;
1509     |-ExpressionStatement
1510     | |-PrefixUnaryOperatorExpression
1511     | | |--
1512     | | `-IdExpression
1513     | |   `-UnqualifiedId
1514     | |     `-a
1515     | `-;
1516     |-ExpressionStatement
1517     | |-PrefixUnaryOperatorExpression
1518     | | |-+
1519     | | `-IdExpression
1520     | |   `-UnqualifiedId
1521     | |     `-a
1522     | `-;
1523     |-ExpressionStatement
1524     | |-PrefixUnaryOperatorExpression
1525     | | |-&
1526     | | `-IdExpression
1527     | |   `-UnqualifiedId
1528     | |     `-a
1529     | `-;
1530     |-ExpressionStatement
1531     | |-PrefixUnaryOperatorExpression
1532     | | |-*
1533     | | `-IdExpression
1534     | |   `-UnqualifiedId
1535     | |     `-ap
1536     | `-;
1537     |-ExpressionStatement
1538     | |-PrefixUnaryOperatorExpression
1539     | | |-!
1540     | | `-IdExpression
1541     | |   `-UnqualifiedId
1542     | |     `-a
1543     | `-;
1544     |-ExpressionStatement
1545     | |-PrefixUnaryOperatorExpression
1546     | | |-__real
1547     | | `-IdExpression
1548     | |   `-UnqualifiedId
1549     | |     `-a
1550     | `-;
1551     |-ExpressionStatement
1552     | |-PrefixUnaryOperatorExpression
1553     | | |-__imag
1554     | | `-IdExpression
1555     | |   `-UnqualifiedId
1556     | |     `-a
1557     | `-;
1558     `-}
1559 )txt"));
1560 }
1561 
1562 TEST_P(SyntaxTreeTest, PrefixUnaryOperatorCxx) {
1563   if (!GetParam().isCXX()) {
1564     return;
1565   }
1566   EXPECT_TRUE(treeDumpEqual(
1567       R"cpp(
1568 void test(int a, bool b) {
1569   compl a;
1570   not b;
1571 }
1572 )cpp",
1573       R"txt(
1574 *: TranslationUnit
1575 `-SimpleDeclaration
1576   |-void
1577   |-SimpleDeclarator
1578   | |-test
1579   | `-ParametersAndQualifiers
1580   |   |-(
1581   |   |-SimpleDeclaration
1582   |   | |-int
1583   |   | `-SimpleDeclarator
1584   |   |   `-a
1585   |   |-,
1586   |   |-SimpleDeclaration
1587   |   | |-bool
1588   |   | `-SimpleDeclarator
1589   |   |   `-b
1590   |   `-)
1591   `-CompoundStatement
1592     |-{
1593     |-ExpressionStatement
1594     | |-PrefixUnaryOperatorExpression
1595     | | |-compl
1596     | | `-IdExpression
1597     | |   `-UnqualifiedId
1598     | |     `-a
1599     | `-;
1600     |-ExpressionStatement
1601     | |-PrefixUnaryOperatorExpression
1602     | | |-not
1603     | | `-IdExpression
1604     | |   `-UnqualifiedId
1605     | |     `-b
1606     | `-;
1607     `-}
1608 )txt"));
1609 }
1610 
1611 TEST_P(SyntaxTreeTest, BinaryOperator) {
1612   EXPECT_TRUE(treeDumpEqual(
1613       R"cpp(
1614 void test(int a) {
1615   1 - 2;
1616   1 == 2;
1617   a = 1;
1618   a <<= 1;
1619   1 || 0;
1620   1 & 2;
1621   a ^= 3;
1622 }
1623 )cpp",
1624       R"txt(
1625 *: TranslationUnit
1626 `-SimpleDeclaration
1627   |-void
1628   |-SimpleDeclarator
1629   | |-test
1630   | `-ParametersAndQualifiers
1631   |   |-(
1632   |   |-SimpleDeclaration
1633   |   | |-int
1634   |   | `-SimpleDeclarator
1635   |   |   `-a
1636   |   `-)
1637   `-CompoundStatement
1638     |-{
1639     |-ExpressionStatement
1640     | |-BinaryOperatorExpression
1641     | | |-IntegerLiteralExpression
1642     | | | `-1
1643     | | |--
1644     | | `-IntegerLiteralExpression
1645     | |   `-2
1646     | `-;
1647     |-ExpressionStatement
1648     | |-BinaryOperatorExpression
1649     | | |-IntegerLiteralExpression
1650     | | | `-1
1651     | | |-==
1652     | | `-IntegerLiteralExpression
1653     | |   `-2
1654     | `-;
1655     |-ExpressionStatement
1656     | |-BinaryOperatorExpression
1657     | | |-IdExpression
1658     | | | `-UnqualifiedId
1659     | | |   `-a
1660     | | |-=
1661     | | `-IntegerLiteralExpression
1662     | |   `-1
1663     | `-;
1664     |-ExpressionStatement
1665     | |-BinaryOperatorExpression
1666     | | |-IdExpression
1667     | | | `-UnqualifiedId
1668     | | |   `-a
1669     | | |-<<=
1670     | | `-IntegerLiteralExpression
1671     | |   `-1
1672     | `-;
1673     |-ExpressionStatement
1674     | |-BinaryOperatorExpression
1675     | | |-IntegerLiteralExpression
1676     | | | `-1
1677     | | |-||
1678     | | `-IntegerLiteralExpression
1679     | |   `-0
1680     | `-;
1681     |-ExpressionStatement
1682     | |-BinaryOperatorExpression
1683     | | |-IntegerLiteralExpression
1684     | | | `-1
1685     | | |-&
1686     | | `-IntegerLiteralExpression
1687     | |   `-2
1688     | `-;
1689     |-ExpressionStatement
1690     | |-BinaryOperatorExpression
1691     | | |-IdExpression
1692     | | | `-UnqualifiedId
1693     | | |   `-a
1694     | | |-^=
1695     | | `-IntegerLiteralExpression
1696     | |   `-3
1697     | `-;
1698     `-}
1699 )txt"));
1700 }
1701 
1702 TEST_P(SyntaxTreeTest, BinaryOperatorCxx) {
1703   if (!GetParam().isCXX()) {
1704     return;
1705   }
1706   EXPECT_TRUE(treeDumpEqual(
1707       R"cpp(
1708 void test(int a) {
1709   true || false;
1710   true or false;
1711   1 bitand 2;
1712   a xor_eq 3;
1713 }
1714 )cpp",
1715       R"txt(
1716 *: TranslationUnit
1717 `-SimpleDeclaration
1718   |-void
1719   |-SimpleDeclarator
1720   | |-test
1721   | `-ParametersAndQualifiers
1722   |   |-(
1723   |   |-SimpleDeclaration
1724   |   | |-int
1725   |   | `-SimpleDeclarator
1726   |   |   `-a
1727   |   `-)
1728   `-CompoundStatement
1729     |-{
1730     |-ExpressionStatement
1731     | |-BinaryOperatorExpression
1732     | | |-BoolLiteralExpression
1733     | | | `-true
1734     | | |-||
1735     | | `-BoolLiteralExpression
1736     | |   `-false
1737     | `-;
1738     |-ExpressionStatement
1739     | |-BinaryOperatorExpression
1740     | | |-BoolLiteralExpression
1741     | | | `-true
1742     | | |-or
1743     | | `-BoolLiteralExpression
1744     | |   `-false
1745     | `-;
1746     |-ExpressionStatement
1747     | |-BinaryOperatorExpression
1748     | | |-IntegerLiteralExpression
1749     | | | `-1
1750     | | |-bitand
1751     | | `-IntegerLiteralExpression
1752     | |   `-2
1753     | `-;
1754     |-ExpressionStatement
1755     | |-BinaryOperatorExpression
1756     | | |-IdExpression
1757     | | | `-UnqualifiedId
1758     | | |   `-a
1759     | | |-xor_eq
1760     | | `-IntegerLiteralExpression
1761     | |   `-3
1762     | `-;
1763     `-}
1764 )txt"));
1765 }
1766 
1767 TEST_P(SyntaxTreeTest, NestedBinaryOperator) {
1768   EXPECT_TRUE(treeDumpEqual(
1769       R"cpp(
1770 void test(int a, int b) {
1771   (1 + 2) * (4 / 2);
1772   a + b + 42;
1773   a = b = 42;
1774   a + b * 4 + 2;
1775   a % 2 + b * 42;
1776 }
1777 )cpp",
1778       R"txt(
1779 *: TranslationUnit
1780 `-SimpleDeclaration
1781   |-void
1782   |-SimpleDeclarator
1783   | |-test
1784   | `-ParametersAndQualifiers
1785   |   |-(
1786   |   |-SimpleDeclaration
1787   |   | |-int
1788   |   | `-SimpleDeclarator
1789   |   |   `-a
1790   |   |-,
1791   |   |-SimpleDeclaration
1792   |   | |-int
1793   |   | `-SimpleDeclarator
1794   |   |   `-b
1795   |   `-)
1796   `-CompoundStatement
1797     |-{
1798     |-ExpressionStatement
1799     | |-BinaryOperatorExpression
1800     | | |-UnknownExpression
1801     | | | |-(
1802     | | | |-BinaryOperatorExpression
1803     | | | | |-IntegerLiteralExpression
1804     | | | | | `-1
1805     | | | | |-+
1806     | | | | `-IntegerLiteralExpression
1807     | | | |   `-2
1808     | | | `-)
1809     | | |-*
1810     | | `-UnknownExpression
1811     | |   |-(
1812     | |   |-BinaryOperatorExpression
1813     | |   | |-IntegerLiteralExpression
1814     | |   | | `-4
1815     | |   | |-/
1816     | |   | `-IntegerLiteralExpression
1817     | |   |   `-2
1818     | |   `-)
1819     | `-;
1820     |-ExpressionStatement
1821     | |-BinaryOperatorExpression
1822     | | |-BinaryOperatorExpression
1823     | | | |-IdExpression
1824     | | | | `-UnqualifiedId
1825     | | | |   `-a
1826     | | | |-+
1827     | | | `-IdExpression
1828     | | |   `-UnqualifiedId
1829     | | |     `-b
1830     | | |-+
1831     | | `-IntegerLiteralExpression
1832     | |   `-42
1833     | `-;
1834     |-ExpressionStatement
1835     | |-BinaryOperatorExpression
1836     | | |-IdExpression
1837     | | | `-UnqualifiedId
1838     | | |   `-a
1839     | | |-=
1840     | | `-BinaryOperatorExpression
1841     | |   |-IdExpression
1842     | |   | `-UnqualifiedId
1843     | |   |   `-b
1844     | |   |-=
1845     | |   `-IntegerLiteralExpression
1846     | |     `-42
1847     | `-;
1848     |-ExpressionStatement
1849     | |-BinaryOperatorExpression
1850     | | |-BinaryOperatorExpression
1851     | | | |-IdExpression
1852     | | | | `-UnqualifiedId
1853     | | | |   `-a
1854     | | | |-+
1855     | | | `-BinaryOperatorExpression
1856     | | |   |-IdExpression
1857     | | |   | `-UnqualifiedId
1858     | | |   |   `-b
1859     | | |   |-*
1860     | | |   `-IntegerLiteralExpression
1861     | | |     `-4
1862     | | |-+
1863     | | `-IntegerLiteralExpression
1864     | |   `-2
1865     | `-;
1866     |-ExpressionStatement
1867     | |-BinaryOperatorExpression
1868     | | |-BinaryOperatorExpression
1869     | | | |-IdExpression
1870     | | | | `-UnqualifiedId
1871     | | | |   `-a
1872     | | | |-%
1873     | | | `-IntegerLiteralExpression
1874     | | |   `-2
1875     | | |-+
1876     | | `-BinaryOperatorExpression
1877     | |   |-IdExpression
1878     | |   | `-UnqualifiedId
1879     | |   |   `-b
1880     | |   |-*
1881     | |   `-IntegerLiteralExpression
1882     | |     `-42
1883     | `-;
1884     `-}
1885 )txt"));
1886 }
1887 
1888 TEST_P(SyntaxTreeTest, UserDefinedBinaryOperator) {
1889   if (!GetParam().isCXX()) {
1890     return;
1891   }
1892   EXPECT_TRUE(treeDumpEqual(
1893       R"cpp(
1894 struct X {
1895   X& operator=(const X&);
1896   friend X operator+(X, const X&);
1897   friend bool operator<(const X&, const X&);
1898 };
1899 void test(X x, X y) {
1900   x = y;
1901   x + y;
1902   x < y;
1903 }
1904 )cpp",
1905       R"txt(
1906 *: TranslationUnit
1907 |-SimpleDeclaration
1908 | |-struct
1909 | |-X
1910 | |-{
1911 | |-SimpleDeclaration
1912 | | |-X
1913 | | |-SimpleDeclarator
1914 | | | |-&
1915 | | | |-operator
1916 | | | |-=
1917 | | | `-ParametersAndQualifiers
1918 | | |   |-(
1919 | | |   |-SimpleDeclaration
1920 | | |   | |-const
1921 | | |   | |-X
1922 | | |   | `-SimpleDeclarator
1923 | | |   |   `-&
1924 | | |   `-)
1925 | | `-;
1926 | |-UnknownDeclaration
1927 | | `-SimpleDeclaration
1928 | |   |-friend
1929 | |   |-X
1930 | |   |-SimpleDeclarator
1931 | |   | |-operator
1932 | |   | |-+
1933 | |   | `-ParametersAndQualifiers
1934 | |   |   |-(
1935 | |   |   |-SimpleDeclaration
1936 | |   |   | `-X
1937 | |   |   |-,
1938 | |   |   |-SimpleDeclaration
1939 | |   |   | |-const
1940 | |   |   | |-X
1941 | |   |   | `-SimpleDeclarator
1942 | |   |   |   `-&
1943 | |   |   `-)
1944 | |   `-;
1945 | |-UnknownDeclaration
1946 | | `-SimpleDeclaration
1947 | |   |-friend
1948 | |   |-bool
1949 | |   |-SimpleDeclarator
1950 | |   | |-operator
1951 | |   | |-<
1952 | |   | `-ParametersAndQualifiers
1953 | |   |   |-(
1954 | |   |   |-SimpleDeclaration
1955 | |   |   | |-const
1956 | |   |   | |-X
1957 | |   |   | `-SimpleDeclarator
1958 | |   |   |   `-&
1959 | |   |   |-,
1960 | |   |   |-SimpleDeclaration
1961 | |   |   | |-const
1962 | |   |   | |-X
1963 | |   |   | `-SimpleDeclarator
1964 | |   |   |   `-&
1965 | |   |   `-)
1966 | |   `-;
1967 | |-}
1968 | `-;
1969 `-SimpleDeclaration
1970   |-void
1971   |-SimpleDeclarator
1972   | |-test
1973   | `-ParametersAndQualifiers
1974   |   |-(
1975   |   |-SimpleDeclaration
1976   |   | |-X
1977   |   | `-SimpleDeclarator
1978   |   |   `-x
1979   |   |-,
1980   |   |-SimpleDeclaration
1981   |   | |-X
1982   |   | `-SimpleDeclarator
1983   |   |   `-y
1984   |   `-)
1985   `-CompoundStatement
1986     |-{
1987     |-ExpressionStatement
1988     | |-BinaryOperatorExpression
1989     | | |-IdExpression
1990     | | | `-UnqualifiedId
1991     | | |   `-x
1992     | | |-IdExpression
1993     | | | `-UnqualifiedId
1994     | | |   `-=
1995     | | `-IdExpression
1996     | |   `-UnqualifiedId
1997     | |     `-y
1998     | `-;
1999     |-ExpressionStatement
2000     | |-BinaryOperatorExpression
2001     | | |-UnknownExpression
2002     | | | `-IdExpression
2003     | | |   `-UnqualifiedId
2004     | | |     `-x
2005     | | |-IdExpression
2006     | | | `-UnqualifiedId
2007     | | |   `-+
2008     | | `-IdExpression
2009     | |   `-UnqualifiedId
2010     | |     `-y
2011     | `-;
2012     |-ExpressionStatement
2013     | |-BinaryOperatorExpression
2014     | | |-IdExpression
2015     | | | `-UnqualifiedId
2016     | | |   `-x
2017     | | |-IdExpression
2018     | | | `-UnqualifiedId
2019     | | |   `-<
2020     | | `-IdExpression
2021     | |   `-UnqualifiedId
2022     | |     `-y
2023     | `-;
2024     `-}
2025 )txt"));
2026 }
2027 
2028 TEST_P(SyntaxTreeTest, MultipleDeclaratorsGrouping) {
2029   EXPECT_TRUE(treeDumpEqual(
2030       R"cpp(
2031 int *a, b;
2032 int *c, d;
2033 )cpp",
2034       R"txt(
2035 *: TranslationUnit
2036 |-SimpleDeclaration
2037 | |-int
2038 | |-SimpleDeclarator
2039 | | |-*
2040 | | `-a
2041 | |-,
2042 | |-SimpleDeclarator
2043 | | `-b
2044 | `-;
2045 `-SimpleDeclaration
2046   |-int
2047   |-SimpleDeclarator
2048   | |-*
2049   | `-c
2050   |-,
2051   |-SimpleDeclarator
2052   | `-d
2053   `-;
2054 )txt"));
2055 }
2056 
2057 TEST_P(SyntaxTreeTest, MultipleDeclaratorsGroupingTypedef) {
2058   EXPECT_TRUE(treeDumpEqual(
2059       R"cpp(
2060 typedef int *a, b;
2061 )cpp",
2062       R"txt(
2063 *: TranslationUnit
2064 `-SimpleDeclaration
2065   |-typedef
2066   |-int
2067   |-SimpleDeclarator
2068   | |-*
2069   | `-a
2070   |-,
2071   |-SimpleDeclarator
2072   | `-b
2073   `-;
2074 )txt"));
2075 }
2076 
2077 TEST_P(SyntaxTreeTest, MultipleDeclaratorsInsideStatement) {
2078   EXPECT_TRUE(treeDumpEqual(
2079       R"cpp(
2080 void foo() {
2081   int *a, b;
2082   typedef int *ta, tb;
2083 }
2084 )cpp",
2085       R"txt(
2086 *: TranslationUnit
2087 `-SimpleDeclaration
2088   |-void
2089   |-SimpleDeclarator
2090   | |-foo
2091   | `-ParametersAndQualifiers
2092   |   |-(
2093   |   `-)
2094   `-CompoundStatement
2095     |-{
2096     |-DeclarationStatement
2097     | |-SimpleDeclaration
2098     | | |-int
2099     | | |-SimpleDeclarator
2100     | | | |-*
2101     | | | `-a
2102     | | |-,
2103     | | `-SimpleDeclarator
2104     | |   `-b
2105     | `-;
2106     |-DeclarationStatement
2107     | |-SimpleDeclaration
2108     | | |-typedef
2109     | | |-int
2110     | | |-SimpleDeclarator
2111     | | | |-*
2112     | | | `-ta
2113     | | |-,
2114     | | `-SimpleDeclarator
2115     | |   `-tb
2116     | `-;
2117     `-}
2118 )txt"));
2119 }
2120 
2121 TEST_P(SyntaxTreeTest, Namespaces) {
2122   if (!GetParam().isCXX()) {
2123     return;
2124   }
2125   EXPECT_TRUE(treeDumpEqual(
2126       R"cpp(
2127 namespace a { namespace b {} }
2128 namespace a::b {}
2129 namespace {}
2130 
2131 namespace foo = a;
2132 )cpp",
2133       R"txt(
2134 *: TranslationUnit
2135 |-NamespaceDefinition
2136 | |-namespace
2137 | |-a
2138 | |-{
2139 | |-NamespaceDefinition
2140 | | |-namespace
2141 | | |-b
2142 | | |-{
2143 | | `-}
2144 | `-}
2145 |-NamespaceDefinition
2146 | |-namespace
2147 | |-a
2148 | |-::
2149 | |-b
2150 | |-{
2151 | `-}
2152 |-NamespaceDefinition
2153 | |-namespace
2154 | |-{
2155 | `-}
2156 `-NamespaceAliasDefinition
2157   |-namespace
2158   |-foo
2159   |-=
2160   |-a
2161   `-;
2162 )txt"));
2163 }
2164 
2165 TEST_P(SyntaxTreeTest, UsingDirective) {
2166   if (!GetParam().isCXX()) {
2167     return;
2168   }
2169   EXPECT_TRUE(treeDumpEqual(
2170       R"cpp(
2171 namespace ns {}
2172 using namespace ::ns;
2173 )cpp",
2174       R"txt(
2175 *: TranslationUnit
2176 |-NamespaceDefinition
2177 | |-namespace
2178 | |-ns
2179 | |-{
2180 | `-}
2181 `-UsingNamespaceDirective
2182   |-using
2183   |-namespace
2184   |-::
2185   |-ns
2186   `-;
2187 )txt"));
2188 }
2189 
2190 TEST_P(SyntaxTreeTest, UsingDeclaration) {
2191   if (!GetParam().isCXX()) {
2192     return;
2193   }
2194   EXPECT_TRUE(treeDumpEqual(
2195       R"cpp(
2196 namespace ns { int a; }
2197 using ns::a;
2198 )cpp",
2199       R"txt(
2200 *: TranslationUnit
2201 |-NamespaceDefinition
2202 | |-namespace
2203 | |-ns
2204 | |-{
2205 | |-SimpleDeclaration
2206 | | |-int
2207 | | |-SimpleDeclarator
2208 | | | `-a
2209 | | `-;
2210 | `-}
2211 `-UsingDeclaration
2212   |-using
2213   |-ns
2214   |-::
2215   |-a
2216   `-;
2217 )txt"));
2218 }
2219 
2220 TEST_P(SyntaxTreeTest, FreeStandingClasses) {
2221   // Free-standing classes, must live inside a SimpleDeclaration.
2222   EXPECT_TRUE(treeDumpEqual(
2223       R"cpp(
2224 struct X;
2225 struct X {};
2226 
2227 struct Y *y1;
2228 struct Y {} *y2;
2229 
2230 struct {} *a1;
2231 )cpp",
2232       R"txt(
2233 *: TranslationUnit
2234 |-SimpleDeclaration
2235 | |-struct
2236 | |-X
2237 | `-;
2238 |-SimpleDeclaration
2239 | |-struct
2240 | |-X
2241 | |-{
2242 | |-}
2243 | `-;
2244 |-SimpleDeclaration
2245 | |-struct
2246 | |-Y
2247 | |-SimpleDeclarator
2248 | | |-*
2249 | | `-y1
2250 | `-;
2251 |-SimpleDeclaration
2252 | |-struct
2253 | |-Y
2254 | |-{
2255 | |-}
2256 | |-SimpleDeclarator
2257 | | |-*
2258 | | `-y2
2259 | `-;
2260 `-SimpleDeclaration
2261   |-struct
2262   |-{
2263   |-}
2264   |-SimpleDeclarator
2265   | |-*
2266   | `-a1
2267   `-;
2268 )txt"));
2269 }
2270 
2271 TEST_P(SyntaxTreeTest, Templates) {
2272   if (!GetParam().isCXX()) {
2273     return;
2274   }
2275   if (GetParam().hasDelayedTemplateParsing()) {
2276     // FIXME: Make this test work on Windows by generating the expected syntax
2277     // tree when `-fdelayed-template-parsing` is active.
2278     return;
2279   }
2280   EXPECT_TRUE(treeDumpEqual(
2281       R"cpp(
2282 template <class T> struct cls {};
2283 template <class T> int var = 10;
2284 template <class T> int fun() {}
2285 )cpp",
2286       R"txt(
2287 *: TranslationUnit
2288 |-TemplateDeclaration
2289 | |-template
2290 | |-<
2291 | |-UnknownDeclaration
2292 | | |-class
2293 | | `-T
2294 | |->
2295 | `-SimpleDeclaration
2296 |   |-struct
2297 |   |-cls
2298 |   |-{
2299 |   |-}
2300 |   `-;
2301 |-TemplateDeclaration
2302 | |-template
2303 | |-<
2304 | |-UnknownDeclaration
2305 | | |-class
2306 | | `-T
2307 | |->
2308 | `-SimpleDeclaration
2309 |   |-int
2310 |   |-SimpleDeclarator
2311 |   | |-var
2312 |   | |-=
2313 |   | `-IntegerLiteralExpression
2314 |   |   `-10
2315 |   `-;
2316 `-TemplateDeclaration
2317   |-template
2318   |-<
2319   |-UnknownDeclaration
2320   | |-class
2321   | `-T
2322   |->
2323   `-SimpleDeclaration
2324     |-int
2325     |-SimpleDeclarator
2326     | |-fun
2327     | `-ParametersAndQualifiers
2328     |   |-(
2329     |   `-)
2330     `-CompoundStatement
2331       |-{
2332       `-}
2333 )txt"));
2334 }
2335 
2336 TEST_P(SyntaxTreeTest, NestedTemplates) {
2337   if (!GetParam().isCXX()) {
2338     return;
2339   }
2340   EXPECT_TRUE(treeDumpEqual(
2341       R"cpp(
2342 template <class T>
2343 struct X {
2344   template <class U>
2345   U foo();
2346 };
2347 )cpp",
2348       R"txt(
2349 *: TranslationUnit
2350 `-TemplateDeclaration
2351   |-template
2352   |-<
2353   |-UnknownDeclaration
2354   | |-class
2355   | `-T
2356   |->
2357   `-SimpleDeclaration
2358     |-struct
2359     |-X
2360     |-{
2361     |-TemplateDeclaration
2362     | |-template
2363     | |-<
2364     | |-UnknownDeclaration
2365     | | |-class
2366     | | `-U
2367     | |->
2368     | `-SimpleDeclaration
2369     |   |-U
2370     |   |-SimpleDeclarator
2371     |   | |-foo
2372     |   | `-ParametersAndQualifiers
2373     |   |   |-(
2374     |   |   `-)
2375     |   `-;
2376     |-}
2377     `-;
2378 )txt"));
2379 }
2380 
2381 TEST_P(SyntaxTreeTest, Templates2) {
2382   if (!GetParam().isCXX()) {
2383     return;
2384   }
2385   EXPECT_TRUE(treeDumpEqual(
2386       R"cpp(
2387 template <class T> struct X { struct Y; };
2388 template <class T> struct X<T>::Y {};
2389 )cpp",
2390       R"txt(
2391 *: TranslationUnit
2392 |-TemplateDeclaration
2393 | |-template
2394 | |-<
2395 | |-UnknownDeclaration
2396 | | |-class
2397 | | `-T
2398 | |->
2399 | `-SimpleDeclaration
2400 |   |-struct
2401 |   |-X
2402 |   |-{
2403 |   |-SimpleDeclaration
2404 |   | |-struct
2405 |   | |-Y
2406 |   | `-;
2407 |   |-}
2408 |   `-;
2409 `-TemplateDeclaration
2410   |-template
2411   |-<
2412   |-UnknownDeclaration
2413   | |-class
2414   | `-T
2415   |->
2416   `-SimpleDeclaration
2417     |-struct
2418     |-X
2419     |-<
2420     |-T
2421     |->
2422     |-::
2423     |-Y
2424     |-{
2425     |-}
2426     `-;
2427 )txt"));
2428 }
2429 
2430 TEST_P(SyntaxTreeTest, TemplatesUsingUsing) {
2431   if (!GetParam().isCXX()) {
2432     return;
2433   }
2434   EXPECT_TRUE(treeDumpEqual(
2435       R"cpp(
2436 template <class T> struct X {
2437   using T::foo;
2438   using typename T::bar;
2439 };
2440 )cpp",
2441       R"txt(
2442 *: TranslationUnit
2443 `-TemplateDeclaration
2444   |-template
2445   |-<
2446   |-UnknownDeclaration
2447   | |-class
2448   | `-T
2449   |->
2450   `-SimpleDeclaration
2451     |-struct
2452     |-X
2453     |-{
2454     |-UsingDeclaration
2455     | |-using
2456     | |-T
2457     | |-::
2458     | |-foo
2459     | `-;
2460     |-UsingDeclaration
2461     | |-using
2462     | |-typename
2463     | |-T
2464     | |-::
2465     | |-bar
2466     | `-;
2467     |-}
2468     `-;
2469 )txt"));
2470 }
2471 
2472 TEST_P(SyntaxTreeTest, ExplicitTemplateInstantations) {
2473   if (!GetParam().isCXX()) {
2474     return;
2475   }
2476   EXPECT_TRUE(treeDumpEqual(
2477       R"cpp(
2478 template <class T> struct X {};
2479 template <class T> struct X<T*> {};
2480 template <> struct X<int> {};
2481 
2482 template struct X<double>;
2483 extern template struct X<float>;
2484 )cpp",
2485       R"txt(
2486 *: TranslationUnit
2487 |-TemplateDeclaration
2488 | |-template
2489 | |-<
2490 | |-UnknownDeclaration
2491 | | |-class
2492 | | `-T
2493 | |->
2494 | `-SimpleDeclaration
2495 |   |-struct
2496 |   |-X
2497 |   |-{
2498 |   |-}
2499 |   `-;
2500 |-TemplateDeclaration
2501 | |-template
2502 | |-<
2503 | |-UnknownDeclaration
2504 | | |-class
2505 | | `-T
2506 | |->
2507 | `-SimpleDeclaration
2508 |   |-struct
2509 |   |-X
2510 |   |-<
2511 |   |-T
2512 |   |-*
2513 |   |->
2514 |   |-{
2515 |   |-}
2516 |   `-;
2517 |-TemplateDeclaration
2518 | |-template
2519 | |-<
2520 | |->
2521 | `-SimpleDeclaration
2522 |   |-struct
2523 |   |-X
2524 |   |-<
2525 |   |-int
2526 |   |->
2527 |   |-{
2528 |   |-}
2529 |   `-;
2530 |-ExplicitTemplateInstantiation
2531 | |-template
2532 | `-SimpleDeclaration
2533 |   |-struct
2534 |   |-X
2535 |   |-<
2536 |   |-double
2537 |   |->
2538 |   `-;
2539 `-ExplicitTemplateInstantiation
2540   |-extern
2541   |-template
2542   `-SimpleDeclaration
2543     |-struct
2544     |-X
2545     |-<
2546     |-float
2547     |->
2548     `-;
2549 )txt"));
2550 }
2551 
2552 TEST_P(SyntaxTreeTest, UsingType) {
2553   if (!GetParam().isCXX()) {
2554     return;
2555   }
2556   EXPECT_TRUE(treeDumpEqual(
2557       R"cpp(
2558 using type = int;
2559 )cpp",
2560       R"txt(
2561 *: TranslationUnit
2562 `-TypeAliasDeclaration
2563   |-using
2564   |-type
2565   |-=
2566   |-int
2567   `-;
2568 )txt"));
2569 }
2570 
2571 TEST_P(SyntaxTreeTest, EmptyDeclaration) {
2572   EXPECT_TRUE(treeDumpEqual(
2573       R"cpp(
2574 ;
2575 )cpp",
2576       R"txt(
2577 *: TranslationUnit
2578 `-EmptyDeclaration
2579   `-;
2580 )txt"));
2581 }
2582 
2583 TEST_P(SyntaxTreeTest, StaticAssert) {
2584   if (!GetParam().isCXX11OrLater()) {
2585     return;
2586   }
2587   EXPECT_TRUE(treeDumpEqual(
2588       R"cpp(
2589 static_assert(true, "message");
2590 static_assert(true);
2591 )cpp",
2592       R"txt(
2593 *: TranslationUnit
2594 |-StaticAssertDeclaration
2595 | |-static_assert
2596 | |-(
2597 | |-BoolLiteralExpression
2598 | | `-true
2599 | |-,
2600 | |-UnknownExpression
2601 | | `-"message"
2602 | |-)
2603 | `-;
2604 `-StaticAssertDeclaration
2605   |-static_assert
2606   |-(
2607   |-BoolLiteralExpression
2608   | `-true
2609   |-)
2610   `-;
2611 )txt"));
2612 }
2613 
2614 TEST_P(SyntaxTreeTest, ExternC) {
2615   if (!GetParam().isCXX()) {
2616     return;
2617   }
2618   EXPECT_TRUE(treeDumpEqual(
2619       R"cpp(
2620 extern "C" int a;
2621 extern "C" { int b; int c; }
2622 )cpp",
2623       R"txt(
2624 *: TranslationUnit
2625 |-LinkageSpecificationDeclaration
2626 | |-extern
2627 | |-"C"
2628 | `-SimpleDeclaration
2629 |   |-int
2630 |   |-SimpleDeclarator
2631 |   | `-a
2632 |   `-;
2633 `-LinkageSpecificationDeclaration
2634   |-extern
2635   |-"C"
2636   |-{
2637   |-SimpleDeclaration
2638   | |-int
2639   | |-SimpleDeclarator
2640   | | `-b
2641   | `-;
2642   |-SimpleDeclaration
2643   | |-int
2644   | |-SimpleDeclarator
2645   | | `-c
2646   | `-;
2647   `-}
2648 )txt"));
2649 }
2650 
2651 TEST_P(SyntaxTreeTest, NonModifiableNodes) {
2652   // Some nodes are non-modifiable, they are marked with 'I:'.
2653   EXPECT_TRUE(treeDumpEqual(
2654       R"cpp(
2655 #define HALF_IF if (1+
2656 #define HALF_IF_2 1) {}
2657 void test() {
2658   HALF_IF HALF_IF_2 else {}
2659 })cpp",
2660       R"txt(
2661 *: TranslationUnit
2662 `-SimpleDeclaration
2663   |-void
2664   |-SimpleDeclarator
2665   | |-test
2666   | `-ParametersAndQualifiers
2667   |   |-(
2668   |   `-)
2669   `-CompoundStatement
2670     |-{
2671     |-IfStatement
2672     | |-I: if
2673     | |-I: (
2674     | |-I: BinaryOperatorExpression
2675     | | |-I: IntegerLiteralExpression
2676     | | | `-I: 1
2677     | | |-I: +
2678     | | `-I: IntegerLiteralExpression
2679     | |   `-I: 1
2680     | |-I: )
2681     | |-I: CompoundStatement
2682     | | |-I: {
2683     | | `-I: }
2684     | |-else
2685     | `-CompoundStatement
2686     |   |-{
2687     |   `-}
2688     `-}
2689 )txt"));
2690 }
2691 
2692 TEST_P(SyntaxTreeTest, ModifiableNodes) {
2693   // All nodes can be mutated.
2694   EXPECT_TRUE(treeDumpEqual(
2695       R"cpp(
2696 #define OPEN {
2697 #define CLOSE }
2698 
2699 void test() {
2700   OPEN
2701     1;
2702   CLOSE
2703 
2704   OPEN
2705     2;
2706   }
2707 }
2708 )cpp",
2709       R"txt(
2710 *: TranslationUnit
2711 `-SimpleDeclaration
2712   |-void
2713   |-SimpleDeclarator
2714   | |-test
2715   | `-ParametersAndQualifiers
2716   |   |-(
2717   |   `-)
2718   `-CompoundStatement
2719     |-{
2720     |-CompoundStatement
2721     | |-{
2722     | |-ExpressionStatement
2723     | | |-IntegerLiteralExpression
2724     | | | `-1
2725     | | `-;
2726     | `-}
2727     |-CompoundStatement
2728     | |-{
2729     | |-ExpressionStatement
2730     | | |-IntegerLiteralExpression
2731     | | | `-2
2732     | | `-;
2733     | `-}
2734     `-}
2735 )txt"));
2736 }
2737 
2738 TEST_P(SyntaxTreeTest, ArraySubscriptsInDeclarators) {
2739   EXPECT_TRUE(treeDumpEqual(
2740       R"cpp(
2741 int a[10];
2742 int b[1][2][3];
2743 int c[] = {1,2,3};
2744 )cpp",
2745       R"txt(
2746 *: TranslationUnit
2747 |-SimpleDeclaration
2748 | |-int
2749 | |-SimpleDeclarator
2750 | | |-a
2751 | | `-ArraySubscript
2752 | |   |-[
2753 | |   |-IntegerLiteralExpression
2754 | |   | `-10
2755 | |   `-]
2756 | `-;
2757 |-SimpleDeclaration
2758 | |-int
2759 | |-SimpleDeclarator
2760 | | |-b
2761 | | |-ArraySubscript
2762 | | | |-[
2763 | | | |-IntegerLiteralExpression
2764 | | | | `-1
2765 | | | `-]
2766 | | |-ArraySubscript
2767 | | | |-[
2768 | | | |-IntegerLiteralExpression
2769 | | | | `-2
2770 | | | `-]
2771 | | `-ArraySubscript
2772 | |   |-[
2773 | |   |-IntegerLiteralExpression
2774 | |   | `-3
2775 | |   `-]
2776 | `-;
2777 `-SimpleDeclaration
2778   |-int
2779   |-SimpleDeclarator
2780   | |-c
2781   | |-ArraySubscript
2782   | | |-[
2783   | | `-]
2784   | |-=
2785   | `-UnknownExpression
2786   |   `-UnknownExpression
2787   |     |-{
2788   |     |-IntegerLiteralExpression
2789   |     | `-1
2790   |     |-,
2791   |     |-IntegerLiteralExpression
2792   |     | `-2
2793   |     |-,
2794   |     |-IntegerLiteralExpression
2795   |     | `-3
2796   |     `-}
2797   `-;
2798 )txt"));
2799 }
2800 
2801 TEST_P(SyntaxTreeTest, StaticArraySubscriptsInDeclarators) {
2802   if (!GetParam().isC99OrLater()) {
2803     return;
2804   }
2805   EXPECT_TRUE(treeDumpEqual(
2806       R"cpp(
2807 void f(int xs[static 10]);
2808 )cpp",
2809       R"txt(
2810 *: TranslationUnit
2811 `-SimpleDeclaration
2812   |-void
2813   |-SimpleDeclarator
2814   | |-f
2815   | `-ParametersAndQualifiers
2816   |   |-(
2817   |   |-SimpleDeclaration
2818   |   | |-int
2819   |   | `-SimpleDeclarator
2820   |   |   |-xs
2821   |   |   `-ArraySubscript
2822   |   |     |-[
2823   |   |     |-static
2824   |   |     |-IntegerLiteralExpression
2825   |   |     | `-10
2826   |   |     `-]
2827   |   `-)
2828   `-;
2829 )txt"));
2830 }
2831 
2832 TEST_P(SyntaxTreeTest, ParametersAndQualifiersInFreeFunctions) {
2833   if (!GetParam().isCXX()) {
2834     return;
2835   }
2836   EXPECT_TRUE(treeDumpEqual(
2837       R"cpp(
2838 int func1();
2839 int func2a(int a);
2840 int func2b(int);
2841 int func3a(int *ap);
2842 int func3b(int *);
2843 int func4a(int a, float b);
2844 int func4b(int, float);
2845 )cpp",
2846       R"txt(
2847 *: TranslationUnit
2848 |-SimpleDeclaration
2849 | |-int
2850 | |-SimpleDeclarator
2851 | | |-func1
2852 | | `-ParametersAndQualifiers
2853 | |   |-(
2854 | |   `-)
2855 | `-;
2856 |-SimpleDeclaration
2857 | |-int
2858 | |-SimpleDeclarator
2859 | | |-func2a
2860 | | `-ParametersAndQualifiers
2861 | |   |-(
2862 | |   |-SimpleDeclaration
2863 | |   | |-int
2864 | |   | `-SimpleDeclarator
2865 | |   |   `-a
2866 | |   `-)
2867 | `-;
2868 |-SimpleDeclaration
2869 | |-int
2870 | |-SimpleDeclarator
2871 | | |-func2b
2872 | | `-ParametersAndQualifiers
2873 | |   |-(
2874 | |   |-SimpleDeclaration
2875 | |   | `-int
2876 | |   `-)
2877 | `-;
2878 |-SimpleDeclaration
2879 | |-int
2880 | |-SimpleDeclarator
2881 | | |-func3a
2882 | | `-ParametersAndQualifiers
2883 | |   |-(
2884 | |   |-SimpleDeclaration
2885 | |   | |-int
2886 | |   | `-SimpleDeclarator
2887 | |   |   |-*
2888 | |   |   `-ap
2889 | |   `-)
2890 | `-;
2891 |-SimpleDeclaration
2892 | |-int
2893 | |-SimpleDeclarator
2894 | | |-func3b
2895 | | `-ParametersAndQualifiers
2896 | |   |-(
2897 | |   |-SimpleDeclaration
2898 | |   | |-int
2899 | |   | `-SimpleDeclarator
2900 | |   |   `-*
2901 | |   `-)
2902 | `-;
2903 |-SimpleDeclaration
2904 | |-int
2905 | |-SimpleDeclarator
2906 | | |-func4a
2907 | | `-ParametersAndQualifiers
2908 | |   |-(
2909 | |   |-SimpleDeclaration
2910 | |   | |-int
2911 | |   | `-SimpleDeclarator
2912 | |   |   `-a
2913 | |   |-,
2914 | |   |-SimpleDeclaration
2915 | |   | |-float
2916 | |   | `-SimpleDeclarator
2917 | |   |   `-b
2918 | |   `-)
2919 | `-;
2920 `-SimpleDeclaration
2921   |-int
2922   |-SimpleDeclarator
2923   | |-func4b
2924   | `-ParametersAndQualifiers
2925   |   |-(
2926   |   |-SimpleDeclaration
2927   |   | `-int
2928   |   |-,
2929   |   |-SimpleDeclaration
2930   |   | `-float
2931   |   `-)
2932   `-;
2933 )txt"));
2934 }
2935 
2936 TEST_P(SyntaxTreeTest, ParametersAndQualifiersInFreeFunctionsCxx) {
2937   if (!GetParam().isCXX()) {
2938     return;
2939   }
2940   EXPECT_TRUE(treeDumpEqual(
2941       R"cpp(
2942 int func1(const int a, volatile int b, const volatile int c);
2943 int func2(int& a);
2944 )cpp",
2945       R"txt(
2946 *: TranslationUnit
2947 |-SimpleDeclaration
2948 | |-int
2949 | |-SimpleDeclarator
2950 | | |-func1
2951 | | `-ParametersAndQualifiers
2952 | |   |-(
2953 | |   |-SimpleDeclaration
2954 | |   | |-const
2955 | |   | |-int
2956 | |   | `-SimpleDeclarator
2957 | |   |   `-a
2958 | |   |-,
2959 | |   |-SimpleDeclaration
2960 | |   | |-volatile
2961 | |   | |-int
2962 | |   | `-SimpleDeclarator
2963 | |   |   `-b
2964 | |   |-,
2965 | |   |-SimpleDeclaration
2966 | |   | |-const
2967 | |   | |-volatile
2968 | |   | |-int
2969 | |   | `-SimpleDeclarator
2970 | |   |   `-c
2971 | |   `-)
2972 | `-;
2973 `-SimpleDeclaration
2974   |-int
2975   |-SimpleDeclarator
2976   | |-func2
2977   | `-ParametersAndQualifiers
2978   |   |-(
2979   |   |-SimpleDeclaration
2980   |   | |-int
2981   |   | `-SimpleDeclarator
2982   |   |   |-&
2983   |   |   `-a
2984   |   `-)
2985   `-;
2986 )txt"));
2987 }
2988 
2989 TEST_P(SyntaxTreeTest, ParametersAndQualifiersInFreeFunctionsCxx11) {
2990   if (!GetParam().isCXX11OrLater()) {
2991     return;
2992   }
2993   EXPECT_TRUE(treeDumpEqual(
2994       R"cpp(
2995 int func1(int&& a);
2996 )cpp",
2997       R"txt(
2998 *: TranslationUnit
2999 `-SimpleDeclaration
3000   |-int
3001   |-SimpleDeclarator
3002   | |-func1
3003   | `-ParametersAndQualifiers
3004   |   |-(
3005   |   |-SimpleDeclaration
3006   |   | |-int
3007   |   | `-SimpleDeclarator
3008   |   |   |-&&
3009   |   |   `-a
3010   |   `-)
3011   `-;
3012 )txt"));
3013 }
3014 
3015 TEST_P(SyntaxTreeTest, ParametersAndQualifiersInMemberFunctions) {
3016   if (!GetParam().isCXX()) {
3017     return;
3018   }
3019   EXPECT_TRUE(treeDumpEqual(
3020       R"cpp(
3021 struct Test {
3022   int a();
3023   int b() const;
3024   int c() volatile;
3025   int d() const volatile;
3026   int e() &;
3027   int f() &&;
3028 };
3029 )cpp",
3030       R"txt(
3031 *: TranslationUnit
3032 `-SimpleDeclaration
3033   |-struct
3034   |-Test
3035   |-{
3036   |-SimpleDeclaration
3037   | |-int
3038   | |-SimpleDeclarator
3039   | | |-a
3040   | | `-ParametersAndQualifiers
3041   | |   |-(
3042   | |   `-)
3043   | `-;
3044   |-SimpleDeclaration
3045   | |-int
3046   | |-SimpleDeclarator
3047   | | |-b
3048   | | `-ParametersAndQualifiers
3049   | |   |-(
3050   | |   |-)
3051   | |   `-const
3052   | `-;
3053   |-SimpleDeclaration
3054   | |-int
3055   | |-SimpleDeclarator
3056   | | |-c
3057   | | `-ParametersAndQualifiers
3058   | |   |-(
3059   | |   |-)
3060   | |   `-volatile
3061   | `-;
3062   |-SimpleDeclaration
3063   | |-int
3064   | |-SimpleDeclarator
3065   | | |-d
3066   | | `-ParametersAndQualifiers
3067   | |   |-(
3068   | |   |-)
3069   | |   |-const
3070   | |   `-volatile
3071   | `-;
3072   |-SimpleDeclaration
3073   | |-int
3074   | |-SimpleDeclarator
3075   | | |-e
3076   | | `-ParametersAndQualifiers
3077   | |   |-(
3078   | |   |-)
3079   | |   `-&
3080   | `-;
3081   |-SimpleDeclaration
3082   | |-int
3083   | |-SimpleDeclarator
3084   | | |-f
3085   | | `-ParametersAndQualifiers
3086   | |   |-(
3087   | |   |-)
3088   | |   `-&&
3089   | `-;
3090   |-}
3091   `-;
3092 )txt"));
3093 }
3094 
3095 TEST_P(SyntaxTreeTest, TrailingReturn) {
3096   if (!GetParam().isCXX11OrLater()) {
3097     return;
3098   }
3099   EXPECT_TRUE(treeDumpEqual(
3100       R"cpp(
3101 auto foo() -> int;
3102 )cpp",
3103       R"txt(
3104 *: TranslationUnit
3105 `-SimpleDeclaration
3106   |-auto
3107   |-SimpleDeclarator
3108   | |-foo
3109   | `-ParametersAndQualifiers
3110   |   |-(
3111   |   |-)
3112   |   `-TrailingReturnType
3113   |     |-->
3114   |     `-int
3115   `-;
3116 )txt"));
3117 }
3118 
3119 TEST_P(SyntaxTreeTest, DynamicExceptionSpecification) {
3120   if (!GetParam().supportsCXXDynamicExceptionSpecification()) {
3121     return;
3122   }
3123   EXPECT_TRUE(treeDumpEqual(
3124       R"cpp(
3125 struct MyException1 {};
3126 struct MyException2 {};
3127 int a() throw();
3128 int b() throw(...);
3129 int c() throw(MyException1);
3130 int d() throw(MyException1, MyException2);
3131 )cpp",
3132       R"txt(
3133 *: TranslationUnit
3134 |-SimpleDeclaration
3135 | |-struct
3136 | |-MyException1
3137 | |-{
3138 | |-}
3139 | `-;
3140 |-SimpleDeclaration
3141 | |-struct
3142 | |-MyException2
3143 | |-{
3144 | |-}
3145 | `-;
3146 |-SimpleDeclaration
3147 | |-int
3148 | |-SimpleDeclarator
3149 | | |-a
3150 | | `-ParametersAndQualifiers
3151 | |   |-(
3152 | |   |-)
3153 | |   |-throw
3154 | |   |-(
3155 | |   `-)
3156 | `-;
3157 |-SimpleDeclaration
3158 | |-int
3159 | |-SimpleDeclarator
3160 | | |-b
3161 | | `-ParametersAndQualifiers
3162 | |   |-(
3163 | |   |-)
3164 | |   |-throw
3165 | |   |-(
3166 | |   |-...
3167 | |   `-)
3168 | `-;
3169 |-SimpleDeclaration
3170 | |-int
3171 | |-SimpleDeclarator
3172 | | |-c
3173 | | `-ParametersAndQualifiers
3174 | |   |-(
3175 | |   |-)
3176 | |   |-throw
3177 | |   |-(
3178 | |   |-MyException1
3179 | |   `-)
3180 | `-;
3181 `-SimpleDeclaration
3182   |-int
3183   |-SimpleDeclarator
3184   | |-d
3185   | `-ParametersAndQualifiers
3186   |   |-(
3187   |   |-)
3188   |   |-throw
3189   |   |-(
3190   |   |-MyException1
3191   |   |-,
3192   |   |-MyException2
3193   |   `-)
3194   `-;
3195 )txt"));
3196 }
3197 
3198 TEST_P(SyntaxTreeTest, NoexceptExceptionSpecification) {
3199   if (!GetParam().isCXX11OrLater()) {
3200     return;
3201   }
3202   EXPECT_TRUE(treeDumpEqual(
3203       R"cpp(
3204 int a() noexcept;
3205 int b() noexcept(true);
3206 )cpp",
3207       R"txt(
3208 *: TranslationUnit
3209 |-SimpleDeclaration
3210 | |-int
3211 | |-SimpleDeclarator
3212 | | |-a
3213 | | `-ParametersAndQualifiers
3214 | |   |-(
3215 | |   |-)
3216 | |   `-noexcept
3217 | `-;
3218 `-SimpleDeclaration
3219   |-int
3220   |-SimpleDeclarator
3221   | |-b
3222   | `-ParametersAndQualifiers
3223   |   |-(
3224   |   |-)
3225   |   |-noexcept
3226   |   |-(
3227   |   |-BoolLiteralExpression
3228   |   | `-true
3229   |   `-)
3230   `-;
3231 )txt"));
3232 }
3233 
3234 TEST_P(SyntaxTreeTest, DeclaratorsInParentheses) {
3235   EXPECT_TRUE(treeDumpEqual(
3236       R"cpp(
3237 int (a);
3238 int *(b);
3239 int (*c)(int);
3240 int *(d)(int);
3241 )cpp",
3242       R"txt(
3243 *: TranslationUnit
3244 |-SimpleDeclaration
3245 | |-int
3246 | |-SimpleDeclarator
3247 | | `-ParenDeclarator
3248 | |   |-(
3249 | |   |-a
3250 | |   `-)
3251 | `-;
3252 |-SimpleDeclaration
3253 | |-int
3254 | |-SimpleDeclarator
3255 | | |-*
3256 | | `-ParenDeclarator
3257 | |   |-(
3258 | |   |-b
3259 | |   `-)
3260 | `-;
3261 |-SimpleDeclaration
3262 | |-int
3263 | |-SimpleDeclarator
3264 | | |-ParenDeclarator
3265 | | | |-(
3266 | | | |-*
3267 | | | |-c
3268 | | | `-)
3269 | | `-ParametersAndQualifiers
3270 | |   |-(
3271 | |   |-SimpleDeclaration
3272 | |   | `-int
3273 | |   `-)
3274 | `-;
3275 `-SimpleDeclaration
3276   |-int
3277   |-SimpleDeclarator
3278   | |-*
3279   | |-ParenDeclarator
3280   | | |-(
3281   | | |-d
3282   | | `-)
3283   | `-ParametersAndQualifiers
3284   |   |-(
3285   |   |-SimpleDeclaration
3286   |   | `-int
3287   |   `-)
3288   `-;
3289 )txt"));
3290 }
3291 
3292 TEST_P(SyntaxTreeTest, ConstVolatileQualifiers) {
3293   EXPECT_TRUE(treeDumpEqual(
3294       R"cpp(
3295 const int west = -1;
3296 int const east = 1;
3297 const int const universal = 0;
3298 const int const *const *volatile b;
3299 )cpp",
3300       R"txt(
3301 *: TranslationUnit
3302 |-SimpleDeclaration
3303 | |-const
3304 | |-int
3305 | |-SimpleDeclarator
3306 | | |-west
3307 | | |-=
3308 | | `-PrefixUnaryOperatorExpression
3309 | |   |--
3310 | |   `-IntegerLiteralExpression
3311 | |     `-1
3312 | `-;
3313 |-SimpleDeclaration
3314 | |-int
3315 | |-const
3316 | |-SimpleDeclarator
3317 | | |-east
3318 | | |-=
3319 | | `-IntegerLiteralExpression
3320 | |   `-1
3321 | `-;
3322 |-SimpleDeclaration
3323 | |-const
3324 | |-int
3325 | |-const
3326 | |-SimpleDeclarator
3327 | | |-universal
3328 | | |-=
3329 | | `-IntegerLiteralExpression
3330 | |   `-0
3331 | `-;
3332 `-SimpleDeclaration
3333   |-const
3334   |-int
3335   |-const
3336   |-SimpleDeclarator
3337   | |-*
3338   | |-const
3339   | |-*
3340   | |-volatile
3341   | `-b
3342   `-;
3343 )txt"));
3344 }
3345 
3346 TEST_P(SyntaxTreeTest, RangesOfDeclaratorsWithTrailingReturnTypes) {
3347   if (!GetParam().isCXX11OrLater()) {
3348     return;
3349   }
3350   EXPECT_TRUE(treeDumpEqual(
3351       R"cpp(
3352 auto foo() -> auto(*)(int) -> double*;
3353 )cpp",
3354       R"txt(
3355 *: TranslationUnit
3356 `-SimpleDeclaration
3357   |-auto
3358   |-SimpleDeclarator
3359   | |-foo
3360   | `-ParametersAndQualifiers
3361   |   |-(
3362   |   |-)
3363   |   `-TrailingReturnType
3364   |     |-->
3365   |     |-auto
3366   |     `-SimpleDeclarator
3367   |       |-ParenDeclarator
3368   |       | |-(
3369   |       | |-*
3370   |       | `-)
3371   |       `-ParametersAndQualifiers
3372   |         |-(
3373   |         |-SimpleDeclaration
3374   |         | `-int
3375   |         |-)
3376   |         `-TrailingReturnType
3377   |           |-->
3378   |           |-double
3379   |           `-SimpleDeclarator
3380   |             `-*
3381   `-;
3382 )txt"));
3383 }
3384 
3385 TEST_P(SyntaxTreeTest, MemberPointers) {
3386   if (!GetParam().isCXX()) {
3387     return;
3388   }
3389   EXPECT_TRUE(treeDumpEqual(
3390       R"cpp(
3391 struct X {};
3392 int X::* a;
3393 const int X::* b;
3394 )cpp",
3395       R"txt(
3396 *: TranslationUnit
3397 |-SimpleDeclaration
3398 | |-struct
3399 | |-X
3400 | |-{
3401 | |-}
3402 | `-;
3403 |-SimpleDeclaration
3404 | |-int
3405 | |-SimpleDeclarator
3406 | | |-MemberPointer
3407 | | | |-X
3408 | | | |-::
3409 | | | `-*
3410 | | `-a
3411 | `-;
3412 `-SimpleDeclaration
3413   |-const
3414   |-int
3415   |-SimpleDeclarator
3416   | |-MemberPointer
3417   | | |-X
3418   | | |-::
3419   | | `-*
3420   | `-b
3421   `-;
3422 )txt"));
3423 }
3424 
3425 TEST_P(SyntaxTreeTest, ComplexDeclarator) {
3426   EXPECT_TRUE(treeDumpEqual(
3427       R"cpp(
3428 void x(char a, short (*b)(int));
3429 )cpp",
3430       R"txt(
3431 *: TranslationUnit
3432 `-SimpleDeclaration
3433   |-void
3434   |-SimpleDeclarator
3435   | |-x
3436   | `-ParametersAndQualifiers
3437   |   |-(
3438   |   |-SimpleDeclaration
3439   |   | |-char
3440   |   | `-SimpleDeclarator
3441   |   |   `-a
3442   |   |-,
3443   |   |-SimpleDeclaration
3444   |   | |-short
3445   |   | `-SimpleDeclarator
3446   |   |   |-ParenDeclarator
3447   |   |   | |-(
3448   |   |   | |-*
3449   |   |   | |-b
3450   |   |   | `-)
3451   |   |   `-ParametersAndQualifiers
3452   |   |     |-(
3453   |   |     |-SimpleDeclaration
3454   |   |     | `-int
3455   |   |     `-)
3456   |   `-)
3457   `-;
3458 )txt"));
3459 }
3460 
3461 TEST_P(SyntaxTreeTest, ComplexDeclarator2) {
3462   EXPECT_TRUE(treeDumpEqual(
3463       R"cpp(
3464 void x(char a, short (*b)(int), long (**c)(long long));
3465 )cpp",
3466       R"txt(
3467 *: TranslationUnit
3468 `-SimpleDeclaration
3469   |-void
3470   |-SimpleDeclarator
3471   | |-x
3472   | `-ParametersAndQualifiers
3473   |   |-(
3474   |   |-SimpleDeclaration
3475   |   | |-char
3476   |   | `-SimpleDeclarator
3477   |   |   `-a
3478   |   |-,
3479   |   |-SimpleDeclaration
3480   |   | |-short
3481   |   | `-SimpleDeclarator
3482   |   |   |-ParenDeclarator
3483   |   |   | |-(
3484   |   |   | |-*
3485   |   |   | |-b
3486   |   |   | `-)
3487   |   |   `-ParametersAndQualifiers
3488   |   |     |-(
3489   |   |     |-SimpleDeclaration
3490   |   |     | `-int
3491   |   |     `-)
3492   |   |-,
3493   |   |-SimpleDeclaration
3494   |   | |-long
3495   |   | `-SimpleDeclarator
3496   |   |   |-ParenDeclarator
3497   |   |   | |-(
3498   |   |   | |-*
3499   |   |   | |-*
3500   |   |   | |-c
3501   |   |   | `-)
3502   |   |   `-ParametersAndQualifiers
3503   |   |     |-(
3504   |   |     |-SimpleDeclaration
3505   |   |     | |-long
3506   |   |     | `-long
3507   |   |     `-)
3508   |   `-)
3509   `-;
3510 )txt"));
3511 }
3512 
3513 TEST_P(SyntaxTreeTest, Mutations) {
3514   if (!GetParam().isCXX11OrLater()) {
3515     return;
3516   }
3517 
3518   using Transformation = std::function<void(
3519       const llvm::Annotations & /*Input*/, syntax::TranslationUnit * /*Root*/)>;
3520   auto CheckTransformation = [this](std::string Input, std::string Expected,
3521                                     Transformation Transform) -> void {
3522     llvm::Annotations Source(Input);
3523     auto *Root = buildTree(Source.code(), GetParam());
3524 
3525     Transform(Source, Root);
3526 
3527     auto Replacements = syntax::computeReplacements(*Arena, *Root);
3528     auto Output = tooling::applyAllReplacements(Source.code(), Replacements);
3529     if (!Output) {
3530       ADD_FAILURE() << "could not apply replacements: "
3531                     << llvm::toString(Output.takeError());
3532       return;
3533     }
3534 
3535     EXPECT_EQ(Expected, *Output) << "input is:\n" << Input;
3536   };
3537 
3538   // Removes the selected statement. Input should have exactly one selected
3539   // range and it should correspond to a single statement.
3540   auto RemoveStatement = [this](const llvm::Annotations &Input,
3541                                 syntax::TranslationUnit *TU) {
3542     auto *S = cast<syntax::Statement>(nodeByRange(Input.range(), TU));
3543     ASSERT_TRUE(S->canModify()) << "cannot remove a statement";
3544     syntax::removeStatement(*Arena, S);
3545     EXPECT_TRUE(S->isDetached());
3546     EXPECT_FALSE(S->isOriginal())
3547         << "node removed from tree cannot be marked as original";
3548   };
3549 
3550   std::vector<std::pair<std::string /*Input*/, std::string /*Expected*/>>
3551       Cases = {
3552           {"void test() { [[100+100;]] test(); }", "void test() {  test(); }"},
3553           {"void test() { if (true) [[{}]] else {} }",
3554            "void test() { if (true) ; else {} }"},
3555           {"void test() { [[;]] }", "void test() {  }"}};
3556   for (const auto &C : Cases)
3557     CheckTransformation(C.first, C.second, RemoveStatement);
3558 }
3559 
3560 TEST_P(SyntaxTreeTest, SynthesizedNodes) {
3561   buildTree("", GetParam());
3562 
3563   auto *C = syntax::createPunctuation(*Arena, tok::comma);
3564   ASSERT_NE(C, nullptr);
3565   EXPECT_EQ(C->token()->kind(), tok::comma);
3566   EXPECT_TRUE(C->canModify());
3567   EXPECT_FALSE(C->isOriginal());
3568   EXPECT_TRUE(C->isDetached());
3569 
3570   auto *S = syntax::createEmptyStatement(*Arena);
3571   ASSERT_NE(S, nullptr);
3572   EXPECT_TRUE(S->canModify());
3573   EXPECT_FALSE(S->isOriginal());
3574   EXPECT_TRUE(S->isDetached());
3575 }
3576 
3577 INSTANTIATE_TEST_CASE_P(SyntaxTreeTests, SyntaxTreeTest,
3578                         testing::ValuesIn(TestClangConfig::allConfigs()), );
3579 
3580 } // namespace
3581