diff --git a/clang/lib/Tooling/Syntax/BuildTree.cpp b/clang/lib/Tooling/Syntax/BuildTree.cpp --- a/clang/lib/Tooling/Syntax/BuildTree.cpp +++ b/clang/lib/Tooling/Syntax/BuildTree.cpp @@ -12,6 +12,7 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/Stmt.h" #include "clang/AST/TypeLoc.h" @@ -114,6 +115,85 @@ }; } // namespace +syntax::NodeKind getOperatorNodeKind(const CXXOperatorCallExpr &E) { + switch (E.getOperator()) { + // Comparison + case OO_EqualEqual: + case OO_ExclaimEqual: + case OO_Greater: + case OO_GreaterEqual: + case OO_Less: + case OO_LessEqual: + case OO_Spaceship: + // Assignment + case OO_Equal: + case OO_SlashEqual: + case OO_PercentEqual: + case OO_CaretEqual: + case OO_PipeEqual: + case OO_LessLessEqual: + case OO_GreaterGreaterEqual: + case OO_PlusEqual: + case OO_MinusEqual: + case OO_StarEqual: + case OO_AmpEqual: + // Binary computation + case OO_Slash: + case OO_Percent: + case OO_Caret: + case OO_Pipe: + case OO_LessLess: + case OO_GreaterGreater: + case OO_AmpAmp: + case OO_PipePipe: + return syntax::NodeKind::BinaryOperatorExpression; + case OO_Tilde: + case OO_Exclaim: + return syntax::NodeKind::PrefixUnaryOperatorExpression; + // Prefix/Postfix increment/decrement + case OO_PlusPlus: + case OO_MinusMinus: + switch (E.getNumArgs()) { + case 1: + return syntax::NodeKind::PrefixUnaryOperatorExpression; + case 2: + return syntax::NodeKind::PostfixUnaryOperatorExpression; + default: + llvm_unreachable("Invalid number of arguments for operator"); + } + // Operators that can be unary or binary + case OO_Plus: + case OO_Minus: + case OO_Star: + case OO_Amp: + switch (E.getNumArgs()) { + case 1: + return syntax::NodeKind::PrefixUnaryOperatorExpression; + case 2: + return syntax::NodeKind::BinaryOperatorExpression; + default: + llvm_unreachable("Invalid number of arguments for operator"); + } + return syntax::NodeKind::BinaryOperatorExpression; + // Not supported by SyntaxTree + case OO_New: + case OO_Delete: + case OO_Array_New: + case OO_Array_Delete: + case OO_Coawait: + case OO_Call: + case OO_Subscript: + case OO_Arrow: + case OO_Comma: + case OO_ArrowStar: + return syntax::NodeKind::UnknownExpression; + case OO_Conditional: // not overloadable + case NUM_OVERLOADED_OPERATORS: + case OO_None: + llvm_unreachable("Not an overloadable operator"); + } +} + /// Gets the range of declarator as defined by the C++ grammar. E.g. /// `int a;` -> range of `a`, /// `int *a;` -> range of `*a`, @@ -658,6 +738,8 @@ } bool WalkUpFromIntegerLiteral(IntegerLiteral *S) { + if (S->getLocation().isInvalid()) + return true; Builder.markChildToken(S->getLocation(), syntax::NodeRole::LiteralToken); Builder.foldNode(Builder.getExprRange(S), new (allocator()) syntax::IntegerLiteralExpression, S); @@ -730,7 +812,8 @@ } bool WalkUpFromCXXOperatorCallExpr(CXXOperatorCallExpr *S) { - if (S->isInfixBinaryOp()) { + switch (getOperatorNodeKind(*S)) { + case syntax::NodeKind::BinaryOperatorExpression: Builder.markExprChild( S->getArg(0), syntax::NodeRole::BinaryOperatorExpression_leftHandSide); @@ -743,8 +826,31 @@ Builder.foldNode(Builder.getExprRange(S), new (allocator()) syntax::BinaryOperatorExpression, S); return true; + case syntax::NodeKind::PrefixUnaryOperatorExpression: + Builder.markChildToken( + S->getOperatorLoc(), + syntax::NodeRole::OperatorExpression_operatorToken); + Builder.markExprChild(S->getArg(0), + syntax::NodeRole::UnaryOperatorExpression_operand); + Builder.foldNode(Builder.getExprRange(S), + new (allocator()) syntax::PrefixUnaryOperatorExpression, + S); + return true; + case syntax::NodeKind::PostfixUnaryOperatorExpression: + Builder.markChildToken( + S->getOperatorLoc(), + syntax::NodeRole::OperatorExpression_operatorToken); + Builder.markExprChild(S->getArg(0), + syntax::NodeRole::UnaryOperatorExpression_operand); + Builder.foldNode(Builder.getExprRange(S), + new (allocator()) syntax::PostfixUnaryOperatorExpression, + S); + return true; + case syntax::NodeKind::UnknownExpression: + return RecursiveASTVisitor::WalkUpFromCXXOperatorCallExpr(S); + default: + llvm_unreachable("getKind does not implement that"); } - return RecursiveASTVisitor::WalkUpFromCXXOperatorCallExpr(S); } bool WalkUpFromNamespaceDecl(NamespaceDecl *S) { 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 @@ -2323,6 +2323,64 @@ )txt")); } +TEST_P(SyntaxTreeTest, UserDefinedUnaryPostfixOperator) { + if (!GetParam().isCXX()) { + return; + } + EXPECT_TRUE(treeDumpEqual( + R"cpp( +struct X { + X operator++(int); +}; +void test(X x) { + x++; +} +)cpp", + R"txt( +*: TranslationUnit +|-SimpleDeclaration +| |-struct +| |-X +| |-{ +| |-SimpleDeclaration +| | |-X +| | |-SimpleDeclarator +| | | |-operator +| | | |-++ +| | | `-ParametersAndQualifiers +| | | |-( +| | | |-SimpleDeclaration +| | | | `-int +| | | `-) +| | `-; +| |-} +| `-; +`-SimpleDeclaration + |-void + |-SimpleDeclarator + | |-test + | `-ParametersAndQualifiers + | |-( + | |-SimpleDeclaration + | | |-X + | | `-SimpleDeclarator + | | `-x + | `-) + `-CompoundStatement + |-{ + |-ExpressionStatement + | |-PostfixUnaryOperatorExpression + | | |-IdExpression + | | | `-UnqualifiedId + | | | `-x + | | `-IdExpression + | | `-UnqualifiedId + | | `-++ + | `-; + `-} +)txt")); +} + TEST_P(SyntaxTreeTest, MultipleDeclaratorsGrouping) { EXPECT_TRUE(treeDumpEqual( R"cpp(