diff --git a/clang/unittests/Tooling/Syntax/TreeTest.cpp b/clang/unittests/Tooling/Syntax/TreeTest.cpp --- a/clang/unittests/Tooling/Syntax/TreeTest.cpp +++ b/clang/unittests/Tooling/Syntax/TreeTest.cpp @@ -121,6 +121,16 @@ return Root; } + void expectTreeDumpEqual(StringRef code, StringRef tree) { + SCOPED_TRACE(code); + + auto *Root = buildTree(code); + std::string Expected = tree.trim().str(); + std::string Actual = + std::string(llvm::StringRef(Root->dump(*Arena)).trim()); + EXPECT_EQ(Expected, Actual) << "the resulting dump is:\n" << Actual; + } + // Adds a file to the test VFS. void addFile(llvm::StringRef Path, llvm::StringRef Contents) { if (!FS->addFile(Path, time_t(), @@ -164,14 +174,13 @@ std::unique_ptr Arena; }; -TEST_F(SyntaxTreeTest, Basic) { - std::pair Cases[] = { - { - R"cpp( +TEST_F(SyntaxTreeTest, Simple) { + expectTreeDumpEqual( + R"cpp( int main() {} void foo() {} )cpp", - R"txt( + R"txt( *: TranslationUnit |-SimpleDeclaration | |-int @@ -193,16 +202,18 @@ `-CompoundStatement |-{ `-} -)txt"}, - // if. - { - R"cpp( +)txt"); +} + +TEST_F(SyntaxTreeTest, If) { + expectTreeDumpEqual( + R"cpp( int main() { if (true) {} if (true) {} else if (false) {} } )cpp", - R"txt( + R"txt( *: TranslationUnit `-SimpleDeclaration |-int @@ -242,14 +253,17 @@ | |-{ | `-} `-} - )txt"}, - // for. - {R"cpp( + )txt"); +} + +TEST_F(SyntaxTreeTest, For) { + expectTreeDumpEqual( + R"cpp( void test() { for (;;) {} } )cpp", - R"txt( + R"txt( *: TranslationUnit `-SimpleDeclaration |-void @@ -270,10 +284,18 @@ | |-{ | `-} `-} - )txt"}, - // declaration statement. - {"void test() { int a = 10; }", - R"txt( + )txt"); +} + +TEST_F(SyntaxTreeTest, RangeBasedFor) { + expectTreeDumpEqual( + R"cpp( +void test() { + int a[3]; + for (int x : a) ; +} + )cpp", + R"txt( *: TranslationUnit `-SimpleDeclaration |-void @@ -289,13 +311,32 @@ | | |-int | | `-SimpleDeclarator | | |-a - | | |-= - | | `-UnknownExpression - | | `-10 + | | `-ArraySubscript + | | |-[ + | | |-UnknownExpression + | | | `-3 + | | `-] | `-; + |-RangeBasedForStatement + | |-for + | |-( + | |-SimpleDeclaration + | | |-int + | | |-SimpleDeclarator + | | | `-x + | | `-: + | |-UnknownExpression + | | `-a + | |-) + | `-EmptyStatement + | `-; `-} -)txt"}, - {"void test() { ; }", R"txt( + )txt"); +} + +TEST_F(SyntaxTreeTest, DeclarationStatement) { + expectTreeDumpEqual("void test() { int a = 10; }", + R"txt( *: TranslationUnit `-SimpleDeclaration |-void @@ -306,12 +347,22 @@ | `-) `-CompoundStatement |-{ - |-EmptyStatement + |-DeclarationStatement + | |-SimpleDeclaration + | | |-int + | | `-SimpleDeclarator + | | |-a + | | |-= + | | `-UnknownExpression + | | `-10 | `-; `-} -)txt"}, - // switch, case and default. - {R"cpp( +)txt"); +} + +TEST_F(SyntaxTreeTest, Switch) { + expectTreeDumpEqual( + R"cpp( void test() { switch (true) { case 0: @@ -319,7 +370,7 @@ } } )cpp", - R"txt( + R"txt( *: TranslationUnit `-SimpleDeclaration |-void @@ -350,14 +401,17 @@ | | `-; | `-} `-} -)txt"}, - // while. - {R"cpp( +)txt"); +} + +TEST_F(SyntaxTreeTest, While) { + expectTreeDumpEqual( + R"cpp( void test() { while (true) { continue; break; } } )cpp", - R"txt( + R"txt( *: TranslationUnit `-SimpleDeclaration |-void @@ -384,77 +438,15 @@ | | `-; | `-} `-} -)txt"}, - // return. - {R"cpp( -int test() { return 1; } - )cpp", - R"txt( -*: TranslationUnit -`-SimpleDeclaration - |-int - |-SimpleDeclarator - | |-test - | `-ParametersAndQualifiers - | |-( - | `-) - `-CompoundStatement - |-{ - |-ReturnStatement - | |-return - | |-UnknownExpression - | | `-1 - | `-; - `-} -)txt"}, - // Range-based for. - {R"cpp( -void test() { - int a[3]; - for (int x : a) ; +)txt"); } - )cpp", - R"txt( -*: TranslationUnit -`-SimpleDeclaration - |-void - |-SimpleDeclarator - | |-test - | `-ParametersAndQualifiers - | |-( - | `-) - `-CompoundStatement - |-{ - |-DeclarationStatement - | |-SimpleDeclaration - | | |-int - | | `-SimpleDeclarator - | | |-a - | | `-ArraySubscript - | | |-[ - | | |-UnknownExpression - | | | `-3 - | | `-] - | `-; - |-RangeBasedForStatement - | |-for - | |-( - | |-SimpleDeclaration - | | |-int - | | |-SimpleDeclarator - | | | `-x - | | `-: - | |-UnknownExpression - | | `-a - | |-) - | `-EmptyStatement - | `-; - `-} - )txt"}, - // Unhandled statements should end up as 'unknown statement'. - // This example uses a 'label statement', which does not yet have a syntax - // counterpart. - {"void main() { foo: return 100; }", R"txt( + +TEST_F(SyntaxTreeTest, UnhandledStatement) { + // Unhandled statements should end up as 'unknown statement'. + // This example uses a 'label statement', which does not yet have a syntax + // counterpart. + expectTreeDumpEqual("void main() { foo: return 100; }", + R"txt( *: TranslationUnit `-SimpleDeclaration |-void @@ -474,16 +466,20 @@ | | `-100 | `-; `-} -)txt"}, - // expressions should be wrapped in 'ExpressionStatement' when they appear - // in a statement position. - {R"cpp( +)txt"); +} + +TEST_F(SyntaxTreeTest, Expressions) { + // expressions should be wrapped in 'ExpressionStatement' when they appear + // in a statement position. + expectTreeDumpEqual( + R"cpp( void test() { test(); if (true) test(); else test(); } )cpp", - R"txt( + R"txt( *: TranslationUnit `-SimpleDeclaration |-void @@ -520,12 +516,15 @@ | | `-) | `-; `-} -)txt"}, - // Multiple declarators group into a single SimpleDeclaration. - {R"cpp( +)txt"); +} + +TEST_F(SyntaxTreeTest, MultipleDeclaratorsGrouping) { + expectTreeDumpEqual( + R"cpp( int *a, b; )cpp", - R"txt( + R"txt( *: TranslationUnit `-SimpleDeclaration |-int @@ -536,11 +535,12 @@ |-SimpleDeclarator | `-b `-; - )txt"}, - {R"cpp( + )txt"); + expectTreeDumpEqual( + R"cpp( typedef int *a, b; )cpp", - R"txt( + R"txt( *: TranslationUnit `-SimpleDeclaration |-typedef @@ -552,15 +552,18 @@ |-SimpleDeclarator | `-b `-; - )txt"}, - // Multiple declarators inside a statement. - {R"cpp( + )txt"); +} + +TEST_F(SyntaxTreeTest, MultipleDeclaratorsInsideStatement) { + expectTreeDumpEqual( + R"cpp( void foo() { int *a, b; typedef int *ta, tb; } )cpp", - R"txt( + R"txt( *: TranslationUnit `-SimpleDeclaration |-void @@ -593,15 +596,19 @@ | | `-tb | `-; `-} - )txt"}, - {R"cpp( + )txt"); +} + +TEST_F(SyntaxTreeTest, Namespaces) { + expectTreeDumpEqual( + R"cpp( namespace a { namespace b {} } namespace a::b {} namespace {} namespace foo = a; )cpp", - R"txt( + R"txt( *: TranslationUnit |-NamespaceDefinition | |-namespace @@ -630,9 +637,62 @@ |-= |-a `-; -)txt"}, - // Free-standing classes, must live inside a SimpleDeclaration. - {R"cpp( +)txt"); +} + +TEST_F(SyntaxTreeTest, UsingDirective) { + expectTreeDumpEqual( + R"cpp( +namespace ns {} +using namespace ::ns; + )cpp", + R"txt( +*: TranslationUnit +|-NamespaceDefinition +| |-namespace +| |-ns +| |-{ +| `-} +`-UsingNamespaceDirective + |-using + |-namespace + |-:: + |-ns + `-; + )txt"); +} + +TEST_F(SyntaxTreeTest, UsingDeclaration) { + expectTreeDumpEqual( + R"cpp( +namespace ns { int a; } +using ns::a; + )cpp", + R"txt( +*: TranslationUnit +|-NamespaceDefinition +| |-namespace +| |-ns +| |-{ +| |-SimpleDeclaration +| | |-int +| | |-SimpleDeclarator +| | | `-a +| | `-; +| `-} +`-UsingDeclaration + |-using + |-ns + |-:: + |-a + `-; + )txt"); +} + +TEST_F(SyntaxTreeTest, FreeStandingClasses) { + // Free-standing classes, must live inside a SimpleDeclaration. + expectTreeDumpEqual( + R"cpp( sturct X; struct X {}; @@ -641,7 +701,7 @@ struct {} *a1; )cpp", - R"txt( + R"txt( *: TranslationUnit |-SimpleDeclaration | |-sturct @@ -677,13 +737,17 @@ | |-* | `-a1 `-; -)txt"}, - {R"cpp( +)txt"); +} + +TEST_F(SyntaxTreeTest, Templates) { + expectTreeDumpEqual( + R"cpp( template struct cls {}; template int var = 10; template int fun() {} )cpp", - R"txt( + R"txt( *: TranslationUnit |-TemplateDeclaration | |-template @@ -730,15 +794,19 @@ `-CompoundStatement |-{ `-} -)txt"}, - {R"cpp( +)txt"); +} + +TEST_F(SyntaxTreeTest, NestedTemplates) { + expectTreeDumpEqual( + R"cpp( template struct X { template U foo(); }; )cpp", - R"txt( + R"txt( *: TranslationUnit `-TemplateDeclaration |-template @@ -768,85 +836,16 @@ | `-; |-} `-; -)txt"}, - {R"cpp( -template struct X {}; -template struct X {}; -template <> struct X {}; +)txt"); +} -template struct X; -extern template struct X; -)cpp", - R"txt( -*: TranslationUnit -|-TemplateDeclaration -| |-template -| |-< -| |-UnknownDeclaration -| | |-class -| | `-T -| |-> -| `-SimpleDeclaration -| |-struct -| |-X -| |-{ -| |-} -| `-; -|-TemplateDeclaration -| |-template -| |-< -| |-UnknownDeclaration -| | |-class -| | `-T -| |-> -| `-SimpleDeclaration -| |-struct -| |-X -| |-< -| |-T -| |-* -| |-> -| |-{ -| |-} -| `-; -|-TemplateDeclaration -| |-template -| |-< -| |-> -| `-SimpleDeclaration -| |-struct -| |-X -| |-< -| |-int -| |-> -| |-{ -| |-} -| `-; -|-ExplicitTemplateInstantiation -| |-template -| `-SimpleDeclaration -| |-struct -| |-X -| |-< -| |-double -| |-> -| `-; -`-ExplicitTemplateInstantiation - |-extern - |-template - `-SimpleDeclaration - |-struct - |-X - |-< - |-float - |-> - `-; -)txt"}, - {R"cpp( +TEST_F(SyntaxTreeTest, Templates2) { + expectTreeDumpEqual( + R"cpp( template struct X { struct Y; }; template struct X::Y {}; )cpp", - R"txt( + R"txt( *: TranslationUnit |-TemplateDeclaration | |-template @@ -883,55 +882,18 @@ |-{ |-} `-; - )txt"}, - {R"cpp( -namespace ns {} -using namespace ::ns; - )cpp", - R"txt( -*: TranslationUnit -|-NamespaceDefinition -| |-namespace -| |-ns -| |-{ -| `-} -`-UsingNamespaceDirective - |-using - |-namespace - |-:: - |-ns - `-; - )txt"}, - {R"cpp( -namespace ns { int a; } -using ns::a; - )cpp", - R"txt( -*: TranslationUnit -|-NamespaceDefinition -| |-namespace -| |-ns -| |-{ -| |-SimpleDeclaration -| | |-int -| | |-SimpleDeclarator -| | | `-a -| | `-; -| `-} -`-UsingDeclaration - |-using - |-ns - |-:: - |-a - `-; - )txt"}, - {R"cpp( + )txt"); +} + +TEST_F(SyntaxTreeTest, TemplatesUsingUsing) { + expectTreeDumpEqual( + R"cpp( template struct X { using T::foo; using typename T::bar; }; )cpp", - R"txt( + R"txt( *: TranslationUnit `-TemplateDeclaration |-template @@ -959,11 +921,92 @@ | `-; |-} `-; - )txt"}, - {R"cpp( + )txt"); +} + +TEST_F(SyntaxTreeTest, ExplicitTemplateInstantations) { + expectTreeDumpEqual( + R"cpp( +template struct X {}; +template struct X {}; +template <> struct X {}; + +template struct X; +extern template struct X; +)cpp", + R"txt( +*: TranslationUnit +|-TemplateDeclaration +| |-template +| |-< +| |-UnknownDeclaration +| | |-class +| | `-T +| |-> +| `-SimpleDeclaration +| |-struct +| |-X +| |-{ +| |-} +| `-; +|-TemplateDeclaration +| |-template +| |-< +| |-UnknownDeclaration +| | |-class +| | `-T +| |-> +| `-SimpleDeclaration +| |-struct +| |-X +| |-< +| |-T +| |-* +| |-> +| |-{ +| |-} +| `-; +|-TemplateDeclaration +| |-template +| |-< +| |-> +| `-SimpleDeclaration +| |-struct +| |-X +| |-< +| |-int +| |-> +| |-{ +| |-} +| `-; +|-ExplicitTemplateInstantiation +| |-template +| `-SimpleDeclaration +| |-struct +| |-X +| |-< +| |-double +| |-> +| `-; +`-ExplicitTemplateInstantiation + |-extern + |-template + `-SimpleDeclaration + |-struct + |-X + |-< + |-float + |-> + `-; +)txt"); +} + +TEST_F(SyntaxTreeTest, UsingType) { + expectTreeDumpEqual( + R"cpp( using type = int; )cpp", - R"txt( + R"txt( *: TranslationUnit `-TypeAliasDeclaration |-using @@ -971,20 +1014,28 @@ |-= |-int `-; - )txt"}, - {R"cpp( + )txt"); +} + +TEST_F(SyntaxTreeTest, EmptyDeclaration) { + expectTreeDumpEqual( + R"cpp( ; )cpp", - R"txt( + R"txt( *: TranslationUnit `-EmptyDeclaration `-; - )txt"}, - {R"cpp( + )txt"); +} + +TEST_F(SyntaxTreeTest, StaticAssert) { + expectTreeDumpEqual( + R"cpp( static_assert(true, "message"); static_assert(true); )cpp", - R"txt( + R"txt( *: TranslationUnit |-StaticAssertDeclaration | |-static_assert @@ -1003,12 +1054,16 @@ | `-true |-) `-; - )txt"}, - {R"cpp( + )txt"); +} + +TEST_F(SyntaxTreeTest, ExternC) { + expectTreeDumpEqual( + R"cpp( extern "C" int a; extern "C" { int b; int c; } )cpp", - R"txt( + R"txt( *: TranslationUnit |-LinkageSpecificationDeclaration | |-extern @@ -1033,15 +1088,19 @@ | | `-c | `-; `-} - )txt"}, - // Some nodes are non-modifiable, they are marked with 'I:'. - {R"cpp( + )txt"); +} + +TEST_F(SyntaxTreeTest, NonModifiableNodes) { + // Some nodes are non-modifiable, they are marked with 'I:'. + expectTreeDumpEqual( + R"cpp( #define HALF_IF if (1+ #define HALF_IF_2 1) {} void test() { HALF_IF HALF_IF_2 else {} })cpp", - R"txt( + R"txt( *: TranslationUnit `-SimpleDeclaration |-void @@ -1068,9 +1127,10 @@ | |-{ | `-} `-} - )txt"}, - // All nodes can be mutated. - {R"cpp( + )txt"); + // All nodes can be mutated. + expectTreeDumpEqual( + R"cpp( #define OPEN { #define CLOSE } @@ -1084,7 +1144,7 @@ } } )cpp", - R"txt( + R"txt( *: TranslationUnit `-SimpleDeclaration |-void @@ -1110,15 +1170,18 @@ | | `-; | `-} `-} - )txt"}, - // Array subscripts in declarators. - {R"cpp( + )txt"); +} + +TEST_F(SyntaxTreeTest, ArraySubscriptsInDeclarators) { + expectTreeDumpEqual( + R"cpp( int a[10]; int b[1][2][3]; int c[] = {1,2,3}; void f(int xs[static 10]); )cpp", - R"txt( + R"txt( *: TranslationUnit |-SimpleDeclaration | |-int @@ -1185,9 +1248,12 @@ | | `-] | `-) `-; - )txt"}, - // Parameter lists in declarators. - {R"cpp( + )txt"); +} + +TEST_F(SyntaxTreeTest, ParameterListsInDeclarators) { + expectTreeDumpEqual( + R"cpp( int a() const; int b() volatile; int c() &; @@ -1202,7 +1268,7 @@ int&& f ); )cpp", - R"txt( + R"txt( *: TranslationUnit |-SimpleDeclaration | |-int @@ -1301,14 +1367,17 @@ | | `-f | `-) `-; - )txt"}, - // Trailing const qualifier. - {R"cpp( + )txt"); +} + +TEST_F(SyntaxTreeTest, TrailingConst) { + expectTreeDumpEqual( + R"cpp( struct X { int foo() const; } )cpp", - R"txt( + R"txt( *: TranslationUnit `-SimpleDeclaration |-struct @@ -1324,12 +1393,15 @@ | | `-const | `-; `-} - )txt"}, - // Trailing return type in parameter lists. - {R"cpp( + )txt"); +} + +TEST_F(SyntaxTreeTest, TrailingReturn) { + expectTreeDumpEqual( + R"cpp( auto foo() -> int; )cpp", - R"txt( + R"txt( *: TranslationUnit `-SimpleDeclaration |-auto @@ -1342,14 +1414,17 @@ | |--> | `-int `-; - )txt"}, - // Exception specification in parameter lists. - {R"cpp( + )txt"); +} + +TEST_F(SyntaxTreeTest, ExceptionSpecification) { + expectTreeDumpEqual( + R"cpp( int a() noexcept; int b() noexcept(true); int c() throw(); )cpp", - R"txt( + R"txt( *: TranslationUnit |-SimpleDeclaration | |-int @@ -1384,15 +1459,18 @@ | |-( | `-) `-; - )txt"}, - // Declarators in parentheses. - {R"cpp( + )txt"); +} + +TEST_F(SyntaxTreeTest, DeclaratorsInParentheses) { + expectTreeDumpEqual( + R"cpp( int (a); int *(b); int (*c)(int); int *(d)(int); )cpp", - R"txt( + R"txt( *: TranslationUnit |-SimpleDeclaration | |-int @@ -1439,15 +1517,18 @@ | | `-int | `-) `-; - )txt"}, - // CV qualifiers. - {R"cpp( + )txt"); +} + +TEST_F(SyntaxTreeTest, ConstVolatileQualifiers) { + expectTreeDumpEqual( + R"cpp( const int west = -1; int const east = 1; const int const universal = 0; const int const *const *volatile b; )cpp", - R"txt( + R"txt( *: TranslationUnit |-SimpleDeclaration | |-const @@ -1489,12 +1570,15 @@ | |-volatile | `-b `-; - )txt"}, - // Ranges of declarators with trailing return types. - {R"cpp( + )txt"); +} + +TEST_F(SyntaxTreeTest, RangesOfDeclaratorsWithTrailingReturnTypes) { + expectTreeDumpEqual( + R"cpp( auto foo() -> auto(*)(int) -> double*; )cpp", - R"txt( + R"txt( *: TranslationUnit `-SimpleDeclaration |-auto @@ -1522,14 +1606,17 @@ | `-SimpleDeclarator | `-* `-; - )txt"}, - // Member pointers. - {R"cpp( + )txt"); +} + +TEST_F(SyntaxTreeTest, MemberPointers) { + expectTreeDumpEqual( + R"cpp( struct X {}; int X::* a; const int X::* b; )cpp", - R"txt( + R"txt( *: TranslationUnit |-SimpleDeclaration | |-struct @@ -1556,12 +1643,15 @@ | | `-* | `-b `-; - )txt"}, - // All-in-one tests. - {R"cpp( + )txt"); +} + +TEST_F(SyntaxTreeTest, ComplexDeclarator) { + expectTreeDumpEqual( + R"cpp( void x(char a, short (*b)(int)); )cpp", - R"txt( + R"txt( *: TranslationUnit `-SimpleDeclaration |-void @@ -1589,11 +1679,15 @@ | | `-) | `-) `-; - )txt"}, - {R"cpp( + )txt"); +} + +TEST_F(SyntaxTreeTest, ComplexDeclarator2) { + expectTreeDumpEqual( + R"cpp( void x(char a, short (*b)(int), long (**c)(long long)); )cpp", - R"txt( + R"txt( *: TranslationUnit `-SimpleDeclaration |-void @@ -1637,18 +1731,7 @@ | | `-) | `-) `-; - )txt"}, - }; - - for (const auto &T : Cases) { - SCOPED_TRACE(T.first); - - auto *Root = buildTree(T.first); - std::string Expected = llvm::StringRef(T.second).trim().str(); - std::string Actual = - std::string(llvm::StringRef(Root->dump(*Arena)).trim()); - EXPECT_EQ(Expected, Actual) << "the resulting dump is:\n" << Actual; - } + )txt"); } TEST_F(SyntaxTreeTest, Mutations) {