Add support for binary operators in Syntax Trees

Reviewers: gribozavr2

Reviewed By: gribozavr2

Subscribers: cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D80540
This commit is contained in:
Eduardo Caldas 2020-05-26 12:19:07 +02:00 committed by Dmitri Gribenko
parent 5229dd1366
commit 3785eb83af
4 changed files with 315 additions and 18 deletions

View File

@ -40,6 +40,7 @@ enum class NodeKind : uint16_t {
// Expressions.
UnknownExpression,
BinaryOperatorExpression,
// Statements.
UnknownStatement,
@ -104,6 +105,9 @@ enum class NodeRole : uint8_t {
BodyStatement,
// Roles specific to particular node kinds.
BinaryOperatorExpression_leftHandSide,
BinaryOperatorExpression_operatorToken,
BinaryOperatorExpression_rightHandSide,
CaseStatement_value,
IfStatement_thenStatement,
IfStatement_elseKeyword,
@ -158,6 +162,24 @@ public:
}
};
/// <lhs> <operator> <rhs>
///
/// For example:
/// a + b
/// a bitor 1
/// a |= b
/// a and_eq b
class BinaryOperatorExpression final : public Expression {
public:
BinaryOperatorExpression() : Expression(NodeKind::BinaryOperatorExpression) {}
static bool classof(const Node *N) {
return N->kind() == NodeKind::BinaryOperatorExpression;
}
syntax::Expression *lhs();
syntax::Leaf *operatorToken();
syntax::Expression *rhs();
};
/// An abstract node for C++ statements, e.g. 'while', 'if', etc.
/// FIXME: add accessors for semicolon of statements that have it.
class Statement : public Tree {

View File

@ -11,6 +11,7 @@
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclarationName.h"
#include "clang/AST/Expr.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/TypeLoc.h"
@ -594,10 +595,7 @@ public:
for (auto *D : DS->decls())
Builder.noticeDeclWithoutSemicolon(D);
} else if (auto *E = llvm::dyn_cast_or_null<Expr>(S)) {
// Do not recurse into subexpressions.
// We do not have syntax trees for expressions yet, so we only want to see
// the first top-level expression.
return WalkUpFromExpr(E->IgnoreImplicit());
return RecursiveASTVisitor::TraverseStmt(E->IgnoreImplicit());
}
return RecursiveASTVisitor::TraverseStmt(S);
}
@ -610,6 +608,19 @@ public:
return true;
}
bool WalkUpFromBinaryOperator(BinaryOperator *S) {
Builder.markExprChild(
S->getLHS(), syntax::NodeRole::BinaryOperatorExpression_leftHandSide);
Builder.markChildToken(
S->getOperatorLoc(),
syntax::NodeRole::BinaryOperatorExpression_operatorToken);
Builder.markExprChild(
S->getRHS(), syntax::NodeRole::BinaryOperatorExpression_rightHandSide);
Builder.foldNode(Builder.getExprRange(S),
new (allocator()) syntax::BinaryOperatorExpression, S);
return true;
}
bool WalkUpFromNamespaceDecl(NamespaceDecl *S) {
auto Tokens = Builder.getDeclarationRange(S);
if (Tokens.front().kind() == tok::coloncolon) {

View File

@ -18,6 +18,8 @@ llvm::raw_ostream &syntax::operator<<(llvm::raw_ostream &OS, NodeKind K) {
return OS << "TranslationUnit";
case NodeKind::UnknownExpression:
return OS << "UnknownExpression";
case NodeKind::BinaryOperatorExpression:
return OS << "BinaryOperatorExpression";
case NodeKind::UnknownStatement:
return OS << "UnknownStatement";
case NodeKind::DeclarationStatement:
@ -110,6 +112,12 @@ llvm::raw_ostream &syntax::operator<<(llvm::raw_ostream &OS, NodeRole R) {
return OS << "IfStatement_elseKeyword";
case syntax::NodeRole::IfStatement_elseStatement:
return OS << "IfStatement_elseStatement";
case syntax::NodeRole::BinaryOperatorExpression_leftHandSide:
return OS << "BinaryOperatorExpression_leftHandSide";
case syntax::NodeRole::BinaryOperatorExpression_operatorToken:
return OS << "BinaryOperatorExpression_operatorToken";
case syntax::NodeRole::BinaryOperatorExpression_rightHandSide:
return OS << "BinaryOperatorExpression_rightHandSide";
case syntax::NodeRole::ReturnStatement_value:
return OS << "ReturnStatement_value";
case syntax::NodeRole::ExpressionStatement_expression:
@ -142,6 +150,21 @@ llvm::raw_ostream &syntax::operator<<(llvm::raw_ostream &OS, NodeRole R) {
llvm_unreachable("invalid role");
}
syntax::Expression *syntax::BinaryOperatorExpression::lhs() {
return llvm::cast_or_null<syntax::Expression>(
findChild(syntax::NodeRole::BinaryOperatorExpression_leftHandSide));
}
syntax::Leaf *syntax::BinaryOperatorExpression::operatorToken() {
return llvm::cast_or_null<syntax::Leaf>(
findChild(syntax::NodeRole::BinaryOperatorExpression_operatorToken));
}
syntax::Expression *syntax::BinaryOperatorExpression::rhs() {
return llvm::cast_or_null<syntax::Expression>(
findChild(syntax::NodeRole::BinaryOperatorExpression_rightHandSide));
}
syntax::Leaf *syntax::SwitchStatement::switchKeyword() {
return llvm::cast_or_null<syntax::Leaf>(
findChild(syntax::NodeRole::IntroducerKeyword));

View File

@ -564,7 +564,8 @@ void test() {
|-{
|-ExpressionStatement
| |-UnknownExpression
| | |-test
| | |-UnknownExpression
| | | `-test
| | |-(
| | `-)
| `-;
@ -576,14 +577,16 @@ void test() {
| |-)
| |-ExpressionStatement
| | |-UnknownExpression
| | | |-test
| | | |-UnknownExpression
| | | | `-test
| | | |-(
| | | `-)
| | `-;
| |-else
| `-ExpressionStatement
| |-UnknownExpression
| | |-test
| | |-UnknownExpression
| | | `-test
| | |-(
| | `-)
| `-;
@ -591,6 +594,237 @@ void test() {
)txt");
}
TEST_F(SyntaxTreeTest, BinaryOperator) {
expectTreeDumpEqual(
R"cpp(
void test(int a) {
1 - 2;
1 == 2;
a = 1;
a <<= 1;
true || false;
true or false;
1 & 2;
1 bitand 2;
a ^= 3;
a xor_eq 3;
}
)cpp",
R"txt(
*: TranslationUnit
`-SimpleDeclaration
|-void
|-SimpleDeclarator
| |-test
| `-ParametersAndQualifiers
| |-(
| |-SimpleDeclaration
| | |-int
| | `-SimpleDeclarator
| | `-a
| `-)
`-CompoundStatement
|-{
|-ExpressionStatement
| |-BinaryOperatorExpression
| | |-UnknownExpression
| | | `-1
| | |--
| | `-UnknownExpression
| | `-2
| `-;
|-ExpressionStatement
| |-BinaryOperatorExpression
| | |-UnknownExpression
| | | `-1
| | |-==
| | `-UnknownExpression
| | `-2
| `-;
|-ExpressionStatement
| |-BinaryOperatorExpression
| | |-UnknownExpression
| | | `-a
| | |-=
| | `-UnknownExpression
| | `-1
| `-;
|-ExpressionStatement
| |-BinaryOperatorExpression
| | |-UnknownExpression
| | | `-a
| | |-<<=
| | `-UnknownExpression
| | `-1
| `-;
|-ExpressionStatement
| |-BinaryOperatorExpression
| | |-UnknownExpression
| | | `-true
| | |-||
| | `-UnknownExpression
| | `-false
| `-;
|-ExpressionStatement
| |-BinaryOperatorExpression
| | |-UnknownExpression
| | | `-true
| | |-or
| | `-UnknownExpression
| | `-false
| `-;
|-ExpressionStatement
| |-BinaryOperatorExpression
| | |-UnknownExpression
| | | `-1
| | |-&
| | `-UnknownExpression
| | `-2
| `-;
|-ExpressionStatement
| |-BinaryOperatorExpression
| | |-UnknownExpression
| | | `-1
| | |-bitand
| | `-UnknownExpression
| | `-2
| `-;
|-ExpressionStatement
| |-BinaryOperatorExpression
| | |-UnknownExpression
| | | `-a
| | |-^=
| | `-UnknownExpression
| | `-3
| `-;
|-ExpressionStatement
| |-BinaryOperatorExpression
| | |-UnknownExpression
| | | `-a
| | |-xor_eq
| | `-UnknownExpression
| | `-3
| `-;
`-}
)txt");
}
TEST_F(SyntaxTreeTest, NestedBinaryOperator) {
expectTreeDumpEqual(
R"cpp(
void test(int a, int b) {
(1 + 2) * (4 / 2);
a + b + 42;
a = b = 42;
a + b * 4 + 2;
a % 2 + b * 42;
}
)cpp",
R"txt(
*: TranslationUnit
`-SimpleDeclaration
|-void
|-SimpleDeclarator
| |-test
| `-ParametersAndQualifiers
| |-(
| |-SimpleDeclaration
| | |-int
| | `-SimpleDeclarator
| | `-a
| |-,
| |-SimpleDeclaration
| | |-int
| | `-SimpleDeclarator
| | `-b
| `-)
`-CompoundStatement
|-{
|-ExpressionStatement
| |-BinaryOperatorExpression
| | |-UnknownExpression
| | | |-(
| | | |-BinaryOperatorExpression
| | | | |-UnknownExpression
| | | | | `-1
| | | | |-+
| | | | `-UnknownExpression
| | | | `-2
| | | `-)
| | |-*
| | `-UnknownExpression
| | |-(
| | |-BinaryOperatorExpression
| | | |-UnknownExpression
| | | | `-4
| | | |-/
| | | `-UnknownExpression
| | | `-2
| | `-)
| `-;
|-ExpressionStatement
| |-BinaryOperatorExpression
| | |-BinaryOperatorExpression
| | | |-UnknownExpression
| | | | `-a
| | | |-+
| | | `-UnknownExpression
| | | `-b
| | |-+
| | `-UnknownExpression
| | `-42
| `-;
|-ExpressionStatement
| |-BinaryOperatorExpression
| | |-UnknownExpression
| | | `-a
| | |-=
| | `-BinaryOperatorExpression
| | |-UnknownExpression
| | | `-b
| | |-=
| | `-UnknownExpression
| | `-42
| `-;
|-ExpressionStatement
| |-BinaryOperatorExpression
| | |-BinaryOperatorExpression
| | | |-UnknownExpression
| | | | `-a
| | | |-+
| | | `-BinaryOperatorExpression
| | | |-UnknownExpression
| | | | `-b
| | | |-*
| | | `-UnknownExpression
| | | `-4
| | |-+
| | `-UnknownExpression
| | `-2
| `-;
|-ExpressionStatement
| |-BinaryOperatorExpression
| | |-BinaryOperatorExpression
| | | |-UnknownExpression
| | | | `-a
| | | |-%
| | | `-UnknownExpression
| | | `-2
| | |-+
| | `-BinaryOperatorExpression
| | |-UnknownExpression
| | | `-b
| | |-*
| | `-UnknownExpression
| | `-42
| `-;
`-}
)txt");
}
TEST_F(SyntaxTreeTest, MultipleDeclaratorsGrouping) {
expectTreeDumpEqual(
R"cpp(
@ -1201,10 +1435,12 @@ void test() {
|-IfStatement
| |-I: if
| |-I: (
| |-I: UnknownExpression
| | |-I: 1
| |-I: BinaryOperatorExpression
| | |-I: UnknownExpression
| | | `-I: 1
| | |-I: +
| | `-I: 1
| | `-I: UnknownExpression
| | `-I: 1
| |-I: )
| |-I: CompoundStatement
| | |-I: {
@ -1312,13 +1548,17 @@ void f(int xs[static 10]);
| | | `-]
| | |-=
| | `-UnknownExpression
| | |-{
| | |-1
| | |-,
| | |-2
| | |-,
| | |-3
| | `-}
| | `-UnknownExpression
| | |-{
| | |-UnknownExpression
| | | `-1
| | |-,
| | |-UnknownExpression
| | | `-2
| | |-,
| | |-UnknownExpression
| | | `-3
| | `-}
| `-;
`-SimpleDeclaration
|-void
@ -1628,7 +1868,8 @@ const int const *const *volatile b;
| | |-=
| | `-UnknownExpression
| | |--
| | `-1
| | `-UnknownExpression
| | `-1
| `-;
|-SimpleDeclaration
| |-int