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