diff --git a/clang/lib/Tooling/Syntax/BuildTree.cpp b/clang/lib/Tooling/Syntax/BuildTree.cpp index 90451539b3b42..11d3997300406 100644 --- a/clang/lib/Tooling/Syntax/BuildTree.cpp +++ b/clang/lib/Tooling/Syntax/BuildTree.cpp @@ -1007,23 +1007,26 @@ class BuildTreeVisitor : public RecursiveASTVisitor { } bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *S) { - if (getOperatorNodeKind(*S) == - syntax::NodeKind::PostfixUnaryOperatorExpression) { + // To construct a syntax tree of the same shape for calls to built-in and + // user-defined operators, ignore the `DeclRefExpr` that refers to the + // operator and treat it as a simple token. Do that by traversing + // arguments instead of children. + for (auto *child : S->arguments()) { // A postfix unary operator is declared as taking two operands. The // second operand is used to distinguish from its prefix counterpart. In // the semantic AST this "phantom" operand is represented as a // `IntegerLiteral` with invalid `SourceLocation`. We skip visiting this // operand because it does not correspond to anything written in source - // code - for (auto *child : S->children()) { - if (child->getSourceRange().isInvalid()) - continue; - if (!TraverseStmt(child)) - return false; + // code. + if (child->getSourceRange().isInvalid()) { + assert(getOperatorNodeKind(*S) == + syntax::NodeKind::PostfixUnaryOperatorExpression); + continue; } - return WalkUpFromCXXOperatorCallExpr(S); - } else - return RecursiveASTVisitor::TraverseCXXOperatorCallExpr(S); + if (!TraverseStmt(child)) + return false; + } + return WalkUpFromCXXOperatorCallExpr(S); } bool WalkUpFromCXXOperatorCallExpr(CXXOperatorCallExpr *S) { diff --git a/clang/unittests/Tooling/Syntax/TreeTest.cpp b/clang/unittests/Tooling/Syntax/TreeTest.cpp index 46101660df8ed..a5d1a4bfcacfc 100644 --- a/clang/unittests/Tooling/Syntax/TreeTest.cpp +++ b/clang/unittests/Tooling/Syntax/TreeTest.cpp @@ -2592,9 +2592,7 @@ void test(X x, X y, X* xp, int X::* pmi) { | | |-IdExpression | | | `-UnqualifiedId | | | `-x - | | |-IdExpression - | | | `-UnqualifiedId - | | | `-= + | | |-= | | `-IdExpression | | `-UnqualifiedId | | `-y @@ -2605,9 +2603,7 @@ void test(X x, X y, X* xp, int X::* pmi) { | | | `-IdExpression | | | `-UnqualifiedId | | | `-x - | | |-IdExpression - | | | `-UnqualifiedId - | | | `-+ + | | |-+ | | `-IdExpression | | `-UnqualifiedId | | `-y @@ -2617,9 +2613,7 @@ void test(X x, X y, X* xp, int X::* pmi) { | | |-IdExpression | | | `-UnqualifiedId | | | `-x - | | |-IdExpression - | | | `-UnqualifiedId - | | | `-< + | | |-< | | `-IdExpression | | `-UnqualifiedId | | `-y @@ -2629,9 +2623,7 @@ void test(X x, X y, X* xp, int X::* pmi) { | | |-IdExpression | | | `-UnqualifiedId | | | `-x - | | |-IdExpression - | | | `-UnqualifiedId - | | | `-<< + | | |-<< | | `-IdExpression | | `-UnqualifiedId | | `-y @@ -2641,9 +2633,7 @@ void test(X x, X y, X* xp, int X::* pmi) { | | |-IdExpression | | | `-UnqualifiedId | | | `-x - | | |-IdExpression - | | | `-UnqualifiedId - | | | `-, + | | |-, | | `-IdExpression | | `-UnqualifiedId | | `-y @@ -2730,27 +2720,21 @@ void test(X x) { |-{ |-ExpressionStatement | |-PrefixUnaryOperatorExpression - | | |-IdExpression - | | | `-UnqualifiedId - | | | `-++ + | | |-++ | | `-IdExpression | | `-UnqualifiedId | | `-x | `-; |-ExpressionStatement | |-PrefixUnaryOperatorExpression - | | |-IdExpression - | | | `-UnqualifiedId - | | | `-! + | | |-! | | `-IdExpression | | `-UnqualifiedId | | `-x | `-; |-ExpressionStatement | |-PrefixUnaryOperatorExpression - | | |-IdExpression - | | | `-UnqualifiedId - | | | `-& + | | |-& | | `-IdExpression | | `-UnqualifiedId | | `-x @@ -2809,9 +2793,7 @@ void test(X x) { | | |-IdExpression | | | `-UnqualifiedId | | | `-x - | | `-IdExpression - | | `-UnqualifiedId - | | `-++ + | | `-++ | `-; `-} )txt"));