diff --git a/include/clang/Interpreter/CppInterOp.h b/include/clang/Interpreter/CppInterOp.h index 4f4f05c64..875d1227e 100644 --- a/include/clang/Interpreter/CppInterOp.h +++ b/include/clang/Interpreter/CppInterOp.h @@ -785,6 +785,11 @@ namespace Cpp { unsigned complete_line = 1U, unsigned complete_column = 1U); + /// Reverts the last N operations performed by the interpreter. + ///\param[in] N The number of operations to undo. Defaults to 1. + ///\returns 0 on success, non-zero on failure. + CPPINTEROP_API int Undo(unsigned N = 1); + } // end namespace Cpp #endif // CPPINTEROP_CPPINTEROP_H diff --git a/lib/Interpreter/CXCppInterOp.cpp b/lib/Interpreter/CXCppInterOp.cpp index 2b5569915..0f4566016 100644 --- a/lib/Interpreter/CXCppInterOp.cpp +++ b/lib/Interpreter/CXCppInterOp.cpp @@ -306,7 +306,10 @@ TInterp_t clang_Interpreter_takeInterpreterAsPtr(CXInterpreter I) { enum CXErrorCode clang_Interpreter_undo(CXInterpreter I, unsigned int N) { #ifdef CPPINTEROP_USE_CLING - return CXError_Failure; + auto* interp = getInterpreter(I); + cling::Interpreter::PushTransactionRAII RAII(interp); + interp->unload(N); + return CXError_Success; #else return getInterpreter(I)->Undo(N) ? CXError_Failure : CXError_Success; #endif // CPPINTEROP_USE_CLING diff --git a/lib/Interpreter/CppInterOp.cpp b/lib/Interpreter/CppInterOp.cpp index 861a610be..2c00d79ba 100755 --- a/lib/Interpreter/CppInterOp.cpp +++ b/lib/Interpreter/CppInterOp.cpp @@ -3684,4 +3684,15 @@ namespace Cpp { complete_column); } + int Undo(unsigned N) { +#ifdef CPPINTEROP_USE_CLING + auto& I = getInterp(); + cling::Interpreter::PushTransactionRAII RAII(&I); + I.unload(N); + return compat::Interpreter::kSuccess; +#else + return getInterp().undo(N); +#endif + } + } // end namespace Cpp diff --git a/lib/Interpreter/CppInterOpInterpreter.h b/lib/Interpreter/CppInterOpInterpreter.h index e35840633..b5b8e7e96 100644 --- a/lib/Interpreter/CppInterOpInterpreter.h +++ b/lib/Interpreter/CppInterOpInterpreter.h @@ -429,6 +429,15 @@ class Interpreter { return ret; // TODO: Implement } + CompilationResult undo(unsigned N = 1) { + if (llvm::Error Err = Undo(N)) { + llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), + "Failed to undo via ::undo"); + return kFailure; + } + return kSuccess; + } + }; // Interpreter } // namespace Cpp diff --git a/unittests/CppInterOp/FunctionReflectionTest.cpp b/unittests/CppInterOp/FunctionReflectionTest.cpp index a8c12ef52..42ab8cb6a 100644 --- a/unittests/CppInterOp/FunctionReflectionTest.cpp +++ b/unittests/CppInterOp/FunctionReflectionTest.cpp @@ -1615,3 +1615,30 @@ TEST(FunctionReflectionTest, Destruct) { clang_Interpreter_takeInterpreterAsPtr(I); clang_Interpreter_dispose(I); } + +TEST(FunctionReflectionTest, UndoTest) { +#ifdef _WIN32 + GTEST_SKIP() << "Disabled on Windows. Needs fixing."; +#endif +#ifdef EMSCRIPTEN + GTEST_SKIP() << "Test fails for Emscipten builds"; +#else + Cpp::CreateInterpreter(); + EXPECT_EQ(Cpp::Process("int a = 5;"), 0); + EXPECT_EQ(Cpp::Process("int b = 10;"), 0); + EXPECT_EQ(Cpp::Process("int x = 5;"), 0); + Cpp::Undo(); + EXPECT_NE(Cpp::Process("int y = x;"), 0); + EXPECT_EQ(Cpp::Process("int x = 10;"), 0); + EXPECT_EQ(Cpp::Process("int y = 10;"), 0); + Cpp::Undo(2); + EXPECT_EQ(Cpp::Process("int x = 20;"), 0); + EXPECT_EQ(Cpp::Process("int y = 20;"), 0); + int ret = Cpp::Undo(100); +#ifdef CPPINTEROP_USE_CLING + EXPECT_EQ(ret, 0); +#else + EXPECT_EQ(ret, 1); +#endif +#endif + } \ No newline at end of file