Removed a RecursiveASTVisitor feature to visit operator kinds with different methods

Summary:
This feature was only used in two places, but contributed a non-trivial
amount to the complexity of RecursiveASTVisitor, and was buggy (see my
recent patches where I was fixing the bugs that I noticed). I don't
think the convenience benefit of this feature is worth the complexity.

Besides complexity, another issue with the current state of
RecursiveASTVisitor is the non-uniformity in how it handles different
AST nodes. All AST nodes follow a regular pattern, but operators are
special -- and this special behavior not documented. Correct usage of
RecursiveASTVisitor relies on shadowing member functions with specific
names and signatures. Near misses don't cause any compile-time errors,
incorrectly named or typed methods are just silently ignored. Therefore,
predictability of RecursiveASTVisitor API is quite important.

This change reduces the size of the `clang` binary by 38 KB (0.2%) in
release mode, and by 7 MB (0.3%) in debug mode. The `clang-tidy` binary
is reduced by 205 KB (0.3%) in release mode, and by 5 MB (0.4%) in debug
mode. I don't think these code size improvements are significant enough
to justify this change on its own (for me, the primary motivation is
reducing code complexity), but they I think are a nice side-effect.

Reviewers: rsmith, sammccall, ymandel, aaron.ballman

Reviewed By: rsmith, sammccall, ymandel, aaron.ballman

Subscribers: cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D82921
This commit is contained in:
Dmitri Gribenko 2020-07-03 17:01:01 +02:00
parent 8e750b1f0a
commit 5689b38c6a
6 changed files with 101 additions and 820 deletions

View File

