diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -589,7 +589,6 @@ BINOP_LIST() #undef OPERATOR -#undef BINOP_LIST #define OPERATOR(NAME) \ case BO_##NAME##Assign: \ @@ -597,7 +596,6 @@ CAO_LIST() #undef OPERATOR -#undef CAO_LIST } } else if (UnaryOperator *UnOp = dyn_cast(S)) { switch (UnOp->getOpcode()) { @@ -607,7 +605,6 @@ UNARYOP_LIST() #undef OPERATOR -#undef UNARYOP_LIST } } @@ -629,27 +626,68 @@ template bool RecursiveASTVisitor::PostVisitStmt(Stmt *S) { + // In pre-order traversal mode, each Traverse##STMT method is responsible for + // calling WalkUpFrom. Therefore, if the user overrides Traverse##STMT and + // does not call the default implementation, the WalkUpFrom callback is not + // called. Post-order traversal mode should provide the same behavior + // regarding method overrides. + // + // In post-order traversal mode the Traverse##STMT method, when it receives a + // DataRecursionQueue, can't call WalkUpFrom after traversing children because + // it only enqueues the children and does not traverse them. TraverseStmt + // traverses the enqueued children, and we call WalkUpFrom here. + // + // However, to make pre-order and post-order modes identical with regards to + // whether they call WalkUpFrom at all, we call WalkUpFrom if and only if the + // user did not override the Traverse##STMT method. We implement the override + // check with isSameMethod calls below. + + if (BinaryOperator *BinOp = dyn_cast(S)) { + switch (BinOp->getOpcode()) { +#define OPERATOR(NAME) \ + case BO_##NAME: \ + if (isSameMethod(&RecursiveASTVisitor::TraverseBin##NAME, \ + &Derived::TraverseBin##NAME)) { \ + TRY_TO(WalkUpFromBin##NAME(static_cast(S))); \ + } \ + return true; + + BINOP_LIST() +#undef OPERATOR + +#define OPERATOR(NAME) \ + case BO_##NAME##Assign: \ + if (isSameMethod(&RecursiveASTVisitor::TraverseBin##NAME##Assign, \ + &Derived::TraverseBin##NAME##Assign)) { \ + TRY_TO(WalkUpFromBin##NAME##Assign( \ + static_cast(S))); \ + } \ + return true; + + CAO_LIST() +#undef OPERATOR + } + } else if (UnaryOperator *UnOp = dyn_cast(S)) { + switch (UnOp->getOpcode()) { +#define OPERATOR(NAME) \ + case UO_##NAME: \ + if (isSameMethod(&RecursiveASTVisitor::TraverseUnary##NAME, \ + &Derived::TraverseUnary##NAME)) { \ + TRY_TO(WalkUpFromUnary##NAME(static_cast(S))); \ + } \ + return true; + + UNARYOP_LIST() +#undef OPERATOR + } + } + switch (S->getStmtClass()) { case Stmt::NoStmtClass: break; #define ABSTRACT_STMT(STMT) #define STMT(CLASS, PARENT) \ case Stmt::CLASS##Class: \ - /* In pre-order traversal mode, each Traverse##STMT method is responsible \ - * for calling WalkUpFrom. Therefore, if the user overrides Traverse##STMT \ - * and does not call the default implementation, the WalkUpFrom callback \ - * is not called. Post-order traversal mode should provide the same \ - * behavior regarding method overrides. \ - * \ - * In post-order traversal mode the Traverse##STMT method, when it \ - * receives a DataRecursionQueue, can't call WalkUpFrom after traversing \ - * children because it only enqueues the children and does not traverse \ - * them. TraverseStmt traverses the enqueued children, and we call \ - * WalkUpFrom here. \ - * \ - * However, to make pre-order and post-order modes identical with regards \ - * to whether they call WalkUpFrom at all, we call WalkUpFrom if and only \ - * if the user did not override the Traverse##STMT method. */ \ if (isSameMethod(&RecursiveASTVisitor::Traverse##CLASS, \ &Derived::Traverse##CLASS)) { \ TRY_TO(WalkUpFrom##CLASS(static_cast(S))); \ @@ -657,7 +695,6 @@ break; #define INITLISTEXPR(CLASS, PARENT) \ case Stmt::CLASS##Class: \ - /* See the comment above for the explanation of the isSameMethod check. */ \ if (isSameMethod(&RecursiveASTVisitor::Traverse##CLASS, \ &Derived::Traverse##CLASS)) { \ auto ILE = static_cast(S); \ @@ -3662,6 +3699,10 @@ #undef TRY_TO +#undef UNARYOP_LIST +#undef BINOP_LIST +#undef CAO_LIST + } // end namespace clang #endif // LLVM_CLANG_AST_RECURSIVEASTVISITOR_H diff --git a/clang/unittests/Tooling/RecursiveASTVisitorTests/Callbacks.cpp b/clang/unittests/Tooling/RecursiveASTVisitorTests/Callbacks.cpp --- a/clang/unittests/Tooling/RecursiveASTVisitorTests/Callbacks.cpp +++ b/clang/unittests/Tooling/RecursiveASTVisitorTests/Callbacks.cpp @@ -414,14 +414,13 @@ WalkUpFromStmt IntegerLiteral(5) )txt")); - // FIXME: The following log should include a call to WalkUpFromStmt for - // BinaryOperator(+). EXPECT_TRUE(visitorCallbackLogEqual( RecordingVisitor(ShouldTraversePostOrder::Yes), Code, R"txt( WalkUpFromStmt IntegerLiteral(1) WalkUpFromStmt IntegerLiteral(2) WalkUpFromStmt IntegerLiteral(3) +WalkUpFromStmt BinaryOperator(+) WalkUpFromStmt DeclRefExpr(add) WalkUpFromStmt ImplicitCastExpr WalkUpFromStmt IntegerLiteral(4) @@ -502,8 +501,6 @@ WalkUpFromStmt IntegerLiteral(5) )txt")); - // FIXME: The following log should include a call to WalkUpFromStmt for - // BinaryOperator(+). EXPECT_TRUE(visitorCallbackLogEqual( RecordingVisitor(ShouldTraversePostOrder::Yes), Code, R"txt( @@ -513,6 +510,9 @@ WalkUpFromStmt IntegerLiteral(2) WalkUpFromExpr IntegerLiteral(3) WalkUpFromStmt IntegerLiteral(3) +WalkUpFromBinaryOperator BinaryOperator(+) + WalkUpFromExpr BinaryOperator(+) + WalkUpFromStmt BinaryOperator(+) WalkUpFromExpr DeclRefExpr(add) WalkUpFromStmt DeclRefExpr(add) WalkUpFromExpr ImplicitCastExpr