//===- BuildTreeTest.cpp --------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file tests the syntax tree generation from the ClangAST. // //===----------------------------------------------------------------------===// #include "TreeTestBase.h" using namespace clang; using namespace clang::syntax; namespace { class BuildSyntaxTreeTest : public SyntaxTreeTest { protected: ::testing::AssertionResult treeDumpEqual(StringRef Code, StringRef Tree) { SCOPED_TRACE(llvm::join(GetParam().getCommandLineArgs(), " ")); auto *Root = buildTree(Code, GetParam()); if (Diags->getClient()->getNumErrors() != 0) { return ::testing::AssertionFailure() << "Source file has syntax errors, they were printed to the test " "log"; } auto Actual = StringRef(Root->dump(Arena->getSourceManager())).trim().str(); // EXPECT_EQ shows the diff between the two strings if they are different. EXPECT_EQ(Tree.trim().str(), Actual); if (Actual != Tree.trim().str()) { return ::testing::AssertionFailure(); } return ::testing::AssertionSuccess(); } ::testing::AssertionResult treeDumpEqualOnAnnotations(StringRef CodeWithAnnotations, ArrayRef TreeDumps) { SCOPED_TRACE(llvm::join(GetParam().getCommandLineArgs(), " ")); auto AnnotatedCode = llvm::Annotations(CodeWithAnnotations); auto *Root = buildTree(AnnotatedCode.code(), GetParam()); if (Diags->getClient()->getNumErrors() != 0) { return ::testing::AssertionFailure() << "Source file has syntax errors, they were printed to the test " "log"; } auto AnnotatedRanges = AnnotatedCode.ranges(); if (AnnotatedRanges.size() != TreeDumps.size()) { return ::testing::AssertionFailure() << "The number of annotated ranges in the source code is " "different " "to the number of their corresponding tree dumps."; } bool Failed = false; for (unsigned i = 0; i < AnnotatedRanges.size(); i++) { auto *AnnotatedNode = nodeByRange(AnnotatedRanges[i], Root); assert(AnnotatedNode); auto AnnotatedNodeDump = StringRef(AnnotatedNode->dump(Arena->getSourceManager())) .trim() .str(); // EXPECT_EQ shows the diff between the two strings if they are different. EXPECT_EQ(TreeDumps[i].trim().str(), AnnotatedNodeDump) << "Dumps diverged for the code:\n" << AnnotatedCode.code().slice(AnnotatedRanges[i].Begin, AnnotatedRanges[i].End); if (AnnotatedNodeDump != TreeDumps[i].trim().str()) Failed = true; } return Failed ? ::testing::AssertionFailure() : ::testing::AssertionSuccess(); } }; INSTANTIATE_TEST_CASE_P(SyntaxTreeTests, BuildSyntaxTreeTest, testing::ValuesIn(allTestClangConfigs()), ); TEST_P(BuildSyntaxTreeTest, Simple) { EXPECT_TRUE(treeDumpEqual( R"cpp( int main() {} void foo() {} )cpp", R"txt( TranslationUnit Detached |-SimpleDeclaration | |-'int' | |-DeclaratorList Declarators | | `-SimpleDeclarator ListElement | | |-'main' | | `-ParametersAndQualifiers | | |-'(' OpenParen | | `-')' CloseParen | `-CompoundStatement | |-'{' OpenParen | `-'}' CloseParen `-SimpleDeclaration |-'void' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'foo' | `-ParametersAndQualifiers | |-'(' OpenParen | `-')' CloseParen `-CompoundStatement |-'{' OpenParen `-'}' CloseParen )txt")); } TEST_P(BuildSyntaxTreeTest, SimpleVariable) { EXPECT_TRUE(treeDumpEqual( R"cpp( int a; int b = 42; )cpp", R"txt( TranslationUnit Detached |-SimpleDeclaration | |-'int' | |-DeclaratorList Declarators | | `-SimpleDeclarator ListElement | | `-'a' | `-';' `-SimpleDeclaration |-'int' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'b' | |-'=' | `-IntegerLiteralExpression | `-'42' LiteralToken `-';' )txt")); } TEST_P(BuildSyntaxTreeTest, SimpleFunction) { EXPECT_TRUE(treeDumpEqual( R"cpp( void foo(int a, int b) {} )cpp", R"txt( TranslationUnit Detached `-SimpleDeclaration |-'void' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'foo' | `-ParametersAndQualifiers | |-'(' OpenParen | |-ParameterDeclarationList Parameters | | |-SimpleDeclaration ListElement | | | |-'int' | | | `-DeclaratorList Declarators | | | `-SimpleDeclarator ListElement | | | `-'a' | | |-',' ListDelimiter | | `-SimpleDeclaration ListElement | | |-'int' | | `-DeclaratorList Declarators | | `-SimpleDeclarator ListElement | | `-'b' | `-')' CloseParen `-CompoundStatement |-'{' OpenParen `-'}' CloseParen )txt")); } TEST_P(BuildSyntaxTreeTest, Simple_BackslashInsideToken) { EXPECT_TRUE(treeDumpEqual( R"cpp( in\ t a; )cpp", R"txt( TranslationUnit Detached `-SimpleDeclaration |-'in\ t' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | `-'a' `-';' )txt")); } TEST_P(BuildSyntaxTreeTest, If) { EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( void test() { [[if (1) {}]] [[if (1) {} else if (0) {}]] } )cpp", {R"txt( IfStatement Statement |-'if' IntroducerKeyword |-'(' |-IntegerLiteralExpression | `-'1' LiteralToken |-')' `-CompoundStatement ThenStatement |-'{' OpenParen `-'}' CloseParen )txt", R"txt( IfStatement Statement |-'if' IntroducerKeyword |-'(' |-IntegerLiteralExpression | `-'1' LiteralToken |-')' |-CompoundStatement ThenStatement | |-'{' OpenParen | `-'}' CloseParen |-'else' ElseKeyword `-IfStatement ElseStatement |-'if' IntroducerKeyword |-'(' |-IntegerLiteralExpression | `-'0' LiteralToken |-')' `-CompoundStatement ThenStatement |-'{' OpenParen `-'}' CloseParen )txt"})); } TEST_P(BuildSyntaxTreeTest, For) { EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( void test() { [[for (;;) {}]] } )cpp", {R"txt( ForStatement Statement |-'for' IntroducerKeyword |-'(' |-';' |-';' |-')' `-CompoundStatement BodyStatement |-'{' OpenParen `-'}' CloseParen )txt"})); } TEST_P(BuildSyntaxTreeTest, RangeBasedFor) { if (!GetParam().isCXX11OrLater()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( void test() { int a[3]; [[for (int x : a) ;]] } )cpp", {R"txt( RangeBasedForStatement Statement |-'for' IntroducerKeyword |-'(' |-SimpleDeclaration | |-'int' | |-DeclaratorList Declarators | | `-SimpleDeclarator ListElement | | `-'x' | `-':' |-IdExpression | `-UnqualifiedId UnqualifiedId | `-'a' |-')' `-EmptyStatement BodyStatement `-';' )txt"})); } TEST_P(BuildSyntaxTreeTest, DeclarationStatement) { EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( void test() { [[int a = 10;]] } )cpp", {R"txt( DeclarationStatement Statement |-SimpleDeclaration | |-'int' | `-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'a' | |-'=' | `-IntegerLiteralExpression | `-'10' LiteralToken `-';' )txt"})); } TEST_P(BuildSyntaxTreeTest, Switch) { EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( void test() { [[switch (1) { case 0: default:; }]] } )cpp", {R"txt( SwitchStatement Statement |-'switch' IntroducerKeyword |-'(' |-IntegerLiteralExpression | `-'1' LiteralToken |-')' `-CompoundStatement BodyStatement |-'{' OpenParen |-CaseStatement Statement | |-'case' IntroducerKeyword | |-IntegerLiteralExpression CaseValue | | `-'0' LiteralToken | |-':' | `-DefaultStatement BodyStatement | |-'default' IntroducerKeyword | |-':' | `-EmptyStatement BodyStatement | `-';' `-'}' CloseParen )txt"})); } TEST_P(BuildSyntaxTreeTest, While) { EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( void test() { [[while (1) { continue; break; }]] } )cpp", {R"txt( WhileStatement Statement |-'while' IntroducerKeyword |-'(' |-IntegerLiteralExpression | `-'1' LiteralToken |-')' `-CompoundStatement BodyStatement |-'{' OpenParen |-ContinueStatement Statement | |-'continue' IntroducerKeyword | `-';' |-BreakStatement Statement | |-'break' IntroducerKeyword | `-';' `-'}' CloseParen )txt"})); } TEST_P(BuildSyntaxTreeTest, UnhandledStatement) { // Unhandled statements should end up as 'unknown statement'. // This example uses a 'label statement', which does not yet have a syntax // counterpart. EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( int test() { [[foo: return 100;]] } )cpp", {R"txt( UnknownStatement Statement |-'foo' |-':' `-ReturnStatement |-'return' IntroducerKeyword |-IntegerLiteralExpression ReturnValue | `-'100' LiteralToken `-';' )txt"})); } TEST_P(BuildSyntaxTreeTest, Expressions) { // expressions should be wrapped in 'ExpressionStatement' when they appear // in a statement position. EXPECT_TRUE(treeDumpEqual( R"cpp( void test() { test(); if (1) test(); else test(); } )cpp", R"txt( TranslationUnit Detached `-SimpleDeclaration |-'void' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'test' | `-ParametersAndQualifiers | |-'(' OpenParen | `-')' CloseParen `-CompoundStatement |-'{' OpenParen |-ExpressionStatement Statement | |-CallExpression Expression | | |-IdExpression Callee | | | `-UnqualifiedId UnqualifiedId | | | `-'test' | | |-'(' OpenParen | | `-')' CloseParen | `-';' |-IfStatement Statement | |-'if' IntroducerKeyword | |-'(' | |-IntegerLiteralExpression | | `-'1' LiteralToken | |-')' | |-ExpressionStatement ThenStatement | | |-CallExpression Expression | | | |-IdExpression Callee | | | | `-UnqualifiedId UnqualifiedId | | | | `-'test' | | | |-'(' OpenParen | | | `-')' CloseParen | | `-';' | |-'else' ElseKeyword | `-ExpressionStatement ElseStatement | |-CallExpression Expression | | |-IdExpression Callee | | | `-UnqualifiedId UnqualifiedId | | | `-'test' | | |-'(' OpenParen | | `-')' CloseParen | `-';' `-'}' CloseParen )txt")); } TEST_P(BuildSyntaxTreeTest, UnqualifiedId_Identifier) { EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( void test(int a) { [[a]]; } )cpp", {R"txt( IdExpression Expression `-UnqualifiedId UnqualifiedId `-'a' )txt"})); } TEST_P(BuildSyntaxTreeTest, UnqualifiedId_OperatorFunctionId) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct X { friend X operator+(const X&, const X&); }; void test(X x) { [[operator+(x, x)]]; } )cpp", {R"txt( CallExpression Expression |-IdExpression Callee | `-UnqualifiedId UnqualifiedId | |-'operator' | `-'+' |-'(' OpenParen |-CallArguments Arguments | |-IdExpression ListElement | | `-UnqualifiedId UnqualifiedId | | `-'x' | |-',' ListDelimiter | `-IdExpression ListElement | `-UnqualifiedId UnqualifiedId | `-'x' `-')' CloseParen )txt"})); } TEST_P(BuildSyntaxTreeTest, UnqualifiedId_ConversionFunctionId) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct X { operator int(); }; void test(X x) { [[x.operator int()]]; } )cpp", {R"txt( CallExpression Expression |-MemberExpression Callee | |-IdExpression Object | | `-UnqualifiedId UnqualifiedId | | `-'x' | |-'.' AccessToken | `-IdExpression Member | `-UnqualifiedId UnqualifiedId | |-'operator' | `-'int' |-'(' OpenParen `-')' CloseParen )txt"})); } TEST_P(BuildSyntaxTreeTest, UnqualifiedId_LiteralOperatorId) { if (!GetParam().isCXX11OrLater()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( unsigned operator "" _w(char); void test() { [[operator "" _w('1')]]; } )cpp", {R"txt( CallExpression Expression |-IdExpression Callee | `-UnqualifiedId UnqualifiedId | |-'operator' | |-'""' | `-'_w' |-'(' OpenParen |-CallArguments Arguments | `-CharacterLiteralExpression ListElement | `-''1'' LiteralToken `-')' CloseParen )txt"})); } TEST_P(BuildSyntaxTreeTest, UnqualifiedId_Destructor) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct X { }; void test(X x) { [[x.~X()]]; } )cpp", {R"txt( CallExpression Expression |-MemberExpression Callee | |-IdExpression Object | | `-UnqualifiedId UnqualifiedId | | `-'x' | |-'.' AccessToken | `-IdExpression Member | `-UnqualifiedId UnqualifiedId | |-'~' | `-'X' |-'(' OpenParen `-')' CloseParen )txt"})); } TEST_P(BuildSyntaxTreeTest, UnqualifiedId_DecltypeDestructor) { if (!GetParam().isCXX11OrLater()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct X { }; void test(X x) { // FIXME: Make `decltype(x)` a child of `MemberExpression`. It is currently // not because `Expr::getSourceRange()` returns the range of `x.~` for the // `MemberExpr` instead of the expected `x.~decltype(x)`, this is a bug in // clang. [[x.~decltype(x)()]]; } )cpp", {R"txt( CallExpression Expression |-MemberExpression Callee | |-IdExpression Object | | `-UnqualifiedId UnqualifiedId | | `-'x' | |-'.' AccessToken | `-IdExpression Member | `-UnqualifiedId UnqualifiedId | `-'~' |-'decltype' |-'(' |-'x' |-')' |-'(' `-')' CloseParen )txt"})); } TEST_P(BuildSyntaxTreeTest, UnqualifiedId_TemplateId) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( template T f(); void test() { [[f()]]; } )cpp", {R"txt( CallExpression Expression |-IdExpression Callee | `-UnqualifiedId UnqualifiedId | |-'f' | |-'<' | |-'int' | `-'>' |-'(' OpenParen `-')' CloseParen )txt"})); } TEST_P(BuildSyntaxTreeTest, QualifiedId_NamespaceSpecifier) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( namespace n { struct S { }; } void test() { [[::n::S s1]]; [[n::S s2]]; } )cpp", {R"txt( SimpleDeclaration |-NestedNameSpecifier | |-'::' ListDelimiter | |-IdentifierNameSpecifier ListElement | | `-'n' | `-'::' ListDelimiter |-'S' `-DeclaratorList Declarators `-SimpleDeclarator ListElement `-'s1' )txt", R"txt( SimpleDeclaration |-NestedNameSpecifier | |-IdentifierNameSpecifier ListElement | | `-'n' | `-'::' ListDelimiter |-'S' `-DeclaratorList Declarators `-SimpleDeclarator ListElement `-'s2' )txt"})); } TEST_P(BuildSyntaxTreeTest, QualifiedId_TemplateSpecifier) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( template struct ST { struct S { }; }; void test() { [[::template ST::S s1]]; [[::ST::S s2]]; } )cpp", {R"txt( SimpleDeclaration |-NestedNameSpecifier | |-'::' ListDelimiter | |-SimpleTemplateNameSpecifier ListElement | | |-'template' | | |-'ST' | | |-'<' | | |-'int' | | `-'>' | `-'::' ListDelimiter |-'S' `-DeclaratorList Declarators `-SimpleDeclarator ListElement `-'s1' )txt", R"txt( SimpleDeclaration |-NestedNameSpecifier | |-'::' ListDelimiter | |-SimpleTemplateNameSpecifier ListElement | | |-'ST' | | |-'<' | | |-'int' | | `-'>' | `-'::' ListDelimiter |-'S' `-DeclaratorList Declarators `-SimpleDeclarator ListElement `-'s2' )txt"})); } TEST_P(BuildSyntaxTreeTest, QualifiedId_DecltypeSpecifier) { if (!GetParam().isCXX11OrLater()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct S { static void f(){} }; void test(S s) { [[decltype(s)::f()]]; } )cpp", {R"txt( CallExpression Expression |-IdExpression Callee | |-NestedNameSpecifier Qualifier | | |-DecltypeNameSpecifier ListElement | | | |-'decltype' | | | |-'(' | | | |-IdExpression | | | | `-UnqualifiedId UnqualifiedId | | | | `-'s' | | | `-')' | | `-'::' ListDelimiter | `-UnqualifiedId UnqualifiedId | `-'f' |-'(' OpenParen `-')' CloseParen )txt"})); } TEST_P(BuildSyntaxTreeTest, QualifiedId_OptionalTemplateKw) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct S { template static U f(); }; void test() { [[S::f()]]; [[S::template f()]]; } )cpp", {R"txt( CallExpression Expression |-IdExpression Callee | |-NestedNameSpecifier Qualifier | | |-IdentifierNameSpecifier ListElement | | | `-'S' | | `-'::' ListDelimiter | `-UnqualifiedId UnqualifiedId | |-'f' | |-'<' | |-'int' | `-'>' |-'(' OpenParen `-')' CloseParen )txt", R"txt( CallExpression Expression |-IdExpression Callee | |-NestedNameSpecifier Qualifier | | |-IdentifierNameSpecifier ListElement | | | `-'S' | | `-'::' ListDelimiter | |-'template' TemplateKeyword | `-UnqualifiedId UnqualifiedId | |-'f' | |-'<' | |-'int' | `-'>' |-'(' OpenParen `-')' CloseParen )txt"})); } TEST_P(BuildSyntaxTreeTest, QualifiedId_Complex) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( namespace n { template struct ST { template static U f(); }; } void test() { [[::n::template ST::template f()]]; } )cpp", {R"txt( CallExpression Expression |-IdExpression Callee | |-NestedNameSpecifier Qualifier | | |-'::' ListDelimiter | | |-IdentifierNameSpecifier ListElement | | | `-'n' | | |-'::' ListDelimiter | | |-SimpleTemplateNameSpecifier ListElement | | | |-'template' | | | |-'ST' | | | |-'<' | | | |-'int' | | | `-'>' | | `-'::' ListDelimiter | |-'template' TemplateKeyword | `-UnqualifiedId UnqualifiedId | |-'f' | |-'<' | |-'int' | `-'>' |-'(' OpenParen `-')' CloseParen )txt"})); } TEST_P(BuildSyntaxTreeTest, QualifiedId_DependentType) { if (!GetParam().isCXX()) { return; } if (GetParam().hasDelayedTemplateParsing()) { // FIXME: Make this test work on Windows by generating the expected syntax // tree when `-fdelayed-template-parsing` is active. return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( template void test() { [[T::template U::f()]]; [[T::U::f()]]; [[T::template f<0>()]]; } )cpp", {R"txt( CallExpression Expression |-IdExpression Callee | |-NestedNameSpecifier Qualifier | | |-IdentifierNameSpecifier ListElement | | | `-'T' | | |-'::' ListDelimiter | | |-SimpleTemplateNameSpecifier ListElement | | | |-'template' | | | |-'U' | | | |-'<' | | | |-'int' | | | `-'>' | | `-'::' ListDelimiter | `-UnqualifiedId UnqualifiedId | `-'f' |-'(' OpenParen `-')' CloseParen )txt", R"txt( CallExpression Expression |-IdExpression Callee | |-NestedNameSpecifier Qualifier | | |-IdentifierNameSpecifier ListElement | | | `-'T' | | |-'::' ListDelimiter | | |-IdentifierNameSpecifier ListElement | | | `-'U' | | `-'::' ListDelimiter | `-UnqualifiedId UnqualifiedId | `-'f' |-'(' OpenParen `-')' CloseParen )txt", R"txt( CallExpression Expression |-IdExpression Callee | |-NestedNameSpecifier Qualifier | | |-IdentifierNameSpecifier ListElement | | | `-'T' | | `-'::' ListDelimiter | |-'template' TemplateKeyword | `-UnqualifiedId UnqualifiedId | |-'f' | |-'<' | |-IntegerLiteralExpression | | `-'0' LiteralToken | `-'>' |-'(' OpenParen `-')' CloseParen )txt"})); } TEST_P(BuildSyntaxTreeTest, This_Simple) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct S { S* test(){ return [[this]]; } }; )cpp", {R"txt( ThisExpression ReturnValue `-'this' IntroducerKeyword )txt"})); } TEST_P(BuildSyntaxTreeTest, This_ExplicitMemberAccess) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct S { int a; void test(){ [[this->a]]; } }; )cpp", {R"txt( MemberExpression Expression |-ThisExpression Object | `-'this' IntroducerKeyword |-'->' AccessToken `-IdExpression Member `-UnqualifiedId UnqualifiedId `-'a' )txt"})); } TEST_P(BuildSyntaxTreeTest, This_ImplicitMemberAccess) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct S { int a; void test(){ [[a]]; } }; )cpp", {R"txt( IdExpression Expression `-UnqualifiedId UnqualifiedId `-'a' )txt"})); } TEST_P(BuildSyntaxTreeTest, ParenExpr) { EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( void test() { [[(1)]]; [[((1))]]; [[(1 + (2))]]; } )cpp", {R"txt( ParenExpression Expression |-'(' OpenParen |-IntegerLiteralExpression SubExpression | `-'1' LiteralToken `-')' CloseParen )txt", R"txt( ParenExpression Expression |-'(' OpenParen |-ParenExpression SubExpression | |-'(' OpenParen | |-IntegerLiteralExpression SubExpression | | `-'1' LiteralToken | `-')' CloseParen `-')' CloseParen )txt", R"txt( ParenExpression Expression |-'(' OpenParen |-BinaryOperatorExpression SubExpression | |-IntegerLiteralExpression LeftHandSide | | `-'1' LiteralToken | |-'+' OperatorToken | `-ParenExpression RightHandSide | |-'(' OpenParen | |-IntegerLiteralExpression SubExpression | | `-'2' LiteralToken | `-')' CloseParen `-')' CloseParen )txt"})); } TEST_P(BuildSyntaxTreeTest, UserDefinedLiteral_Char) { if (!GetParam().isCXX11OrLater()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( unsigned operator "" _c(char); void test() { [['2'_c]]; } )cpp", {R"txt( CharUserDefinedLiteralExpression Expression `-''2'_c' LiteralToken )txt"})); } TEST_P(BuildSyntaxTreeTest, UserDefinedLiteral_String) { if (!GetParam().isCXX11OrLater()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( typedef decltype(sizeof(void *)) size_t; unsigned operator "" _s(const char*, size_t); void test() { [["12"_s]]; } )cpp", {R"txt( StringUserDefinedLiteralExpression Expression `-'"12"_s' LiteralToken )txt"})); } TEST_P(BuildSyntaxTreeTest, UserDefinedLiteral_Integer) { if (!GetParam().isCXX11OrLater()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( unsigned operator "" _i(unsigned long long); unsigned operator "" _r(const char*); template unsigned operator "" _t(); void test() { [[12_i]]; [[12_r]]; [[12_t]]; } )cpp", {R"txt( IntegerUserDefinedLiteralExpression Expression `-'12_i' LiteralToken )txt", R"txt( IntegerUserDefinedLiteralExpression Expression `-'12_r' LiteralToken )txt", R"txt( IntegerUserDefinedLiteralExpression Expression `-'12_t' LiteralToken )txt"})); } TEST_P(BuildSyntaxTreeTest, UserDefinedLiteral_Float) { if (!GetParam().isCXX11OrLater()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( unsigned operator "" _f(long double); unsigned operator "" _r(const char*); template unsigned operator "" _t(); void test() { [[1.2_f]]; [[1.2_r]]; [[1.2_t]]; } )cpp", {R"txt( FloatUserDefinedLiteralExpression Expression `-'1.2_f' LiteralToken )txt", R"txt( FloatUserDefinedLiteralExpression Expression `-'1.2_r' LiteralToken )txt", R"txt( FloatUserDefinedLiteralExpression Expression `-'1.2_t' LiteralToken )txt"})); } TEST_P(BuildSyntaxTreeTest, IntegerLiteral_LongLong) { if (!GetParam().isCXX11OrLater()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( void test() { [[12ll]]; [[12ull]]; } )cpp", {R"txt( IntegerLiteralExpression Expression `-'12ll' LiteralToken )txt", R"txt( IntegerLiteralExpression Expression `-'12ull' LiteralToken )txt"})); } TEST_P(BuildSyntaxTreeTest, IntegerLiteral_Binary) { if (!GetParam().isCXX14OrLater()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( void test() { [[0b1100]]; } )cpp", {R"txt( IntegerLiteralExpression Expression `-'0b1100' LiteralToken )txt"})); } TEST_P(BuildSyntaxTreeTest, IntegerLiteral_WithDigitSeparators) { if (!GetParam().isCXX14OrLater()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( void test() { [[1'2'0ull]]; } )cpp", {R"txt( IntegerLiteralExpression Expression `-'1'2'0ull' LiteralToken )txt"})); } TEST_P(BuildSyntaxTreeTest, CharacterLiteral) { EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( void test() { [['a']]; [['\n']]; [['\x20']]; [['\0']]; [[L'a']]; [[L'α']]; } )cpp", {R"txt( CharacterLiteralExpression Expression `-''a'' LiteralToken )txt", R"txt( CharacterLiteralExpression Expression `-''\n'' LiteralToken )txt", R"txt( CharacterLiteralExpression Expression `-''\x20'' LiteralToken )txt", R"txt( CharacterLiteralExpression Expression `-''\0'' LiteralToken )txt", R"txt( CharacterLiteralExpression Expression `-'L'a'' LiteralToken )txt", R"txt( CharacterLiteralExpression Expression `-'L'α'' LiteralToken )txt"})); } TEST_P(BuildSyntaxTreeTest, CharacterLiteral_Utf) { if (!GetParam().isCXX11OrLater()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( void test() { [[u'a']]; [[u'構']]; [[U'a']]; [[U'🌲']]; } )cpp", {R"txt( CharacterLiteralExpression Expression `-'u'a'' LiteralToken )txt", R"txt( CharacterLiteralExpression Expression `-'u'構'' LiteralToken )txt", R"txt( CharacterLiteralExpression Expression `-'U'a'' LiteralToken )txt", R"txt( CharacterLiteralExpression Expression `-'U'🌲'' LiteralToken )txt"})); } TEST_P(BuildSyntaxTreeTest, CharacterLiteral_Utf8) { if (!GetParam().isCXX17OrLater()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( void test() { [[u8'a']]; [[u8'\x7f']]; } )cpp", {R"txt( CharacterLiteralExpression Expression `-'u8'a'' LiteralToken )txt", R"txt( CharacterLiteralExpression Expression `-'u8'\x7f'' LiteralToken )txt"})); } TEST_P(BuildSyntaxTreeTest, FloatingLiteral) { EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( void test() { [[1e-2]]; [[2.]]; [[.2]]; [[2.f]]; } )cpp", {R"txt( FloatingLiteralExpression Expression `-'1e-2' LiteralToken )txt", R"txt( FloatingLiteralExpression Expression `-'2.' LiteralToken )txt", R"txt( FloatingLiteralExpression Expression `-'.2' LiteralToken )txt", R"txt( FloatingLiteralExpression Expression `-'2.f' LiteralToken )txt"})); } TEST_P(BuildSyntaxTreeTest, FloatingLiteral_Hexadecimal) { if (!GetParam().isCXX17OrLater()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( void test() { [[0xfp1]]; [[0xf.p1]]; [[0x.fp1]]; [[0xf.fp1f]]; } )cpp", {R"txt( FloatingLiteralExpression Expression `-'0xfp1' LiteralToken )txt", R"txt( FloatingLiteralExpression Expression `-'0xf.p1' LiteralToken )txt", R"txt( FloatingLiteralExpression Expression `-'0x.fp1' LiteralToken )txt", R"txt( FloatingLiteralExpression Expression `-'0xf.fp1f' LiteralToken )txt"})); } TEST_P(BuildSyntaxTreeTest, StringLiteral) { EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( void test() { [["a\n\0\x20"]]; [[L"αβ"]]; } )cpp", {R"txt( StringLiteralExpression Expression `-'"a\n\0\x20"' LiteralToken )txt", R"txt( StringLiteralExpression Expression `-'L"αβ"' LiteralToken )txt"})); } TEST_P(BuildSyntaxTreeTest, StringLiteral_Utf) { if (!GetParam().isCXX11OrLater()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( void test() { [[u8"a\x1f\x05"]]; [[u"C++抽象構文木"]]; [[U"📖🌲\n"]]; } )cpp", {R"txt( StringLiteralExpression Expression `-'u8"a\x1f\x05"' LiteralToken )txt", R"txt( StringLiteralExpression Expression `-'u"C++抽象構文木"' LiteralToken )txt", R"txt( StringLiteralExpression Expression `-'U"📖🌲\n"' LiteralToken )txt"})); } TEST_P(BuildSyntaxTreeTest, StringLiteral_Raw) { if (!GetParam().isCXX11OrLater()) { return; } // This test uses regular string literals instead of raw string literals to // hold source code and expected output because of a bug in MSVC up to MSVC // 2019 16.2: // https://developercommunity.visualstudio.com/content/problem/67300/stringifying-raw-string-literal.html EXPECT_TRUE(treeDumpEqual( // "void test() {\n" " R\"SyntaxTree(\n" " Hello \"Syntax\" \\\"\n" " )SyntaxTree\";\n" "}\n", "TranslationUnit Detached\n" "`-SimpleDeclaration\n" " |-'void'\n" " |-DeclaratorList Declarators\n" " | `-SimpleDeclarator ListElement\n" " | |-'test'\n" " | `-ParametersAndQualifiers\n" " | |-'(' OpenParen\n" " | `-')' CloseParen\n" " `-CompoundStatement\n" " |-'{' OpenParen\n" " |-ExpressionStatement Statement\n" " | |-StringLiteralExpression Expression\n" " | | `-'R\"SyntaxTree(\n" " Hello \"Syntax\" \\\"\n" " )SyntaxTree\"' LiteralToken\n" " | `-';'\n" " `-'}' CloseParen\n")); } TEST_P(BuildSyntaxTreeTest, BoolLiteral) { if (GetParam().isC()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( void test() { [[true]]; [[false]]; } )cpp", {R"txt( BoolLiteralExpression Expression `-'true' LiteralToken )txt", R"txt( BoolLiteralExpression Expression `-'false' LiteralToken )txt"})); } TEST_P(BuildSyntaxTreeTest, CxxNullPtrLiteral) { if (!GetParam().isCXX11OrLater()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( void test() { [[nullptr]]; } )cpp", {R"txt( CxxNullPtrExpression Expression `-'nullptr' LiteralToken )txt"})); } TEST_P(BuildSyntaxTreeTest, PostfixUnaryOperator) { EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( void test(int a) { [[a++]]; [[a--]]; } )cpp", {R"txt( PostfixUnaryOperatorExpression Expression |-IdExpression Operand | `-UnqualifiedId UnqualifiedId | `-'a' `-'++' OperatorToken )txt", R"txt( PostfixUnaryOperatorExpression Expression |-IdExpression Operand | `-UnqualifiedId UnqualifiedId | `-'a' `-'--' OperatorToken )txt"})); } TEST_P(BuildSyntaxTreeTest, PrefixUnaryOperator) { EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( void test(int a, int *ap) { [[--a]]; [[++a]]; [[~a]]; [[-a]]; [[+a]]; [[&a]]; [[*ap]]; [[!a]]; [[__real a]]; [[__imag a]]; } )cpp", {R"txt( PrefixUnaryOperatorExpression Expression |-'--' OperatorToken `-IdExpression Operand `-UnqualifiedId UnqualifiedId `-'a' )txt", R"txt( PrefixUnaryOperatorExpression Expression |-'++' OperatorToken `-IdExpression Operand `-UnqualifiedId UnqualifiedId `-'a' )txt", R"txt( PrefixUnaryOperatorExpression Expression |-'~' OperatorToken `-IdExpression Operand `-UnqualifiedId UnqualifiedId `-'a' )txt", R"txt( PrefixUnaryOperatorExpression Expression |-'-' OperatorToken `-IdExpression Operand `-UnqualifiedId UnqualifiedId `-'a' )txt", R"txt( PrefixUnaryOperatorExpression Expression |-'+' OperatorToken `-IdExpression Operand `-UnqualifiedId UnqualifiedId `-'a' )txt", R"txt( PrefixUnaryOperatorExpression Expression |-'&' OperatorToken `-IdExpression Operand `-UnqualifiedId UnqualifiedId `-'a' )txt", R"txt( PrefixUnaryOperatorExpression Expression |-'*' OperatorToken `-IdExpression Operand `-UnqualifiedId UnqualifiedId `-'ap' )txt", R"txt( PrefixUnaryOperatorExpression Expression |-'!' OperatorToken `-IdExpression Operand `-UnqualifiedId UnqualifiedId `-'a' )txt", R"txt( PrefixUnaryOperatorExpression Expression |-'__real' OperatorToken `-IdExpression Operand `-UnqualifiedId UnqualifiedId `-'a' )txt", R"txt( PrefixUnaryOperatorExpression Expression |-'__imag' OperatorToken `-IdExpression Operand `-UnqualifiedId UnqualifiedId `-'a' )txt"})); } TEST_P(BuildSyntaxTreeTest, PrefixUnaryOperatorCxx) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( void test(int a, bool b) { [[compl a]]; [[not b]]; } )cpp", {R"txt( PrefixUnaryOperatorExpression Expression |-'compl' OperatorToken `-IdExpression Operand `-UnqualifiedId UnqualifiedId `-'a' )txt", R"txt( PrefixUnaryOperatorExpression Expression |-'not' OperatorToken `-IdExpression Operand `-UnqualifiedId UnqualifiedId `-'b' )txt"})); } TEST_P(BuildSyntaxTreeTest, BinaryOperator) { EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( void test(int a) { [[1 - 2]]; [[1 == 2]]; [[a = 1]]; [[a <<= 1]]; [[1 || 0]]; [[1 & 2]]; [[a != 3]]; } )cpp", {R"txt( BinaryOperatorExpression Expression |-IntegerLiteralExpression LeftHandSide | `-'1' LiteralToken |-'-' OperatorToken `-IntegerLiteralExpression RightHandSide `-'2' LiteralToken )txt", R"txt( BinaryOperatorExpression Expression |-IntegerLiteralExpression LeftHandSide | `-'1' LiteralToken |-'==' OperatorToken `-IntegerLiteralExpression RightHandSide `-'2' LiteralToken )txt", R"txt( BinaryOperatorExpression Expression |-IdExpression LeftHandSide | `-UnqualifiedId UnqualifiedId | `-'a' |-'=' OperatorToken `-IntegerLiteralExpression RightHandSide `-'1' LiteralToken )txt", R"txt( BinaryOperatorExpression Expression |-IdExpression LeftHandSide | `-UnqualifiedId UnqualifiedId | `-'a' |-'<<=' OperatorToken `-IntegerLiteralExpression RightHandSide `-'1' LiteralToken )txt", R"txt( BinaryOperatorExpression Expression |-IntegerLiteralExpression LeftHandSide | `-'1' LiteralToken |-'||' OperatorToken `-IntegerLiteralExpression RightHandSide `-'0' LiteralToken )txt", R"txt( BinaryOperatorExpression Expression |-IntegerLiteralExpression LeftHandSide | `-'1' LiteralToken |-'&' OperatorToken `-IntegerLiteralExpression RightHandSide `-'2' LiteralToken )txt", R"txt( BinaryOperatorExpression Expression |-IdExpression LeftHandSide | `-UnqualifiedId UnqualifiedId | `-'a' |-'!=' OperatorToken `-IntegerLiteralExpression RightHandSide `-'3' LiteralToken )txt"})); } TEST_P(BuildSyntaxTreeTest, BinaryOperatorCxx) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( void test(int a) { [[true || false]]; [[true or false]]; [[1 bitand 2]]; [[a xor_eq 3]]; } )cpp", {R"txt( BinaryOperatorExpression Expression |-BoolLiteralExpression LeftHandSide | `-'true' LiteralToken |-'||' OperatorToken `-BoolLiteralExpression RightHandSide `-'false' LiteralToken )txt", R"txt( BinaryOperatorExpression Expression |-BoolLiteralExpression LeftHandSide | `-'true' LiteralToken |-'or' OperatorToken `-BoolLiteralExpression RightHandSide `-'false' LiteralToken )txt", R"txt( BinaryOperatorExpression Expression |-IntegerLiteralExpression LeftHandSide | `-'1' LiteralToken |-'bitand' OperatorToken `-IntegerLiteralExpression RightHandSide `-'2' LiteralToken )txt", R"txt( BinaryOperatorExpression Expression |-IdExpression LeftHandSide | `-UnqualifiedId UnqualifiedId | `-'a' |-'xor_eq' OperatorToken `-IntegerLiteralExpression RightHandSide `-'3' LiteralToken )txt"})); } TEST_P(BuildSyntaxTreeTest, BinaryOperator_NestedWithParenthesis) { EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( void test() { [[(1 + 2) * (4 / 2)]]; } )cpp", {R"txt( BinaryOperatorExpression Expression |-ParenExpression LeftHandSide | |-'(' OpenParen | |-BinaryOperatorExpression SubExpression | | |-IntegerLiteralExpression LeftHandSide | | | `-'1' LiteralToken | | |-'+' OperatorToken | | `-IntegerLiteralExpression RightHandSide | | `-'2' LiteralToken | `-')' CloseParen |-'*' OperatorToken `-ParenExpression RightHandSide |-'(' OpenParen |-BinaryOperatorExpression SubExpression | |-IntegerLiteralExpression LeftHandSide | | `-'4' LiteralToken | |-'/' OperatorToken | `-IntegerLiteralExpression RightHandSide | `-'2' LiteralToken `-')' CloseParen )txt"})); } TEST_P(BuildSyntaxTreeTest, BinaryOperator_Associativity) { EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( void test(int a, int b) { [[a + b + 42]]; [[a = b = 42]]; } )cpp", {R"txt( BinaryOperatorExpression Expression |-BinaryOperatorExpression LeftHandSide | |-IdExpression LeftHandSide | | `-UnqualifiedId UnqualifiedId | | `-'a' | |-'+' OperatorToken | `-IdExpression RightHandSide | `-UnqualifiedId UnqualifiedId | `-'b' |-'+' OperatorToken `-IntegerLiteralExpression RightHandSide `-'42' LiteralToken )txt", R"txt( BinaryOperatorExpression Expression |-IdExpression LeftHandSide | `-UnqualifiedId UnqualifiedId | `-'a' |-'=' OperatorToken `-BinaryOperatorExpression RightHandSide |-IdExpression LeftHandSide | `-UnqualifiedId UnqualifiedId | `-'b' |-'=' OperatorToken `-IntegerLiteralExpression RightHandSide `-'42' LiteralToken )txt"})); } TEST_P(BuildSyntaxTreeTest, BinaryOperator_Precedence) { EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( void test() { [[1 + 2 * 3 + 4]]; [[1 % 2 + 3 * 4]]; } )cpp", {R"txt( BinaryOperatorExpression Expression |-BinaryOperatorExpression LeftHandSide | |-IntegerLiteralExpression LeftHandSide | | `-'1' LiteralToken | |-'+' OperatorToken | `-BinaryOperatorExpression RightHandSide | |-IntegerLiteralExpression LeftHandSide | | `-'2' LiteralToken | |-'*' OperatorToken | `-IntegerLiteralExpression RightHandSide | `-'3' LiteralToken |-'+' OperatorToken `-IntegerLiteralExpression RightHandSide `-'4' LiteralToken )txt", R"txt( BinaryOperatorExpression Expression |-BinaryOperatorExpression LeftHandSide | |-IntegerLiteralExpression LeftHandSide | | `-'1' LiteralToken | |-'%' OperatorToken | `-IntegerLiteralExpression RightHandSide | `-'2' LiteralToken |-'+' OperatorToken `-BinaryOperatorExpression RightHandSide |-IntegerLiteralExpression LeftHandSide | `-'3' LiteralToken |-'*' OperatorToken `-IntegerLiteralExpression RightHandSide `-'4' LiteralToken )txt"})); } TEST_P(BuildSyntaxTreeTest, OverloadedOperator_Assignment) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct X { X& operator=(const X&); }; void test(X x, X y) { [[x = y]]; } )cpp", {R"txt( BinaryOperatorExpression Expression |-IdExpression LeftHandSide | `-UnqualifiedId UnqualifiedId | `-'x' |-'=' OperatorToken `-IdExpression RightHandSide `-UnqualifiedId UnqualifiedId `-'y' )txt"})); } TEST_P(BuildSyntaxTreeTest, OverloadedOperator_Plus) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct X { friend X operator+(X, const X&); }; void test(X x, X y) { [[x + y]]; } )cpp", {R"txt( BinaryOperatorExpression Expression |-IdExpression LeftHandSide | `-UnqualifiedId UnqualifiedId | `-'x' |-'+' OperatorToken `-IdExpression RightHandSide `-UnqualifiedId UnqualifiedId `-'y' )txt"})); } TEST_P(BuildSyntaxTreeTest, OverloadedOperator_Less) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct X { friend bool operator<(const X&, const X&); }; void test(X x, X y) { [[x < y]]; } )cpp", {R"txt( BinaryOperatorExpression Expression |-IdExpression LeftHandSide | `-UnqualifiedId UnqualifiedId | `-'x' |-'<' OperatorToken `-IdExpression RightHandSide `-UnqualifiedId UnqualifiedId `-'y' )txt"})); } TEST_P(BuildSyntaxTreeTest, OverloadedOperator_LeftShift) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct X { friend X operator<<(X&, const X&); }; void test(X x, X y) { [[x << y]]; } )cpp", {R"txt( BinaryOperatorExpression Expression |-IdExpression LeftHandSide | `-UnqualifiedId UnqualifiedId | `-'x' |-'<<' OperatorToken `-IdExpression RightHandSide `-UnqualifiedId UnqualifiedId `-'y' )txt"})); } TEST_P(BuildSyntaxTreeTest, OverloadedOperator_Comma) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct X { X operator,(X&); }; void test(X x, X y) { [[x, y]]; } )cpp", {R"txt( BinaryOperatorExpression Expression |-IdExpression LeftHandSide | `-UnqualifiedId UnqualifiedId | `-'x' |-',' OperatorToken `-IdExpression RightHandSide `-UnqualifiedId UnqualifiedId `-'y' )txt"})); } TEST_P(BuildSyntaxTreeTest, OverloadedOperator_PointerToMember) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct X { X operator->*(int); }; void test(X* xp, int X::* pmi) { [[xp->*pmi]]; } )cpp", {R"txt( BinaryOperatorExpression Expression |-IdExpression LeftHandSide | `-UnqualifiedId UnqualifiedId | `-'xp' |-'->*' OperatorToken `-IdExpression RightHandSide `-UnqualifiedId UnqualifiedId `-'pmi' )txt"})); } TEST_P(BuildSyntaxTreeTest, OverloadedOperator_Negation) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct X { bool operator!(); }; void test(X x) { [[!x]]; } )cpp", {R"txt( PrefixUnaryOperatorExpression Expression |-'!' OperatorToken `-IdExpression Operand `-UnqualifiedId UnqualifiedId `-'x' )txt"})); } TEST_P(BuildSyntaxTreeTest, OverloadedOperator_AddressOf) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct X { X* operator&(); }; void test(X x) { [[&x]]; } )cpp", {R"txt( PrefixUnaryOperatorExpression Expression |-'&' OperatorToken `-IdExpression Operand `-UnqualifiedId UnqualifiedId `-'x' )txt"})); } TEST_P(BuildSyntaxTreeTest, OverloadedOperator_PrefixIncrement) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct X { X operator++(); }; void test(X x) { [[++x]]; } )cpp", {R"txt( PrefixUnaryOperatorExpression Expression |-'++' OperatorToken `-IdExpression Operand `-UnqualifiedId UnqualifiedId `-'x' )txt"})); } TEST_P(BuildSyntaxTreeTest, OverloadedOperator_PostfixIncrement) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct X { X operator++(int); }; void test(X x) { [[x++]]; } )cpp", {R"txt( PostfixUnaryOperatorExpression Expression |-IdExpression Operand | `-UnqualifiedId UnqualifiedId | `-'x' `-'++' OperatorToken )txt"})); } TEST_P(BuildSyntaxTreeTest, MemberExpression_SimpleWithDot) { EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct S { int a; }; void test(struct S s) { [[s.a]]; } )cpp", {R"txt( MemberExpression Expression |-IdExpression Object | `-UnqualifiedId UnqualifiedId | `-'s' |-'.' AccessToken `-IdExpression Member `-UnqualifiedId UnqualifiedId `-'a' )txt"})); } TEST_P(BuildSyntaxTreeTest, MemberExpression_StaticDataMember) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct S { static int a; }; void test(S s) { [[s.a]]; } )cpp", {R"txt( MemberExpression Expression |-IdExpression Object | `-UnqualifiedId UnqualifiedId | `-'s' |-'.' AccessToken `-IdExpression Member `-UnqualifiedId UnqualifiedId `-'a' )txt"})); } TEST_P(BuildSyntaxTreeTest, MemberExpression_SimpleWithArrow) { EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct S { int a; }; void test(struct S* sp) { [[sp->a]]; } )cpp", {R"txt( MemberExpression Expression |-IdExpression Object | `-UnqualifiedId UnqualifiedId | `-'sp' |-'->' AccessToken `-IdExpression Member `-UnqualifiedId UnqualifiedId `-'a' )txt"})); } TEST_P(BuildSyntaxTreeTest, MemberExpression_Chaining) { EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct S { struct S* next; }; void test(struct S s){ [[s.next->next]]; } )cpp", {R"txt( MemberExpression Expression |-MemberExpression Object | |-IdExpression Object | | `-UnqualifiedId UnqualifiedId | | `-'s' | |-'.' AccessToken | `-IdExpression Member | `-UnqualifiedId UnqualifiedId | `-'next' |-'->' AccessToken `-IdExpression Member `-UnqualifiedId UnqualifiedId `-'next' )txt"})); } TEST_P(BuildSyntaxTreeTest, MemberExpression_OperatorFunction) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct S { bool operator!(); }; void test(S s) { [[s.operator!()]]; } )cpp", {R"txt( CallExpression Expression |-MemberExpression Callee | |-IdExpression Object | | `-UnqualifiedId UnqualifiedId | | `-'s' | |-'.' AccessToken | `-IdExpression Member | `-UnqualifiedId UnqualifiedId | |-'operator' | `-'!' |-'(' OpenParen `-')' CloseParen )txt"})); } TEST_P(BuildSyntaxTreeTest, MemberExpression_VariableTemplate) { if (!GetParam().isCXX14OrLater()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct S { template static constexpr T x = 42; }; // FIXME: `` should be a child of `MemberExpression` and `;` of // `ExpressionStatement`. This is a bug in clang, in `getSourceRange` methods. void test(S s) [[{ s.x; }]] )cpp", {R"txt( CompoundStatement |-'{' OpenParen |-ExpressionStatement Statement | `-MemberExpression Expression | |-IdExpression Object | | `-UnqualifiedId UnqualifiedId | | `-'s' | |-'.' AccessToken | `-IdExpression Member | `-UnqualifiedId UnqualifiedId | `-'x' |-'<' |-'int' |-'>' |-';' `-'}' CloseParen )txt"})); } TEST_P(BuildSyntaxTreeTest, MemberExpression_FunctionTemplate) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct S { template T f(); }; void test(S* sp){ [[sp->f()]]; } )cpp", {R"txt( CallExpression Expression |-MemberExpression Callee | |-IdExpression Object | | `-UnqualifiedId UnqualifiedId | | `-'sp' | |-'->' AccessToken | `-IdExpression Member | `-UnqualifiedId UnqualifiedId | |-'f' | |-'<' | |-'int' | `-'>' |-'(' OpenParen `-')' CloseParen )txt"})); } TEST_P(BuildSyntaxTreeTest, MemberExpression_FunctionTemplateWithTemplateKeyword) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct S { template T f(); }; void test(S s){ [[s.template f()]]; } )cpp", {R"txt( CallExpression Expression |-MemberExpression Callee | |-IdExpression Object | | `-UnqualifiedId UnqualifiedId | | `-'s' | |-'.' AccessToken | |-'template' | `-IdExpression Member | `-UnqualifiedId UnqualifiedId | |-'f' | |-'<' | |-'int' | `-'>' |-'(' OpenParen `-')' CloseParen )txt"})); } TEST_P(BuildSyntaxTreeTest, MemberExpression_WithQualifier) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct Base { void f(); }; struct S : public Base {}; void test(S s){ [[s.Base::f()]]; [[s.::S::~S()]]; } )cpp", {R"txt( CallExpression Expression |-MemberExpression Callee | |-IdExpression Object | | `-UnqualifiedId UnqualifiedId | | `-'s' | |-'.' AccessToken | `-IdExpression Member | |-NestedNameSpecifier Qualifier | | |-IdentifierNameSpecifier ListElement | | | `-'Base' | | `-'::' ListDelimiter | `-UnqualifiedId UnqualifiedId | `-'f' |-'(' OpenParen `-')' CloseParen )txt", R"txt( CallExpression Expression |-MemberExpression Callee | |-IdExpression Object | | `-UnqualifiedId UnqualifiedId | | `-'s' | |-'.' AccessToken | `-IdExpression Member | |-NestedNameSpecifier Qualifier | | |-'::' ListDelimiter | | |-IdentifierNameSpecifier ListElement | | | `-'S' | | `-'::' ListDelimiter | `-UnqualifiedId UnqualifiedId | |-'~' | `-'S' |-'(' OpenParen `-')' CloseParen )txt"})); } TEST_P(BuildSyntaxTreeTest, MemberExpression_Complex) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( template struct U { template U f(); }; struct S { U getU(); }; void test(S* sp) { // FIXME: The first 'template' keyword is a child of `NestedNameSpecifier`, // but it should be a child of `MemberExpression` according to the grammar. // However one might argue that the 'template' keyword fits better inside // `NestedNameSpecifier` because if we change `U` to `UI` we would like // equally to change the `NameSpecifier` `template U` to just `UI`. [[sp->getU().template U::template f()]]; } )cpp", {R"txt( CallExpression Expression |-MemberExpression Callee | |-CallExpression Object | | |-MemberExpression Callee | | | |-IdExpression Object | | | | `-UnqualifiedId UnqualifiedId | | | | `-'sp' | | | |-'->' AccessToken | | | `-IdExpression Member | | | `-UnqualifiedId UnqualifiedId | | | `-'getU' | | |-'(' OpenParen | | `-')' CloseParen | |-'.' AccessToken | `-IdExpression Member | |-NestedNameSpecifier Qualifier | | |-SimpleTemplateNameSpecifier ListElement | | | |-'template' | | | |-'U' | | | |-'<' | | | |-'int' | | | `-'>' | | `-'::' ListDelimiter | |-'template' TemplateKeyword | `-UnqualifiedId UnqualifiedId | |-'f' | |-'<' | |-'int' | `-'>' |-'(' OpenParen `-')' CloseParen )txt"})); } TEST_P(BuildSyntaxTreeTest, CallExpression_Callee_Member) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct S{ void f(); }; void test(S s) { [[s.f()]]; } )cpp", {R"txt( CallExpression Expression |-MemberExpression Callee | |-IdExpression Object | | `-UnqualifiedId UnqualifiedId | | `-'s' | |-'.' AccessToken | `-IdExpression Member | `-UnqualifiedId UnqualifiedId | `-'f' |-'(' OpenParen `-')' CloseParen )txt"})); } TEST_P(BuildSyntaxTreeTest, CallExpression_Callee_OperatorParens) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct S { void operator()(); }; void test(S s) { [[s()]]; } )cpp", {R"txt( CallExpression Expression |-IdExpression Callee | `-UnqualifiedId UnqualifiedId | `-'s' |-'(' OpenParen `-')' CloseParen )txt"})); } TEST_P(BuildSyntaxTreeTest, CallExpression_Callee_OperatorParensChaining) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct S { S operator()(); }; void test(S s) { [[s()()]]; } )cpp", {R"txt( CallExpression Expression |-CallExpression Callee | |-IdExpression Callee | | `-UnqualifiedId UnqualifiedId | | `-'s' | |-'(' OpenParen | `-')' CloseParen |-'(' OpenParen `-')' CloseParen )txt"})); } TEST_P(BuildSyntaxTreeTest, CallExpression_Callee_MemberWithThis) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct Base { void f(); }; struct S: public Base { void f(); void test() { [[this->f()]]; [[f()]]; [[this->Base::f()]]; } }; )cpp", {R"txt( CallExpression Expression |-MemberExpression Callee | |-ThisExpression Object | | `-'this' IntroducerKeyword | |-'->' AccessToken | `-IdExpression Member | `-UnqualifiedId UnqualifiedId | `-'f' |-'(' OpenParen `-')' CloseParen )txt", R"txt( CallExpression Expression |-IdExpression Callee | `-UnqualifiedId UnqualifiedId | `-'f' |-'(' OpenParen `-')' CloseParen )txt", R"txt( CallExpression Expression |-MemberExpression Callee | |-ThisExpression Object | | `-'this' IntroducerKeyword | |-'->' AccessToken | `-IdExpression Member | |-NestedNameSpecifier Qualifier | | |-IdentifierNameSpecifier ListElement | | | `-'Base' | | `-'::' ListDelimiter | `-UnqualifiedId UnqualifiedId | `-'f' |-'(' OpenParen `-')' CloseParen )txt"})); } TEST_P(BuildSyntaxTreeTest, CallExpression_Callee_FunctionPointer) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( void (*pf)(); void test() { [[pf()]]; [[(*pf)()]]; } )cpp", {R"txt( CallExpression Expression |-IdExpression Callee | `-UnqualifiedId UnqualifiedId | `-'pf' |-'(' OpenParen `-')' CloseParen )txt", R"txt( CallExpression Expression |-ParenExpression Callee | |-'(' OpenParen | |-PrefixUnaryOperatorExpression SubExpression | | |-'*' OperatorToken | | `-IdExpression Operand | | `-UnqualifiedId UnqualifiedId | | `-'pf' | `-')' CloseParen |-'(' OpenParen `-')' CloseParen )txt"})); } TEST_P(BuildSyntaxTreeTest, CallExpression_Callee_MemberFunctionPointer) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct S { void f(); }; void test(S s) { void (S::*pmf)(); pmf = &S::f; [[(s.*pmf)()]]; } )cpp", {R"txt( CallExpression Expression |-ParenExpression Callee | |-'(' OpenParen | |-BinaryOperatorExpression SubExpression | | |-IdExpression LeftHandSide | | | `-UnqualifiedId UnqualifiedId | | | `-'s' | | |-'.*' OperatorToken | | `-IdExpression RightHandSide | | `-UnqualifiedId UnqualifiedId | | `-'pmf' | `-')' CloseParen |-'(' OpenParen `-')' CloseParen )txt"})); } TEST_P(BuildSyntaxTreeTest, CallExpression_Arguments_Zero) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( void f(); void test() { [[f();]] } )cpp", {R"txt( ExpressionStatement Statement |-CallExpression Expression | |-IdExpression Callee | | `-UnqualifiedId UnqualifiedId | | `-'f' | |-'(' OpenParen | `-')' CloseParen `-';' )txt"})); } TEST_P(BuildSyntaxTreeTest, CallExpression_Arguments_One) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( void f(int); void test() { [[f(1);]] } )cpp", {R"txt( ExpressionStatement Statement |-CallExpression Expression | |-IdExpression Callee | | `-UnqualifiedId UnqualifiedId | | `-'f' | |-'(' OpenParen | |-CallArguments Arguments | | `-IntegerLiteralExpression ListElement | | `-'1' LiteralToken | `-')' CloseParen `-';' )txt"})); } TEST_P(BuildSyntaxTreeTest, CallExpression_Arguments_Multiple) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( void f(int, char, float); void test() { [[f(1, '2', 3.);]] } )cpp", {R"txt( ExpressionStatement Statement |-CallExpression Expression | |-IdExpression Callee | | `-UnqualifiedId UnqualifiedId | | `-'f' | |-'(' OpenParen | |-CallArguments Arguments | | |-IntegerLiteralExpression ListElement | | | `-'1' LiteralToken | | |-',' ListDelimiter | | |-CharacterLiteralExpression ListElement | | | `-''2'' LiteralToken | | |-',' ListDelimiter | | `-FloatingLiteralExpression ListElement | | `-'3.' LiteralToken | `-')' CloseParen `-';' )txt"})); } TEST_P(BuildSyntaxTreeTest, CallExpression_Arguments_Assignment) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( void f(int); void test(int a) { [[f(a = 1);]] } )cpp", {R"txt( ExpressionStatement Statement |-CallExpression Expression | |-IdExpression Callee | | `-UnqualifiedId UnqualifiedId | | `-'f' | |-'(' OpenParen | |-CallArguments Arguments | | `-BinaryOperatorExpression ListElement | | |-IdExpression LeftHandSide | | | `-UnqualifiedId UnqualifiedId | | | `-'a' | | |-'=' OperatorToken | | `-IntegerLiteralExpression RightHandSide | | `-'1' LiteralToken | `-')' CloseParen `-';' )txt"})); } TEST_P(BuildSyntaxTreeTest, CallExpression_Arguments_BracedInitList_Empty) { if (!GetParam().isCXX11OrLater()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( void f(int[]); void test() { [[f({});]] } )cpp", {R"txt( ExpressionStatement Statement |-CallExpression Expression | |-IdExpression Callee | | `-UnqualifiedId UnqualifiedId | | `-'f' | |-'(' OpenParen | |-CallArguments Arguments | | `-UnknownExpression ListElement | | `-UnknownExpression | | |-'{' | | `-'}' | `-')' CloseParen `-';' )txt"})); } TEST_P(BuildSyntaxTreeTest, CallExpression_Arguments_BracedInitList_Simple) { if (!GetParam().isCXX11OrLater()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct TT {}; struct T{ int a; TT b; }; void f(T); void test() { [[f({1, {}});]] } )cpp", {R"txt( ExpressionStatement Statement |-CallExpression Expression | |-IdExpression Callee | | `-UnqualifiedId UnqualifiedId | | `-'f' | |-'(' OpenParen | |-CallArguments Arguments | | `-UnknownExpression ListElement | | `-UnknownExpression | | |-'{' | | |-IntegerLiteralExpression | | | `-'1' LiteralToken | | |-',' | | |-UnknownExpression | | | `-UnknownExpression | | | |-'{' | | | `-'}' | | `-'}' | `-')' CloseParen `-';' )txt"})); } TEST_P(BuildSyntaxTreeTest, CallExpression_Arguments_BracedInitList_Designated) { if (!GetParam().isCXX11OrLater()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct TT {}; struct T{ int a; TT b; }; void f(T); void test() { [[f({.a = 1, .b {}});]] } )cpp", {R"txt( ExpressionStatement Statement |-CallExpression Expression | |-IdExpression Callee | | `-UnqualifiedId UnqualifiedId | | `-'f' | |-'(' OpenParen | |-CallArguments Arguments | | `-UnknownExpression ListElement | | `-UnknownExpression | | |-'{' | | |-UnknownExpression | | | |-'.' | | | |-'a' | | | |-'=' | | | `-IntegerLiteralExpression | | | `-'1' LiteralToken | | |-',' | | |-UnknownExpression | | | |-'.' | | | |-'b' | | | `-UnknownExpression | | | `-UnknownExpression | | | |-'{' | | | `-'}' | | `-'}' | `-')' CloseParen `-';' )txt"})); } TEST_P(BuildSyntaxTreeTest, CallExpression_Arguments_ParameterPack) { if (!GetParam().isCXX11OrLater() || GetParam().hasDelayedTemplateParsing()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( template void test(T t, Args... args) { [[test(args...)]]; } )cpp", {R"txt( CallExpression Expression |-UnknownExpression Callee | `-'test' |-'(' OpenParen |-CallArguments Arguments | `-UnknownExpression ListElement | |-IdExpression | | `-UnqualifiedId UnqualifiedId | | `-'args' | `-'...' `-')' CloseParen )txt"})); } TEST_P(BuildSyntaxTreeTest, CallExpression_DefaultArguments) { if (!GetParam().isCXX11OrLater()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( void f(int i = 1, char c = '2'); void test() { [[f()]]; [[f(1)]]; [[f(1, '2')]]; } )cpp", {R"txt( CallExpression Expression |-IdExpression Callee | `-UnqualifiedId UnqualifiedId | `-'f' |-'(' OpenParen `-')' CloseParen )txt", R"txt( CallExpression Expression |-IdExpression Callee | `-UnqualifiedId UnqualifiedId | `-'f' |-'(' OpenParen |-CallArguments Arguments | `-IntegerLiteralExpression ListElement | `-'1' LiteralToken `-')' CloseParen )txt", R"txt( CallExpression Expression |-IdExpression Callee | `-UnqualifiedId UnqualifiedId | `-'f' |-'(' OpenParen |-CallArguments Arguments | |-IntegerLiteralExpression ListElement | | `-'1' LiteralToken | |-',' ListDelimiter | `-CharacterLiteralExpression ListElement | `-''2'' LiteralToken `-')' CloseParen )txt"})); } TEST_P(BuildSyntaxTreeTest, MultipleDeclaratorsGrouping) { EXPECT_TRUE(treeDumpEqual( R"cpp( int *a, b; int *c, d; )cpp", R"txt( TranslationUnit Detached |-SimpleDeclaration | |-'int' | |-DeclaratorList Declarators | | |-SimpleDeclarator ListElement | | | |-'*' | | | `-'a' | | |-',' ListDelimiter | | `-SimpleDeclarator ListElement | | `-'b' | `-';' `-SimpleDeclaration |-'int' |-DeclaratorList Declarators | |-SimpleDeclarator ListElement | | |-'*' | | `-'c' | |-',' ListDelimiter | `-SimpleDeclarator ListElement | `-'d' `-';' )txt")); } TEST_P(BuildSyntaxTreeTest, MultipleDeclaratorsGroupingTypedef) { EXPECT_TRUE(treeDumpEqual( R"cpp( typedef int *a, b; )cpp", R"txt( TranslationUnit Detached `-SimpleDeclaration |-'typedef' |-'int' |-DeclaratorList Declarators | |-SimpleDeclarator ListElement | | |-'*' | | `-'a' | |-',' ListDelimiter | `-SimpleDeclarator ListElement | `-'b' `-';' )txt")); } TEST_P(BuildSyntaxTreeTest, MultipleDeclaratorsInsideStatement) { EXPECT_TRUE(treeDumpEqual( R"cpp( void foo() { int *a, b; typedef int *ta, tb; } )cpp", R"txt( TranslationUnit Detached `-SimpleDeclaration |-'void' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'foo' | `-ParametersAndQualifiers | |-'(' OpenParen | `-')' CloseParen `-CompoundStatement |-'{' OpenParen |-DeclarationStatement Statement | |-SimpleDeclaration | | |-'int' | | `-DeclaratorList Declarators | | |-SimpleDeclarator ListElement | | | |-'*' | | | `-'a' | | |-',' ListDelimiter | | `-SimpleDeclarator ListElement | | `-'b' | `-';' |-DeclarationStatement Statement | |-SimpleDeclaration | | |-'typedef' | | |-'int' | | `-DeclaratorList Declarators | | |-SimpleDeclarator ListElement | | | |-'*' | | | `-'ta' | | |-',' ListDelimiter | | `-SimpleDeclarator ListElement | | `-'tb' | `-';' `-'}' CloseParen )txt")); } TEST_P(BuildSyntaxTreeTest, SizeTTypedef) { if (!GetParam().isCXX11OrLater()) { return; } EXPECT_TRUE(treeDumpEqual( R"cpp( typedef decltype(sizeof(void *)) size_t; )cpp", R"txt( TranslationUnit Detached `-SimpleDeclaration |-'typedef' |-'decltype' |-'(' |-UnknownExpression | |-'sizeof' | |-'(' | |-'void' | |-'*' | `-')' |-')' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | `-'size_t' `-';' )txt")); } TEST_P(BuildSyntaxTreeTest, Namespace_Nested) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqual( R"cpp( namespace a { namespace b {} } )cpp", R"txt( TranslationUnit Detached `-NamespaceDefinition |-'namespace' |-'a' |-'{' |-NamespaceDefinition | |-'namespace' | |-'b' | |-'{' | `-'}' `-'}' )txt")); } TEST_P(BuildSyntaxTreeTest, Namespace_NestedDefinition) { if (!GetParam().isCXX17OrLater()) { return; } EXPECT_TRUE(treeDumpEqual( R"cpp( namespace a::b {} )cpp", R"txt( TranslationUnit Detached `-NamespaceDefinition |-'namespace' |-'a' |-'::' |-'b' |-'{' `-'}' )txt")); } TEST_P(BuildSyntaxTreeTest, Namespace_Unnamed) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqual( R"cpp( namespace {} )cpp", R"txt( TranslationUnit Detached `-NamespaceDefinition |-'namespace' |-'{' `-'}' )txt")); } TEST_P(BuildSyntaxTreeTest, Namespace_Alias) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( namespace a {} [[namespace foo = a;]] )cpp", {R"txt( NamespaceAliasDefinition |-'namespace' |-'foo' |-'=' |-'a' `-';' )txt"})); } TEST_P(BuildSyntaxTreeTest, UsingDirective) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( namespace ns {} [[using namespace ::ns;]] )cpp", {R"txt( UsingNamespaceDirective |-'using' |-'namespace' |-NestedNameSpecifier | `-'::' ListDelimiter |-'ns' `-';' )txt"})); } TEST_P(BuildSyntaxTreeTest, UsingDeclaration_Namespace) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( namespace ns { int a; } [[using ns::a;]] )cpp", {R"txt( UsingDeclaration |-'using' |-NestedNameSpecifier | |-IdentifierNameSpecifier ListElement | | `-'ns' | `-'::' ListDelimiter |-'a' `-';' )txt"})); } TEST_P(BuildSyntaxTreeTest, UsingDeclaration_ClassMember) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( template struct X { [[using T::foo;]] [[using typename T::bar;]] }; )cpp", {R"txt( UsingDeclaration |-'using' |-NestedNameSpecifier | |-IdentifierNameSpecifier ListElement | | `-'T' | `-'::' ListDelimiter |-'foo' `-';' )txt", R"txt( UsingDeclaration |-'using' |-'typename' |-NestedNameSpecifier | |-IdentifierNameSpecifier ListElement | | `-'T' | `-'::' ListDelimiter |-'bar' `-';' )txt"})); } TEST_P(BuildSyntaxTreeTest, UsingTypeAlias) { if (!GetParam().isCXX11OrLater()) { return; } EXPECT_TRUE(treeDumpEqual( R"cpp( using type = int; )cpp", R"txt( TranslationUnit Detached `-TypeAliasDeclaration |-'using' |-'type' |-'=' |-'int' `-';' )txt")); } TEST_P(BuildSyntaxTreeTest, FreeStandingClass_ForwardDeclaration) { EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( [[struct X;]] [[struct Y *y1;]] )cpp", {R"txt( SimpleDeclaration |-'struct' |-'X' `-';' )txt", R"txt( SimpleDeclaration |-'struct' |-'Y' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'*' | `-'y1' `-';' )txt"})); } TEST_P(BuildSyntaxTreeTest, FreeStandingClasses_Definition) { EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( [[struct X {};]] [[struct Y {} *y2;]] [[struct {} *a1;]] )cpp", {R"txt( SimpleDeclaration |-'struct' |-'X' |-'{' |-'}' `-';' )txt", R"txt( SimpleDeclaration |-'struct' |-'Y' |-'{' |-'}' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'*' | `-'y2' `-';' )txt", R"txt( SimpleDeclaration |-'struct' |-'{' |-'}' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'*' | `-'a1' `-';' )txt"})); } TEST_P(BuildSyntaxTreeTest, StaticMemberFunction) { if (!GetParam().isCXX11OrLater()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct S { [[static void f(){}]] }; )cpp", {R"txt( SimpleDeclaration |-'static' |-'void' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'f' | `-ParametersAndQualifiers | |-'(' OpenParen | `-')' CloseParen `-CompoundStatement |-'{' OpenParen `-'}' CloseParen )txt"})); } TEST_P(BuildSyntaxTreeTest, OutOfLineMemberFunctionDefinition) { if (!GetParam().isCXX11OrLater()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct S { void f(); }; [[void S::f(){}]] )cpp", {R"txt( SimpleDeclaration |-'void' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-NestedNameSpecifier | | |-IdentifierNameSpecifier ListElement | | | `-'S' | | `-'::' ListDelimiter | |-'f' | `-ParametersAndQualifiers | |-'(' OpenParen | `-')' CloseParen `-CompoundStatement |-'{' OpenParen `-'}' CloseParen )txt"})); } TEST_P(BuildSyntaxTreeTest, ConversionMemberFunction) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct X { [[operator int();]] }; )cpp", {R"txt( SimpleDeclaration |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'operator' | |-'int' | `-ParametersAndQualifiers | |-'(' OpenParen | `-')' CloseParen `-';' )txt"})); } TEST_P(BuildSyntaxTreeTest, LiteralOperatorDeclaration) { if (!GetParam().isCXX11OrLater()) { return; } EXPECT_TRUE(treeDumpEqual( R"cpp( unsigned operator "" _c(char); )cpp", R"txt( TranslationUnit Detached `-SimpleDeclaration |-'unsigned' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'operator' | |-'""' | |-'_c' | `-ParametersAndQualifiers | |-'(' OpenParen | |-ParameterDeclarationList Parameters | | `-SimpleDeclaration ListElement | | `-'char' | `-')' CloseParen `-';' )txt")); } TEST_P(BuildSyntaxTreeTest, NumericLiteralOperatorTemplateDeclaration) { if (!GetParam().isCXX11OrLater()) { return; } EXPECT_TRUE(treeDumpEqual( R"cpp( template unsigned operator "" _t(); )cpp", R"txt( TranslationUnit Detached `-TemplateDeclaration Declaration |-'template' IntroducerKeyword |-'<' |-SimpleDeclaration | `-'char' |-'...' |-'>' `-SimpleDeclaration |-'unsigned' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'operator' | |-'""' | |-'_t' | `-ParametersAndQualifiers | |-'(' OpenParen | `-')' CloseParen `-';' )txt")); } TEST_P(BuildSyntaxTreeTest, OverloadedOperatorDeclaration) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct X { [[X& operator=(const X&);]] }; )cpp", {R"txt( SimpleDeclaration |-'X' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'&' | |-'operator' | |-'=' | `-ParametersAndQualifiers | |-'(' OpenParen | |-ParameterDeclarationList Parameters | | `-SimpleDeclaration ListElement | | |-'const' | | |-'X' | | `-DeclaratorList Declarators | | `-SimpleDeclarator ListElement | | `-'&' | `-')' CloseParen `-';' )txt"})); } TEST_P(BuildSyntaxTreeTest, OverloadedOperatorFriendDeclaration) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct X { [[friend X operator+(X, const X&);]] }; )cpp", {R"txt( UnknownDeclaration `-SimpleDeclaration |-'friend' |-'X' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'operator' | |-'+' | `-ParametersAndQualifiers | |-'(' OpenParen | |-ParameterDeclarationList Parameters | | |-SimpleDeclaration ListElement | | | `-'X' | | |-',' ListDelimiter | | `-SimpleDeclaration ListElement | | |-'const' | | |-'X' | | `-DeclaratorList Declarators | | `-SimpleDeclarator ListElement | | `-'&' | `-')' CloseParen `-';' )txt"})); } TEST_P(BuildSyntaxTreeTest, ClassTemplateDeclaration) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqual( R"cpp( template struct ST {}; )cpp", R"txt( TranslationUnit Detached `-TemplateDeclaration Declaration |-'template' IntroducerKeyword |-'<' |-UnknownDeclaration | |-'typename' | `-'T' |-'>' `-SimpleDeclaration |-'struct' |-'ST' |-'{' |-'}' `-';' )txt")); } TEST_P(BuildSyntaxTreeTest, FunctionTemplateDeclaration) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqual( R"cpp( template T f(); )cpp", R"txt( TranslationUnit Detached `-TemplateDeclaration Declaration |-'template' IntroducerKeyword |-'<' |-UnknownDeclaration | |-'typename' | `-'T' |-'>' `-SimpleDeclaration |-'T' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'f' | `-ParametersAndQualifiers | |-'(' OpenParen | `-')' CloseParen `-';' )txt")); } TEST_P(BuildSyntaxTreeTest, VariableTemplateDeclaration) { if (!GetParam().isCXX14OrLater()) { return; } EXPECT_TRUE(treeDumpEqual( R"cpp( template T var = 10; )cpp", R"txt( TranslationUnit Detached `-TemplateDeclaration Declaration |-'template' IntroducerKeyword |-'<' |-UnknownDeclaration | |-'class' | `-'T' |-'>' `-SimpleDeclaration |-'T' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'var' | |-'=' | `-IntegerLiteralExpression | `-'10' LiteralToken `-';' )txt")); } TEST_P(BuildSyntaxTreeTest, StaticMemberFunctionTemplate) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct S { [[template static U f();]] }; )cpp", {R"txt( TemplateDeclaration Declaration |-'template' IntroducerKeyword |-'<' |-UnknownDeclaration | |-'typename' | `-'U' |-'>' `-SimpleDeclaration |-'static' |-'U' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'f' | `-ParametersAndQualifiers | |-'(' OpenParen | `-')' CloseParen `-';' )txt"})); } TEST_P(BuildSyntaxTreeTest, NestedTemplates) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqual( R"cpp( template struct X { template U foo(); }; )cpp", R"txt( TranslationUnit Detached `-TemplateDeclaration Declaration |-'template' IntroducerKeyword |-'<' |-UnknownDeclaration | |-'class' | `-'T' |-'>' `-SimpleDeclaration |-'struct' |-'X' |-'{' |-TemplateDeclaration Declaration | |-'template' IntroducerKeyword | |-'<' | |-UnknownDeclaration | | |-'class' | | `-'U' | |-'>' | `-SimpleDeclaration | |-'U' | |-DeclaratorList Declarators | | `-SimpleDeclarator ListElement | | |-'foo' | | `-ParametersAndQualifiers | | |-'(' OpenParen | | `-')' CloseParen | `-';' |-'}' `-';' )txt")); } TEST_P(BuildSyntaxTreeTest, NestedTemplatesInNamespace) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqual( R"cpp( namespace n { template struct ST { template static U f(); }; } )cpp", R"txt( TranslationUnit Detached `-NamespaceDefinition |-'namespace' |-'n' |-'{' |-TemplateDeclaration Declaration | |-'template' IntroducerKeyword | |-'<' | |-UnknownDeclaration | | |-'typename' | | `-'T' | |-'>' | `-SimpleDeclaration | |-'struct' | |-'ST' | |-'{' | |-TemplateDeclaration Declaration | | |-'template' IntroducerKeyword | | |-'<' | | |-UnknownDeclaration | | | |-'typename' | | | `-'U' | | |-'>' | | `-SimpleDeclaration | | |-'static' | | |-'U' | | |-DeclaratorList Declarators | | | `-SimpleDeclarator ListElement | | | |-'f' | | | `-ParametersAndQualifiers | | | |-'(' OpenParen | | | `-')' CloseParen | | `-';' | |-'}' | `-';' `-'}' )txt")); } TEST_P(BuildSyntaxTreeTest, ClassTemplate_MemberClassDefinition) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( template struct X { struct Y; }; [[template struct X::Y {};]] )cpp", {R"txt( TemplateDeclaration Declaration |-'template' IntroducerKeyword |-'<' |-UnknownDeclaration | |-'class' | `-'T' |-'>' `-SimpleDeclaration |-'struct' |-NestedNameSpecifier | |-SimpleTemplateNameSpecifier ListElement | | |-'X' | | |-'<' | | |-'T' | | `-'>' | `-'::' ListDelimiter |-'Y' |-'{' |-'}' `-';' )txt"})); } TEST_P(BuildSyntaxTreeTest, ExplicitClassTemplateInstantiation_Definition) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( template struct X {}; [[template struct X;]] )cpp", {R"txt( ExplicitTemplateInstantiation |-'template' IntroducerKeyword `-SimpleDeclaration Declaration |-'struct' |-'X' |-'<' |-'double' |-'>' `-';' )txt"})); } TEST_P(BuildSyntaxTreeTest, ExplicitClassTemplateInstantiation_Declaration) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( template struct X {}; [[extern template struct X;]] )cpp", {R"txt( ExplicitTemplateInstantiation |-'extern' ExternKeyword |-'template' IntroducerKeyword `-SimpleDeclaration Declaration |-'struct' |-'X' |-'<' |-'float' |-'>' `-';' )txt"})); } TEST_P(BuildSyntaxTreeTest, ClassTemplateSpecialization_Partial) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( template struct X {}; [[template struct X {};]] )cpp", {R"txt( TemplateDeclaration Declaration |-'template' IntroducerKeyword |-'<' |-UnknownDeclaration | |-'class' | `-'T' |-'>' `-SimpleDeclaration |-'struct' |-'X' |-'<' |-'T' |-'*' |-'>' |-'{' |-'}' `-';' )txt"})); } TEST_P(BuildSyntaxTreeTest, ClassTemplateSpecialization_Full) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( template struct X {}; [[template <> struct X {};]] )cpp", {R"txt( TemplateDeclaration Declaration |-'template' IntroducerKeyword |-'<' |-'>' `-SimpleDeclaration |-'struct' |-'X' |-'<' |-'int' |-'>' |-'{' |-'}' `-';' )txt"})); } TEST_P(BuildSyntaxTreeTest, EmptyDeclaration) { EXPECT_TRUE(treeDumpEqual( R"cpp( ; )cpp", R"txt( TranslationUnit Detached `-EmptyDeclaration `-';' )txt")); } TEST_P(BuildSyntaxTreeTest, StaticAssert) { if (!GetParam().isCXX11OrLater()) { return; } EXPECT_TRUE(treeDumpEqual( R"cpp( static_assert(true, "message"); )cpp", R"txt( TranslationUnit Detached `-StaticAssertDeclaration |-'static_assert' |-'(' |-BoolLiteralExpression Condition | `-'true' LiteralToken |-',' |-StringLiteralExpression Message | `-'"message"' LiteralToken |-')' `-';' )txt")); } TEST_P(BuildSyntaxTreeTest, StaticAssert_WithoutMessage) { if (!GetParam().isCXX17OrLater()) { return; } EXPECT_TRUE(treeDumpEqual( R"cpp( static_assert(true); )cpp", R"txt( TranslationUnit Detached `-StaticAssertDeclaration |-'static_assert' |-'(' |-BoolLiteralExpression Condition | `-'true' LiteralToken |-')' `-';' )txt")); } TEST_P(BuildSyntaxTreeTest, ExternC) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqual( R"cpp( extern "C" int a; extern "C" { int b; int c; } )cpp", R"txt( TranslationUnit Detached |-LinkageSpecificationDeclaration | |-'extern' | |-'"C"' | `-SimpleDeclaration | |-'int' | |-DeclaratorList Declarators | | `-SimpleDeclarator ListElement | | `-'a' | `-';' `-LinkageSpecificationDeclaration |-'extern' |-'"C"' |-'{' |-SimpleDeclaration | |-'int' | |-DeclaratorList Declarators | | `-SimpleDeclarator ListElement | | `-'b' | `-';' |-SimpleDeclaration | |-'int' | |-DeclaratorList Declarators | | `-SimpleDeclarator ListElement | | `-'c' | `-';' `-'}' )txt")); } TEST_P(BuildSyntaxTreeTest, Macro_ObjectLike_Leaf) { // All nodes can be mutated. EXPECT_TRUE(treeDumpEqual( R"cpp( #define OPEN { #define CLOSE } void test() { OPEN 1; CLOSE OPEN 2; } } )cpp", R"txt( TranslationUnit Detached `-SimpleDeclaration |-'void' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'test' | `-ParametersAndQualifiers | |-'(' OpenParen | `-')' CloseParen `-CompoundStatement |-'{' OpenParen |-CompoundStatement Statement | |-'{' OpenParen | |-ExpressionStatement Statement | | |-IntegerLiteralExpression Expression | | | `-'1' LiteralToken | | `-';' | `-'}' CloseParen |-CompoundStatement Statement | |-'{' OpenParen | |-ExpressionStatement Statement | | |-IntegerLiteralExpression Expression | | | `-'2' LiteralToken | | `-';' | `-'}' CloseParen `-'}' CloseParen )txt")); } TEST_P(BuildSyntaxTreeTest, Macro_ObjectLike_MatchTree) { // Some nodes are unmodifiable, they are marked with 'unmodifiable'. EXPECT_TRUE(treeDumpEqual( R"cpp( #define BRACES {} void test() BRACES )cpp", R"txt( TranslationUnit Detached `-SimpleDeclaration |-'void' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'test' | `-ParametersAndQualifiers | |-'(' OpenParen | `-')' CloseParen `-CompoundStatement |-'{' OpenParen unmodifiable `-'}' CloseParen unmodifiable )txt")); } TEST_P(BuildSyntaxTreeTest, Macro_ObjectLike_MismatchTree) { EXPECT_TRUE(treeDumpEqual( R"cpp( #define HALF_IF if (1+ #define HALF_IF_2 1) {} void test() { HALF_IF HALF_IF_2 else {} })cpp", R"txt( TranslationUnit Detached `-SimpleDeclaration |-'void' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'test' | `-ParametersAndQualifiers | |-'(' OpenParen | `-')' CloseParen `-CompoundStatement |-'{' OpenParen |-IfStatement Statement | |-'if' IntroducerKeyword unmodifiable | |-'(' unmodifiable | |-BinaryOperatorExpression unmodifiable | | |-IntegerLiteralExpression LeftHandSide unmodifiable | | | `-'1' LiteralToken unmodifiable | | |-'+' OperatorToken unmodifiable | | `-IntegerLiteralExpression RightHandSide unmodifiable | | `-'1' LiteralToken unmodifiable | |-')' unmodifiable | |-CompoundStatement ThenStatement unmodifiable | | |-'{' OpenParen unmodifiable | | `-'}' CloseParen unmodifiable | |-'else' ElseKeyword | `-CompoundStatement ElseStatement | |-'{' OpenParen | `-'}' CloseParen `-'}' CloseParen )txt")); } TEST_P(BuildSyntaxTreeTest, Macro_FunctionLike_ModifiableArguments) { // FIXME: Note that the substitutions for `X` and `Y` are marked modifiable. // However we cannot change `X` freely. Indeed if we change its substitution // in the condition we should also change it the then-branch. EXPECT_TRUE(treeDumpEqual( R"cpp( #define MIN(X,Y) X < Y ? X : Y void test() { MIN(1,2); } )cpp", R"txt( TranslationUnit Detached `-SimpleDeclaration |-'void' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'test' | `-ParametersAndQualifiers | |-'(' OpenParen | `-')' CloseParen `-CompoundStatement |-'{' OpenParen |-ExpressionStatement Statement | |-UnknownExpression Expression | | |-BinaryOperatorExpression unmodifiable | | | |-IntegerLiteralExpression LeftHandSide | | | | `-'1' LiteralToken | | | |-'<' OperatorToken unmodifiable | | | `-IntegerLiteralExpression RightHandSide | | | `-'2' LiteralToken | | |-'?' unmodifiable | | |-IntegerLiteralExpression | | | `-'1' LiteralToken | | |-':' unmodifiable | | `-IntegerLiteralExpression | | `-'2' LiteralToken | `-';' `-'}' CloseParen )txt")); } TEST_P(BuildSyntaxTreeTest, Macro_FunctionLike_MismatchTree) { EXPECT_TRUE(treeDumpEqual( R"cpp( #define HALF_IF(X) if (X && #define HALF_IF_2(Y) Y) {} void test() { HALF_IF(1) HALF_IF_2(0) else {} })cpp", R"txt( TranslationUnit Detached `-SimpleDeclaration |-'void' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'test' | `-ParametersAndQualifiers | |-'(' OpenParen | `-')' CloseParen `-CompoundStatement |-'{' OpenParen |-IfStatement Statement | |-'if' IntroducerKeyword unmodifiable | |-'(' unmodifiable | |-BinaryOperatorExpression unmodifiable | | |-IntegerLiteralExpression LeftHandSide | | | `-'1' LiteralToken | | |-'&&' OperatorToken unmodifiable | | `-IntegerLiteralExpression RightHandSide | | `-'0' LiteralToken | |-')' unmodifiable | |-CompoundStatement ThenStatement unmodifiable | | |-'{' OpenParen unmodifiable | | `-'}' CloseParen unmodifiable | |-'else' ElseKeyword | `-CompoundStatement ElseStatement | |-'{' OpenParen | `-'}' CloseParen `-'}' CloseParen )txt")); } TEST_P(BuildSyntaxTreeTest, Macro_FunctionLike_Variadic) { EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( #define CALL(F_NAME, ...) F_NAME(__VA_ARGS__) void f(int); void g(int, int); void test() [[{ CALL(f, 0); CALL(g, 0, 1); }]] )cpp", {R"txt( CompoundStatement |-'{' OpenParen |-ExpressionStatement Statement | |-CallExpression Expression | | |-IdExpression Callee | | | `-UnqualifiedId UnqualifiedId | | | `-'f' | | |-'(' OpenParen unmodifiable | | |-CallArguments Arguments | | | `-IntegerLiteralExpression ListElement | | | `-'0' LiteralToken | | `-')' CloseParen unmodifiable | `-';' |-ExpressionStatement Statement | |-CallExpression Expression | | |-IdExpression Callee | | | `-UnqualifiedId UnqualifiedId | | | `-'g' | | |-'(' OpenParen unmodifiable | | |-CallArguments Arguments | | | |-IntegerLiteralExpression ListElement | | | | `-'0' LiteralToken | | | |-',' ListDelimiter | | | `-IntegerLiteralExpression ListElement | | | `-'1' LiteralToken | | `-')' CloseParen unmodifiable | `-';' `-'}' CloseParen )txt"})); } TEST_P(BuildSyntaxTreeTest, InitDeclarator_Equal) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct S { S(int);}; void test() { [[S s = 1]]; } )cpp", {R"txt( SimpleDeclaration |-'S' `-DeclaratorList Declarators `-SimpleDeclarator ListElement |-'s' |-'=' `-IntegerLiteralExpression `-'1' LiteralToken )txt"})); } TEST_P(BuildSyntaxTreeTest, InitDeclarator_Brace) { if (!GetParam().isCXX11OrLater()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct S { S(); S(int); S(int, float); }; void test(){ // FIXME: 's...' is a declarator and '{...}' is initializer [[S s0{}]]; [[S s1{1}]]; [[S s2{1, 2.}]]; } )cpp", {R"txt( SimpleDeclaration |-'S' `-DeclaratorList Declarators `-SimpleDeclarator ListElement `-UnknownExpression |-'s0' |-'{' `-'}' )txt", R"txt( SimpleDeclaration |-'S' `-DeclaratorList Declarators `-SimpleDeclarator ListElement `-UnknownExpression |-'s1' |-'{' |-IntegerLiteralExpression | `-'1' LiteralToken `-'}' )txt", R"txt( SimpleDeclaration |-'S' `-DeclaratorList Declarators `-SimpleDeclarator ListElement `-UnknownExpression |-'s2' |-'{' |-IntegerLiteralExpression | `-'1' LiteralToken |-',' |-FloatingLiteralExpression | `-'2.' LiteralToken `-'}' )txt"})); } TEST_P(BuildSyntaxTreeTest, InitDeclarator_EqualBrace) { if (!GetParam().isCXX11OrLater()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct S { S(); S(int); S(int, float); }; void test() { // FIXME: '= {...}' is initializer [[S s0 = {}]]; [[S s1 = {1}]]; [[S s2 = {1, 2.}]]; } )cpp", {R"txt( SimpleDeclaration |-'S' `-DeclaratorList Declarators `-SimpleDeclarator ListElement |-'s0' |-'=' `-UnknownExpression |-'{' `-'}' )txt", R"txt( SimpleDeclaration |-'S' `-DeclaratorList Declarators `-SimpleDeclarator ListElement |-'s1' |-'=' `-UnknownExpression |-'{' |-IntegerLiteralExpression | `-'1' LiteralToken `-'}' )txt", R"txt( SimpleDeclaration |-'S' `-DeclaratorList Declarators `-SimpleDeclarator ListElement |-'s2' |-'=' `-UnknownExpression |-'{' |-IntegerLiteralExpression | `-'1' LiteralToken |-',' |-FloatingLiteralExpression | `-'2.' LiteralToken `-'}' )txt"})); } TEST_P(BuildSyntaxTreeTest, InitDeclarator_Paren) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct S { S(int); S(int, float); }; // FIXME: 's...' is a declarator and '(...)' is initializer [[S s1(1);]] [[S s2(1, 2.);]] )cpp", {R"txt( SimpleDeclaration |-'S' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | `-UnknownExpression | |-'s1' | |-'(' | |-IntegerLiteralExpression | | `-'1' LiteralToken | `-')' `-';' )txt", R"txt( SimpleDeclaration |-'S' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | `-UnknownExpression | |-'s2' | |-'(' | |-IntegerLiteralExpression | | `-'1' LiteralToken | |-',' | |-FloatingLiteralExpression | | `-'2.' LiteralToken | `-')' `-';' )txt"})); } TEST_P(BuildSyntaxTreeTest, InitDeclarator_Paren_DefaultArguments) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct S { S(int i = 1, float = 2.); }; [[S s0;]] // FIXME: 's...' is a declarator and '(...)' is initializer [[S s1(1);]] [[S s2(1, 2.);]] )cpp", {R"txt( SimpleDeclaration |-'S' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | `-'s0' `-';' )txt", R"txt( SimpleDeclaration |-'S' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | `-UnknownExpression | |-'s1' | |-'(' | |-IntegerLiteralExpression | | `-'1' LiteralToken | `-')' `-';' )txt", R"txt( SimpleDeclaration |-'S' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | `-UnknownExpression | |-'s2' | |-'(' | |-IntegerLiteralExpression | | `-'1' LiteralToken | |-',' | |-FloatingLiteralExpression | | `-'2.' LiteralToken | `-')' `-';' )txt"})); } TEST_P(BuildSyntaxTreeTest, ImplicitConversion_Argument) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct X { X(int); }; void TakeX(const X&); void test() { [[TakeX(1)]]; } )cpp", {R"txt( CallExpression Expression |-IdExpression Callee | `-UnqualifiedId UnqualifiedId | `-'TakeX' |-'(' OpenParen |-CallArguments Arguments | `-IntegerLiteralExpression ListElement | `-'1' LiteralToken `-')' CloseParen )txt"})); } TEST_P(BuildSyntaxTreeTest, ImplicitConversion_Return) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct X { X(int); }; X CreateX(){ [[return 1;]] } )cpp", {R"txt( ReturnStatement Statement |-'return' IntroducerKeyword |-IntegerLiteralExpression ReturnValue | `-'1' LiteralToken `-';' )txt"})); } TEST_P(BuildSyntaxTreeTest, ConstructorCall_ZeroArguments) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct X { X(); }; X test() { [[return X();]] } )cpp", {R"txt( ReturnStatement Statement |-'return' IntroducerKeyword |-UnknownExpression ReturnValue | |-'X' | |-'(' | `-')' `-';' )txt"})); } TEST_P(BuildSyntaxTreeTest, ConstructorCall_OneArgument) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct X { X(int); }; X test() { [[return X(1);]] } )cpp", {R"txt( ReturnStatement Statement |-'return' IntroducerKeyword |-UnknownExpression ReturnValue | |-'X' | |-'(' | |-IntegerLiteralExpression | | `-'1' LiteralToken | `-')' `-';' )txt"})); } TEST_P(BuildSyntaxTreeTest, ConstructorCall_MultipleArguments) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct X { X(int, char); }; X test() { [[return X(1, '2');]] } )cpp", {R"txt( ReturnStatement Statement |-'return' IntroducerKeyword |-UnknownExpression ReturnValue | |-'X' | |-'(' | |-IntegerLiteralExpression | | `-'1' LiteralToken | |-',' | |-CharacterLiteralExpression | | `-''2'' LiteralToken | `-')' `-';' )txt"})); } TEST_P(BuildSyntaxTreeTest, ConstructorCall_DefaultArguments) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct X { X(int i = 1, char c = '2'); }; X test() { auto x0 = [[X()]]; auto x1 = [[X(1)]]; auto x2 = [[X(1, '2')]]; } )cpp", {R"txt( UnknownExpression |-'X' |-'(' `-')' )txt", R"txt( UnknownExpression |-'X' |-'(' |-IntegerLiteralExpression | `-'1' LiteralToken `-')' )txt", R"txt( UnknownExpression |-'X' |-'(' |-IntegerLiteralExpression | `-'1' LiteralToken |-',' |-CharacterLiteralExpression | `-''2'' LiteralToken `-')' )txt"})); } TEST_P(BuildSyntaxTreeTest, TypeConversion_FunctionalNotation) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( float test() { [[return float(1);]] } )cpp", {R"txt( ReturnStatement Statement |-'return' IntroducerKeyword |-UnknownExpression ReturnValue | |-'float' | |-'(' | |-IntegerLiteralExpression | | `-'1' LiteralToken | `-')' `-';' )txt"})); } TEST_P(BuildSyntaxTreeTest, ArrayDeclarator_Simple) { EXPECT_TRUE(treeDumpEqual( R"cpp( int a[10]; )cpp", R"txt( TranslationUnit Detached `-SimpleDeclaration |-'int' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'a' | `-ArraySubscript | |-'[' OpenParen | |-IntegerLiteralExpression Size | | `-'10' LiteralToken | `-']' CloseParen `-';' )txt")); } TEST_P(BuildSyntaxTreeTest, ArrayDeclarator_Multidimensional) { EXPECT_TRUE(treeDumpEqual( R"cpp( int b[1][2][3]; )cpp", R"txt( TranslationUnit Detached `-SimpleDeclaration |-'int' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'b' | |-ArraySubscript | | |-'[' OpenParen | | |-IntegerLiteralExpression Size | | | `-'1' LiteralToken | | `-']' CloseParen | |-ArraySubscript | | |-'[' OpenParen | | |-IntegerLiteralExpression Size | | | `-'2' LiteralToken | | `-']' CloseParen | `-ArraySubscript | |-'[' OpenParen | |-IntegerLiteralExpression Size | | `-'3' LiteralToken | `-']' CloseParen `-';' )txt")); } TEST_P(BuildSyntaxTreeTest, ArrayDeclarator_UnknownBound) { EXPECT_TRUE(treeDumpEqual( R"cpp( int c[] = {1,2,3}; )cpp", R"txt( TranslationUnit Detached `-SimpleDeclaration |-'int' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'c' | |-ArraySubscript | | |-'[' OpenParen | | `-']' CloseParen | |-'=' | `-UnknownExpression | `-UnknownExpression | |-'{' | |-IntegerLiteralExpression | | `-'1' LiteralToken | |-',' | |-IntegerLiteralExpression | | `-'2' LiteralToken | |-',' | |-IntegerLiteralExpression | | `-'3' LiteralToken | `-'}' `-';' )txt")); } TEST_P(BuildSyntaxTreeTest, ArrayDeclarator_Static) { if (!GetParam().isC99OrLater()) { return; } EXPECT_TRUE(treeDumpEqual( R"cpp( void f(int xs[static 10]); )cpp", R"txt( TranslationUnit Detached `-SimpleDeclaration |-'void' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'f' | `-ParametersAndQualifiers | |-'(' OpenParen | |-ParameterDeclarationList Parameters | | `-SimpleDeclaration ListElement | | |-'int' | | `-DeclaratorList Declarators | | `-SimpleDeclarator ListElement | | |-'xs' | | `-ArraySubscript | | |-'[' OpenParen | | |-'static' | | |-IntegerLiteralExpression Size | | | `-'10' LiteralToken | | `-']' CloseParen | `-')' CloseParen `-';' )txt")); } TEST_P(BuildSyntaxTreeTest, ParametersAndQualifiers_InFreeFunctions_Empty) { EXPECT_TRUE(treeDumpEqual( R"cpp( int func(); )cpp", R"txt( TranslationUnit Detached `-SimpleDeclaration |-'int' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'func' | `-ParametersAndQualifiers | |-'(' OpenParen | `-')' CloseParen `-';' )txt")); } TEST_P(BuildSyntaxTreeTest, ParametersAndQualifiers_InFreeFunctions_Named) { EXPECT_TRUE(treeDumpEqual( R"cpp( int func1(int a); int func2(int *ap); int func3(int a, float b); )cpp", R"txt( TranslationUnit Detached |-SimpleDeclaration | |-'int' | |-DeclaratorList Declarators | | `-SimpleDeclarator ListElement | | |-'func1' | | `-ParametersAndQualifiers | | |-'(' OpenParen | | |-ParameterDeclarationList Parameters | | | `-SimpleDeclaration ListElement | | | |-'int' | | | `-DeclaratorList Declarators | | | `-SimpleDeclarator ListElement | | | `-'a' | | `-')' CloseParen | `-';' |-SimpleDeclaration | |-'int' | |-DeclaratorList Declarators | | `-SimpleDeclarator ListElement | | |-'func2' | | `-ParametersAndQualifiers | | |-'(' OpenParen | | |-ParameterDeclarationList Parameters | | | `-SimpleDeclaration ListElement | | | |-'int' | | | `-DeclaratorList Declarators | | | `-SimpleDeclarator ListElement | | | |-'*' | | | `-'ap' | | `-')' CloseParen | `-';' `-SimpleDeclaration |-'int' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'func3' | `-ParametersAndQualifiers | |-'(' OpenParen | |-ParameterDeclarationList Parameters | | |-SimpleDeclaration ListElement | | | |-'int' | | | `-DeclaratorList Declarators | | | `-SimpleDeclarator ListElement | | | `-'a' | | |-',' ListDelimiter | | `-SimpleDeclaration ListElement | | |-'float' | | `-DeclaratorList Declarators | | `-SimpleDeclarator ListElement | | `-'b' | `-')' CloseParen `-';' )txt")); } TEST_P(BuildSyntaxTreeTest, ParametersAndQualifiers_InFreeFunctions_Unnamed) { EXPECT_TRUE(treeDumpEqual( R"cpp( int func1(int); int func2(int *); int func3(int, float); )cpp", R"txt( TranslationUnit Detached |-SimpleDeclaration | |-'int' | |-DeclaratorList Declarators | | `-SimpleDeclarator ListElement | | |-'func1' | | `-ParametersAndQualifiers | | |-'(' OpenParen | | |-ParameterDeclarationList Parameters | | | `-SimpleDeclaration ListElement | | | `-'int' | | `-')' CloseParen | `-';' |-SimpleDeclaration | |-'int' | |-DeclaratorList Declarators | | `-SimpleDeclarator ListElement | | |-'func2' | | `-ParametersAndQualifiers | | |-'(' OpenParen | | |-ParameterDeclarationList Parameters | | | `-SimpleDeclaration ListElement | | | |-'int' | | | `-DeclaratorList Declarators | | | `-SimpleDeclarator ListElement | | | `-'*' | | `-')' CloseParen | `-';' `-SimpleDeclaration |-'int' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'func3' | `-ParametersAndQualifiers | |-'(' OpenParen | |-ParameterDeclarationList Parameters | | |-SimpleDeclaration ListElement | | | `-'int' | | |-',' ListDelimiter | | `-SimpleDeclaration ListElement | | `-'float' | `-')' CloseParen `-';' )txt")); } TEST_P(BuildSyntaxTreeTest, ParametersAndQualifiers_InFreeFunctions_Default_One) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( int func1([[int a = 1]]); )cpp", {R"txt( ParameterDeclarationList Parameters `-SimpleDeclaration ListElement |-'int' `-DeclaratorList Declarators `-SimpleDeclarator ListElement |-'a' |-'=' `-IntegerLiteralExpression `-'1' LiteralToken )txt"})); } TEST_P(BuildSyntaxTreeTest, ParametersAndQualifiers_InFreeFunctions_Default_Multiple) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( int func2([[int *ap, int a = 1, char c = '2']]); )cpp", {R"txt( ParameterDeclarationList Parameters |-SimpleDeclaration ListElement | |-'int' | `-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'*' | `-'ap' |-',' ListDelimiter |-SimpleDeclaration ListElement | |-'int' | `-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'a' | |-'=' | `-IntegerLiteralExpression | `-'1' LiteralToken |-',' ListDelimiter `-SimpleDeclaration ListElement |-'char' `-DeclaratorList Declarators `-SimpleDeclarator ListElement |-'c' |-'=' `-CharacterLiteralExpression `-''2'' LiteralToken )txt"})); } TEST_P(BuildSyntaxTreeTest, ParametersAndQualifiers_InVariadicFunctionTemplate_ParameterPack) { if (!GetParam().isCXX11OrLater() || GetParam().hasDelayedTemplateParsing()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( template [[void test(T , Args... );]] )cpp", {R"txt( SimpleDeclaration |-'void' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'test' | `-ParametersAndQualifiers | |-'(' OpenParen | |-ParameterDeclarationList Parameters | | |-SimpleDeclaration ListElement | | | `-'T' | | |-',' ListDelimiter | | `-SimpleDeclaration ListElement | | |-'Args' | | `-'...' | `-')' CloseParen `-';' )txt"})); } TEST_P(BuildSyntaxTreeTest, ParametersAndQualifiers_InVariadicFunctionTemplate_NamedParameterPack) { if (!GetParam().isCXX11OrLater() || GetParam().hasDelayedTemplateParsing()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( template [[void test(T t, Args... args);]] )cpp", {R"txt( SimpleDeclaration |-'void' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'test' | `-ParametersAndQualifiers | |-'(' OpenParen | |-ParameterDeclarationList Parameters | | |-SimpleDeclaration ListElement | | | |-'T' | | | `-DeclaratorList Declarators | | | `-SimpleDeclarator ListElement | | | `-'t' | | |-',' ListDelimiter | | `-SimpleDeclaration ListElement | | |-'Args' | | |-'...' | | `-DeclaratorList Declarators | | `-SimpleDeclarator ListElement | | `-'args' | `-')' CloseParen `-';' )txt"})); } TEST_P(BuildSyntaxTreeTest, ParametersAndQualifiers_InFreeFunctions_VariadicArguments) { if (!GetParam().isCXX11OrLater()) { return; } EXPECT_TRUE(treeDumpEqual( R"cpp( void test(int , char ...); )cpp", R"txt( TranslationUnit Detached `-SimpleDeclaration |-'void' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'test' | `-ParametersAndQualifiers | |-'(' OpenParen | |-ParameterDeclarationList Parameters | | |-SimpleDeclaration ListElement | | | `-'int' | | |-',' ListDelimiter | | `-SimpleDeclaration ListElement | | `-'char' | |-'...' | `-')' CloseParen `-';' )txt")); } TEST_P(BuildSyntaxTreeTest, ParametersAndQualifiers_InFreeFunctions_Cxx_CvQualifiers) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqual( R"cpp( int func(const int a, volatile int b, const volatile int c); )cpp", R"txt( TranslationUnit Detached `-SimpleDeclaration |-'int' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'func' | `-ParametersAndQualifiers | |-'(' OpenParen | |-ParameterDeclarationList Parameters | | |-SimpleDeclaration ListElement | | | |-'const' | | | |-'int' | | | `-DeclaratorList Declarators | | | `-SimpleDeclarator ListElement | | | `-'a' | | |-',' ListDelimiter | | |-SimpleDeclaration ListElement | | | |-'volatile' | | | |-'int' | | | `-DeclaratorList Declarators | | | `-SimpleDeclarator ListElement | | | `-'b' | | |-',' ListDelimiter | | `-SimpleDeclaration ListElement | | |-'const' | | |-'volatile' | | |-'int' | | `-DeclaratorList Declarators | | `-SimpleDeclarator ListElement | | `-'c' | `-')' CloseParen `-';' )txt")); } TEST_P(BuildSyntaxTreeTest, ParametersAndQualifiers_InFreeFunctions_Cxx_Ref) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqual( R"cpp( int func(int& a); )cpp", R"txt( TranslationUnit Detached `-SimpleDeclaration |-'int' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'func' | `-ParametersAndQualifiers | |-'(' OpenParen | |-ParameterDeclarationList Parameters | | `-SimpleDeclaration ListElement | | |-'int' | | `-DeclaratorList Declarators | | `-SimpleDeclarator ListElement | | |-'&' | | `-'a' | `-')' CloseParen `-';' )txt")); } TEST_P(BuildSyntaxTreeTest, ParametersAndQualifiers_InFreeFunctions_Cxx11_RefRef) { if (!GetParam().isCXX11OrLater()) { return; } EXPECT_TRUE(treeDumpEqual( R"cpp( int func(int&& a); )cpp", R"txt( TranslationUnit Detached `-SimpleDeclaration |-'int' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'func' | `-ParametersAndQualifiers | |-'(' OpenParen | |-ParameterDeclarationList Parameters | | `-SimpleDeclaration ListElement | | |-'int' | | `-DeclaratorList Declarators | | `-SimpleDeclarator ListElement | | |-'&&' | | `-'a' | `-')' CloseParen `-';' )txt")); } TEST_P(BuildSyntaxTreeTest, ParametersAndQualifiers_InMemberFunctions_Simple) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqual( R"cpp( struct Test { int a(); }; )cpp", R"txt( TranslationUnit Detached `-SimpleDeclaration |-'struct' |-'Test' |-'{' |-SimpleDeclaration | |-'int' | |-DeclaratorList Declarators | | `-SimpleDeclarator ListElement | | |-'a' | | `-ParametersAndQualifiers | | |-'(' OpenParen | | `-')' CloseParen | `-';' |-'}' `-';' )txt")); } TEST_P(BuildSyntaxTreeTest, ParametersAndQualifiers_InMemberFunctions_CvQualifiers) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct Test { [[int b() const;]] [[int c() volatile;]] [[int d() const volatile;]] }; )cpp", {R"txt( SimpleDeclaration |-'int' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'b' | `-ParametersAndQualifiers | |-'(' OpenParen | |-')' CloseParen | `-'const' `-';' )txt", R"txt( SimpleDeclaration |-'int' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'c' | `-ParametersAndQualifiers | |-'(' OpenParen | |-')' CloseParen | `-'volatile' `-';' )txt", R"txt( SimpleDeclaration |-'int' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'d' | `-ParametersAndQualifiers | |-'(' OpenParen | |-')' CloseParen | |-'const' | `-'volatile' `-';' )txt"})); } TEST_P(BuildSyntaxTreeTest, ParametersAndQualifiers_InMemberFunctions_Ref) { if (!GetParam().isCXX11OrLater()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct Test { [[int e() &;]] }; )cpp", {R"txt( SimpleDeclaration |-'int' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'e' | `-ParametersAndQualifiers | |-'(' OpenParen | |-')' CloseParen | `-'&' `-';' )txt"})); } TEST_P(BuildSyntaxTreeTest, ParametersAndQualifiers_InMemberFunctions_RefRef) { if (!GetParam().isCXX11OrLater()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct Test { [[int f() &&;]] }; )cpp", {R"txt( SimpleDeclaration |-'int' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'f' | `-ParametersAndQualifiers | |-'(' OpenParen | |-')' CloseParen | `-'&&' `-';' )txt"})); } TEST_P(BuildSyntaxTreeTest, TrailingReturn) { if (!GetParam().isCXX11OrLater()) { return; } EXPECT_TRUE(treeDumpEqual( R"cpp( auto foo() -> int; )cpp", R"txt( TranslationUnit Detached `-SimpleDeclaration |-'auto' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'foo' | `-ParametersAndQualifiers | |-'(' OpenParen | |-')' CloseParen | `-TrailingReturnType TrailingReturn | |-'->' ArrowToken | `-'int' `-';' )txt")); } TEST_P(BuildSyntaxTreeTest, DynamicExceptionSpecification) { if (!GetParam().supportsCXXDynamicExceptionSpecification()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct MyException1 {}; struct MyException2 {}; [[int a() throw();]] [[int b() throw(...);]] [[int c() throw(MyException1);]] [[int d() throw(MyException1, MyException2);]] )cpp", {R"txt( SimpleDeclaration |-'int' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'a' | `-ParametersAndQualifiers | |-'(' OpenParen | |-')' CloseParen | |-'throw' | |-'(' | `-')' `-';' )txt", R"txt( SimpleDeclaration |-'int' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'b' | `-ParametersAndQualifiers | |-'(' OpenParen | |-')' CloseParen | |-'throw' | |-'(' | |-'...' | `-')' `-';' )txt", R"txt( SimpleDeclaration |-'int' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'c' | `-ParametersAndQualifiers | |-'(' OpenParen | |-')' CloseParen | |-'throw' | |-'(' | |-'MyException1' | `-')' `-';' )txt", R"txt( SimpleDeclaration |-'int' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'d' | `-ParametersAndQualifiers | |-'(' OpenParen | |-')' CloseParen | |-'throw' | |-'(' | |-'MyException1' | |-',' | |-'MyException2' | `-')' `-';' )txt"})); } TEST_P(BuildSyntaxTreeTest, NoexceptExceptionSpecification) { if (!GetParam().isCXX11OrLater()) { return; } EXPECT_TRUE(treeDumpEqual( R"cpp( int a() noexcept; int b() noexcept(true); )cpp", R"txt( TranslationUnit Detached |-SimpleDeclaration | |-'int' | |-DeclaratorList Declarators | | `-SimpleDeclarator ListElement | | |-'a' | | `-ParametersAndQualifiers | | |-'(' OpenParen | | |-')' CloseParen | | `-'noexcept' | `-';' `-SimpleDeclaration |-'int' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'b' | `-ParametersAndQualifiers | |-'(' OpenParen | |-')' CloseParen | |-'noexcept' | |-'(' | |-BoolLiteralExpression | | `-'true' LiteralToken | `-')' `-';' )txt")); } TEST_P(BuildSyntaxTreeTest, DeclaratorsInParentheses) { EXPECT_TRUE(treeDumpEqual( R"cpp( int (a); int *(b); int (*c)(int); int *(d)(int); )cpp", R"txt( TranslationUnit Detached |-SimpleDeclaration | |-'int' | |-DeclaratorList Declarators | | `-SimpleDeclarator ListElement | | `-ParenDeclarator | | |-'(' OpenParen | | |-'a' | | `-')' CloseParen | `-';' |-SimpleDeclaration | |-'int' | |-DeclaratorList Declarators | | `-SimpleDeclarator ListElement | | |-'*' | | `-ParenDeclarator | | |-'(' OpenParen | | |-'b' | | `-')' CloseParen | `-';' |-SimpleDeclaration | |-'int' | |-DeclaratorList Declarators | | `-SimpleDeclarator ListElement | | |-ParenDeclarator | | | |-'(' OpenParen | | | |-'*' | | | |-'c' | | | `-')' CloseParen | | `-ParametersAndQualifiers | | |-'(' OpenParen | | |-ParameterDeclarationList Parameters | | | `-SimpleDeclaration ListElement | | | `-'int' | | `-')' CloseParen | `-';' `-SimpleDeclaration |-'int' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'*' | |-ParenDeclarator | | |-'(' OpenParen | | |-'d' | | `-')' CloseParen | `-ParametersAndQualifiers | |-'(' OpenParen | |-ParameterDeclarationList Parameters | | `-SimpleDeclaration ListElement | | `-'int' | `-')' CloseParen `-';' )txt")); } TEST_P(BuildSyntaxTreeTest, Declaration_ConstVolatileQualifiers_SimpleConst) { EXPECT_TRUE(treeDumpEqual( R"cpp( const int west = -1; int const east = 1; )cpp", R"txt( TranslationUnit Detached |-SimpleDeclaration | |-'const' | |-'int' | |-DeclaratorList Declarators | | `-SimpleDeclarator ListElement | | |-'west' | | |-'=' | | `-PrefixUnaryOperatorExpression | | |-'-' OperatorToken | | `-IntegerLiteralExpression Operand | | `-'1' LiteralToken | `-';' `-SimpleDeclaration |-'int' |-'const' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'east' | |-'=' | `-IntegerLiteralExpression | `-'1' LiteralToken `-';' )txt")); } TEST_P(BuildSyntaxTreeTest, Declaration_ConstVolatileQualifiers_MultipleConst) { EXPECT_TRUE(treeDumpEqual( R"cpp( const int const universal = 0; )cpp", R"txt( TranslationUnit Detached `-SimpleDeclaration |-'const' |-'int' |-'const' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'universal' | |-'=' | `-IntegerLiteralExpression | `-'0' LiteralToken `-';' )txt")); } TEST_P(BuildSyntaxTreeTest, Declaration_ConstVolatileQualifiers_ConstAndVolatile) { EXPECT_TRUE(treeDumpEqual( R"cpp( const int const *const *volatile b; )cpp", R"txt( TranslationUnit Detached `-SimpleDeclaration |-'const' |-'int' |-'const' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'*' | |-'const' | |-'*' | |-'volatile' | `-'b' `-';' )txt")); } TEST_P(BuildSyntaxTreeTest, RangesOfDeclaratorsWithTrailingReturnTypes) { if (!GetParam().isCXX11OrLater()) { return; } EXPECT_TRUE(treeDumpEqual( R"cpp( auto foo() -> auto(*)(int) -> double*; )cpp", R"txt( TranslationUnit Detached `-SimpleDeclaration |-'auto' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'foo' | `-ParametersAndQualifiers | |-'(' OpenParen | |-')' CloseParen | `-TrailingReturnType TrailingReturn | |-'->' ArrowToken | |-'auto' | `-SimpleDeclarator Declarator | |-ParenDeclarator | | |-'(' OpenParen | | |-'*' | | `-')' CloseParen | `-ParametersAndQualifiers | |-'(' OpenParen | |-ParameterDeclarationList Parameters | | `-SimpleDeclaration ListElement | | `-'int' | |-')' CloseParen | `-TrailingReturnType TrailingReturn | |-'->' ArrowToken | |-'double' | `-SimpleDeclarator Declarator | `-'*' `-';' )txt")); } TEST_P(BuildSyntaxTreeTest, MemberPointers) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct X {}; [[int X::* a;]] [[const int X::* b;]] )cpp", {R"txt( SimpleDeclaration |-'int' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-MemberPointer | | |-'X' | | |-'::' | | `-'*' | `-'a' `-';' )txt", R"txt( SimpleDeclaration |-'const' |-'int' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-MemberPointer | | |-'X' | | |-'::' | | `-'*' | `-'b' `-';' )txt"})); } TEST_P(BuildSyntaxTreeTest, MemberFunctionPointer) { if (!GetParam().isCXX()) { return; } EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( struct X { struct Y {}; }; [[void (X::*xp)();]] [[void (X::**xpp)(const int*);]] // FIXME: Generate the right syntax tree for this type, // i.e. create a syntax node for the outer member pointer [[void (X::Y::*xyp)(const int*, char);]] )cpp", {R"txt( SimpleDeclaration |-'void' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-ParenDeclarator | | |-'(' OpenParen | | |-MemberPointer | | | |-'X' | | | |-'::' | | | `-'*' | | |-'xp' | | `-')' CloseParen | `-ParametersAndQualifiers | |-'(' OpenParen | `-')' CloseParen `-';' )txt", R"txt( SimpleDeclaration |-'void' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-ParenDeclarator | | |-'(' OpenParen | | |-MemberPointer | | | |-'X' | | | |-'::' | | | `-'*' | | |-'*' | | |-'xpp' | | `-')' CloseParen | `-ParametersAndQualifiers | |-'(' OpenParen | |-ParameterDeclarationList Parameters | | `-SimpleDeclaration ListElement | | |-'const' | | |-'int' | | `-DeclaratorList Declarators | | `-SimpleDeclarator ListElement | | `-'*' | `-')' CloseParen `-';' )txt", R"txt( SimpleDeclaration |-'void' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-ParenDeclarator | | |-'(' OpenParen | | |-'X' | | |-'::' | | |-MemberPointer | | | |-'Y' | | | |-'::' | | | `-'*' | | |-'xyp' | | `-')' CloseParen | `-ParametersAndQualifiers | |-'(' OpenParen | |-ParameterDeclarationList Parameters | | |-SimpleDeclaration ListElement | | | |-'const' | | | |-'int' | | | `-DeclaratorList Declarators | | | `-SimpleDeclarator ListElement | | | `-'*' | | |-',' ListDelimiter | | `-SimpleDeclaration ListElement | | `-'char' | `-')' CloseParen `-';' )txt"})); } TEST_P(BuildSyntaxTreeTest, ComplexDeclarator) { EXPECT_TRUE(treeDumpEqual( R"cpp( void x(char a, short (*b)(int)); )cpp", R"txt( TranslationUnit Detached `-SimpleDeclaration |-'void' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'x' | `-ParametersAndQualifiers | |-'(' OpenParen | |-ParameterDeclarationList Parameters | | |-SimpleDeclaration ListElement | | | |-'char' | | | `-DeclaratorList Declarators | | | `-SimpleDeclarator ListElement | | | `-'a' | | |-',' ListDelimiter | | `-SimpleDeclaration ListElement | | |-'short' | | `-DeclaratorList Declarators | | `-SimpleDeclarator ListElement | | |-ParenDeclarator | | | |-'(' OpenParen | | | |-'*' | | | |-'b' | | | `-')' CloseParen | | `-ParametersAndQualifiers | | |-'(' OpenParen | | |-ParameterDeclarationList Parameters | | | `-SimpleDeclaration ListElement | | | `-'int' | | `-')' CloseParen | `-')' CloseParen `-';' )txt")); } TEST_P(BuildSyntaxTreeTest, ComplexDeclarator2) { EXPECT_TRUE(treeDumpEqual( R"cpp( void x(char a, short (*b)(int), long (**c)(long long)); )cpp", R"txt( TranslationUnit Detached `-SimpleDeclaration |-'void' |-DeclaratorList Declarators | `-SimpleDeclarator ListElement | |-'x' | `-ParametersAndQualifiers | |-'(' OpenParen | |-ParameterDeclarationList Parameters | | |-SimpleDeclaration ListElement | | | |-'char' | | | `-DeclaratorList Declarators | | | `-SimpleDeclarator ListElement | | | `-'a' | | |-',' ListDelimiter | | |-SimpleDeclaration ListElement | | | |-'short' | | | `-DeclaratorList Declarators | | | `-SimpleDeclarator ListElement | | | |-ParenDeclarator | | | | |-'(' OpenParen | | | | |-'*' | | | | |-'b' | | | | `-')' CloseParen | | | `-ParametersAndQualifiers | | | |-'(' OpenParen | | | |-ParameterDeclarationList Parameters | | | | `-SimpleDeclaration ListElement | | | | `-'int' | | | `-')' CloseParen | | |-',' ListDelimiter | | `-SimpleDeclaration ListElement | | |-'long' | | `-DeclaratorList Declarators | | `-SimpleDeclarator ListElement | | |-ParenDeclarator | | | |-'(' OpenParen | | | |-'*' | | | |-'*' | | | |-'c' | | | `-')' CloseParen | | `-ParametersAndQualifiers | | |-'(' OpenParen | | |-ParameterDeclarationList Parameters | | | `-SimpleDeclaration ListElement | | | |-'long' | | | `-'long' | | `-')' CloseParen | `-')' CloseParen `-';' )txt")); } } // namespace