From 221d7bbe49cceb0e408f0f46d9f8371e6c9fee2c Mon Sep 17 00:00:00 2001 From: Eduardo Caldas Date: Thu, 25 Jun 2020 16:10:19 +0000 Subject: [PATCH] Add `CharLiteral` to SyntaxTree Subscribers: cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D82312 --- clang/include/clang/Tooling/Syntax/Nodes.h | 12 +++ clang/lib/Tooling/Syntax/BuildTree.cpp | 7 ++ clang/lib/Tooling/Syntax/Nodes.cpp | 7 ++ clang/unittests/Tooling/Syntax/TreeTest.cpp | 133 ++++++++++++++++++++++++++++ 4 files changed, 159 insertions(+) diff --git a/clang/include/clang/Tooling/Syntax/Nodes.h b/clang/include/clang/Tooling/Syntax/Nodes.h index 255a108133b..4310bc5dc81 100644 --- a/clang/include/clang/Tooling/Syntax/Nodes.h +++ b/clang/include/clang/Tooling/Syntax/Nodes.h @@ -46,6 +46,7 @@ enum class NodeKind : uint16_t { CxxNullPtrExpression, IntegerLiteralExpression, BoolLiteralExpression, + CharacterLiteralExpression, IdExpression, // Statements. @@ -255,6 +256,17 @@ public: syntax::Leaf *nullPtrKeyword(); }; +/// Expression for character literals. C++ [lex.ccon] +class CharacterLiteralExpression final : public Expression { +public: + CharacterLiteralExpression() + : Expression(NodeKind::CharacterLiteralExpression) {} + static bool classof(const Node *N) { + return N->kind() == NodeKind::CharacterLiteralExpression; + } + syntax::Leaf *literalToken(); +}; + /// Expression for integer literals. class IntegerLiteralExpression final : public Expression { public: diff --git a/clang/lib/Tooling/Syntax/BuildTree.cpp b/clang/lib/Tooling/Syntax/BuildTree.cpp index 7ff603fbd33..5912a54d1be 100644 --- a/clang/lib/Tooling/Syntax/BuildTree.cpp +++ b/clang/lib/Tooling/Syntax/BuildTree.cpp @@ -661,6 +661,13 @@ public: return true; } + bool WalkUpFromCharacterLiteral(CharacterLiteral *S) { + Builder.markChildToken(S->getLocation(), syntax::NodeRole::LiteralToken); + Builder.foldNode(Builder.getExprRange(S), + new (allocator()) syntax::CharacterLiteralExpression, S); + return true; + } + bool WalkUpFromCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *S) { Builder.markChildToken(S->getLocation(), syntax::NodeRole::LiteralToken); Builder.foldNode(Builder.getExprRange(S), diff --git a/clang/lib/Tooling/Syntax/Nodes.cpp b/clang/lib/Tooling/Syntax/Nodes.cpp index 498721d3a37..e6e280e9cb1 100644 --- a/clang/lib/Tooling/Syntax/Nodes.cpp +++ b/clang/lib/Tooling/Syntax/Nodes.cpp @@ -24,6 +24,8 @@ llvm::raw_ostream &syntax::operator<<(llvm::raw_ostream &OS, NodeKind K) { return OS << "IntegerLiteralExpression"; case NodeKind::BoolLiteralExpression: return OS << "BoolLiteralExpression"; + case NodeKind::CharacterLiteralExpression: + return OS << "CharacterLiteralExpression"; case NodeKind::PrefixUnaryOperatorExpression: return OS << "PrefixUnaryOperatorExpression"; case NodeKind::PostfixUnaryOperatorExpression: @@ -207,6 +209,11 @@ syntax::Leaf *syntax::BoolLiteralExpression::literalToken() { findChild(syntax::NodeRole::LiteralToken)); } +syntax::Leaf *syntax::CharacterLiteralExpression::literalToken() { + return llvm::cast_or_null( + findChild(syntax::NodeRole::LiteralToken)); +} + syntax::Leaf *syntax::CxxNullPtrExpression::nullPtrKeyword() { return llvm::cast_or_null( findChild(syntax::NodeRole::LiteralToken)); diff --git a/clang/unittests/Tooling/Syntax/TreeTest.cpp b/clang/unittests/Tooling/Syntax/TreeTest.cpp index d32ce620391..0a20950458d 100644 --- a/clang/unittests/Tooling/Syntax/TreeTest.cpp +++ b/clang/unittests/Tooling/Syntax/TreeTest.cpp @@ -73,6 +73,10 @@ struct TestClangConfig { return Language == Lang_C89 || Language == Lang_C99; } + bool isCXX17OrLater() const { + return Language == Lang_CXX17 || Language == Lang_CXX20; + } + bool supportsCXXDynamicExceptionSpecification() const { return Language == Lang_CXX03 || Language == Lang_CXX11 || Language == Lang_CXX14; @@ -1232,6 +1236,135 @@ void test() { )txt")); } +TEST_P(SyntaxTreeTest, CharacterLiteral) { + EXPECT_TRUE(treeDumpEqual( + R"cpp( +void test() { + 'a'; + '\n'; + '\x20'; + '\0'; + L'a'; + L'α'; +} +)cpp", + R"txt( +*: TranslationUnit +`-SimpleDeclaration + |-void + |-SimpleDeclarator + | |-test + | `-ParametersAndQualifiers + | |-( + | `-) + `-CompoundStatement + |-{ + |-ExpressionStatement + | |-CharacterLiteralExpression + | | `-'a' + | `-; + |-ExpressionStatement + | |-CharacterLiteralExpression + | | `-'\n' + | `-; + |-ExpressionStatement + | |-CharacterLiteralExpression + | | `-'\x20' + | `-; + |-ExpressionStatement + | |-CharacterLiteralExpression + | | `-'\0' + | `-; + |-ExpressionStatement + | |-CharacterLiteralExpression + | | `-L'a' + | `-; + |-ExpressionStatement + | |-CharacterLiteralExpression + | | `-L'α' + | `-; + `-} +)txt")); +} + +TEST_P(SyntaxTreeTest, CharacterLiteralUtf) { + if (!GetParam().isCXX11OrLater()) { + return; + } + EXPECT_TRUE(treeDumpEqual( + R"cpp( +void test() { + u'a'; + u'構'; + U'a'; + U'🌲'; +} +)cpp", + R"txt( +*: TranslationUnit +`-SimpleDeclaration + |-void + |-SimpleDeclarator + | |-test + | `-ParametersAndQualifiers + | |-( + | `-) + `-CompoundStatement + |-{ + |-ExpressionStatement + | |-CharacterLiteralExpression + | | `-u'a' + | `-; + |-ExpressionStatement + | |-CharacterLiteralExpression + | | `-u'構' + | `-; + |-ExpressionStatement + | |-CharacterLiteralExpression + | | `-U'a' + | `-; + |-ExpressionStatement + | |-CharacterLiteralExpression + | | `-U'🌲' + | `-; + `-} +)txt")); +} + +TEST_P(SyntaxTreeTest, CharacterLiteralUtf8) { + if (!GetParam().isCXX17OrLater()) { + return; + } + EXPECT_TRUE(treeDumpEqual( + R"cpp( +void test() { + u8'a'; + u8'\x7f'; +} +)cpp", + R"txt( +*: TranslationUnit +`-SimpleDeclaration + |-void + |-SimpleDeclarator + | |-test + | `-ParametersAndQualifiers + | |-( + | `-) + `-CompoundStatement + |-{ + |-ExpressionStatement + | |-CharacterLiteralExpression + | | `-u8'a' + | `-; + |-ExpressionStatement + | |-CharacterLiteralExpression + | | `-u8'\x7f' + | `-; + `-} +)txt")); +} + TEST_P(SyntaxTreeTest, BoolLiteral) { if (GetParam().hasBoolType()) { return; -- 2.11.0