diff --git a/clang/unittests/Tooling/CMakeLists.txt b/clang/unittests/Tooling/CMakeLists.txt --- a/clang/unittests/Tooling/CMakeLists.txt +++ b/clang/unittests/Tooling/CMakeLists.txt @@ -27,6 +27,7 @@ QualTypeNamesTest.cpp RangeSelectorTest.cpp RecursiveASTVisitorTests/Attr.cpp + RecursiveASTVisitorTests/Callbacks.cpp RecursiveASTVisitorTests/Class.cpp RecursiveASTVisitorTests/ConstructExpr.cpp RecursiveASTVisitorTests/CXXBoolLiteralExpr.cpp diff --git a/clang/unittests/Tooling/RecursiveASTVisitorTests/Callbacks.cpp b/clang/unittests/Tooling/RecursiveASTVisitorTests/Callbacks.cpp new file mode 100644 --- /dev/null +++ b/clang/unittests/Tooling/RecursiveASTVisitorTests/Callbacks.cpp @@ -0,0 +1,628 @@ +//===--- clang/unittests/Tooling/RecursiveASTVisitorTests/Callbacks.cpp ---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "TestVisitor.h" + +using namespace clang; + +namespace { + +template +class RecordingVisitorBase : public TestVisitor { + bool VisitPostOrder; + +public: + RecordingVisitorBase(bool VisitPostOrder) : VisitPostOrder(VisitPostOrder) {} + + bool shouldTraversePostOrder() const { return VisitPostOrder; } + + // Callbacks received during traversal. + std::string CallbackLog; + + std::string stmtToString(Stmt *S) { + StringRef ClassName = S->getStmtClassName(); + if (IntegerLiteral *IL = dyn_cast(S)) { + return (ClassName + "(" + IL->getValue().toString(10, false) + ")").str(); + } + if (BinaryOperator *BO = dyn_cast(S)) { + return (ClassName + "(" + BinaryOperator::getOpcodeStr(BO->getOpcode()) + + ")") + .str(); + } + if (CallExpr *CE = dyn_cast(S)) { + if (FunctionDecl *Callee = CE->getDirectCallee()) { + if (Callee->getIdentifier()) { + return (ClassName + "(" + Callee->getName() + ")").str(); + } + } + } + if (DeclRefExpr *DRE = dyn_cast(S)) { + if (NamedDecl *ND = DRE->getFoundDecl()) { + if (ND->getIdentifier()) { + return (ClassName + "(" + ND->getName() + ")").str(); + } + } + } + return ClassName.str(); + } + + void recordCallback(StringRef CallbackName, Stmt *S) { + CallbackLog += (CallbackName + " " + stmtToString(S) + "\n").str(); + } +}; + +template +::testing::AssertionResult visitorCallbackLogEqual(VisitorTy Visitor, + StringRef Code, + StringRef ExpectedLog) { + Visitor.runOver(Code); + // EXPECT_EQ shows the diff between the two strings if they are different. + EXPECT_EQ(ExpectedLog.trim().str(), + StringRef(Visitor.CallbackLog).trim().str()); + if (ExpectedLog.trim() != StringRef(Visitor.CallbackLog).trim()) { + return ::testing::AssertionFailure(); + } + return ::testing::AssertionSuccess(); +} + +} // namespace + +TEST(RecursiveASTVisitor, Callbacks_TraverseLeaf) { + class RecordingVisitor : public RecordingVisitorBase { + public: + RecordingVisitor(bool VisitPostOrder) + : RecordingVisitorBase(VisitPostOrder) {} + + bool TraverseIntegerLiteral(IntegerLiteral *E) { + recordCallback(__func__, E); + return true; + } + + bool WalkUpFromStmt(Stmt *S) { + recordCallback(__func__, S); + return true; + } + }; + + StringRef Code = R"cpp( +void add(int, int); +void test() { + 1; + 2 + 3; + add(4, 5); +} +)cpp"; + + EXPECT_TRUE( + visitorCallbackLogEqual(RecordingVisitor(/*VisitPostOrder=*/false), Code, + R"txt( +WalkUpFromStmt CompoundStmt +TraverseIntegerLiteral IntegerLiteral(1) +WalkUpFromStmt BinaryOperator(+) +TraverseIntegerLiteral IntegerLiteral(2) +TraverseIntegerLiteral IntegerLiteral(3) +WalkUpFromStmt CallExpr(add) +WalkUpFromStmt ImplicitCastExpr +WalkUpFromStmt DeclRefExpr(add) +TraverseIntegerLiteral IntegerLiteral(4) +TraverseIntegerLiteral IntegerLiteral(5) +)txt")); + + EXPECT_TRUE(visitorCallbackLogEqual(RecordingVisitor(/*VisitPostOrder=*/true), + Code, + R"txt( +TraverseIntegerLiteral IntegerLiteral(1) +WalkUpFromStmt IntegerLiteral(1) +TraverseIntegerLiteral IntegerLiteral(2) +WalkUpFromStmt IntegerLiteral(2) +TraverseIntegerLiteral IntegerLiteral(3) +WalkUpFromStmt IntegerLiteral(3) +WalkUpFromStmt BinaryOperator(+) +WalkUpFromStmt DeclRefExpr(add) +WalkUpFromStmt ImplicitCastExpr +TraverseIntegerLiteral IntegerLiteral(4) +WalkUpFromStmt IntegerLiteral(4) +TraverseIntegerLiteral IntegerLiteral(5) +WalkUpFromStmt IntegerLiteral(5) +WalkUpFromStmt CallExpr(add) +WalkUpFromStmt CompoundStmt +)txt")); +} + +TEST(RecursiveASTVisitor, Callbacks_TraverseLeaf_WalkUpFromLeaf) { + class RecordingVisitor : public RecordingVisitorBase { + public: + RecordingVisitor(bool VisitPostOrder) + : RecordingVisitorBase(VisitPostOrder) {} + + bool TraverseIntegerLiteral(IntegerLiteral *E) { + recordCallback(__func__, E); + return true; + } + + bool WalkUpFromStmt(Stmt *S) { + recordCallback(__func__, S); + return true; + } + + bool WalkUpFromExpr(Expr *E) { + recordCallback(__func__, E); + return true; + } + + bool WalkUpFromIntegerLiteral(IntegerLiteral *E) { + recordCallback(__func__, E); + return true; + } + }; + + StringRef Code = R"cpp( +void add(int, int); +void test() { + 1; + 2 + 3; + add(4, 5); +} +)cpp"; + + EXPECT_TRUE( + visitorCallbackLogEqual(RecordingVisitor(/*VisitPostOrder=*/false), Code, + R"txt( +WalkUpFromStmt CompoundStmt +TraverseIntegerLiteral IntegerLiteral(1) +WalkUpFromExpr BinaryOperator(+) +TraverseIntegerLiteral IntegerLiteral(2) +TraverseIntegerLiteral IntegerLiteral(3) +WalkUpFromExpr CallExpr(add) +WalkUpFromExpr ImplicitCastExpr +WalkUpFromExpr DeclRefExpr(add) +TraverseIntegerLiteral IntegerLiteral(4) +TraverseIntegerLiteral IntegerLiteral(5) +)txt")); + + EXPECT_TRUE(visitorCallbackLogEqual(RecordingVisitor(/*VisitPostOrder=*/true), + Code, + R"txt( +TraverseIntegerLiteral IntegerLiteral(1) +WalkUpFromIntegerLiteral IntegerLiteral(1) +TraverseIntegerLiteral IntegerLiteral(2) +WalkUpFromIntegerLiteral IntegerLiteral(2) +TraverseIntegerLiteral IntegerLiteral(3) +WalkUpFromIntegerLiteral IntegerLiteral(3) +WalkUpFromExpr BinaryOperator(+) +WalkUpFromExpr DeclRefExpr(add) +WalkUpFromExpr ImplicitCastExpr +TraverseIntegerLiteral IntegerLiteral(4) +WalkUpFromIntegerLiteral IntegerLiteral(4) +TraverseIntegerLiteral IntegerLiteral(5) +WalkUpFromIntegerLiteral IntegerLiteral(5) +WalkUpFromExpr CallExpr(add) +WalkUpFromStmt CompoundStmt +)txt")); +} + +TEST(RecursiveASTVisitor, Callbacks_WalkUpFromLeaf) { + class RecordingVisitor : public RecordingVisitorBase { + public: + RecordingVisitor(bool VisitPostOrder) + : RecordingVisitorBase(VisitPostOrder) {} + + bool WalkUpFromStmt(Stmt *S) { + recordCallback(__func__, S); + return true; + } + + bool WalkUpFromExpr(Expr *E) { + recordCallback(__func__, E); + return true; + } + + bool WalkUpFromIntegerLiteral(IntegerLiteral *E) { + recordCallback(__func__, E); + return true; + } + }; + + StringRef Code = R"cpp( +void add(int, int); +void test() { + 1; + 2 + 3; + add(4, 5); +} +)cpp"; + + EXPECT_TRUE( + visitorCallbackLogEqual(RecordingVisitor(/*VisitPostOrder=*/false), Code, + R"txt( +WalkUpFromStmt CompoundStmt +WalkUpFromIntegerLiteral IntegerLiteral(1) +WalkUpFromExpr BinaryOperator(+) +WalkUpFromIntegerLiteral IntegerLiteral(2) +WalkUpFromIntegerLiteral IntegerLiteral(3) +WalkUpFromExpr CallExpr(add) +WalkUpFromExpr ImplicitCastExpr +WalkUpFromExpr DeclRefExpr(add) +WalkUpFromIntegerLiteral IntegerLiteral(4) +WalkUpFromIntegerLiteral IntegerLiteral(5) +)txt")); + + EXPECT_TRUE(visitorCallbackLogEqual(RecordingVisitor(/*VisitPostOrder=*/true), + Code, + R"txt( +WalkUpFromIntegerLiteral IntegerLiteral(1) +WalkUpFromIntegerLiteral IntegerLiteral(2) +WalkUpFromIntegerLiteral IntegerLiteral(3) +WalkUpFromExpr BinaryOperator(+) +WalkUpFromExpr DeclRefExpr(add) +WalkUpFromExpr ImplicitCastExpr +WalkUpFromIntegerLiteral IntegerLiteral(4) +WalkUpFromIntegerLiteral IntegerLiteral(5) +WalkUpFromExpr CallExpr(add) +WalkUpFromStmt CompoundStmt +)txt")); +} + +TEST(RecursiveASTVisitor, Callbacks_TraverseBinaryOperator) { + class RecordingVisitor : public RecordingVisitorBase { + public: + RecordingVisitor(bool VisitPostOrder) + : RecordingVisitorBase(VisitPostOrder) {} + + bool TraverseBinaryOperator(BinaryOperator *BO) { + recordCallback(__func__, BO); + return true; + } + + bool WalkUpFromStmt(Stmt *S) { + recordCallback(__func__, S); + return true; + } + }; + + StringRef Code = R"cpp( +void add(int, int); +void test() { + 1; + 2 + 3; + add(4, 5); +} +)cpp"; + + EXPECT_TRUE( + visitorCallbackLogEqual(RecordingVisitor(/*VisitPostOrder=*/false), Code, + R"txt( +WalkUpFromStmt CompoundStmt +WalkUpFromStmt IntegerLiteral(1) +WalkUpFromStmt BinaryOperator(+) +WalkUpFromStmt IntegerLiteral(2) +WalkUpFromStmt IntegerLiteral(3) +WalkUpFromStmt CallExpr(add) +WalkUpFromStmt ImplicitCastExpr +WalkUpFromStmt DeclRefExpr(add) +WalkUpFromStmt IntegerLiteral(4) +WalkUpFromStmt IntegerLiteral(5) +)txt")); + + EXPECT_TRUE(visitorCallbackLogEqual(RecordingVisitor(/*VisitPostOrder=*/true), + Code, + R"txt( +WalkUpFromStmt IntegerLiteral(1) +WalkUpFromStmt IntegerLiteral(2) +WalkUpFromStmt IntegerLiteral(3) +WalkUpFromStmt BinaryOperator(+) +WalkUpFromStmt DeclRefExpr(add) +WalkUpFromStmt ImplicitCastExpr +WalkUpFromStmt IntegerLiteral(4) +WalkUpFromStmt IntegerLiteral(5) +WalkUpFromStmt CallExpr(add) +WalkUpFromStmt CompoundStmt +)txt")); +} + +TEST(RecursiveASTVisitor, + Callbacks_TraverseBinaryOperator_WalkUpFromBinaryOperator) { + class RecordingVisitor : public RecordingVisitorBase { + public: + RecordingVisitor(bool VisitPostOrder) + : RecordingVisitorBase(VisitPostOrder) {} + + bool TraverseBinaryOperator(BinaryOperator *BO) { + recordCallback(__func__, BO); + return true; + } + + bool WalkUpFromStmt(Stmt *S) { + recordCallback(__func__, S); + return true; + } + + bool WalkUpFromExpr(Expr *E) { + recordCallback(__func__, E); + return true; + } + + bool WalkUpFromBinaryOperator(BinaryOperator *BO) { + recordCallback(__func__, BO); + return true; + } + }; + + StringRef Code = R"cpp( +void add(int, int); +void test() { + 1; + 2 + 3; + add(4, 5); +} +)cpp"; + + EXPECT_TRUE( + visitorCallbackLogEqual(RecordingVisitor(/*VisitPostOrder=*/false), Code, + R"txt( +WalkUpFromStmt CompoundStmt +WalkUpFromExpr IntegerLiteral(1) +WalkUpFromBinaryOperator BinaryOperator(+) +WalkUpFromExpr IntegerLiteral(2) +WalkUpFromExpr IntegerLiteral(3) +WalkUpFromExpr CallExpr(add) +WalkUpFromExpr ImplicitCastExpr +WalkUpFromExpr DeclRefExpr(add) +WalkUpFromExpr IntegerLiteral(4) +WalkUpFromExpr IntegerLiteral(5) +)txt")); + + EXPECT_TRUE(visitorCallbackLogEqual(RecordingVisitor(/*VisitPostOrder=*/true), + Code, + R"txt( +WalkUpFromExpr IntegerLiteral(1) +WalkUpFromExpr IntegerLiteral(2) +WalkUpFromExpr IntegerLiteral(3) +WalkUpFromBinaryOperator BinaryOperator(+) +WalkUpFromExpr DeclRefExpr(add) +WalkUpFromExpr ImplicitCastExpr +WalkUpFromExpr IntegerLiteral(4) +WalkUpFromExpr IntegerLiteral(5) +WalkUpFromExpr CallExpr(add) +WalkUpFromStmt CompoundStmt +)txt")); +} + +TEST(RecursiveASTVisitor, Callbacks_WalkUpFromBinaryOperator) { + class RecordingVisitor : public RecordingVisitorBase { + public: + RecordingVisitor(bool VisitPostOrder) + : RecordingVisitorBase(VisitPostOrder) {} + + bool WalkUpFromStmt(Stmt *S) { + recordCallback(__func__, S); + return true; + } + + bool WalkUpFromExpr(Expr *E) { + recordCallback(__func__, E); + return true; + } + + bool WalkUpFromBinaryOperator(BinaryOperator *BO) { + recordCallback(__func__, BO); + return true; + } + }; + + StringRef Code = R"cpp( +void add(int, int); +void test() { + 1; + 2 + 3; + add(4, 5); +} +)cpp"; + + EXPECT_TRUE( + visitorCallbackLogEqual(RecordingVisitor(/*VisitPostOrder=*/false), Code, + R"txt( +WalkUpFromStmt CompoundStmt +WalkUpFromExpr IntegerLiteral(1) +WalkUpFromBinaryOperator BinaryOperator(+) +WalkUpFromExpr IntegerLiteral(2) +WalkUpFromExpr IntegerLiteral(3) +WalkUpFromExpr CallExpr(add) +WalkUpFromExpr ImplicitCastExpr +WalkUpFromExpr DeclRefExpr(add) +WalkUpFromExpr IntegerLiteral(4) +WalkUpFromExpr IntegerLiteral(5) +)txt")); + + EXPECT_TRUE(visitorCallbackLogEqual(RecordingVisitor(/*VisitPostOrder=*/true), + Code, + R"txt( +WalkUpFromExpr IntegerLiteral(1) +WalkUpFromExpr IntegerLiteral(2) +WalkUpFromExpr IntegerLiteral(3) +WalkUpFromBinaryOperator BinaryOperator(+) +WalkUpFromExpr DeclRefExpr(add) +WalkUpFromExpr ImplicitCastExpr +WalkUpFromExpr IntegerLiteral(4) +WalkUpFromExpr IntegerLiteral(5) +WalkUpFromExpr CallExpr(add) +WalkUpFromStmt CompoundStmt +)txt")); +} + +TEST(RecursiveASTVisitor, Callbacks_TraverseCallExpr) { + class RecordingVisitor : public RecordingVisitorBase { + public: + RecordingVisitor(bool VisitPostOrder) + : RecordingVisitorBase(VisitPostOrder) {} + + bool TraverseCallExpr(CallExpr *CE) { + recordCallback(__func__, CE); + return true; + } + + bool WalkUpFromStmt(Stmt *S) { + recordCallback(__func__, S); + return true; + } + }; + + StringRef Code = R"cpp( +void add(int, int); +void test() { + 1; + 2 + 3; + add(4, 5); +} +)cpp"; + + EXPECT_TRUE( + visitorCallbackLogEqual(RecordingVisitor(/*VisitPostOrder=*/false), Code, + R"txt( +WalkUpFromStmt CompoundStmt +WalkUpFromStmt IntegerLiteral(1) +WalkUpFromStmt BinaryOperator(+) +WalkUpFromStmt IntegerLiteral(2) +WalkUpFromStmt IntegerLiteral(3) +TraverseCallExpr CallExpr(add) +)txt")); + + EXPECT_TRUE(visitorCallbackLogEqual(RecordingVisitor(/*VisitPostOrder=*/true), + Code, + R"txt( +WalkUpFromStmt IntegerLiteral(1) +WalkUpFromStmt IntegerLiteral(2) +WalkUpFromStmt IntegerLiteral(3) +WalkUpFromStmt BinaryOperator(+) +TraverseCallExpr CallExpr(add) +WalkUpFromStmt CallExpr(add) +WalkUpFromStmt CompoundStmt +)txt")); +} + +TEST(RecursiveASTVisitor, Callbacks_TraverseCallExpr_WalkUpFromCallExpr) { + class RecordingVisitor : public RecordingVisitorBase { + public: + RecordingVisitor(bool VisitPostOrder) + : RecordingVisitorBase(VisitPostOrder) {} + + bool TraverseCallExpr(CallExpr *CE) { + recordCallback(__func__, CE); + return true; + } + + bool WalkUpFromStmt(Stmt *S) { + recordCallback(__func__, S); + return true; + } + + bool WalkUpFromExpr(Expr *E) { + recordCallback(__func__, E); + return true; + } + + bool WalkUpFromCallExpr(CallExpr *CE) { + recordCallback(__func__, CE); + return true; + } + }; + + StringRef Code = R"cpp( +void add(int, int); +void test() { + 1; + 2 + 3; + add(4, 5); +} +)cpp"; + + EXPECT_TRUE( + visitorCallbackLogEqual(RecordingVisitor(/*VisitPostOrder=*/false), Code, + R"txt( +WalkUpFromStmt CompoundStmt +WalkUpFromExpr IntegerLiteral(1) +WalkUpFromExpr BinaryOperator(+) +WalkUpFromExpr IntegerLiteral(2) +WalkUpFromExpr IntegerLiteral(3) +TraverseCallExpr CallExpr(add) +)txt")); + + EXPECT_TRUE(visitorCallbackLogEqual(RecordingVisitor(/*VisitPostOrder=*/true), + Code, + R"txt( +WalkUpFromExpr IntegerLiteral(1) +WalkUpFromExpr IntegerLiteral(2) +WalkUpFromExpr IntegerLiteral(3) +WalkUpFromExpr BinaryOperator(+) +TraverseCallExpr CallExpr(add) +WalkUpFromCallExpr CallExpr(add) +WalkUpFromStmt CompoundStmt +)txt")); +} + +TEST(RecursiveASTVisitor, Callbacks_WalkUpFromCallExpr) { + class RecordingVisitor : public RecordingVisitorBase { + public: + RecordingVisitor(bool VisitPostOrder) + : RecordingVisitorBase(VisitPostOrder) {} + + bool WalkUpFromStmt(Stmt *S) { + recordCallback(__func__, S); + return true; + } + + bool WalkUpFromExpr(Expr *E) { + recordCallback(__func__, E); + return true; + } + + bool WalkUpFromCallExpr(CallExpr *CE) { + recordCallback(__func__, CE); + return true; + } + }; + + StringRef Code = R"cpp( +void add(int, int); +void test() { + 1; + 2 + 3; + add(4, 5); +} +)cpp"; + + EXPECT_TRUE( + visitorCallbackLogEqual(RecordingVisitor(/*VisitPostOrder=*/false), Code, + R"txt( +WalkUpFromStmt CompoundStmt +WalkUpFromExpr IntegerLiteral(1) +WalkUpFromExpr BinaryOperator(+) +WalkUpFromExpr IntegerLiteral(2) +WalkUpFromExpr IntegerLiteral(3) +WalkUpFromCallExpr CallExpr(add) +WalkUpFromExpr ImplicitCastExpr +WalkUpFromExpr DeclRefExpr(add) +WalkUpFromExpr IntegerLiteral(4) +WalkUpFromExpr IntegerLiteral(5) +)txt")); + + EXPECT_TRUE(visitorCallbackLogEqual(RecordingVisitor(/*VisitPostOrder=*/true), + Code, + R"txt( +WalkUpFromExpr IntegerLiteral(1) +WalkUpFromExpr IntegerLiteral(2) +WalkUpFromExpr IntegerLiteral(3) +WalkUpFromExpr BinaryOperator(+) +WalkUpFromExpr DeclRefExpr(add) +WalkUpFromExpr ImplicitCastExpr +WalkUpFromExpr IntegerLiteral(4) +WalkUpFromExpr IntegerLiteral(5) +WalkUpFromCallExpr CallExpr(add) +WalkUpFromStmt CompoundStmt +)txt")); +}