diff options
author | Jun Zhang <jun@junz.org> | 2022-06-19 10:39:03 +0800 |
---|---|---|
committer | Jun Zhang <jun@junz.org> | 2022-06-26 18:32:18 +0800 |
commit | dea5a9cc929048be261a4c030407e4d7e1e70fec (patch) | |
tree | 1f3d283a91bf82b48deddec6b36bfa9ddbae7259 /clang/unittests/Interpreter/InterpreterTest.cpp | |
parent | 9de8b05bfe0de2915d2443d06159396c5f9d389f (diff) | |
download | llvm-dea5a9cc929048be261a4c030407e4d7e1e70fec.zip llvm-dea5a9cc929048be261a4c030407e4d7e1e70fec.tar.gz llvm-dea5a9cc929048be261a4c030407e4d7e1e70fec.tar.bz2 |
[clang-repl] Implement code undo.
In interactive C++ it is convenient to roll back to a previous state of the
compiler. For example:
clang-repl> int x = 42;
clang-repl> %undo
clang-repl> float x = 24 // not an error
To support this, the patch extends the functionality used to recover from
errors and adds functionality to recover the low-level execution infrastructure.
The current implementation is based on watermarks. It exploits the fact that
at each incremental input the underlying compiler infrastructure is in a valid
state. We can only go N incremental inputs back to a previous valid state. We do
not need and do not do any further dependency tracking.
This patch was co-developed with V. Vassilev, relies on the past work of Purva
Chaudhari in clang-repl and is inspired by the past work on the same feature
in the Cling interpreter.
Co-authored-by: Purva-Chaudhari <purva.chaudhari02@gmail.com>
Co-authored-by: Vassil Vassilev <v.g.vassilev@gmail.com>
Signed-off-by: Jun Zhang <jun@junz.org>
Diffstat (limited to 'clang/unittests/Interpreter/InterpreterTest.cpp')
-rw-r--r-- | clang/unittests/Interpreter/InterpreterTest.cpp | 45 |
1 files changed, 45 insertions, 0 deletions
diff --git a/clang/unittests/Interpreter/InterpreterTest.cpp b/clang/unittests/Interpreter/InterpreterTest.cpp index 280c6d7f..720e30f 100644 --- a/clang/unittests/Interpreter/InterpreterTest.cpp +++ b/clang/unittests/Interpreter/InterpreterTest.cpp @@ -128,6 +128,51 @@ TEST(InterpreterTest, DeclsAndStatements) { EXPECT_EQ("Parsing failed.", llvm::toString(std::move(Err))); } +TEST(InterpreterTest, UndoCommand) { + Args ExtraArgs = {"-Xclang", "-diagnostic-log-file", "-Xclang", "-"}; + + // Create the diagnostic engine with unowned consumer. + std::string DiagnosticOutput; + llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput); + auto DiagPrinter = std::make_unique<TextDiagnosticPrinter>( + DiagnosticsOS, new DiagnosticOptions()); + + auto Interp = createInterpreter(ExtraArgs, DiagPrinter.get()); + + // Fail to undo. + auto Err1 = Interp->Undo(); + EXPECT_EQ("Operation failed. Too many undos", + llvm::toString(std::move(Err1))); + auto Err2 = Interp->Parse("int foo = 42;"); + EXPECT_TRUE(!!Err2); + auto Err3 = Interp->Undo(2); + EXPECT_EQ("Operation failed. Too many undos", + llvm::toString(std::move(Err3))); + + // Succeed to undo. + auto Err4 = Interp->Parse("int x = 42;"); + EXPECT_TRUE(!!Err4); + auto Err5 = Interp->Undo(); + EXPECT_FALSE(Err5); + auto Err6 = Interp->Parse("int x = 24;"); + EXPECT_TRUE(!!Err6); + auto Err7 = Interp->Parse("#define X 42"); + EXPECT_TRUE(!!Err7); + auto Err8 = Interp->Undo(); + EXPECT_FALSE(Err8); + auto Err9 = Interp->Parse("#define X 24"); + EXPECT_TRUE(!!Err9); + + // Undo input contains errors. + auto Err10 = Interp->Parse("int y = ;"); + EXPECT_FALSE(!!Err10); + EXPECT_EQ("Parsing failed.", llvm::toString(Err10.takeError())); + auto Err11 = Interp->Parse("int y = 42;"); + EXPECT_TRUE(!!Err11); + auto Err12 = Interp->Undo(); + EXPECT_FALSE(Err12); +} + static std::string MangleName(NamedDecl *ND) { ASTContext &C = ND->getASTContext(); std::unique_ptr<MangleContext> MangleC(C.createMangleContext()); |