@ -500,7 +500,7 @@ void ForLoopIndexUseVisitor::addUsage(const Usage &U) {
/// int k = *i + 2;
/// }
/// \endcode
bool ForLoopIndexUseVisitor::TraverseUnaryDeref(UnaryOperator *Uop) {
bool ForLoopIndexUseVisitor::TraverseUnaryOperator(UnaryOperator *Uop) {
// If we dereference an iterator that's actually a pointer, count the
// occurrence.
if (isDereferenceOfUop(Uop, IndexVar)) {

View File

@ -346,7 +346,7 @@ private:
bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C,
Expr *Init);
bool TraverseMemberExpr(MemberExpr *Member);
bool TraverseUnaryDeref(UnaryOperator *Uop);
bool TraverseUnaryOperator(UnaryOperator *Uop);
bool VisitDeclRefExpr(DeclRefExpr *E);
bool VisitDeclStmt(DeclStmt *S);
bool TraverseStmt(Stmt *S);

View File

@ -243,6 +243,34 @@ These are major API changes that have happened since the 10.0.0 release of
Clang. If upgrading an external codebase that uses Clang as a library,
this section should help get you past the largest hurdles of upgrading.
- ``RecursiveASTVisitor`` no longer calls separate methods to visit specific
operator kinds. Previously, ``RecursiveASTVisitor`` treated unary, binary,
and compound assignment operators as if they were subclasses of the
corresponding AST node. For example, the binary operator plus was treated as
if it was a ``BinAdd`` subclass of the ``BinaryOperator`` class: during AST
traversal of a ``BinaryOperator`` AST node that had a ``BO_Add`` opcode,
``RecursiveASTVisitor`` was calling the ``TraverseBinAdd`` method instead of
``TraverseBinaryOperator``. This feature was contributing a non-trivial
amount of complexity to the implementation of ``RecursiveASTVisitor``, it was
used only in a minor way in Clang, was not tested, and as a result it was
buggy. Furthermore, this feature was creating a non-uniformity in the API.
Since this feature was not documented, it was quite difficult to figure out
how to use ``RecursiveASTVisitor`` to visit operators.
To update your code to the new uniform API, move the code from separate
visitation methods into methods that correspond to the actual AST node and
perform case analysis based on the operator opcode as needed:
* ``TraverseUnary*() => TraverseUnaryOperator()``
* ``WalkUpFromUnary*() => WalkUpFromUnaryOperator()``
* ``VisitUnary*() => VisiUnaryOperator()``
* ``TraverseBin*() => TraverseBinaryOperator()``
* ``WalkUpFromBin*() => WalkUpFromBinaryOperator()``
* ``VisitBin*() => VisiBinaryOperator()``
* ``TraverseBin*Assign() => TraverseCompoundAssignOperator()``
* ``WalkUpFromBin*Assign() => WalkUpFromCompoundAssignOperator()``
* ``VisitBin*Assign() => VisiCompoundAssignOperator()``
Build System Changes
--------------------

View File

@ -48,29 +48,6 @@
#include <cstddef>
#include <type_traits>
// The following three macros are used for meta programming. The code
// using them is responsible for defining macro OPERATOR().
// All unary operators.
#define UNARYOP_LIST() \
OPERATOR(PostInc) OPERATOR(PostDec) OPERATOR(PreInc) OPERATOR(PreDec) \
OPERATOR(AddrOf) OPERATOR(Deref) OPERATOR(Plus) OPERATOR(Minus) \
OPERATOR(Not) OPERATOR(LNot) OPERATOR(Real) OPERATOR(Imag) \
OPERATOR(Extension) OPERATOR(Coawait)
// All binary operators (excluding compound assign operators).
#define BINOP_LIST() \
OPERATOR(PtrMemD) OPERATOR(PtrMemI) OPERATOR(Mul) OPERATOR(Div) \
OPERATOR(Rem) OPERATOR(Add) OPERATOR(Sub) OPERATOR(Shl) OPERATOR(Shr) \
OPERATOR(LT) OPERATOR(GT) OPERATOR(LE) OPERATOR(GE) OPERATOR(EQ) \
OPERATOR(NE) OPERATOR(Cmp) OPERATOR(And) OPERATOR(Xor) OPERATOR(Or) \
OPERATOR(LAnd) OPERATOR(LOr) OPERATOR(Assign) OPERATOR(Comma)
// All compound assign operators.
#define CAO_LIST() \
OPERATOR(Mul) OPERATOR(Div) OPERATOR(Rem) OPERATOR(Add) OPERATOR(Sub) \
OPERATOR(Shl) OPERATOR(Shr) OPERATOR(And) OPERATOR(Or) OPERATOR(Xor)
namespace clang {
// A helper macro to implement short-circuiting when recursing. It
@ -407,64 +384,6 @@ public:
bool Visit##CLASS(CLASS *S) { return true; }
#include "clang/AST/StmtNodes.inc"
// Define Traverse*(), WalkUpFrom*(), and Visit*() for unary
// operator methods. Unary operators are not classes in themselves
// (they're all opcodes in UnaryOperator) but do have visitors.
#define OPERATOR(NAME) \
bool TraverseUnary##NAME(UnaryOperator *S, \
DataRecursionQueue *Queue = nullptr) { \
if (!getDerived().shouldTraversePostOrder()) \
TRY_TO(WalkUpFromUnary##NAME(S)); \
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getSubExpr()); \
if (!Queue && getDerived().shouldTraversePostOrder()) \
TRY_TO(WalkUpFromUnary##NAME(S)); \
return true; \
} \
bool WalkUpFromUnary##NAME(UnaryOperator *S) { \
TRY_TO(WalkUpFromUnaryOperator(S)); \
TRY_TO(VisitUnary##NAME(S)); \
return true; \
} \
bool VisitUnary##NAME(UnaryOperator *S) { return true; }
UNARYOP_LIST()
#undef OPERATOR
// Define Traverse*(), WalkUpFrom*(), and Visit*() for binary
// operator methods. Binary operators are not classes in themselves
// (they're all opcodes in BinaryOperator) but do have visitors.
#define GENERAL_BINOP_FALLBACK(NAME, BINOP_TYPE) \
bool TraverseBin##NAME(BINOP_TYPE *S, DataRecursionQueue *Queue = nullptr) { \
if (!getDerived().shouldTraversePostOrder()) \
TRY_TO(WalkUpFromBin##NAME(S)); \
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getLHS()); \
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getRHS()); \
if (!Queue && getDerived().shouldTraversePostOrder()) \
TRY_TO(WalkUpFromBin##NAME(S)); \
return true; \
} \
bool WalkUpFromBin##NAME(BINOP_TYPE *S) { \
TRY_TO(WalkUpFrom##BINOP_TYPE(S)); \
TRY_TO(VisitBin##NAME(S)); \
return true; \
} \
bool VisitBin##NAME(BINOP_TYPE *S) { return true; }
#define OPERATOR(NAME) GENERAL_BINOP_FALLBACK(NAME, BinaryOperator)
BINOP_LIST()
#undef OPERATOR
// Define Traverse*(), WalkUpFrom*(), and Visit*() for compound
// assignment methods. Compound assignment operators are not
// classes in themselves (they're all opcodes in
// CompoundAssignOperator) but do have visitors.
#define OPERATOR(NAME) \
GENERAL_BINOP_FALLBACK(NAME##Assign, CompoundAssignOperator)
CAO_LIST()
#undef OPERATOR
#undef GENERAL_BINOP_FALLBACK
// ---- Methods on Types ----
// FIXME: revamp to take TypeLoc's rather than Types.
@ -583,39 +502,6 @@ private:
template <typename Derived>
bool RecursiveASTVisitor<Derived>::dataTraverseNode(Stmt *S,
DataRecursionQueue *Queue) {
#define DISPATCH_STMT(NAME, CLASS, VAR) \
return TRAVERSE_STMT_BASE(NAME, CLASS, VAR, Queue);
// If we have a binary expr, dispatch to the subcode of the binop. A smart
// optimizer (e.g. LLVM) will fold this comparison into the switch stmt
// below.
if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(S)) {
switch (BinOp->getOpcode()) {
#define OPERATOR(NAME) \
case BO_##NAME: \
DISPATCH_STMT(Bin##NAME, BinaryOperator, S);
BINOP_LIST()
#undef OPERATOR
#define OPERATOR(NAME) \
case BO_##NAME##Assign: \
DISPATCH_STMT(Bin##NAME##Assign, CompoundAssignOperator, S);
CAO_LIST()
#undef OPERATOR
}
} else if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(S)) {
switch (UnOp->getOpcode()) {
#define OPERATOR(NAME) \
case UO_##NAME: \
DISPATCH_STMT(Unary##NAME, UnaryOperator, S);
UNARYOP_LIST()
#undef OPERATOR
}
}
// Top switch stmt: dispatch to TraverseFooStmt for each concrete FooStmt.
switch (S->getStmtClass()) {
case Stmt::NoStmtClass:
@ -623,7 +509,7 @@ bool RecursiveASTVisitor<Derived>::dataTraverseNode(Stmt *S,
#define ABSTRACT_STMT(STMT)
#define STMT(CLASS, PARENT) \
case Stmt::CLASS##Class: \
DISPATCH_STMT(CLASS, CLASS, S);
return TRAVERSE_STMT_BASE(CLASS, CLASS, S, Queue);
#include "clang/AST/StmtNodes.inc"
}
@ -650,48 +536,6 @@ bool RecursiveASTVisitor<Derived>::PostVisitStmt(Stmt *S) {
// user did not override the Traverse##STMT method. We implement the override
// check with isSameMethod calls below.
if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(S)) {
switch (BinOp->getOpcode()) {
#define OPERATOR(NAME) \
case BO_##NAME: \
if (::clang::detail::isSameMethod(&RecursiveASTVisitor::TraverseBin##NAME, \
&Derived::TraverseBin##NAME)) { \
TRY_TO(WalkUpFromBin##NAME(static_cast<BinaryOperator *>(S))); \
} \
return true;
BINOP_LIST()
#undef OPERATOR
#define OPERATOR(NAME) \
case BO_##NAME##Assign: \
if (::clang::detail::isSameMethod( \
&RecursiveASTVisitor::TraverseBin##NAME##Assign, \
&Derived::TraverseBin##NAME##Assign)) { \
TRY_TO(WalkUpFromBin##NAME##Assign( \
static_cast<CompoundAssignOperator *>(S))); \
} \
return true;
CAO_LIST()
#undef OPERATOR
}
} else if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(S)) {
switch (UnOp->getOpcode()) {
#define OPERATOR(NAME) \
case UO_##NAME: \
if (::clang::detail::isSameMethod( \
&RecursiveASTVisitor::TraverseUnary##NAME, \
&Derived::TraverseUnary##NAME)) { \
TRY_TO(WalkUpFromUnary##NAME(static_cast<UnaryOperator *>(S))); \
} \
return true;
UNARYOP_LIST()
#undef OPERATOR
}
}
switch (S->getStmtClass()) {
case Stmt::NoStmtClass:
break;
@ -3711,10 +3555,6 @@ bool RecursiveASTVisitor<Derived>::VisitOMPAffinityClause(
#undef TRY_TO
#undef UNARYOP_LIST
#undef BINOP_LIST
#undef CAO_LIST
} // end namespace clang
#endif // LLVM_CLANG_AST_RECURSIVEASTVISITOR_H

View File

@ -287,7 +287,10 @@ private:
public:
PlusOneAssign(ObjCIvarDecl *D) : Ivar(D) {}
bool VisitBinAssign(BinaryOperator *E) {
bool VisitBinaryOperator(BinaryOperator *E) {
if (E->getOpcode() != BO_Assign)
return true;
Expr *lhs = E->getLHS()->IgnoreParenImpCasts();
if (ObjCIvarRefExpr *RE = dyn_cast<ObjCIvarRefExpr>(lhs)) {
if (RE->getDecl() != Ivar)

View File

@ -403,16 +403,14 @@ void test() {
}
)cpp";
// TraverseUnaryOperator is not called because RecursiveASTVisitor treats
// individual operators as subclasses, for which it calls their Traverse
// methods.
EXPECT_TRUE(visitorCallbackLogEqual(
RecordingVisitor(ShouldTraversePostOrder::No), Code,
R"txt(
WalkUpFromStmt CompoundStmt
WalkUpFromStmt IntegerLiteral(1)
WalkUpFromStmt UnaryOperator(-)
WalkUpFromStmt IntegerLiteral(2)
TraverseUnaryOperator UnaryOperator(-)
WalkUpFromStmt UnaryOperator(-)
WalkUpFromStmt IntegerLiteral(2)
WalkUpFromStmt IntegerLiteral(3)
)txt"));
@ -420,8 +418,9 @@ WalkUpFromStmt IntegerLiteral(3)
RecordingVisitor(ShouldTraversePostOrder::Yes), Code,
R"txt(
WalkUpFromStmt IntegerLiteral(1)
WalkUpFromStmt IntegerLiteral(2)
WalkUpFromStmt UnaryOperator(-)
TraverseUnaryOperator UnaryOperator(-)
WalkUpFromStmt IntegerLiteral(2)
WalkUpFromStmt UnaryOperator(-)
WalkUpFromStmt IntegerLiteral(3)
WalkUpFromStmt CompoundStmt
)txt"));
@ -469,20 +468,18 @@ void test() {
}
)cpp";
// TraverseUnaryOperator is not called because RecursiveASTVisitor treats
// individual operators as subclasses, for which it calls their Traverse
// methods.
EXPECT_TRUE(visitorCallbackLogEqual(
RecordingVisitor(ShouldTraversePostOrder::No), Code,
R"txt(
WalkUpFromStmt CompoundStmt
WalkUpFromExpr IntegerLiteral(1)
WalkUpFromStmt IntegerLiteral(1)
WalkUpFromUnaryOperator UnaryOperator(-)
WalkUpFromExpr UnaryOperator(-)
WalkUpFromStmt UnaryOperator(-)
WalkUpFromExpr IntegerLiteral(2)
WalkUpFromStmt IntegerLiteral(2)
TraverseUnaryOperator UnaryOperator(-)
WalkUpFromUnaryOperator UnaryOperator(-)
WalkUpFromExpr UnaryOperator(-)
WalkUpFromStmt UnaryOperator(-)
WalkUpFromExpr IntegerLiteral(2)
WalkUpFromStmt IntegerLiteral(2)
WalkUpFromExpr IntegerLiteral(3)
WalkUpFromStmt IntegerLiteral(3)
)txt"));
@ -492,11 +489,12 @@ WalkUpFromExpr IntegerLiteral(3)
R"txt(
WalkUpFromExpr IntegerLiteral(1)
WalkUpFromStmt IntegerLiteral(1)
WalkUpFromExpr IntegerLiteral(2)
WalkUpFromStmt IntegerLiteral(2)
WalkUpFromUnaryOperator UnaryOperator(-)
WalkUpFromExpr UnaryOperator(-)
WalkUpFromStmt UnaryOperator(-)
TraverseUnaryOperator UnaryOperator(-)
WalkUpFromExpr IntegerLiteral(2)
WalkUpFromStmt IntegerLiteral(2)
WalkUpFromUnaryOperator UnaryOperator(-)
WalkUpFromExpr UnaryOperator(-)
WalkUpFromStmt UnaryOperator(-)
WalkUpFromExpr IntegerLiteral(3)
WalkUpFromStmt IntegerLiteral(3)
WalkUpFromStmt CompoundStmt
@ -568,193 +566,6 @@ WalkUpFromStmt CompoundStmt
)txt"));
}
TEST(RecursiveASTVisitor, StmtCallbacks_TraverseUnaryMinus) {
class RecordingVisitor : public RecordingVisitorBase<RecordingVisitor> {
public:
RecordingVisitor(ShouldTraversePostOrder ShouldTraversePostOrderValue)
: RecordingVisitorBase(ShouldTraversePostOrderValue) {}
bool TraverseUnaryMinus(UnaryOperator *UO) {
recordCallback(__func__, UO,
[&]() { RecordingVisitorBase::TraverseUnaryMinus(UO); });
return true;
}
bool WalkUpFromStmt(Stmt *S) {
recordCallback(__func__, S,
[&]() { RecordingVisitorBase::WalkUpFromStmt(S); });
return true;
}
};
StringRef Code = R"cpp(
void test() {
1;
-2;
3;
}
)cpp";
EXPECT_TRUE(visitorCallbackLogEqual(
RecordingVisitor(ShouldTraversePostOrder::No), Code,
R"txt(
WalkUpFromStmt CompoundStmt
WalkUpFromStmt IntegerLiteral(1)
TraverseUnaryMinus UnaryOperator(-)
WalkUpFromStmt UnaryOperator(-)
WalkUpFromStmt IntegerLiteral(2)
WalkUpFromStmt IntegerLiteral(3)
)txt"));
EXPECT_TRUE(visitorCallbackLogEqual(
RecordingVisitor(ShouldTraversePostOrder::Yes), Code,
R"txt(
WalkUpFromStmt IntegerLiteral(1)
TraverseUnaryMinus UnaryOperator(-)
WalkUpFromStmt IntegerLiteral(2)
WalkUpFromStmt UnaryOperator(-)
WalkUpFromStmt IntegerLiteral(3)
WalkUpFromStmt CompoundStmt
)txt"));
}
TEST(RecursiveASTVisitor,
StmtCallbacks_TraverseUnaryMinus_WalkUpFromUnaryMinus) {
class RecordingVisitor : public RecordingVisitorBase<RecordingVisitor> {
public:
RecordingVisitor(ShouldTraversePostOrder ShouldTraversePostOrderValue)
: RecordingVisitorBase(ShouldTraversePostOrderValue) {}
bool TraverseUnaryMinus(UnaryOperator *UO) {
recordCallback(__func__, UO,
[&]() { RecordingVisitorBase::TraverseUnaryMinus(UO); });
return true;
}
bool WalkUpFromStmt(Stmt *S) {
recordCallback(__func__, S,
[&]() { RecordingVisitorBase::WalkUpFromStmt(S); });
return true;
}
bool WalkUpFromExpr(Expr *E) {
recordCallback(__func__, E,
[&]() { RecordingVisitorBase::WalkUpFromExpr(E); });
return true;
}
bool WalkUpFromUnaryMinus(UnaryOperator *UO) {
recordCallback(__func__, UO,
[&]() { RecordingVisitorBase::WalkUpFromUnaryMinus(UO); });
return true;
}
};
StringRef Code = R"cpp(
void test() {
1;
-2;
3;
}
)cpp";
EXPECT_TRUE(visitorCallbackLogEqual(
RecordingVisitor(ShouldTraversePostOrder::No), Code,
R"txt(
WalkUpFromStmt CompoundStmt
WalkUpFromExpr IntegerLiteral(1)
WalkUpFromStmt IntegerLiteral(1)
TraverseUnaryMinus UnaryOperator(-)
WalkUpFromUnaryMinus UnaryOperator(-)
WalkUpFromExpr UnaryOperator(-)
WalkUpFromStmt UnaryOperator(-)
WalkUpFromExpr IntegerLiteral(2)
WalkUpFromStmt IntegerLiteral(2)
WalkUpFromExpr IntegerLiteral(3)
WalkUpFromStmt IntegerLiteral(3)
)txt"));
EXPECT_TRUE(visitorCallbackLogEqual(
RecordingVisitor(ShouldTraversePostOrder::Yes), Code,
R"txt(
WalkUpFromExpr IntegerLiteral(1)
WalkUpFromStmt IntegerLiteral(1)
TraverseUnaryMinus UnaryOperator(-)
WalkUpFromExpr IntegerLiteral(2)
WalkUpFromStmt IntegerLiteral(2)
WalkUpFromUnaryMinus UnaryOperator(-)
WalkUpFromExpr UnaryOperator(-)
WalkUpFromStmt UnaryOperator(-)
WalkUpFromExpr IntegerLiteral(3)
WalkUpFromStmt IntegerLiteral(3)
WalkUpFromStmt CompoundStmt
)txt"));
}
TEST(RecursiveASTVisitor, StmtCallbacks_WalkUpFromUnaryMinus) {
class RecordingVisitor : public RecordingVisitorBase<RecordingVisitor> {
public:
RecordingVisitor(ShouldTraversePostOrder ShouldTraversePostOrderValue)
: RecordingVisitorBase(ShouldTraversePostOrderValue) {}
bool WalkUpFromStmt(Stmt *S) {
recordCallback(__func__, S,
[&]() { RecordingVisitorBase::WalkUpFromStmt(S); });
return true;
}
bool WalkUpFromExpr(Expr *E) {
recordCallback(__func__, E,
[&]() { RecordingVisitorBase::WalkUpFromExpr(E); });
return true;
}
bool WalkUpFromUnaryMinus(UnaryOperator *UO) {
recordCallback(__func__, UO,
[&]() { RecordingVisitorBase::WalkUpFromUnaryMinus(UO); });
return true;
}
};
StringRef Code = R"cpp(
void test() {
1;
-2;
3;
}
)cpp";
EXPECT_TRUE(visitorCallbackLogEqual(
RecordingVisitor(ShouldTraversePostOrder::No), Code,
R"txt(
WalkUpFromStmt CompoundStmt
WalkUpFromExpr IntegerLiteral(1)
WalkUpFromStmt IntegerLiteral(1)
WalkUpFromUnaryMinus UnaryOperator(-)
WalkUpFromExpr UnaryOperator(-)
WalkUpFromStmt UnaryOperator(-)
WalkUpFromExpr IntegerLiteral(2)
WalkUpFromStmt IntegerLiteral(2)
WalkUpFromExpr IntegerLiteral(3)
WalkUpFromStmt IntegerLiteral(3)
)txt"));
EXPECT_TRUE(visitorCallbackLogEqual(
RecordingVisitor(ShouldTraversePostOrder::Yes), Code,
R"txt(
WalkUpFromExpr IntegerLiteral(1)
WalkUpFromStmt IntegerLiteral(1)
WalkUpFromExpr IntegerLiteral(2)
WalkUpFromStmt IntegerLiteral(2)
WalkUpFromUnaryMinus UnaryOperator(-)
WalkUpFromExpr UnaryOperator(-)
WalkUpFromStmt UnaryOperator(-)
WalkUpFromExpr IntegerLiteral(3)
WalkUpFromStmt IntegerLiteral(3)
WalkUpFromStmt CompoundStmt
)txt"));
}
TEST(RecursiveASTVisitor, StmtCallbacks_TraverseBinaryOperator) {
class RecordingVisitor : public RecordingVisitorBase<RecordingVisitor> {
public:
@ -783,17 +594,15 @@ void test() {
}
)cpp";
// TraverseBinaryOperator is not called because RecursiveASTVisitor treats
// individual operators as subclasses, for which it calls their Traverse
// methods.
EXPECT_TRUE(visitorCallbackLogEqual(
RecordingVisitor(ShouldTraversePostOrder::No), Code,
R"txt(
WalkUpFromStmt CompoundStmt
WalkUpFromStmt IntegerLiteral(1)
WalkUpFromStmt BinaryOperator(+)
WalkUpFromStmt IntegerLiteral(2)
WalkUpFromStmt IntegerLiteral(3)
TraverseBinaryOperator BinaryOperator(+)
WalkUpFromStmt BinaryOperator(+)
WalkUpFromStmt IntegerLiteral(2)
WalkUpFromStmt IntegerLiteral(3)
WalkUpFromStmt IntegerLiteral(4)
)txt"));
@ -801,9 +610,10 @@ WalkUpFromStmt IntegerLiteral(4)
RecordingVisitor(ShouldTraversePostOrder::Yes), Code,
R"txt(
WalkUpFromStmt IntegerLiteral(1)
WalkUpFromStmt IntegerLiteral(2)
WalkUpFromStmt IntegerLiteral(3)
WalkUpFromStmt BinaryOperator(+)
TraverseBinaryOperator BinaryOperator(+)
WalkUpFromStmt IntegerLiteral(2)
WalkUpFromStmt IntegerLiteral(3)
WalkUpFromStmt BinaryOperator(+)
WalkUpFromStmt IntegerLiteral(4)
WalkUpFromStmt CompoundStmt
)txt"));
@ -851,22 +661,20 @@ void test() {
}
)cpp";
// TraverseBinaryOperator is not called because RecursiveASTVisitor treats
// individual operators as subclasses, for which it calls their Traverse
// methods.
EXPECT_TRUE(visitorCallbackLogEqual(
RecordingVisitor(ShouldTraversePostOrder::No), Code,
R"txt(
WalkUpFromStmt CompoundStmt
WalkUpFromExpr IntegerLiteral(1)
WalkUpFromStmt IntegerLiteral(1)
WalkUpFromBinaryOperator BinaryOperator(+)
WalkUpFromExpr BinaryOperator(+)
WalkUpFromStmt BinaryOperator(+)
WalkUpFromExpr IntegerLiteral(2)
WalkUpFromStmt IntegerLiteral(2)
WalkUpFromExpr IntegerLiteral(3)
WalkUpFromStmt IntegerLiteral(3)
TraverseBinaryOperator BinaryOperator(+)
WalkUpFromBinaryOperator BinaryOperator(+)
WalkUpFromExpr BinaryOperator(+)
WalkUpFromStmt BinaryOperator(+)
WalkUpFromExpr IntegerLiteral(2)
WalkUpFromStmt IntegerLiteral(2)
WalkUpFromExpr IntegerLiteral(3)
WalkUpFromStmt IntegerLiteral(3)
WalkUpFromExpr IntegerLiteral(4)
WalkUpFromStmt IntegerLiteral(4)
)txt"));
@ -876,13 +684,14 @@ WalkUpFromExpr IntegerLiteral(4)
R"txt(
WalkUpFromExpr IntegerLiteral(1)
WalkUpFromStmt IntegerLiteral(1)
WalkUpFromExpr IntegerLiteral(2)
WalkUpFromStmt IntegerLiteral(2)
WalkUpFromExpr IntegerLiteral(3)
WalkUpFromStmt IntegerLiteral(3)
WalkUpFromBinaryOperator BinaryOperator(+)
WalkUpFromExpr BinaryOperator(+)
WalkUpFromStmt BinaryOperator(+)
TraverseBinaryOperator BinaryOperator(+)
WalkUpFromExpr IntegerLiteral(2)
WalkUpFromStmt IntegerLiteral(2)
WalkUpFromExpr IntegerLiteral(3)
WalkUpFromStmt IntegerLiteral(3)
WalkUpFromBinaryOperator BinaryOperator(+)
WalkUpFromExpr BinaryOperator(+)
WalkUpFromStmt BinaryOperator(+)
WalkUpFromExpr IntegerLiteral(4)
WalkUpFromStmt IntegerLiteral(4)
WalkUpFromStmt CompoundStmt
@ -958,202 +767,6 @@ WalkUpFromStmt CompoundStmt
)txt"));
}
TEST(RecursiveASTVisitor, StmtCallbacks_TraverseBinAdd) {
class RecordingVisitor : public RecordingVisitorBase<RecordingVisitor> {
public:
RecordingVisitor(ShouldTraversePostOrder ShouldTraversePostOrderValue)
: RecordingVisitorBase(ShouldTraversePostOrderValue) {}
bool TraverseBinAdd(BinaryOperator *BO) {
recordCallback(__func__, BO,
[&]() { RecordingVisitorBase::TraverseBinAdd(BO); });
return true;
}
bool WalkUpFromStmt(Stmt *S) {
recordCallback(__func__, S,
[&]() { RecordingVisitorBase::WalkUpFromStmt(S); });
return true;
}
};
StringRef Code = R"cpp(
void test() {
1;
2 + 3;
4;
}
)cpp";
EXPECT_TRUE(visitorCallbackLogEqual(
RecordingVisitor(ShouldTraversePostOrder::No), Code,
R"txt(
WalkUpFromStmt CompoundStmt
WalkUpFromStmt IntegerLiteral(1)
TraverseBinAdd BinaryOperator(+)
WalkUpFromStmt BinaryOperator(+)
WalkUpFromStmt IntegerLiteral(2)
WalkUpFromStmt IntegerLiteral(3)
WalkUpFromStmt IntegerLiteral(4)
)txt"));
EXPECT_TRUE(visitorCallbackLogEqual(
RecordingVisitor(ShouldTraversePostOrder::Yes), Code,
R"txt(
WalkUpFromStmt IntegerLiteral(1)
TraverseBinAdd BinaryOperator(+)
WalkUpFromStmt IntegerLiteral(2)
WalkUpFromStmt IntegerLiteral(3)
WalkUpFromStmt BinaryOperator(+)
WalkUpFromStmt IntegerLiteral(4)
WalkUpFromStmt CompoundStmt
)txt"));
}
TEST(RecursiveASTVisitor, StmtCallbacks_TraverseBinAdd_WalkUpFromBinAdd) {
class RecordingVisitor : public RecordingVisitorBase<RecordingVisitor> {
public:
RecordingVisitor(ShouldTraversePostOrder ShouldTraversePostOrderValue)
: RecordingVisitorBase(ShouldTraversePostOrderValue) {}
bool TraverseBinAdd(BinaryOperator *BO) {
recordCallback(__func__, BO,
[&]() { RecordingVisitorBase::TraverseBinAdd(BO); });
return true;
}
bool WalkUpFromStmt(Stmt *S) {
recordCallback(__func__, S,
[&]() { RecordingVisitorBase::WalkUpFromStmt(S); });
return true;
}
bool WalkUpFromExpr(Expr *E) {
recordCallback(__func__, E,
[&]() { RecordingVisitorBase::WalkUpFromExpr(E); });
return true;
}
bool WalkUpFromBinAdd(BinaryOperator *BO) {
recordCallback(__func__, BO,
[&]() { RecordingVisitorBase::WalkUpFromBinAdd(BO); });
return true;
}
};
StringRef Code = R"cpp(
void test() {
1;
2 + 3;
4;
}
)cpp";
EXPECT_TRUE(visitorCallbackLogEqual(
RecordingVisitor(ShouldTraversePostOrder::No), Code,
R"txt(
WalkUpFromStmt CompoundStmt
WalkUpFromExpr IntegerLiteral(1)
WalkUpFromStmt IntegerLiteral(1)
TraverseBinAdd BinaryOperator(+)
WalkUpFromBinAdd BinaryOperator(+)
WalkUpFromExpr BinaryOperator(+)
WalkUpFromStmt BinaryOperator(+)
WalkUpFromExpr IntegerLiteral(2)
WalkUpFromStmt IntegerLiteral(2)
WalkUpFromExpr IntegerLiteral(3)
WalkUpFromStmt IntegerLiteral(3)
WalkUpFromExpr IntegerLiteral(4)
WalkUpFromStmt IntegerLiteral(4)
)txt"));
EXPECT_TRUE(visitorCallbackLogEqual(
RecordingVisitor(ShouldTraversePostOrder::Yes), Code,
R"txt(
WalkUpFromExpr IntegerLiteral(1)
WalkUpFromStmt IntegerLiteral(1)
TraverseBinAdd BinaryOperator(+)
WalkUpFromExpr IntegerLiteral(2)
WalkUpFromStmt IntegerLiteral(2)
WalkUpFromExpr IntegerLiteral(3)
WalkUpFromStmt IntegerLiteral(3)
WalkUpFromBinAdd BinaryOperator(+)
WalkUpFromExpr BinaryOperator(+)
WalkUpFromStmt BinaryOperator(+)
WalkUpFromExpr IntegerLiteral(4)
WalkUpFromStmt IntegerLiteral(4)
WalkUpFromStmt CompoundStmt
)txt"));
}
TEST(RecursiveASTVisitor, StmtCallbacks_WalkUpFromBinAdd) {
class RecordingVisitor : public RecordingVisitorBase<RecordingVisitor> {
public:
RecordingVisitor(ShouldTraversePostOrder ShouldTraversePostOrderValue)
: RecordingVisitorBase(ShouldTraversePostOrderValue) {}
bool WalkUpFromStmt(Stmt *S) {
recordCallback(__func__, S,
[&]() { RecordingVisitorBase::WalkUpFromStmt(S); });
return true;
}
bool WalkUpFromExpr(Expr *E) {
recordCallback(__func__, E,
[&]() { RecordingVisitorBase::WalkUpFromExpr(E); });
return true;
}
bool WalkUpFromBinAdd(BinaryOperator *BO) {
recordCallback(__func__, BO,
[&]() { RecordingVisitorBase::WalkUpFromBinAdd(BO); });
return true;
}
};
StringRef Code = R"cpp(
void test() {
1;
2 + 3;
4;
}
)cpp";
EXPECT_TRUE(visitorCallbackLogEqual(
RecordingVisitor(ShouldTraversePostOrder::No), Code,
R"txt(
WalkUpFromStmt CompoundStmt
WalkUpFromExpr IntegerLiteral(1)
WalkUpFromStmt IntegerLiteral(1)
WalkUpFromBinAdd BinaryOperator(+)
WalkUpFromExpr BinaryOperator(+)
WalkUpFromStmt BinaryOperator(+)
WalkUpFromExpr IntegerLiteral(2)
WalkUpFromStmt IntegerLiteral(2)
WalkUpFromExpr IntegerLiteral(3)
WalkUpFromStmt IntegerLiteral(3)
WalkUpFromExpr IntegerLiteral(4)
WalkUpFromStmt IntegerLiteral(4)
)txt"));
EXPECT_TRUE(visitorCallbackLogEqual(
RecordingVisitor(ShouldTraversePostOrder::Yes), Code,
R"txt(
WalkUpFromExpr IntegerLiteral(1)
WalkUpFromStmt IntegerLiteral(1)
WalkUpFromExpr IntegerLiteral(2)
WalkUpFromStmt IntegerLiteral(2)
WalkUpFromExpr IntegerLiteral(3)
WalkUpFromStmt IntegerLiteral(3)
WalkUpFromBinAdd BinaryOperator(+)
WalkUpFromExpr BinaryOperator(+)
WalkUpFromStmt BinaryOperator(+)
WalkUpFromExpr IntegerLiteral(4)
WalkUpFromStmt IntegerLiteral(4)
WalkUpFromStmt CompoundStmt
)txt"));
}
TEST(RecursiveASTVisitor, StmtCallbacks_TraverseCompoundAssignOperator) {
class RecordingVisitor : public RecordingVisitorBase<RecordingVisitor> {
public:
@ -1182,17 +795,15 @@ void test(int a) {
}
)cpp";
// TraverseCompoundAssignOperator is not called because RecursiveASTVisitor
// treats individual operators as subclasses, for which it calls their
// Traverse methods.
EXPECT_TRUE(visitorCallbackLogEqual(
RecordingVisitor(ShouldTraversePostOrder::No), Code,
R"txt(
WalkUpFromStmt CompoundStmt
WalkUpFromStmt IntegerLiteral(1)
WalkUpFromStmt CompoundAssignOperator(+=)
WalkUpFromStmt DeclRefExpr(a)
WalkUpFromStmt IntegerLiteral(2)
TraverseCompoundAssignOperator CompoundAssignOperator(+=)
WalkUpFromStmt CompoundAssignOperator(+=)
WalkUpFromStmt DeclRefExpr(a)
WalkUpFromStmt IntegerLiteral(2)
WalkUpFromStmt IntegerLiteral(3)
)txt"));
@ -1200,9 +811,10 @@ WalkUpFromStmt IntegerLiteral(3)
RecordingVisitor(ShouldTraversePostOrder::Yes), Code,
R"txt(
WalkUpFromStmt IntegerLiteral(1)
WalkUpFromStmt DeclRefExpr(a)
WalkUpFromStmt IntegerLiteral(2)
WalkUpFromStmt CompoundAssignOperator(+=)
TraverseCompoundAssignOperator CompoundAssignOperator(+=)
WalkUpFromStmt DeclRefExpr(a)
WalkUpFromStmt IntegerLiteral(2)
WalkUpFromStmt CompoundAssignOperator(+=)
WalkUpFromStmt IntegerLiteral(3)
WalkUpFromStmt CompoundStmt
)txt"));
@ -1251,22 +863,20 @@ void test(int a) {
}
)cpp";
// TraverseCompoundAssignOperator is not called because RecursiveASTVisitor
// treats individual operators as subclasses, for which it calls their
// Traverse methods.
EXPECT_TRUE(visitorCallbackLogEqual(
RecordingVisitor(ShouldTraversePostOrder::No), Code,
R"txt(
WalkUpFromStmt CompoundStmt
WalkUpFromExpr IntegerLiteral(1)
WalkUpFromStmt IntegerLiteral(1)
WalkUpFromCompoundAssignOperator CompoundAssignOperator(+=)
WalkUpFromExpr CompoundAssignOperator(+=)
WalkUpFromStmt CompoundAssignOperator(+=)
WalkUpFromExpr DeclRefExpr(a)
WalkUpFromStmt DeclRefExpr(a)
WalkUpFromExpr IntegerLiteral(2)
WalkUpFromStmt IntegerLiteral(2)
TraverseCompoundAssignOperator CompoundAssignOperator(+=)
WalkUpFromCompoundAssignOperator CompoundAssignOperator(+=)
WalkUpFromExpr CompoundAssignOperator(+=)
WalkUpFromStmt CompoundAssignOperator(+=)
WalkUpFromExpr DeclRefExpr(a)
WalkUpFromStmt DeclRefExpr(a)
WalkUpFromExpr IntegerLiteral(2)
WalkUpFromStmt IntegerLiteral(2)
WalkUpFromExpr IntegerLiteral(3)
WalkUpFromStmt IntegerLiteral(3)
)txt"));
@ -1276,13 +886,14 @@ WalkUpFromExpr IntegerLiteral(3)
R"txt(
WalkUpFromExpr IntegerLiteral(1)
WalkUpFromStmt IntegerLiteral(1)
WalkUpFromExpr DeclRefExpr(a)
WalkUpFromStmt DeclRefExpr(a)
WalkUpFromExpr IntegerLiteral(2)
WalkUpFromStmt IntegerLiteral(2)
WalkUpFromCompoundAssignOperator CompoundAssignOperator(+=)
WalkUpFromExpr CompoundAssignOperator(+=)
WalkUpFromStmt CompoundAssignOperator(+=)
TraverseCompoundAssignOperator CompoundAssignOperator(+=)
WalkUpFromExpr DeclRefExpr(a)
WalkUpFromStmt DeclRefExpr(a)
WalkUpFromExpr IntegerLiteral(2)
WalkUpFromStmt IntegerLiteral(2)
WalkUpFromCompoundAssignOperator CompoundAssignOperator(+=)
WalkUpFromExpr CompoundAssignOperator(+=)
WalkUpFromStmt CompoundAssignOperator(+=)
WalkUpFromExpr IntegerLiteral(3)
WalkUpFromStmt IntegerLiteral(3)
WalkUpFromStmt CompoundStmt
@ -1358,207 +969,6 @@ WalkUpFromStmt CompoundStmt
)txt"));
}
TEST(RecursiveASTVisitor, StmtCallbacks_TraverseBinAddAssign) {
class RecordingVisitor : public RecordingVisitorBase<RecordingVisitor> {
public:
RecordingVisitor(ShouldTraversePostOrder ShouldTraversePostOrderValue)
: RecordingVisitorBase(ShouldTraversePostOrderValue) {}
bool TraverseBinAddAssign(CompoundAssignOperator *CAO) {
recordCallback(__func__, CAO, [&]() {
RecordingVisitorBase::TraverseBinAddAssign(CAO);
});
return true;
}
bool WalkUpFromStmt(Stmt *S) {
recordCallback(__func__, S,
[&]() { RecordingVisitorBase::WalkUpFromStmt(S); });
return true;
}
};
StringRef Code = R"cpp(
void test(int a) {
1;
a += 2;
3;
}
)cpp";
EXPECT_TRUE(visitorCallbackLogEqual(
RecordingVisitor(ShouldTraversePostOrder::No), Code,
R"txt(
WalkUpFromStmt CompoundStmt
WalkUpFromStmt IntegerLiteral(1)
TraverseBinAddAssign CompoundAssignOperator(+=)
WalkUpFromStmt CompoundAssignOperator(+=)
WalkUpFromStmt DeclRefExpr(a)
WalkUpFromStmt IntegerLiteral(2)
WalkUpFromStmt IntegerLiteral(3)
)txt"));
EXPECT_TRUE(visitorCallbackLogEqual(
RecordingVisitor(ShouldTraversePostOrder::Yes), Code,
R"txt(
WalkUpFromStmt IntegerLiteral(1)
TraverseBinAddAssign CompoundAssignOperator(+=)
WalkUpFromStmt DeclRefExpr(a)
WalkUpFromStmt IntegerLiteral(2)
WalkUpFromStmt CompoundAssignOperator(+=)
WalkUpFromStmt IntegerLiteral(3)
WalkUpFromStmt CompoundStmt
)txt"));
}
TEST(RecursiveASTVisitor,
StmtCallbacks_TraverseBinAddAssign_WalkUpFromBinAddAssign) {
class RecordingVisitor : public RecordingVisitorBase<RecordingVisitor> {
public:
RecordingVisitor(ShouldTraversePostOrder ShouldTraversePostOrderValue)
: RecordingVisitorBase(ShouldTraversePostOrderValue) {}
bool TraverseBinAddAssign(CompoundAssignOperator *CAO) {
recordCallback(__func__, CAO, [&]() {
RecordingVisitorBase::TraverseBinAddAssign(CAO);
});
return true;
}
bool WalkUpFromStmt(Stmt *S) {
recordCallback(__func__, S,
[&]() { RecordingVisitorBase::WalkUpFromStmt(S); });
return true;
}
bool WalkUpFromExpr(Expr *E) {
recordCallback(__func__, E,
[&]() { RecordingVisitorBase::WalkUpFromExpr(E); });
return true;
}
bool WalkUpFromBinAddAssign(CompoundAssignOperator *CAO) {
recordCallback(__func__, CAO, [&]() {
RecordingVisitorBase::WalkUpFromBinAddAssign(CAO);
});
return true;
}
};
StringRef Code = R"cpp(
void test(int a) {
1;
a += 2;
3;
}
)cpp";
EXPECT_TRUE(visitorCallbackLogEqual(
RecordingVisitor(ShouldTraversePostOrder::No), Code,
R"txt(
WalkUpFromStmt CompoundStmt
WalkUpFromExpr IntegerLiteral(1)
WalkUpFromStmt IntegerLiteral(1)
TraverseBinAddAssign CompoundAssignOperator(+=)
WalkUpFromBinAddAssign CompoundAssignOperator(+=)
WalkUpFromExpr CompoundAssignOperator(+=)
WalkUpFromStmt CompoundAssignOperator(+=)
WalkUpFromExpr DeclRefExpr(a)
WalkUpFromStmt DeclRefExpr(a)
WalkUpFromExpr IntegerLiteral(2)
WalkUpFromStmt IntegerLiteral(2)
WalkUpFromExpr IntegerLiteral(3)
WalkUpFromStmt IntegerLiteral(3)
)txt"));
EXPECT_TRUE(visitorCallbackLogEqual(
RecordingVisitor(ShouldTraversePostOrder::Yes), Code,
R"txt(
WalkUpFromExpr IntegerLiteral(1)
WalkUpFromStmt IntegerLiteral(1)
TraverseBinAddAssign CompoundAssignOperator(+=)
WalkUpFromExpr DeclRefExpr(a)
WalkUpFromStmt DeclRefExpr(a)
WalkUpFromExpr IntegerLiteral(2)
WalkUpFromStmt IntegerLiteral(2)
WalkUpFromBinAddAssign CompoundAssignOperator(+=)
WalkUpFromExpr CompoundAssignOperator(+=)
WalkUpFromStmt CompoundAssignOperator(+=)
WalkUpFromExpr IntegerLiteral(3)
WalkUpFromStmt IntegerLiteral(3)
WalkUpFromStmt CompoundStmt
)txt"));
}
TEST(RecursiveASTVisitor, StmtCallbacks_WalkUpFromBinAddAssign) {
class RecordingVisitor : public RecordingVisitorBase<RecordingVisitor> {
public:
RecordingVisitor(ShouldTraversePostOrder ShouldTraversePostOrderValue)
: RecordingVisitorBase(ShouldTraversePostOrderValue) {}
bool WalkUpFromStmt(Stmt *S) {
recordCallback(__func__, S,
[&]() { RecordingVisitorBase::WalkUpFromStmt(S); });
return true;
}
bool WalkUpFromExpr(Expr *E) {
recordCallback(__func__, E,
[&]() { RecordingVisitorBase::WalkUpFromExpr(E); });
return true;
}
bool WalkUpFromBinAddAssign(CompoundAssignOperator *CAO) {
recordCallback(__func__, CAO, [&]() {
RecordingVisitorBase::WalkUpFromBinAddAssign(CAO);
});
return true;
}
};
StringRef Code = R"cpp(
void test(int a) {
1;
a += 2;
3;
}
)cpp";
EXPECT_TRUE(visitorCallbackLogEqual(
RecordingVisitor(ShouldTraversePostOrder::No), Code,
R"txt(
WalkUpFromStmt CompoundStmt
WalkUpFromExpr IntegerLiteral(1)
WalkUpFromStmt IntegerLiteral(1)
WalkUpFromBinAddAssign CompoundAssignOperator(+=)
WalkUpFromExpr CompoundAssignOperator(+=)
WalkUpFromStmt CompoundAssignOperator(+=)
WalkUpFromExpr DeclRefExpr(a)
WalkUpFromStmt DeclRefExpr(a)
WalkUpFromExpr IntegerLiteral(2)
WalkUpFromStmt IntegerLiteral(2)
WalkUpFromExpr IntegerLiteral(3)
WalkUpFromStmt IntegerLiteral(3)
)txt"));
EXPECT_TRUE(visitorCallbackLogEqual(
RecordingVisitor(ShouldTraversePostOrder::Yes), Code,
R"txt(
WalkUpFromExpr IntegerLiteral(1)
WalkUpFromStmt IntegerLiteral(1)
WalkUpFromExpr DeclRefExpr(a)
WalkUpFromStmt DeclRefExpr(a)
WalkUpFromExpr IntegerLiteral(2)
WalkUpFromStmt IntegerLiteral(2)
WalkUpFromBinAddAssign CompoundAssignOperator(+=)
WalkUpFromExpr CompoundAssignOperator(+=)
WalkUpFromStmt CompoundAssignOperator(+=)
WalkUpFromExpr IntegerLiteral(3)
WalkUpFromStmt IntegerLiteral(3)
WalkUpFromStmt CompoundStmt
)txt"));
}
TEST(RecursiveASTVisitor, StmtCallbacks_TraverseCallExpr) {
class RecordingVisitor : public RecordingVisitorBase<RecordingVisitor> {
public: