[PATCH] D154382: [ClangRepl] support code completion at a REPL
This revision was landed with ongoing or failed builds. This revision was automatically updated to reflect the committed changes. Closed by commit rG5ab25a42ba70: Reland "[clang-repl] support code completion at a REPL." (authored by capfredf, committed by v.g.vassilev). Changed prior to commit: https://reviews.llvm.org/D154382?vs=554002&id=554027#toc Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 Files: clang-tools-extra/clangd/CodeComplete.cpp clang/include/clang/Frontend/ASTUnit.h clang/include/clang/Sema/CodeCompleteConsumer.h clang/include/clang/Sema/Sema.h clang/lib/Frontend/ASTUnit.cpp clang/lib/Interpreter/CMakeLists.txt clang/lib/Interpreter/IncrementalParser.cpp clang/lib/Interpreter/IncrementalParser.h clang/lib/Interpreter/Interpreter.cpp clang/lib/Parse/ParseDecl.cpp clang/lib/Parse/Parser.cpp clang/lib/Sema/CodeCompleteConsumer.cpp clang/lib/Sema/SemaCodeComplete.cpp clang/tools/clang-repl/ClangRepl.cpp clang/tools/libclang/CIndexCodeCompletion.cpp clang/unittests/Interpreter/CMakeLists.txt Index: clang/unittests/Interpreter/CMakeLists.txt === --- clang/unittests/Interpreter/CMakeLists.txt +++ clang/unittests/Interpreter/CMakeLists.txt @@ -9,6 +9,7 @@ add_clang_unittest(ClangReplInterpreterTests IncrementalProcessingTest.cpp InterpreterTest.cpp + CodeCompletionTest.cpp ) target_link_libraries(ClangReplInterpreterTests PUBLIC clangAST Index: clang/tools/libclang/CIndexCodeCompletion.cpp === --- clang/tools/libclang/CIndexCodeCompletion.cpp +++ clang/tools/libclang/CIndexCodeCompletion.cpp @@ -11,8 +11,8 @@ // //===--===// -#include "CIndexer.h" #include "CIndexDiagnostic.h" +#include "CIndexer.h" #include "CLog.h" #include "CXCursor.h" #include "CXSourceLocation.h" @@ -25,6 +25,7 @@ #include "clang/Basic/SourceManager.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendActions.h" #include "clang/Sema/CodeCompleteConsumer.h" #include "clang/Sema/Sema.h" #include "llvm/ADT/SmallString.h" @@ -41,7 +42,6 @@ #include #include - #ifdef UDP_CODE_COMPLETION_LOGGER #include "clang/Basic/Version.h" #include @@ -543,6 +543,7 @@ case CodeCompletionContext::CCC_PreprocessorExpression: case CodeCompletionContext::CCC_PreprocessorDirective: case CodeCompletionContext::CCC_Attribute: +case CodeCompletionContext::CCC_TopLevelOrExpression: case CodeCompletionContext::CCC_TypeQualifiers: { //Only Clang results should be accepted, so we'll set all of the other //context bits to 0 (i.e. the empty set) Index: clang/tools/clang-repl/ClangRepl.cpp === --- clang/tools/clang-repl/ClangRepl.cpp +++ clang/tools/clang-repl/ClangRepl.cpp @@ -13,6 +13,7 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Interpreter/CodeCompletion.h" #include "clang/Interpreter/Interpreter.h" #include "llvm/ExecutionEngine/Orc/LLJIT.h" @@ -70,6 +71,70 @@ return (Errs || HasError) ? EXIT_FAILURE : EXIT_SUCCESS; } +struct ReplListCompleter { + clang::IncrementalCompilerBuilder &CB; + clang::Interpreter &MainInterp; + ReplListCompleter(clang::IncrementalCompilerBuilder &CB, +clang::Interpreter &Interp) + : CB(CB), MainInterp(Interp){}; + + std::vector operator()(llvm::StringRef Buffer, + size_t Pos) const; + std::vector + operator()(llvm::StringRef Buffer, size_t Pos, llvm::Error &ErrRes) const; +}; + +std::vector +ReplListCompleter::operator()(llvm::StringRef Buffer, size_t Pos) const { + auto Err = llvm::Error::success(); + auto res = (*this)(Buffer, Pos, Err); + if (Err) +llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), "error: "); + return res; +} + +std::vector +ReplListCompleter::operator()(llvm::StringRef Buffer, size_t Pos, + llvm::Error &ErrRes) const { + std::vector Comps; + std::vector Results; + + auto CI = CB.CreateCpp(); + if (auto Err = CI.takeError()) { +ErrRes = std::move(Err); +return {}; + } + + size_t Lines = + std::count(Buffer.begin(), std::next(Buffer.begin(), Pos), '\n') + 1; + auto Interp = clang::Interpreter::create(std::move(*CI)); + + if (auto Err = Interp.takeError()) { +// log the error and returns an empty vector; +ErrRes = std::move(Err); + +return {}; + } + + codeComplete( + const_cast((*Interp)->getCompilerInstance()), + Buffer, Lines, Pos + 1, MainInterp.getCompilerInstance(), Results); + + size_t space_po
[PATCH] D154382: [ClangRepl] support code completion at a REPL
capfredf updated this revision to Diff 554002. capfredf added a comment. fix memory issues Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 Files: clang-tools-extra/clangd/CodeComplete.cpp clang/include/clang/Frontend/ASTUnit.h clang/include/clang/Interpreter/CodeCompletion.h clang/include/clang/Sema/CodeCompleteConsumer.h clang/include/clang/Sema/Sema.h clang/lib/Frontend/ASTUnit.cpp clang/lib/Interpreter/CMakeLists.txt clang/lib/Interpreter/CodeCompletion.cpp clang/lib/Interpreter/IncrementalParser.cpp clang/lib/Interpreter/IncrementalParser.h clang/lib/Interpreter/Interpreter.cpp clang/lib/Parse/ParseDecl.cpp clang/lib/Parse/Parser.cpp clang/lib/Sema/CodeCompleteConsumer.cpp clang/lib/Sema/SemaCodeComplete.cpp clang/test/CodeCompletion/incrememal-mode-completion-no-error.cpp clang/test/CodeCompletion/incremental-top-level.cpp clang/tools/clang-repl/ClangRepl.cpp clang/tools/libclang/CIndexCodeCompletion.cpp clang/unittests/Interpreter/CMakeLists.txt clang/unittests/Interpreter/CodeCompletionTest.cpp Index: clang/unittests/Interpreter/CodeCompletionTest.cpp === --- /dev/null +++ clang/unittests/Interpreter/CodeCompletionTest.cpp @@ -0,0 +1,101 @@ +#include "clang/Interpreter/CodeCompletion.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Interpreter/Interpreter.h" +#include "clang/Sema/CodeCompleteConsumer.h" +#include "llvm/LineEditor/LineEditor.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/raw_ostream.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using namespace clang; +namespace { +auto CB = clang::IncrementalCompilerBuilder(); + +static std::unique_ptr createInterpreter() { + auto CI = cantFail(CB.CreateCpp()); + return cantFail(clang::Interpreter::create(std::move(CI))); +} + +static std::vector runComp(clang::Interpreter &MainInterp, +llvm::StringRef Prefix, +llvm::Error &ErrR) { + auto CI = CB.CreateCpp(); + if (auto Err = CI.takeError()) { +ErrR = std::move(Err); +return {}; + } + + auto Interp = clang::Interpreter::create(std::move(*CI)); + if (auto Err = Interp.takeError()) { +// log the error and returns an empty vector; +ErrR = std::move(Err); + +return {}; + } + + std::vector Results; + std::vector Comps; + + codeComplete( + const_cast((*Interp)->getCompilerInstance()), + Prefix, /* Lines */ 1, Prefix.size(), MainInterp.getCompilerInstance(), + Results); + + for (auto Res : Results) +if (Res.find(Prefix) == 0) + Comps.push_back(Res); + + return Comps; +} + +TEST(CodeCompletionTest, Sanity) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "f", Err); + EXPECT_EQ((size_t)2, comps.size()); // foo and float + EXPECT_EQ(comps[0], std::string("foo")); + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, SanityNoneValid) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "babanana", Err); + EXPECT_EQ((size_t)0, comps.size()); // foo and float + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, TwoDecls) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int application = 12;")) { +consumeError(std::move(R)); +return; + } + if (auto R = Interp->ParseAndExecute("int apple = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "app", Err); + EXPECT_EQ((size_t)2, comps.size()); + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, CompFunDeclsNoError) { + auto Interp = createInterpreter(); + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "void app(", Err); + EXPECT_EQ((bool)Err, false); +} + +} // anonymous namespace Index: clang/unittests/Interpreter/CMakeLists.txt === --- clang/unittests/Interpreter/CMakeLists.txt +++ clang/unittests/Interpreter/CMakeLists.txt @@ -9,6 +9,7 @@ add_clang_unittest(ClangReplInterpreterTests IncrementalProcessingTest.cpp InterpreterTest.cpp + CodeCompletionTest.cpp ) target_link_libraries(ClangReplInterpreterTests PUBLIC clangAST Index: clang/tools/libclang/CIndexCodeCompletion.cpp === --- clang/tools/libclang/CIndexCodeCompletion.cpp +++ clang/tools/libclang/CIndexCodeCompletion.cpp @@ -11,8 +11,8 @@ // //===
[PATCH] D154382: [ClangRepl] support code completion at a REPL
capfredf updated this revision to Diff 553762. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 Files: clang-tools-extra/clangd/CodeComplete.cpp clang/include/clang/Frontend/ASTUnit.h clang/include/clang/Interpreter/CodeCompletion.h clang/include/clang/Sema/CodeCompleteConsumer.h clang/include/clang/Sema/Sema.h clang/lib/Frontend/ASTUnit.cpp clang/lib/Interpreter/CMakeLists.txt clang/lib/Interpreter/CodeCompletion.cpp clang/lib/Interpreter/IncrementalParser.cpp clang/lib/Interpreter/IncrementalParser.h clang/lib/Interpreter/Interpreter.cpp clang/lib/Parse/ParseDecl.cpp clang/lib/Parse/Parser.cpp clang/lib/Sema/CodeCompleteConsumer.cpp clang/lib/Sema/SemaCodeComplete.cpp clang/test/CodeCompletion/incrememal-mode-completion-no-error.cpp clang/test/CodeCompletion/incremental-top-level.cpp clang/tools/clang-repl/ClangRepl.cpp clang/tools/libclang/CIndexCodeCompletion.cpp clang/unittests/Interpreter/CMakeLists.txt clang/unittests/Interpreter/CodeCompletionTest.cpp Index: clang/unittests/Interpreter/CodeCompletionTest.cpp === --- /dev/null +++ clang/unittests/Interpreter/CodeCompletionTest.cpp @@ -0,0 +1,101 @@ +#include "clang/Interpreter/CodeCompletion.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Interpreter/Interpreter.h" +#include "clang/Sema/CodeCompleteConsumer.h" +#include "llvm/LineEditor/LineEditor.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/raw_ostream.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using namespace clang; +namespace { +auto CB = clang::IncrementalCompilerBuilder(); + +static std::unique_ptr createInterpreter() { + auto CI = cantFail(CB.CreateCpp()); + return cantFail(clang::Interpreter::create(std::move(CI))); +} + +static std::vector runComp(clang::Interpreter &MainInterp, +llvm::StringRef Prefix, +llvm::Error &ErrR) { + auto CI = CB.CreateCpp(); + if (auto Err = CI.takeError()) { +ErrR = std::move(Err); +return {}; + } + + auto Interp = clang::Interpreter::create(std::move(*CI)); + if (auto Err = Interp.takeError()) { +// log the error and returns an empty vector; +ErrR = std::move(Err); + +return {}; + } + + std::vector Results; + std::vector Comps; + + codeComplete( + const_cast((*Interp)->getCompilerInstance()), + Prefix, /* Lines */ 1, Prefix.size(), MainInterp.getCompilerInstance(), + Results); + + for (auto Res : Results) +if (Res.find(Prefix) == 0) + Comps.push_back(Res); + + return Comps; +} + +TEST(CodeCompletionTest, Sanity) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "f", Err); + EXPECT_EQ((size_t)2, comps.size()); // foo and float + EXPECT_EQ(comps[0], std::string("foo")); + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, SanityNoneValid) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "babanana", Err); + EXPECT_EQ((size_t)0, comps.size()); // foo and float + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, TwoDecls) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int application = 12;")) { +consumeError(std::move(R)); +return; + } + if (auto R = Interp->ParseAndExecute("int apple = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "app", Err); + EXPECT_EQ((size_t)2, comps.size()); + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, CompFunDeclsNoError) { + auto Interp = createInterpreter(); + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "void app(", Err); + EXPECT_EQ((bool)Err, false); +} + +} // anonymous namespace Index: clang/unittests/Interpreter/CMakeLists.txt === --- clang/unittests/Interpreter/CMakeLists.txt +++ clang/unittests/Interpreter/CMakeLists.txt @@ -9,6 +9,7 @@ add_clang_unittest(ClangReplInterpreterTests IncrementalProcessingTest.cpp InterpreterTest.cpp + CodeCompletionTest.cpp ) target_link_libraries(ClangReplInterpreterTests PUBLIC clangAST Index: clang/tools/libclang/CIndexCodeCompletion.cpp === --- clang/tools/libclang/CIndexCodeCompletion.cpp +++ clang/tools/libclang/CIndexCodeCompletion.cpp @@ -11,8 +11,8 @@ // //===--===// -#in
[PATCH] D154382: [ClangRepl] support code completion at a REPL
capfredf updated this revision to Diff 553759. capfredf added a comment. fix potential memory issues Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 Files: clang-tools-extra/clangd/CodeComplete.cpp clang/include/clang/Frontend/ASTUnit.h clang/include/clang/Interpreter/CodeCompletion.h clang/include/clang/Sema/CodeCompleteConsumer.h clang/include/clang/Sema/Sema.h clang/lib/Frontend/ASTUnit.cpp clang/lib/Interpreter/CMakeLists.txt clang/lib/Interpreter/CodeCompletion.cpp clang/lib/Interpreter/IncrementalParser.cpp clang/lib/Interpreter/IncrementalParser.h clang/lib/Interpreter/Interpreter.cpp clang/lib/Parse/ParseDecl.cpp clang/lib/Parse/Parser.cpp clang/lib/Sema/CodeCompleteConsumer.cpp clang/lib/Sema/SemaCodeComplete.cpp clang/test/CodeCompletion/incrememal-mode-completion-no-error.cpp clang/test/CodeCompletion/incremental-top-level.cpp clang/tools/clang-repl/ClangRepl.cpp clang/tools/libclang/CIndexCodeCompletion.cpp clang/unittests/Interpreter/CMakeLists.txt clang/unittests/Interpreter/CodeCompletionTest.cpp Index: clang/unittests/Interpreter/CodeCompletionTest.cpp === --- /dev/null +++ clang/unittests/Interpreter/CodeCompletionTest.cpp @@ -0,0 +1,100 @@ +#include "clang/Interpreter/CodeCompletion.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Interpreter/Interpreter.h" +#include "clang/Sema/CodeCompleteConsumer.h" +#include "llvm/LineEditor/LineEditor.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/raw_ostream.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using namespace clang; +namespace { +auto CB = clang::IncrementalCompilerBuilder(); + +static std::unique_ptr createInterpreter() { + auto CI = cantFail(CB.CreateCpp()); + return cantFail(clang::Interpreter::create(std::move(CI))); +} + +static std::vector runComp(clang::Interpreter &MainInterp, +llvm::StringRef Prefix, +llvm::Error &ErrR) { + auto CI = CB.CreateCpp(); + if (auto Err = CI.takeError()) { +ErrR = std::move(Err); +return {}; + } + + auto Interp = clang::Interpreter::create(std::move(*CI)); + if (auto Err = Interp.takeError()) { +// log the error and returns an empty vector; +ErrR = std::move(Err); + +return {}; + } + + std::vector Results; + std::vector Comps; + + codeComplete( + const_cast((*Interp)->getCompilerInstance()), + Prefix, 1, Prefix.size(), MainInterp.getCompilerInstance(), Results); + + for (auto Res : Results) +if (Res.find(Prefix) == 0) + Comps.push_back(Res); + + return Comps; +} + +TEST(CodeCompletionTest, Sanity) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "f", Err); + EXPECT_EQ((size_t)2, comps.size()); // foo and float + EXPECT_EQ(comps[0], std::string("foo")); + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, SanityNoneValid) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "babanana", Err); + EXPECT_EQ((size_t)0, comps.size()); // foo and float + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, TwoDecls) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int application = 12;")) { +consumeError(std::move(R)); +return; + } + if (auto R = Interp->ParseAndExecute("int apple = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "app", Err); + EXPECT_EQ((size_t)2, comps.size()); + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, CompFunDeclsNoError) { + auto Interp = createInterpreter(); + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "void app(", Err); + EXPECT_EQ((bool)Err, false); +} + +} // anonymous namespace Index: clang/unittests/Interpreter/CMakeLists.txt === --- clang/unittests/Interpreter/CMakeLists.txt +++ clang/unittests/Interpreter/CMakeLists.txt @@ -9,6 +9,7 @@ add_clang_unittest(ClangReplInterpreterTests IncrementalProcessingTest.cpp InterpreterTest.cpp + CodeCompletionTest.cpp ) target_link_libraries(ClangReplInterpreterTests PUBLIC clangAST Index: clang/tools/libclang/CIndexCodeCompletion.cpp === --- clang/tools/libclang/CIndexCodeCompletion.cpp +++ clang/tools/libclang/CIndexCodeCompletion.cpp @@ -11,8 +11,8 @@ // //===-
[PATCH] D154382: [ClangRepl] support code completion at a REPL
sammccall added inline comments. Comment at: clang-tools-extra/clangd/CodeComplete.cpp:845 case CodeCompletionContext::CCC_NewName: + case CodeCompletionContext::CCC_TopLevelOrExpression: return false; This should be `true` rather than `false`, since both TopLevel and Expression are completed using the index. (Though I realize that for now we'll never hit this context) Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D154382: [ClangRepl] support code completion at a REPL
v.g.vassilev added inline comments. Comment at: clang/unittests/Interpreter/CodeCompletionTest.cpp:38 + + std::vector Results; + We should make this an out parameter instead of returning it by copy. Comment at: clang/unittests/Interpreter/CodeCompletionTest.cpp:42 + const_cast((*Interp)->getCompilerInstance()), + Prefix, 1, Prefix.size(), MainInterp.getCompilerInstance(), Results); + Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D154382: [ClangRepl] support code completion at a REPL
capfredf updated this revision to Diff 552736. capfredf added a comment. Herald added a subscriber: kadircet. Herald added a project: clang-tools-extra. fix code in Clangd Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 Files: clang-tools-extra/clangd/CodeComplete.cpp clang/include/clang/Frontend/ASTUnit.h clang/include/clang/Interpreter/CodeCompletion.h clang/include/clang/Sema/CodeCompleteConsumer.h clang/include/clang/Sema/Sema.h clang/lib/Frontend/ASTUnit.cpp clang/lib/Interpreter/CMakeLists.txt clang/lib/Interpreter/CodeCompletion.cpp clang/lib/Interpreter/IncrementalParser.cpp clang/lib/Interpreter/IncrementalParser.h clang/lib/Interpreter/Interpreter.cpp clang/lib/Parse/ParseDecl.cpp clang/lib/Parse/Parser.cpp clang/lib/Sema/CodeCompleteConsumer.cpp clang/lib/Sema/SemaCodeComplete.cpp clang/test/CodeCompletion/incrememal-mode-completion-no-error.cpp clang/test/CodeCompletion/incremental-top-level.cpp clang/tools/clang-repl/ClangRepl.cpp clang/tools/libclang/CIndexCodeCompletion.cpp clang/unittests/Interpreter/CMakeLists.txt clang/unittests/Interpreter/CodeCompletionTest.cpp Index: clang/unittests/Interpreter/CodeCompletionTest.cpp === --- /dev/null +++ clang/unittests/Interpreter/CodeCompletionTest.cpp @@ -0,0 +1,101 @@ +#include "clang/Interpreter/CodeCompletion.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Interpreter/Interpreter.h" +#include "clang/Sema/CodeCompleteConsumer.h" +#include "llvm/LineEditor/LineEditor.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/raw_ostream.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using namespace clang; +namespace { +auto CB = clang::IncrementalCompilerBuilder(); + +static std::unique_ptr createInterpreter() { + auto CI = cantFail(CB.CreateCpp()); + return cantFail(clang::Interpreter::create(std::move(CI))); +} + +static std::vector runComp(clang::Interpreter &MainInterp, +llvm::StringRef Prefix, +llvm::Error &ErrR) { + auto CI = CB.CreateCpp(); + if (auto Err = CI.takeError()) { +ErrR = std::move(Err); +return {}; + } + + auto Interp = clang::Interpreter::create(std::move(*CI)); + if (auto Err = Interp.takeError()) { +// log the error and returns an empty vector; +ErrR = std::move(Err); + +return {}; + } + + std::vector Results; + + codeComplete( + const_cast((*Interp)->getCompilerInstance()), + Prefix, 1, Prefix.size(), MainInterp.getCompilerInstance(), Results); + + std::vector Comps; + for (auto c : convertToCodeCompleteStrings(Results)) { +if (c.find(Prefix) == 0) + Comps.push_back(c.substr(Prefix.size())); + } + + return Comps; +} + +TEST(CodeCompletionTest, Sanity) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "f", Err); + EXPECT_EQ((size_t)2, comps.size()); // foo and float + EXPECT_EQ(comps[0], std::string("oo")); + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, SanityNoneValid) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "babanana", Err); + EXPECT_EQ((size_t)0, comps.size()); // foo and float + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, TwoDecls) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int application = 12;")) { +consumeError(std::move(R)); +return; + } + if (auto R = Interp->ParseAndExecute("int apple = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "app", Err); + EXPECT_EQ((size_t)2, comps.size()); + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, CompFunDeclsNoError) { + auto Interp = createInterpreter(); + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "void app(", Err); + EXPECT_EQ((bool)Err, false); +} + +} // anonymous namespace Index: clang/unittests/Interpreter/CMakeLists.txt === --- clang/unittests/Interpreter/CMakeLists.txt +++ clang/unittests/Interpreter/CMakeLists.txt @@ -9,6 +9,7 @@ add_clang_unittest(ClangReplInterpreterTests IncrementalProcessingTest.cpp InterpreterTest.cpp + CodeCompletionTest.cpp ) target_link_libraries(ClangReplInterpreterTests PUBLIC clangAST Index: clang/tools/libclang/CIndexCodeCompletion.cpp === --- clang/tools/libclang/CIndexCodeCompletion.cpp
[PATCH] D154382: [ClangRepl] support code completion at a REPL
This revision was automatically updated to reflect the committed changes. Closed by commit rGeb0e6c3134ef: [clang-repl] support code completion at a REPL. (authored by capfredf, committed by v.g.vassilev). Changed prior to commit: https://reviews.llvm.org/D154382?vs=552418&id=552696#toc Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 Files: clang/include/clang/Frontend/ASTUnit.h clang/include/clang/Interpreter/CodeCompletion.h clang/include/clang/Sema/CodeCompleteConsumer.h clang/include/clang/Sema/Sema.h clang/lib/Frontend/ASTUnit.cpp clang/lib/Interpreter/CMakeLists.txt clang/lib/Interpreter/CodeCompletion.cpp clang/lib/Interpreter/IncrementalParser.cpp clang/lib/Interpreter/IncrementalParser.h clang/lib/Interpreter/Interpreter.cpp clang/lib/Parse/ParseDecl.cpp clang/lib/Parse/Parser.cpp clang/lib/Sema/CodeCompleteConsumer.cpp clang/lib/Sema/SemaCodeComplete.cpp clang/test/CodeCompletion/incrememal-mode-completion-no-error.cpp clang/test/CodeCompletion/incremental-top-level.cpp clang/tools/clang-repl/ClangRepl.cpp clang/tools/libclang/CIndexCodeCompletion.cpp clang/unittests/Interpreter/CMakeLists.txt clang/unittests/Interpreter/CodeCompletionTest.cpp Index: clang/unittests/Interpreter/CodeCompletionTest.cpp === --- /dev/null +++ clang/unittests/Interpreter/CodeCompletionTest.cpp @@ -0,0 +1,101 @@ +#include "clang/Interpreter/CodeCompletion.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Interpreter/Interpreter.h" +#include "clang/Sema/CodeCompleteConsumer.h" +#include "llvm/LineEditor/LineEditor.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/raw_ostream.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using namespace clang; +namespace { +auto CB = clang::IncrementalCompilerBuilder(); + +static std::unique_ptr createInterpreter() { + auto CI = cantFail(CB.CreateCpp()); + return cantFail(clang::Interpreter::create(std::move(CI))); +} + +static std::vector runComp(clang::Interpreter &MainInterp, +llvm::StringRef Prefix, +llvm::Error &ErrR) { + auto CI = CB.CreateCpp(); + if (auto Err = CI.takeError()) { +ErrR = std::move(Err); +return {}; + } + + auto Interp = clang::Interpreter::create(std::move(*CI)); + if (auto Err = Interp.takeError()) { +// log the error and returns an empty vector; +ErrR = std::move(Err); + +return {}; + } + + std::vector Results; + + codeComplete( + const_cast((*Interp)->getCompilerInstance()), + Prefix, 1, Prefix.size(), MainInterp.getCompilerInstance(), Results); + + std::vector Comps; + for (auto c : convertToCodeCompleteStrings(Results)) { +if (c.find(Prefix) == 0) + Comps.push_back(c.substr(Prefix.size())); + } + + return Comps; +} + +TEST(CodeCompletionTest, Sanity) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "f", Err); + EXPECT_EQ((size_t)2, comps.size()); // foo and float + EXPECT_EQ(comps[0], std::string("oo")); + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, SanityNoneValid) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "babanana", Err); + EXPECT_EQ((size_t)0, comps.size()); // foo and float + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, TwoDecls) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int application = 12;")) { +consumeError(std::move(R)); +return; + } + if (auto R = Interp->ParseAndExecute("int apple = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "app", Err); + EXPECT_EQ((size_t)2, comps.size()); + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, CompFunDeclsNoError) { + auto Interp = createInterpreter(); + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "void app(", Err); + EXPECT_EQ((bool)Err, false); +} + +} // anonymous namespace Index: clang/unittests/Interpreter/CMakeLists.txt === --- clang/unittests/Interpreter/CMakeLists.txt +++ clang/unittests/Interpreter/CMakeLists.txt @@ -9,6 +9,7 @@ add_clang_unittest(ClangReplInterpreterTests IncrementalProcessingTest.cpp InterpreterTest.cpp + CodeCompletionTest.cpp ) target_link_libraries(ClangReplInterpreterTests PUBLIC clangAST Index: clang/tools/libclang/CIndexCodeCompletion.cpp
[PATCH] D154382: [ClangRepl] support code completion at a REPL
capfredf updated this revision to Diff 552418. capfredf edited the summary of this revision. capfredf added a comment. update the commit message Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 Files: clang/include/clang/Frontend/ASTUnit.h clang/include/clang/Interpreter/CodeCompletion.h clang/include/clang/Sema/CodeCompleteConsumer.h clang/include/clang/Sema/Sema.h clang/lib/Frontend/ASTUnit.cpp clang/lib/Interpreter/CMakeLists.txt clang/lib/Interpreter/CodeCompletion.cpp clang/lib/Interpreter/IncrementalParser.cpp clang/lib/Interpreter/IncrementalParser.h clang/lib/Interpreter/Interpreter.cpp clang/lib/Parse/ParseDecl.cpp clang/lib/Parse/Parser.cpp clang/lib/Sema/CodeCompleteConsumer.cpp clang/lib/Sema/SemaCodeComplete.cpp clang/test/CodeCompletion/incrememal-mode-completion-no-error.cpp clang/test/CodeCompletion/incremental-top-level.cpp clang/tools/clang-repl/ClangRepl.cpp clang/tools/libclang/CIndexCodeCompletion.cpp clang/unittests/Interpreter/CMakeLists.txt clang/unittests/Interpreter/CodeCompletionTest.cpp Index: clang/unittests/Interpreter/CodeCompletionTest.cpp === --- /dev/null +++ clang/unittests/Interpreter/CodeCompletionTest.cpp @@ -0,0 +1,101 @@ +#include "clang/Interpreter/CodeCompletion.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Interpreter/Interpreter.h" +#include "clang/Sema/CodeCompleteConsumer.h" +#include "llvm/LineEditor/LineEditor.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/raw_ostream.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using namespace clang; +namespace { +auto CB = clang::IncrementalCompilerBuilder(); + +static std::unique_ptr createInterpreter() { + auto CI = cantFail(CB.CreateCpp()); + return cantFail(clang::Interpreter::create(std::move(CI))); +} + +static std::vector runComp(clang::Interpreter &MainInterp, +llvm::StringRef Prefix, +llvm::Error &ErrR) { + auto CI = CB.CreateCpp(); + if (auto Err = CI.takeError()) { +ErrR = std::move(Err); +return {}; + } + + auto Interp = clang::Interpreter::create(std::move(*CI)); + if (auto Err = Interp.takeError()) { +// log the error and returns an empty vector; +ErrR = std::move(Err); + +return {}; + } + + std::vector Results; + + codeComplete( + const_cast((*Interp)->getCompilerInstance()), + Prefix, 1, Prefix.size(), MainInterp.getCompilerInstance(), Results); + + std::vector Comps; + for (auto c : convertToCodeCompleteStrings(Results)) { +if (c.find(Prefix) == 0) + Comps.push_back(c.substr(Prefix.size())); + } + + return Comps; +} + +TEST(CodeCompletionTest, Sanity) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "f", Err); + EXPECT_EQ((size_t)2, comps.size()); // foo and float + EXPECT_EQ(comps[0], std::string("oo")); + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, SanityNoneValid) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "babanana", Err); + EXPECT_EQ((size_t)0, comps.size()); // foo and float + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, TwoDecls) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int application = 12;")) { +consumeError(std::move(R)); +return; + } + if (auto R = Interp->ParseAndExecute("int apple = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "app", Err); + EXPECT_EQ((size_t)2, comps.size()); + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, CompFunDeclsNoError) { + auto Interp = createInterpreter(); + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "void app(", Err); + EXPECT_EQ((bool)Err, false); +} + +} // anonymous namespace Index: clang/unittests/Interpreter/CMakeLists.txt === --- clang/unittests/Interpreter/CMakeLists.txt +++ clang/unittests/Interpreter/CMakeLists.txt @@ -9,6 +9,7 @@ add_clang_unittest(ClangReplInterpreterTests IncrementalProcessingTest.cpp InterpreterTest.cpp + CodeCompletionTest.cpp ) target_link_libraries(ClangReplInterpreterTests PUBLIC clangAST Index: clang/tools/libclang/CIndexCodeCompletion.cpp === --- clang/tools/libclang/CIndexCodeCompletion.cpp +++ clang/tools/libclang/CIndexCodeCompletion.cpp @@ -11,8 +11,8 @@ //
[PATCH] D154382: [ClangRepl] support code completion at a REPL
v.g.vassilev accepted this revision. v.g.vassilev added a comment. Thanks for working on this @capfredf. Let me know if I should land that for you. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D154382: [ClangRepl] support code completion at a REPL
sammccall accepted this revision. sammccall added a comment. This revision is now accepted and ready to land. LGTM, thanks! Comment at: clang/include/clang/Sema/CodeCompleteConsumer.h:341 + +/// Code completion at a top level in a REPL session. +CCC_TopLevelOrExpression, I think this is non-obvious & worthy of more explanation ``` /// Completion in a namespace or global scope, but also accept expressions. /// This occurs in REPL inputs, which may declare things or print expression /// values. ``` Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D154382: [ClangRepl] support code completion at a REPL
v.g.vassilev added a comment. @sammccall could you take another look? It seems quite ready to me to land. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D154382: [ClangRepl] support code completion at a REPL
capfredf updated this revision to Diff 551218. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 Files: clang/include/clang/Frontend/ASTUnit.h clang/include/clang/Interpreter/CodeCompletion.h clang/include/clang/Sema/CodeCompleteConsumer.h clang/include/clang/Sema/Sema.h clang/lib/Frontend/ASTUnit.cpp clang/lib/Interpreter/CMakeLists.txt clang/lib/Interpreter/CodeCompletion.cpp clang/lib/Interpreter/IncrementalParser.cpp clang/lib/Interpreter/IncrementalParser.h clang/lib/Interpreter/Interpreter.cpp clang/lib/Parse/ParseDecl.cpp clang/lib/Parse/Parser.cpp clang/lib/Sema/CodeCompleteConsumer.cpp clang/lib/Sema/SemaCodeComplete.cpp clang/test/CodeCompletion/incrememal-mode-completion-no-error.cpp clang/test/CodeCompletion/incremental-top-level.cpp clang/tools/clang-repl/ClangRepl.cpp clang/tools/libclang/CIndexCodeCompletion.cpp clang/unittests/Interpreter/CMakeLists.txt clang/unittests/Interpreter/CodeCompletionTest.cpp Index: clang/unittests/Interpreter/CodeCompletionTest.cpp === --- /dev/null +++ clang/unittests/Interpreter/CodeCompletionTest.cpp @@ -0,0 +1,101 @@ +#include "clang/Interpreter/CodeCompletion.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Interpreter/Interpreter.h" +#include "clang/Sema/CodeCompleteConsumer.h" +#include "llvm/LineEditor/LineEditor.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/raw_ostream.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using namespace clang; +namespace { +auto CB = clang::IncrementalCompilerBuilder(); + +static std::unique_ptr createInterpreter() { + auto CI = cantFail(CB.CreateCpp()); + return cantFail(clang::Interpreter::create(std::move(CI))); +} + +static std::vector runComp(clang::Interpreter &MainInterp, +llvm::StringRef Prefix, +llvm::Error &ErrR) { + auto CI = CB.CreateCpp(); + if (auto Err = CI.takeError()) { +ErrR = std::move(Err); +return {}; + } + + auto Interp = clang::Interpreter::create(std::move(*CI)); + if (auto Err = Interp.takeError()) { +// log the error and returns an empty vector; +ErrR = std::move(Err); + +return {}; + } + + std::vector Results; + + codeComplete( + const_cast((*Interp)->getCompilerInstance()), + Prefix, 1, Prefix.size(), MainInterp.getCompilerInstance(), Results); + + std::vector Comps; + for (auto c : convertToCodeCompleteStrings(Results)) { +if (c.find(Prefix) == 0) + Comps.push_back(c.substr(Prefix.size())); + } + + return Comps; +} + +TEST(CodeCompletionTest, Sanity) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "f", Err); + EXPECT_EQ((size_t)2, comps.size()); // foo and float + EXPECT_EQ(comps[0], std::string("oo")); + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, SanityNoneValid) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "babanana", Err); + EXPECT_EQ((size_t)0, comps.size()); // foo and float + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, TwoDecls) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int application = 12;")) { +consumeError(std::move(R)); +return; + } + if (auto R = Interp->ParseAndExecute("int apple = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "app", Err); + EXPECT_EQ((size_t)2, comps.size()); + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, CompFunDeclsNoError) { + auto Interp = createInterpreter(); + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "void app(", Err); + EXPECT_EQ((bool)Err, false); +} + +} // anonymous namespace Index: clang/unittests/Interpreter/CMakeLists.txt === --- clang/unittests/Interpreter/CMakeLists.txt +++ clang/unittests/Interpreter/CMakeLists.txt @@ -9,6 +9,7 @@ add_clang_unittest(ClangReplInterpreterTests IncrementalProcessingTest.cpp InterpreterTest.cpp + CodeCompletionTest.cpp ) target_link_libraries(ClangReplInterpreterTests PUBLIC clangAST Index: clang/tools/libclang/CIndexCodeCompletion.cpp === --- clang/tools/libclang/CIndexCodeCompletion.cpp +++ clang/tools/libclang/CIndexCodeCompletion.cpp @@ -11,8 +11,8 @@ // //===--===// -#include "CInd
[PATCH] D154382: [ClangRepl] support code completion at a REPL
capfredf updated this revision to Diff 550940. capfredf added a comment. up Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 Files: clang/include/clang/Frontend/ASTUnit.h clang/include/clang/Interpreter/InterpreterCodeCompletion.h clang/include/clang/Sema/CodeCompleteConsumer.h clang/include/clang/Sema/Sema.h clang/lib/Frontend/ASTUnit.cpp clang/lib/Interpreter/CMakeLists.txt clang/lib/Interpreter/IncrementalParser.cpp clang/lib/Interpreter/IncrementalParser.h clang/lib/Interpreter/Interpreter.cpp clang/lib/Interpreter/InterpreterCodeCompletion.cpp clang/lib/Parse/ParseDecl.cpp clang/lib/Parse/Parser.cpp clang/lib/Sema/CodeCompleteConsumer.cpp clang/lib/Sema/SemaCodeComplete.cpp clang/test/CodeCompletion/incrememal-mode-completion-no-error.cpp clang/test/CodeCompletion/incremental-top-level.cpp clang/tools/clang-repl/ClangRepl.cpp clang/tools/libclang/CIndexCodeCompletion.cpp clang/unittests/Interpreter/CMakeLists.txt clang/unittests/Interpreter/CodeCompletionTest.cpp Index: clang/unittests/Interpreter/CodeCompletionTest.cpp === --- /dev/null +++ clang/unittests/Interpreter/CodeCompletionTest.cpp @@ -0,0 +1,101 @@ +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Interpreter/Interpreter.h" +#include "clang/Interpreter/InterpreterCodeCompletion.h" +#include "clang/Sema/CodeCompleteConsumer.h" +#include "llvm/LineEditor/LineEditor.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/raw_ostream.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using namespace clang; +namespace { +auto CB = clang::IncrementalCompilerBuilder(); + +static std::unique_ptr createInterpreter() { + auto CI = cantFail(CB.CreateCpp()); + return cantFail(clang::Interpreter::create(std::move(CI))); +} + +static std::vector runComp(clang::Interpreter &MainInterp, +llvm::StringRef Prefix, +llvm::Error &ErrR) { + auto CI = CB.CreateCpp(); + if (auto Err = CI.takeError()) { +ErrR = std::move(Err); +return {}; + } + + auto Interp = clang::Interpreter::create(std::move(*CI)); + if (auto Err = Interp.takeError()) { +// log the error and returns an empty vector; +ErrR = std::move(Err); + +return {}; + } + + std::vector Results; + + codeComplete( + const_cast((*Interp)->getCompilerInstance()), + Prefix, 1, Prefix.size(), MainInterp.getCompilerInstance(), Results); + + std::vector Comps; + for (auto c : convertToCodeCompleteStrings(Results)) { +if (c.find(Prefix) == 0) + Comps.push_back(c.substr(Prefix.size())); + } + + return Comps; +} + +TEST(CodeCompletionTest, Sanity) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "f", Err); + EXPECT_EQ((size_t)2, comps.size()); // foo and float + EXPECT_EQ(comps[0], std::string("oo")); + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, SanityNoneValid) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "babanana", Err); + EXPECT_EQ((size_t)0, comps.size()); // foo and float + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, TwoDecls) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int application = 12;")) { +consumeError(std::move(R)); +return; + } + if (auto R = Interp->ParseAndExecute("int apple = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "app", Err); + EXPECT_EQ((size_t)2, comps.size()); + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, CompFunDeclsNoError) { + auto Interp = createInterpreter(); + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "void app(", Err); + EXPECT_EQ((bool)Err, false); +} + +} // anonymous namespace Index: clang/unittests/Interpreter/CMakeLists.txt === --- clang/unittests/Interpreter/CMakeLists.txt +++ clang/unittests/Interpreter/CMakeLists.txt @@ -9,6 +9,7 @@ add_clang_unittest(ClangReplInterpreterTests IncrementalProcessingTest.cpp InterpreterTest.cpp + CodeCompletionTest.cpp ) target_link_libraries(ClangReplInterpreterTests PUBLIC clangAST Index: clang/tools/libclang/CIndexCodeCompletion.cpp === --- clang/tools/libclang/CIndexCodeCompletion.cpp +++ clang/tools/libclang/CIndexCodeCompletion.cpp @@ -11,8 +11,8 @@ // //===-
[PATCH] D154382: [ClangRepl] support code completion at a REPL
capfredf added a comment. @sammccall Thank you very much for your valuable input. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D154382: [ClangRepl] support code completion at a REPL
capfredf added inline comments. Comment at: clang/include/clang/Frontend/ASTUnit.h:901 +SmallVectorImpl &OwnedBuffers, +std::function AfterBeginSourceFile = [](CompilerInstance& CI) -> void {}); sammccall wrote: > capfredf wrote: > > @v.g.vassilev Not sure if this is the right solution or idiom to extend > > this method. > > > > we can make this high order function more general, like > > `std::unique_ptr<()>` > There's no need for this to be a SyntaxOnlyAction, you can take > FrontendAction here. > > I don't think there's any need to provide a factory, it's safe to assume it > will always create one action. (We have FrontendActionFactory in tooling, and > it's a pain.) Ideally, this method requires a FrontendAction with `hasCodeCompletionSupport` returning `true`. The reason I chose `SyntaxOnlyAction` are 1. the old code used it 2. `SyntaxOnlyAction::hasCodeCompletionSupport` returns `true`. Certainly, right now `SyntaxOnlyAction` does not prevent its subclasses from overriding this method. Comment at: clang/include/clang/Sema/CodeCompleteConsumer.h:342 +/// Code completion at a top level in a REPL session. +CCC_ReplTopLevel, }; sammccall wrote: > v.g.vassilev wrote: > > > I don't think this name fits with the others, it describes the client rather > than the grammatical/semantic context. > > I would suggest maybe `CCC_TopLevelOrExpression`? Nice. This one sounds better indeed. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D154382: [ClangRepl] support code completion at a REPL
capfredf updated this revision to Diff 550489. capfredf marked 7 inline comments as done. capfredf added a comment. address @sammccall 's comments Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 Files: clang/include/clang/Frontend/ASTUnit.h clang/include/clang/Interpreter/InterpreterCodeCompletion.h clang/include/clang/Sema/CodeCompleteConsumer.h clang/include/clang/Sema/Sema.h clang/lib/Frontend/ASTUnit.cpp clang/lib/Interpreter/InterpreterCodeCompletion.cpp clang/lib/Parse/ParseDecl.cpp clang/lib/Parse/Parser.cpp clang/lib/Sema/CodeCompleteConsumer.cpp clang/lib/Sema/SemaCodeComplete.cpp clang/tools/clang-repl/ClangRepl.cpp clang/tools/libclang/CIndexCodeCompletion.cpp clang/unittests/Interpreter/CodeCompletionTest.cpp Index: clang/unittests/Interpreter/CodeCompletionTest.cpp === --- clang/unittests/Interpreter/CodeCompletionTest.cpp +++ clang/unittests/Interpreter/CodeCompletionTest.cpp @@ -42,9 +42,9 @@ Prefix, 1, Prefix.size(), MainInterp.getCompilerInstance(), Results); std::vector Comps; - for (auto c : ConvertToCodeCompleteStrings(Results)) { -if (c.startswith(Prefix)) - Comps.push_back(c.substr(Prefix.size()).str()); + for (auto c : convertToCodeCompleteStrings(Results)) { +if (c.find(Prefix) == 0) + Comps.push_back(c.substr(Prefix.size())); } return Comps; Index: clang/tools/libclang/CIndexCodeCompletion.cpp === --- clang/tools/libclang/CIndexCodeCompletion.cpp +++ clang/tools/libclang/CIndexCodeCompletion.cpp @@ -543,7 +543,7 @@ case CodeCompletionContext::CCC_PreprocessorExpression: case CodeCompletionContext::CCC_PreprocessorDirective: case CodeCompletionContext::CCC_Attribute: -case CodeCompletionContext::CCC_ReplTopLevel: +case CodeCompletionContext::CCC_TopLevelOrExpression: case CodeCompletionContext::CCC_TypeQualifiers: { //Only Clang results should be accepted, so we'll set all of the other //context bits to 0 (i.e. the empty set) Index: clang/tools/clang-repl/ClangRepl.cpp === --- clang/tools/clang-repl/ClangRepl.cpp +++ clang/tools/clang-repl/ClangRepl.cpp @@ -129,13 +129,14 @@ s = Buffer.substr(space_pos + 1); } - for (auto c : ConvertToCodeCompleteStrings(Results)) { -if (c.startswith(s)) + for (auto c : convertToCodeCompleteStrings(Results)) { +if (c.find(s) == 0) Comps.push_back( - llvm::LineEditor::Completion(c.substr(s.size()).str(), c.str())); + llvm::LineEditor::Completion(c.substr(s.size()), c)); } return Comps; } + llvm::ExitOnError ExitOnErr; int main(int argc, const char **argv) { ExitOnErr.setBanner("clang-repl: "); Index: clang/lib/Sema/SemaCodeComplete.cpp === --- clang/lib/Sema/SemaCodeComplete.cpp +++ clang/lib/Sema/SemaCodeComplete.cpp @@ -225,7 +225,7 @@ case CodeCompletionContext::CCC_ObjCMessageReceiver: case CodeCompletionContext::CCC_ParenthesizedExpression: case CodeCompletionContext::CCC_Statement: -case CodeCompletionContext::CCC_ReplTopLevel: +case CodeCompletionContext::CCC_TopLevelOrExpression: case CodeCompletionContext::CCC_Recovery: if (ObjCMethodDecl *Method = SemaRef.getCurMethodDecl()) if (Method->isInstanceMethod()) @@ -1851,7 +1851,7 @@ case Sema::PCC_ObjCInstanceVariableList: case Sema::PCC_Expression: case Sema::PCC_Statement: - case Sema::PCC_TopLevelStmtDecl: + case Sema::PCC_TopLevelOrExpression: case Sema::PCC_ForInit: case Sema::PCC_Condition: case Sema::PCC_RecoveryInFunction: @@ -1909,7 +1909,7 @@ case Sema::PCC_Type: case Sema::PCC_ParenthesizedExpression: case Sema::PCC_LocalDeclarationSpecifiers: - case Sema::PCC_TopLevelStmtDecl: + case Sema::PCC_TopLevelOrExpression: return true; case Sema::PCC_Expression: @@ -,7 +,7 @@ break; case Sema::PCC_RecoveryInFunction: - case Sema::PCC_TopLevelStmtDecl: + case Sema::PCC_TopLevelOrExpression: case Sema::PCC_Statement: { if (SemaRef.getLangOpts().CPlusPlus11) AddUsingAliasResult(Builder, Results); @@ -4212,8 +4212,8 @@ case Sema::PCC_LocalDeclarationSpecifiers: return CodeCompletionContext::CCC_Type; - case Sema::PCC_TopLevelStmtDecl: -return CodeCompletionContext::CCC_ReplTopLevel; + case Sema::PCC_TopLevelOrExpression: +return CodeCompletionContext::CCC_TopLevelOrExpression; } llvm_unreachable("Invalid ParserCompletionContext!"); @@ -4354,7 +4354,7 @@ break; case PCC_Statement: - case PCC_TopLevelStmtDecl: + case PCC_TopLevelOrExpression: case PCC_ParenthesizedExpression: case PCC_Expression: case PCC_ForInit: @@ -4392,7
[PATCH] D154382: [ClangRepl] support code completion at a REPL
sammccall added a comment. This mostly looks good. My main concern is adding code to the parser to suppress errors when code completing: this is unlikely to be the only such place. Existing consumers seem happy to ignore errors, if this doesn't work for clang-repl it'd be good to understand why. Comment at: clang/include/clang/Frontend/ASTUnit.h:891 /// + /// \param Act A SyntaxOnlyAction performs actions on the syntax. + /// This comment doesn't really say anything beyond echoing the name/type, either remove it or add some separate explanation? e.g. "If Act is specified, it will be used to parse the file. This allows customizing the parse by overriding FrontendAction's lifecycle methods." Comment at: clang/include/clang/Frontend/ASTUnit.h:901 +SmallVectorImpl &OwnedBuffers, +std::function AfterBeginSourceFile = [](CompilerInstance& CI) -> void {}); capfredf wrote: > @v.g.vassilev Not sure if this is the right solution or idiom to extend this > method. > > we can make this high order function more general, like > `std::unique_ptr<()>` There's no need for this to be a SyntaxOnlyAction, you can take FrontendAction here. I don't think there's any need to provide a factory, it's safe to assume it will always create one action. (We have FrontendActionFactory in tooling, and it's a pain.) Comment at: clang/include/clang/Interpreter/InterpreterCodeCompletion.h:30 +std::vector +ConvertToCodeCompleteStrings(const std::vector &Results); +} // namespace clang nit: lowercase initial letter for functions Comment at: clang/include/clang/Interpreter/InterpreterCodeCompletion.h:30 +std::vector +ConvertToCodeCompleteStrings(const std::vector &Results); +} // namespace clang sammccall wrote: > nit: lowercase initial letter for functions you might consider `vector` instead. this signature doesn't provide any way to return owned names, and so requires that the results are already allocated somewhere as contiguous strings. This will prevents completing names like `operator int`, as well as some non-names that might prove useful. This is an interactive operation, copying the strings is unlikely to add significant latency on human scale. Comment at: clang/include/clang/Sema/CodeCompleteConsumer.h:342 +/// Code completion at a top level in a REPL session. +CCC_ReplTopLevel, }; v.g.vassilev wrote: > I don't think this name fits with the others, it describes the client rather than the grammatical/semantic context. I would suggest maybe `CCC_TopLevelOrExpression`? Comment at: clang/lib/Interpreter/InterpreterCodeCompletion.cpp:72 + break; +default: + break; (up to you, but default between cases seems surprising) Comment at: clang/lib/Parse/ParseDecl.cpp:6648 if (Tok.is(tok::l_paren)) { + if (PP.isIncrementalProcessingEnabled() && + NextToken().is(tok::code_completion)) { AIUI, all code completion actions should be ignoring errors, and we should always be happy to cut off parsing and give up as soon as the completion token is reached. So why do we need special handling for incremental processing here? (i.e. what behavior do non-repl users see here - if it's correct can clang-repl do the same, if it's wrong why don't we fix both?) Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D154382: [ClangRepl] support code completion at a REPL
capfredf updated this revision to Diff 549760. capfredf added a comment. format Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 Files: clang/include/clang/Frontend/ASTUnit.h clang/include/clang/Interpreter/InterpreterCodeCompletion.h clang/include/clang/Sema/CodeCompleteConsumer.h clang/include/clang/Sema/Sema.h clang/lib/Frontend/ASTUnit.cpp clang/lib/Interpreter/CMakeLists.txt clang/lib/Interpreter/IncrementalParser.cpp clang/lib/Interpreter/IncrementalParser.h clang/lib/Interpreter/Interpreter.cpp clang/lib/Interpreter/InterpreterCodeCompletion.cpp clang/lib/Parse/ParseDecl.cpp clang/lib/Parse/Parser.cpp clang/lib/Sema/CodeCompleteConsumer.cpp clang/lib/Sema/SemaCodeComplete.cpp clang/test/CodeCompletion/incrememal-mode-completion-no-error.cpp clang/test/CodeCompletion/incremental-top-level.cpp clang/tools/clang-repl/ClangRepl.cpp clang/tools/libclang/CIndexCodeCompletion.cpp clang/unittests/Interpreter/CMakeLists.txt clang/unittests/Interpreter/CodeCompletionTest.cpp Index: clang/unittests/Interpreter/CodeCompletionTest.cpp === --- /dev/null +++ clang/unittests/Interpreter/CodeCompletionTest.cpp @@ -0,0 +1,101 @@ +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Interpreter/Interpreter.h" +#include "clang/Interpreter/InterpreterCodeCompletion.h" +#include "clang/Sema/CodeCompleteConsumer.h" +#include "llvm/LineEditor/LineEditor.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/raw_ostream.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using namespace clang; +namespace { +auto CB = clang::IncrementalCompilerBuilder(); + +static std::unique_ptr createInterpreter() { + auto CI = cantFail(CB.CreateCpp()); + return cantFail(clang::Interpreter::create(std::move(CI))); +} + +static std::vector runComp(clang::Interpreter &MainInterp, +llvm::StringRef Prefix, +llvm::Error &ErrR) { + auto CI = CB.CreateCpp(); + if (auto Err = CI.takeError()) { +ErrR = std::move(Err); +return {}; + } + + auto Interp = clang::Interpreter::create(std::move(*CI)); + if (auto Err = Interp.takeError()) { +// log the error and returns an empty vector; +ErrR = std::move(Err); + +return {}; + } + + std::vector Results; + + codeComplete( + const_cast((*Interp)->getCompilerInstance()), + Prefix, 1, Prefix.size(), MainInterp.getCompilerInstance(), Results); + + std::vector Comps; + for (auto c : ConvertToCodeCompleteStrings(Results)) { +if (c.startswith(Prefix)) + Comps.push_back(c.substr(Prefix.size()).str()); + } + + return Comps; +} + +TEST(CodeCompletionTest, Sanity) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "f", Err); + EXPECT_EQ((size_t)2, comps.size()); // foo and float + EXPECT_EQ(comps[0], std::string("oo")); + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, SanityNoneValid) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "babanana", Err); + EXPECT_EQ((size_t)0, comps.size()); // foo and float + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, TwoDecls) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int application = 12;")) { +consumeError(std::move(R)); +return; + } + if (auto R = Interp->ParseAndExecute("int apple = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "app", Err); + EXPECT_EQ((size_t)2, comps.size()); + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, CompFunDeclsNoError) { + auto Interp = createInterpreter(); + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "void app(", Err); + EXPECT_EQ((bool)Err, false); +} + +} // anonymous namespace Index: clang/unittests/Interpreter/CMakeLists.txt === --- clang/unittests/Interpreter/CMakeLists.txt +++ clang/unittests/Interpreter/CMakeLists.txt @@ -9,6 +9,7 @@ add_clang_unittest(ClangReplInterpreterTests IncrementalProcessingTest.cpp InterpreterTest.cpp + CodeCompletionTest.cpp ) target_link_libraries(ClangReplInterpreterTests PUBLIC clangAST Index: clang/tools/libclang/CIndexCodeCompletion.cpp === --- clang/tools/libclang/CIndexCodeCompletion.cpp +++ clang/tools/libclang/CIndexCodeCompletion.cpp @@ -11,8 +11,8 @@ // //===--
[PATCH] D154382: [ClangRepl] support code completion at a REPL
capfredf updated this revision to Diff 549759. capfredf added a comment. move everything into InterpreterCodeCompletion. the entry point for code completion is now a function, codeCompletion Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 Files: clang/include/clang/Frontend/ASTUnit.h clang/include/clang/Interpreter/InterpreterCodeCompletion.h clang/include/clang/Sema/CodeCompleteConsumer.h clang/include/clang/Sema/Sema.h clang/lib/Frontend/ASTUnit.cpp clang/lib/Interpreter/CMakeLists.txt clang/lib/Interpreter/IncrementalParser.cpp clang/lib/Interpreter/IncrementalParser.h clang/lib/Interpreter/Interpreter.cpp clang/lib/Interpreter/InterpreterCodeCompletion.cpp clang/lib/Parse/ParseDecl.cpp clang/lib/Parse/Parser.cpp clang/lib/Sema/CodeCompleteConsumer.cpp clang/lib/Sema/SemaCodeComplete.cpp clang/test/CodeCompletion/incrememal-mode-completion-no-error.cpp clang/test/CodeCompletion/incremental-top-level.cpp clang/tools/clang-repl/ClangRepl.cpp clang/tools/libclang/CIndexCodeCompletion.cpp clang/unittests/Interpreter/CMakeLists.txt clang/unittests/Interpreter/CodeCompletionTest.cpp Index: clang/unittests/Interpreter/CodeCompletionTest.cpp === --- /dev/null +++ clang/unittests/Interpreter/CodeCompletionTest.cpp @@ -0,0 +1,101 @@ +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Interpreter/Interpreter.h" +#include "clang/Interpreter/InterpreterCodeCompletion.h" +#include "clang/Sema/CodeCompleteConsumer.h" +#include "llvm/LineEditor/LineEditor.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/raw_ostream.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using namespace clang; +namespace { +auto CB = clang::IncrementalCompilerBuilder(); + +static std::unique_ptr createInterpreter() { + auto CI = cantFail(CB.CreateCpp()); + return cantFail(clang::Interpreter::create(std::move(CI))); +} + +static std::vector runComp(clang::Interpreter &MainInterp, +llvm::StringRef Prefix, +llvm::Error &ErrR) { + auto CI = CB.CreateCpp(); + if (auto Err = CI.takeError()) { +ErrR = std::move(Err); +return {}; + } + + auto Interp = clang::Interpreter::create(std::move(*CI)); + if (auto Err = Interp.takeError()) { +// log the error and returns an empty vector; +ErrR = std::move(Err); + +return {}; + } + + std::vector Results; + + codeComplete( + const_cast((*Interp)->getCompilerInstance()), + Prefix, 1, Prefix.size(), MainInterp.getCompilerInstance(), Results); + + std::vector Comps; + for (auto c : ConvertToCodeCompleteStrings(Results)) { +if (c.startswith(Prefix)) + Comps.push_back(c.substr(Prefix.size()).str()); + } + + return Comps; +} + +TEST(CodeCompletionTest, Sanity) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "f", Err); + EXPECT_EQ((size_t)2, comps.size()); // foo and float + EXPECT_EQ(comps[0], std::string("oo")); + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, SanityNoneValid) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "babanana", Err); + EXPECT_EQ((size_t)0, comps.size()); // foo and float + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, TwoDecls) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int application = 12;")) { +consumeError(std::move(R)); +return; + } + if (auto R = Interp->ParseAndExecute("int apple = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "app", Err); + EXPECT_EQ((size_t)2, comps.size()); + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, CompFunDeclsNoError) { + auto Interp = createInterpreter(); + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "void app(", Err); + EXPECT_EQ((bool)Err, false); +} + +} // anonymous namespace Index: clang/unittests/Interpreter/CMakeLists.txt === --- clang/unittests/Interpreter/CMakeLists.txt +++ clang/unittests/Interpreter/CMakeLists.txt @@ -9,6 +9,7 @@ add_clang_unittest(ClangReplInterpreterTests IncrementalProcessingTest.cpp InterpreterTest.cpp + CodeCompletionTest.cpp ) target_link_libraries(ClangReplInterpreterTests PUBLIC clangAST Index: clang/tools/libclang/CIndexCodeCompletion.cpp === --- clang/tools/libclang/CIndexCod
[PATCH] D154382: [ClangRepl] support code completion at a REPL
v.g.vassilev added inline comments. Comment at: clang/lib/Interpreter/CodeCompletion.cpp:1 +//===-- CodeCompletion.cpp - Code Completion for ClangRepl ---===// +// I would propose to rename this file to `InterpreterCodeCompletion.cpp` and implement the `Interpreter::codeComplete` interface. Then we can move all of the content of `ExternalSource.{h,cpp}`, `CodeCompletion.h` and `ExternalSource.h` in it. That will increase the encapsulation of the code. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D154382: [ClangRepl] support code completion at a REPL
capfredf updated this revision to Diff 549751. capfredf added a comment. use auto Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 Files: clang/include/clang/Frontend/ASTUnit.h clang/include/clang/Interpreter/CodeCompletion.h clang/include/clang/Interpreter/ExternalSource.h clang/include/clang/Interpreter/Interpreter.h clang/include/clang/Sema/CodeCompleteConsumer.h clang/include/clang/Sema/Sema.h clang/lib/Frontend/ASTUnit.cpp clang/lib/Interpreter/CMakeLists.txt clang/lib/Interpreter/CodeCompletion.cpp clang/lib/Interpreter/DeviceOffload.cpp clang/lib/Interpreter/ExternalSource.cpp clang/lib/Interpreter/ExternalSource.h clang/lib/Interpreter/IncrementalParser.cpp clang/lib/Interpreter/IncrementalParser.h clang/lib/Interpreter/Interpreter.cpp clang/lib/Parse/ParseDecl.cpp clang/lib/Parse/Parser.cpp clang/lib/Sema/CodeCompleteConsumer.cpp clang/lib/Sema/SemaCodeComplete.cpp clang/test/CodeCompletion/incrememal-mode-completion-no-error.cpp clang/test/CodeCompletion/incremental-top-level.cpp clang/tools/clang-repl/ClangRepl.cpp clang/tools/libclang/CIndexCodeCompletion.cpp clang/unittests/Interpreter/CMakeLists.txt clang/unittests/Interpreter/CodeCompletionTest.cpp Index: clang/unittests/Interpreter/CodeCompletionTest.cpp === --- /dev/null +++ clang/unittests/Interpreter/CodeCompletionTest.cpp @@ -0,0 +1,100 @@ +#include "clang/Interpreter/CodeCompletion.h" +#include "clang/Interpreter/Interpreter.h" + +#include "clang/Frontend/CompilerInstance.h" +#include "llvm/LineEditor/LineEditor.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/raw_ostream.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using namespace clang; +namespace { +auto CB = clang::IncrementalCompilerBuilder(); + +static std::unique_ptr createInterpreter() { + auto CI = cantFail(CB.CreateCpp()); + return cantFail(clang::Interpreter::create(std::move(CI))); +} + +static std::vector runComp(clang::Interpreter &MainInterp, +llvm::StringRef Prefix, +llvm::Error &ErrR) { + auto CI = CB.CreateCpp(); + if (auto Err = CI.takeError()) { +ErrR = std::move(Err); +return {}; + } + + auto Interp = clang::Interpreter::create(std::move(*CI)); + if (auto Err = Interp.takeError()) { +// log the error and returns an empty vector; +ErrR = std::move(Err); + +return {}; + } + + std::vector Results; + + (*Interp)->codeComplete(Prefix, 1, Prefix.size(), + MainInterp.getCompilerInstance(), Results); + + std::vector Comps; + for (auto c : ConvertToCodeCompleteStrings(Results)) { +if (c.startswith(Prefix)) + Comps.push_back(c.substr(Prefix.size()).str()); + } + + return Comps; +} + +TEST(CodeCompletionTest, Sanity) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "f", Err); + EXPECT_EQ((size_t)2, comps.size()); // foo and float + EXPECT_EQ(comps[0], std::string("oo")); + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, SanityNoneValid) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "babanana", Err); + EXPECT_EQ((size_t)0, comps.size()); // foo and float + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, TwoDecls) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int application = 12;")) { +consumeError(std::move(R)); +return; + } + if (auto R = Interp->ParseAndExecute("int apple = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "app", Err); + EXPECT_EQ((size_t)2, comps.size()); + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, CompFunDeclsNoError) { + auto Interp = createInterpreter(); + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "void app(", Err); + EXPECT_EQ((bool)Err, false); +} + +} // anonymous namespace Index: clang/unittests/Interpreter/CMakeLists.txt === --- clang/unittests/Interpreter/CMakeLists.txt +++ clang/unittests/Interpreter/CMakeLists.txt @@ -9,6 +9,7 @@ add_clang_unittest(ClangReplInterpreterTests IncrementalProcessingTest.cpp InterpreterTest.cpp + CodeCompletionTest.cpp ) target_link_libraries(ClangReplInterpreterTests PUBLIC clangAST Index: clang/tools/libclang/CIndexCodeCompletion.cpp === --- clang/tools/lib
[PATCH] D154382: [ClangRepl] support code completion at a REPL
capfredf updated this revision to Diff 549750. capfredf added a comment. up Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 Files: clang/include/clang/Frontend/ASTUnit.h clang/include/clang/Interpreter/CodeCompletion.h clang/include/clang/Interpreter/ExternalSource.h clang/include/clang/Interpreter/Interpreter.h clang/include/clang/Sema/CodeCompleteConsumer.h clang/include/clang/Sema/Sema.h clang/lib/Frontend/ASTUnit.cpp clang/lib/Interpreter/CMakeLists.txt clang/lib/Interpreter/CodeCompletion.cpp clang/lib/Interpreter/DeviceOffload.cpp clang/lib/Interpreter/ExternalSource.cpp clang/lib/Interpreter/ExternalSource.h clang/lib/Interpreter/IncrementalParser.cpp clang/lib/Interpreter/IncrementalParser.h clang/lib/Interpreter/Interpreter.cpp clang/lib/Parse/ParseDecl.cpp clang/lib/Parse/Parser.cpp clang/lib/Sema/CodeCompleteConsumer.cpp clang/lib/Sema/SemaCodeComplete.cpp clang/test/CodeCompletion/incrememal-mode-completion-no-error.cpp clang/test/CodeCompletion/incremental-top-level.cpp clang/tools/clang-repl/ClangRepl.cpp clang/tools/libclang/CIndexCodeCompletion.cpp clang/unittests/Interpreter/CMakeLists.txt clang/unittests/Interpreter/CodeCompletionTest.cpp Index: clang/unittests/Interpreter/CodeCompletionTest.cpp === --- /dev/null +++ clang/unittests/Interpreter/CodeCompletionTest.cpp @@ -0,0 +1,100 @@ +#include "clang/Interpreter/CodeCompletion.h" +#include "clang/Interpreter/Interpreter.h" + +#include "clang/Frontend/CompilerInstance.h" +#include "llvm/LineEditor/LineEditor.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/raw_ostream.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using namespace clang; +namespace { +auto CB = clang::IncrementalCompilerBuilder(); + +static std::unique_ptr createInterpreter() { + auto CI = cantFail(CB.CreateCpp()); + return cantFail(clang::Interpreter::create(std::move(CI))); +} + +static std::vector runComp(clang::Interpreter &MainInterp, +llvm::StringRef Prefix, +llvm::Error &ErrR) { + auto CI = CB.CreateCpp(); + if (auto Err = CI.takeError()) { +ErrR = std::move(Err); +return {}; + } + + auto Interp = clang::Interpreter::create(std::move(*CI)); + if (auto Err = Interp.takeError()) { +// log the error and returns an empty vector; +ErrR = std::move(Err); + +return {}; + } + + std::vector Results; + + (*Interp)->codeComplete(Prefix, 1, Prefix.size(), + MainInterp.getCompilerInstance(), Results); + + std::vector Comps; + for (auto c : ConvertToCodeCompleteStrings(Results)) { +if (c.startswith(Prefix)) + Comps.push_back(c.substr(Prefix.size()).str()); + } + + return Comps; +} + +TEST(CodeCompletionTest, Sanity) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "f", Err); + EXPECT_EQ((size_t)2, comps.size()); // foo and float + EXPECT_EQ(comps[0], std::string("oo")); + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, SanityNoneValid) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "babanana", Err); + EXPECT_EQ((size_t)0, comps.size()); // foo and float + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, TwoDecls) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int application = 12;")) { +consumeError(std::move(R)); +return; + } + if (auto R = Interp->ParseAndExecute("int apple = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "app", Err); + EXPECT_EQ((size_t)2, comps.size()); + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, CompFunDeclsNoError) { + auto Interp = createInterpreter(); + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "void app(", Err); + EXPECT_EQ((bool)Err, false); +} + +} // anonymous namespace Index: clang/unittests/Interpreter/CMakeLists.txt === --- clang/unittests/Interpreter/CMakeLists.txt +++ clang/unittests/Interpreter/CMakeLists.txt @@ -9,6 +9,7 @@ add_clang_unittest(ClangReplInterpreterTests IncrementalProcessingTest.cpp InterpreterTest.cpp + CodeCompletionTest.cpp ) target_link_libraries(ClangReplInterpreterTests PUBLIC clangAST Index: clang/tools/libclang/CIndexCodeCompletion.cpp === --- clang/tools/libclang/
[PATCH] D154382: [ClangRepl] support code completion at a REPL
capfredf updated this revision to Diff 549749. capfredf added a comment. up Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 Files: clang/include/clang/Frontend/ASTUnit.h clang/include/clang/Interpreter/CodeCompletion.h clang/include/clang/Interpreter/ExternalSource.h clang/include/clang/Interpreter/Interpreter.h clang/include/clang/Sema/CodeCompleteConsumer.h clang/include/clang/Sema/Sema.h clang/lib/Frontend/ASTUnit.cpp clang/lib/Interpreter/CMakeLists.txt clang/lib/Interpreter/CodeCompletion.cpp clang/lib/Interpreter/DeviceOffload.cpp clang/lib/Interpreter/ExternalSource.cpp clang/lib/Interpreter/ExternalSource.h clang/lib/Interpreter/IncrementalParser.cpp clang/lib/Interpreter/IncrementalParser.h clang/lib/Interpreter/Interpreter.cpp clang/lib/Parse/ParseDecl.cpp clang/lib/Parse/Parser.cpp clang/lib/Sema/CodeCompleteConsumer.cpp clang/lib/Sema/SemaCodeComplete.cpp clang/test/CodeCompletion/incrememal-mode-completion-no-error.cpp clang/test/CodeCompletion/incremental-top-level.cpp clang/tools/clang-repl/ClangRepl.cpp clang/tools/libclang/CIndexCodeCompletion.cpp clang/unittests/Interpreter/CMakeLists.txt clang/unittests/Interpreter/CodeCompletionTest.cpp Index: clang/unittests/Interpreter/CodeCompletionTest.cpp === --- /dev/null +++ clang/unittests/Interpreter/CodeCompletionTest.cpp @@ -0,0 +1,100 @@ +#include "clang/Interpreter/CodeCompletion.h" +#include "clang/Interpreter/Interpreter.h" + +#include "clang/Frontend/CompilerInstance.h" +#include "llvm/LineEditor/LineEditor.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/raw_ostream.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using namespace clang; +namespace { +auto CB = clang::IncrementalCompilerBuilder(); + +static std::unique_ptr createInterpreter() { + auto CI = cantFail(CB.CreateCpp()); + return cantFail(clang::Interpreter::create(std::move(CI))); +} + +static std::vector runComp(clang::Interpreter &MainInterp, +llvm::StringRef Prefix, +llvm::Error &ErrR) { + auto CI = CB.CreateCpp(); + if (auto Err = CI.takeError()) { +ErrR = std::move(Err); +return {}; + } + + auto Interp = clang::Interpreter::create(std::move(*CI)); + if (auto Err = Interp.takeError()) { +// log the error and returns an empty vector; +ErrR = std::move(Err); + +return {}; + } + + std::vector Results; + + (*Interp)->codeComplete(Prefix, 1, Prefix.size(), + MainInterp.getCompilerInstance(), Results); + + std::vector Comps; + for (auto c : ConvertToCodeCompleteStrings(Results)) { +if (c.startswith(Prefix)) + Comps.push_back(c.substr(Prefix.size()).str()); + } + + return Comps; +} + +TEST(CodeCompletionTest, Sanity) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "f", Err); + EXPECT_EQ((size_t)2, comps.size()); // foo and float + EXPECT_EQ(comps[0], std::string("oo")); + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, SanityNoneValid) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "babanana", Err); + EXPECT_EQ((size_t)0, comps.size()); // foo and float + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, TwoDecls) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int application = 12;")) { +consumeError(std::move(R)); +return; + } + if (auto R = Interp->ParseAndExecute("int apple = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "app", Err); + EXPECT_EQ((size_t)2, comps.size()); + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, CompFunDeclsNoError) { + auto Interp = createInterpreter(); + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "void app(", Err); + EXPECT_EQ((bool)Err, false); +} + +} // anonymous namespace Index: clang/unittests/Interpreter/CMakeLists.txt === --- clang/unittests/Interpreter/CMakeLists.txt +++ clang/unittests/Interpreter/CMakeLists.txt @@ -9,6 +9,7 @@ add_clang_unittest(ClangReplInterpreterTests IncrementalProcessingTest.cpp InterpreterTest.cpp + CodeCompletionTest.cpp ) target_link_libraries(ClangReplInterpreterTests PUBLIC clangAST Index: clang/tools/libclang/CIndexCodeCompletion.cpp === --- clang/tools/libclang/
[PATCH] D154382: [ClangRepl] support code completion at a REPL
v.g.vassilev added a reviewer: sammccall. v.g.vassilev added a subscriber: sammccall. v.g.vassilev added a comment. This looks mostly good to me. I noticed that @sammccall has done some work in that area in clangd and I was wondering if he has some thoughts about this patch. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D154382: [ClangRepl] support code completion at a REPL
v.g.vassilev added inline comments. Comment at: clang/lib/Interpreter/IncrementalParser.h:91 + +class IncrementalSyntaxOnlyAction : public SyntaxOnlyAction { + const CompilerInstance *ParentCI; Can we not move this class definition locally to the CodeComplete interface? Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D154382: [ClangRepl] support code completion at a REPL
capfredf updated this revision to Diff 549739. capfredf added a comment. Herald added a subscriber: ChuanqiXu. changes per discussions Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 Files: clang/include/clang/Frontend/ASTUnit.h clang/include/clang/Interpreter/CodeCompletion.h clang/include/clang/Interpreter/ExternalSource.h clang/include/clang/Interpreter/Interpreter.h clang/include/clang/Sema/CodeCompleteConsumer.h clang/include/clang/Sema/Sema.h clang/lib/Frontend/ASTUnit.cpp clang/lib/Interpreter/CMakeLists.txt clang/lib/Interpreter/CodeCompletion.cpp clang/lib/Interpreter/DeviceOffload.cpp clang/lib/Interpreter/ExternalSource.cpp clang/lib/Interpreter/ExternalSource.h clang/lib/Interpreter/IncrementalParser.cpp clang/lib/Interpreter/IncrementalParser.h clang/lib/Interpreter/Interpreter.cpp clang/lib/Parse/ParseDecl.cpp clang/lib/Parse/Parser.cpp clang/lib/Sema/CodeCompleteConsumer.cpp clang/lib/Sema/SemaCodeComplete.cpp clang/test/CodeCompletion/incrememal-mode-completion-no-error.cpp clang/test/CodeCompletion/incremental-top-level.cpp clang/tools/clang-repl/ClangRepl.cpp clang/tools/libclang/CIndexCodeCompletion.cpp clang/unittests/Interpreter/CMakeLists.txt clang/unittests/Interpreter/CodeCompletionTest.cpp Index: clang/unittests/Interpreter/CodeCompletionTest.cpp === --- /dev/null +++ clang/unittests/Interpreter/CodeCompletionTest.cpp @@ -0,0 +1,100 @@ +#include "clang/Interpreter/CodeCompletion.h" +#include "clang/Interpreter/Interpreter.h" + +#include "clang/Frontend/CompilerInstance.h" +#include "llvm/LineEditor/LineEditor.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/raw_ostream.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using namespace clang; +namespace { +auto CB = clang::IncrementalCompilerBuilder(); + +static std::unique_ptr createInterpreter() { + auto CI = cantFail(CB.CreateCpp()); + return cantFail(clang::Interpreter::create(std::move(CI))); +} + +static std::vector runComp(clang::Interpreter &MainInterp, +llvm::StringRef Prefix, +llvm::Error &ErrR) { + auto CI = CB.CreateCpp(); + if (auto Err = CI.takeError()) { +ErrR = std::move(Err); +return {}; + } + + + auto Interp = clang::Interpreter::create(std::move(*CI)); + if (auto Err = Interp.takeError()) { +// log the error and returns an empty vector; +ErrR = std::move(Err); + +return {}; + } + + std::vector Results; + + (*Interp)->codeComplete(Prefix, Prefix.size(), MainInterp.getCompilerInstance(), Results); + + std::vector Comps; + for (auto c : ConvertToCodeCompleteStrings(Results)) { +if (c.startswith(Prefix)) + Comps.push_back(c.substr(Prefix.size()).str()); + } + + return Comps; +} + +TEST(CodeCompletionTest, Sanity) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "f", Err); + EXPECT_EQ((size_t)2, comps.size()); // foo and float + EXPECT_EQ(comps[0], std::string("oo")); + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, SanityNoneValid) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "babanana", Err); + EXPECT_EQ((size_t)0, comps.size()); // foo and float + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, TwoDecls) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int application = 12;")) { +consumeError(std::move(R)); +return; + } + if (auto R = Interp->ParseAndExecute("int apple = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "app", Err); + EXPECT_EQ((size_t)2, comps.size()); + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, CompFunDeclsNoError) { + auto Interp = createInterpreter(); + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "void app(", Err); + EXPECT_EQ((bool)Err, false); +} + +} // anonymous namespace Index: clang/unittests/Interpreter/CMakeLists.txt === --- clang/unittests/Interpreter/CMakeLists.txt +++ clang/unittests/Interpreter/CMakeLists.txt @@ -9,6 +9,7 @@ add_clang_unittest(ClangReplInterpreterTests IncrementalProcessingTest.cpp InterpreterTest.cpp + CodeCompletionTest.cpp ) target_link_libraries(ClangReplInterpreterTests PUBLIC clangAST Index: clang/tools/libclang/CIndexCodeCompletion.cpp ==
[PATCH] D154382: [ClangRepl] support code completion at a REPL
capfredf added inline comments. Comment at: clang/include/clang/Frontend/ASTUnit.h:901 +SmallVectorImpl &OwnedBuffers, +std::function AfterBeginSourceFile = [](CompilerInstance& CI) -> void {}); @v.g.vassilev Not sure if this is the right solution or idiom to extend this method. we can make this high order function more general, like `std::unique_ptr<()>` Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D154382: [ClangRepl] support code completion at a REPL
capfredf updated this revision to Diff 549658. capfredf added a comment. use ASTUnit::codeComplete Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 Files: clang/include/clang/Frontend/ASTUnit.h clang/include/clang/Interpreter/CodeCompletion.h clang/include/clang/Interpreter/ExternalSource.h clang/include/clang/Interpreter/Interpreter.h clang/include/clang/Sema/CodeCompleteConsumer.h clang/include/clang/Sema/Sema.h clang/lib/Frontend/ASTUnit.cpp clang/lib/Interpreter/CMakeLists.txt clang/lib/Interpreter/CodeCompletion.cpp clang/lib/Interpreter/DeviceOffload.cpp clang/lib/Interpreter/ExternalSource.cpp clang/lib/Interpreter/ExternalSource.h clang/lib/Interpreter/IncrementalParser.cpp clang/lib/Interpreter/IncrementalParser.h clang/lib/Interpreter/Interpreter.cpp clang/lib/Parse/ParseDecl.cpp clang/lib/Parse/Parser.cpp clang/lib/Sema/CodeCompleteConsumer.cpp clang/lib/Sema/SemaCodeComplete.cpp clang/test/CodeCompletion/incrememal-mode-completion-no-error.cpp clang/test/CodeCompletion/incremental-top-level.cpp clang/tools/clang-repl/ClangRepl.cpp clang/tools/libclang/CIndexCodeCompletion.cpp clang/unittests/Interpreter/CMakeLists.txt clang/unittests/Interpreter/CodeCompletionTest.cpp Index: clang/unittests/Interpreter/CodeCompletionTest.cpp === --- /dev/null +++ clang/unittests/Interpreter/CodeCompletionTest.cpp @@ -0,0 +1,100 @@ +#include "clang/Interpreter/CodeCompletion.h" +#include "clang/Interpreter/Interpreter.h" + +#include "clang/Frontend/CompilerInstance.h" +#include "llvm/LineEditor/LineEditor.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/raw_ostream.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using namespace clang; +namespace { +auto CB = clang::IncrementalCompilerBuilder(); + +static std::unique_ptr createInterpreter() { + auto CI = cantFail(CB.CreateCpp()); + return cantFail(clang::Interpreter::create(std::move(CI))); +} + +static std::vector runComp(clang::Interpreter &MainInterp, +llvm::StringRef Prefix, +llvm::Error &ErrR) { + auto CI = CB.CreateCpp(); + if (auto Err = CI.takeError()) { +ErrR = std::move(Err); +return {}; + } + + + auto Interp = clang::Interpreter::create(std::move(*CI)); + if (auto Err = Interp.takeError()) { +// log the error and returns an empty vector; +ErrR = std::move(Err); + +return {}; + } + + std::vector Results; + + (*Interp)->codeComplete(Prefix, Prefix.size(), MainInterp.getCompilerInstance(), Results); + + std::vector Comps; + for (auto c : ConvertToCodeCompleteStrings(Results)) { +if (c.startswith(Prefix)) + Comps.push_back(c.substr(Prefix.size()).str()); + } + + return Comps; +} + +TEST(CodeCompletionTest, Sanity) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "f", Err); + EXPECT_EQ((size_t)2, comps.size()); // foo and float + EXPECT_EQ(comps[0], std::string("oo")); + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, SanityNoneValid) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "babanana", Err); + EXPECT_EQ((size_t)0, comps.size()); // foo and float + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, TwoDecls) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int application = 12;")) { +consumeError(std::move(R)); +return; + } + if (auto R = Interp->ParseAndExecute("int apple = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "app", Err); + EXPECT_EQ((size_t)2, comps.size()); + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, CompFunDeclsNoError) { + auto Interp = createInterpreter(); + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "void app(", Err); + EXPECT_EQ((bool)Err, false); +} + +} // anonymous namespace Index: clang/unittests/Interpreter/CMakeLists.txt === --- clang/unittests/Interpreter/CMakeLists.txt +++ clang/unittests/Interpreter/CMakeLists.txt @@ -9,6 +9,7 @@ add_clang_unittest(ClangReplInterpreterTests IncrementalProcessingTest.cpp InterpreterTest.cpp + CodeCompletionTest.cpp ) target_link_libraries(ClangReplInterpreterTests PUBLIC clangAST Index: clang/tools/libclang/CIndexCodeCompletion.cpp === --- clang/tools/libclang/CInde
[PATCH] D154382: [ClangRepl] support code completion at a REPL
capfredf updated this revision to Diff 547241. capfredf marked 2 inline comments as done. capfredf added a comment. changes per discussions Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 Files: clang/include/clang/Interpreter/CodeCompletion.h clang/include/clang/Interpreter/Interpreter.h clang/include/clang/Sema/CodeCompleteConsumer.h clang/include/clang/Sema/Sema.h clang/lib/Frontend/ASTUnit.cpp clang/lib/Interpreter/CMakeLists.txt clang/lib/Interpreter/CodeCompletion.cpp clang/lib/Interpreter/DeviceOffload.cpp clang/lib/Interpreter/ExternalSource.cpp clang/lib/Interpreter/ExternalSource.h clang/lib/Interpreter/IncrementalParser.cpp clang/lib/Interpreter/IncrementalParser.h clang/lib/Interpreter/Interpreter.cpp clang/lib/Parse/ParseDecl.cpp clang/lib/Parse/Parser.cpp clang/lib/Sema/CodeCompleteConsumer.cpp clang/lib/Sema/SemaCodeComplete.cpp clang/test/CodeCompletion/incrememal-mode-completion-no-error.cpp clang/test/CodeCompletion/incremental-top-level.cpp clang/tools/clang-repl/ClangRepl.cpp clang/tools/libclang/CIndexCodeCompletion.cpp clang/unittests/Interpreter/CMakeLists.txt clang/unittests/Interpreter/CodeCompletionTest.cpp clang/unittests/Interpreter/IncrementalProcessingTest.cpp clang/unittests/Interpreter/InterpreterTest.cpp Index: clang/unittests/Interpreter/InterpreterTest.cpp === --- clang/unittests/Interpreter/InterpreterTest.cpp +++ clang/unittests/Interpreter/InterpreterTest.cpp @@ -41,6 +41,7 @@ namespace { using Args = std::vector; + static std::unique_ptr createInterpreter(const Args &ExtraArgs = {}, DiagnosticConsumer *Client = nullptr) { Index: clang/unittests/Interpreter/IncrementalProcessingTest.cpp === --- clang/unittests/Interpreter/IncrementalProcessingTest.cpp +++ clang/unittests/Interpreter/IncrementalProcessingTest.cpp @@ -55,6 +55,7 @@ auto CB = clang::IncrementalCompilerBuilder(); CB.SetCompilerArgs(ClangArgv); auto CI = cantFail(CB.CreateCpp()); + auto Interp = llvm::cantFail(Interpreter::create(std::move(CI))); std::array PTUs; Index: clang/unittests/Interpreter/CodeCompletionTest.cpp === --- /dev/null +++ clang/unittests/Interpreter/CodeCompletionTest.cpp @@ -0,0 +1,107 @@ +#include "clang/Interpreter/CodeCompletion.h" +#include "clang/Interpreter/Interpreter.h" + +#include "clang/Frontend/CompilerInstance.h" +#include "llvm/LineEditor/LineEditor.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/raw_ostream.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using namespace clang; +namespace { +auto CB = clang::IncrementalCompilerBuilder(); + +static std::unique_ptr createInterpreter() { + auto CI = cantFail(CB.CreateCpp()); + return cantFail(clang::Interpreter::create(std::move(CI))); +} + +static std::vector runComp(clang::Interpreter &MainInterp, +llvm::StringRef Prefix, +llvm::Error &ErrR) { + std::vector Results; + auto CI = CB.CreateCpp(); + if (auto Err = CI.takeError()) { +ErrR = std::move(Err); +return {}; + } + + size_t Lines = std::count(Prefix.begin(), Prefix.end(), '\n') + 1; + auto CFG = clang::CodeCompletionCfg{ + Prefix.size(), Lines, + const_cast(MainInterp.getCompilerInstance()), + Results}; + + auto Interp = clang::Interpreter::create(std::move(*CI), CFG); + if (auto Err = Interp.takeError()) { +// log the error and returns an empty vector; +ErrR = std::move(Err); + +return {}; + } + + if (auto PTU = (*Interp)->Parse(Prefix); !PTU) { +ErrR = std::move(PTU.takeError()); +return {}; + } + + std::vector Comps; + for (auto c : ConvertToCodeCompleteStrings(Results)) { +if (c.startswith(Prefix)) + Comps.push_back(c.substr(Prefix.size()).str()); + } + + return Comps; +} + +TEST(CodeCompletionTest, Sanity) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "f", Err); + EXPECT_EQ((size_t)2, comps.size()); // foo and float + EXPECT_EQ(comps[0], std::string("oo")); + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, SanityNoneValid) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Err = llvm::Error::success(); + auto comps = runComp(*Interp, "babanana", Err); + EXPECT_EQ((size_t)0, comps.size()); // foo and float + EXPECT_EQ((bool)Err, false); +} + +TEST(CodeCompletionTest, TwoDecls) { + auto Interp = createInterpreter(); + if (auto
[PATCH] D154382: [ClangRepl] support code completion at a REPL
capfredf marked 5 inline comments as done. capfredf added inline comments. Comment at: clang/lib/Interpreter/CodeCompletion.cpp:111 + auto *CConsumer = new ReplCompletionConsumer(Results); + auto Interp = Interpreter::createForCodeCompletion( + CB, MainInterp.getCompilerInstance(), CConsumer); v.g.vassilev wrote: > I do not believe we need a spe I am not sure I am following. For a regular interpreter, create Interpreter -> create Incremental Parser -> IncrmentalASTAction triggered -> set a default code completion consumer(PrintCodeCompletionConsumer) to CI if no code consumer has been set -> Sema initialized. Based on this logic, we need to provide our CodeConsumer so that IncrementalASTAction does not create the default, plus we need to a parent CI to a new code completion interpreter. I don't see how we can avoid a special code path for creation Comment at: clang/lib/Interpreter/IncrementalParser.cpp:324 -llvm::Expected -IncrementalParser::Parse(llvm::StringRef input) { +llvm::Error IncrementalParser::ParseForCodeCompletion(llvm::StringRef input, + size_t Col, size_t Line) { v.g.vassilev wrote: > Is there any other particular reason for this routine to be different rather > than `PP.SetCodeCompletionPoint(*FE, Line, Col)`? That is, can we merge back > the old code and only set the point of completion externally? The regular `Parse` does some lexing after parsing, which I don't think is necessary for code completion. Also, this is more or less because, as a functional programmer, I prefer building things using small functions with explicit arguments. I'll try if I can use the old parse with the completion point set and tested. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D154382: [ClangRepl] support code completion at a REPL
v.g.vassilev added a comment. I think we are getting there. I added a few suggestions how to improve the current design. Comment at: clang/include/clang/Interpreter/CodeCompletion.h:15 +#define LLVM_CLANG_INTERPRETER_CODE_COMPLETION_H +#include "llvm/LineEditor/LineEditor.h" + I still am a bit uncomfortable with relying on a line editor api to address a generic question one could as the interpreter such as "What's visible at that code position"? Can we not make the overloaded operators outside of the `ReplListCompleter` class. That means moving them in ClangRepl.cpp? Comment at: clang/include/clang/Interpreter/Interpreter.h:42 class IncrementalParser; +class CodeCompleteConsumer; We should put that in its alphabetical order. Comment at: clang/lib/Interpreter/CodeCompletion.cpp:111 + auto *CConsumer = new ReplCompletionConsumer(Results); + auto Interp = Interpreter::createForCodeCompletion( + CB, MainInterp.getCompilerInstance(), CConsumer); I do not believe we need a spe Comment at: clang/lib/Interpreter/IncrementalParser.cpp:324 -llvm::Expected -IncrementalParser::Parse(llvm::StringRef input) { +llvm::Error IncrementalParser::ParseForCodeCompletion(llvm::StringRef input, + size_t Col, size_t Line) { Is there any other particular reason for this routine to be different rather than `PP.SetCodeCompletionPoint(*FE, Line, Col)`? That is, can we merge back the old code and only set the point of completion externally? Comment at: clang/lib/Interpreter/Interpreter.cpp:304 +llvm::Expected> +Interpreter::createForCodeCompletion( +IncrementalCompilerBuilder &CB, const CompilerInstance *ParentCI, capfredf wrote: > v.g.vassilev wrote: > > I still do not entirely understand why we can "just" ask the codecompletion > > infrastructure for the possible options at the current position. I know > > that's probably easier set than done but I'd like to entertain that idea > > for a while.. > I'm a bit confused. Can you expand on the suggestion? I do not believe we need a special case for creating a CodeCompletionConsumer. I think we could rely on the logic in `CompilerInstance::createCodeCompletionConsumer` which can be triggered in `IncrementalAction::ExecuteAction` just like in `ASTFrontendAction::ExecuteAction`. We will need to copy some of the code over but then you could start the same interpreter infrastructure with slightly different flags. Comment at: clang/lib/Parse/ParseDecl.cpp:6652 +break; + } + Can we test this change separately outside of clang-repl? That would mean creating a tests and run it with `clang -Xclang -fincremental-extensions` Comment at: clang/lib/Parse/Parser.cpp:934 + PCC = Sema::PCC_Namespace; +}; Actions.CodeCompleteOrdinaryName( Likewise, it would be great if we have a test in clang-only mode. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D154382: [ClangRepl] support code completion at a REPL
capfredf updated this revision to Diff 543000. capfredf added a comment. changes per @v.g.vassilev's comments Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 Files: clang/include/clang/Interpreter/CodeCompletion.h clang/include/clang/Interpreter/Interpreter.h clang/include/clang/Sema/CodeCompleteConsumer.h clang/include/clang/Sema/Sema.h clang/lib/Frontend/ASTUnit.cpp clang/lib/Interpreter/CMakeLists.txt clang/lib/Interpreter/CodeCompletion.cpp clang/lib/Interpreter/ExternalSource.cpp clang/lib/Interpreter/ExternalSource.h clang/lib/Interpreter/IncrementalParser.cpp clang/lib/Interpreter/IncrementalParser.h clang/lib/Interpreter/Interpreter.cpp clang/lib/Parse/ParseDecl.cpp clang/lib/Parse/Parser.cpp clang/lib/Sema/CodeCompleteConsumer.cpp clang/lib/Sema/SemaCodeComplete.cpp clang/tools/clang-repl/ClangRepl.cpp clang/tools/libclang/CIndexCodeCompletion.cpp clang/unittests/Interpreter/CMakeLists.txt clang/unittests/Interpreter/CodeCompletionTest.cpp Index: clang/unittests/Interpreter/CodeCompletionTest.cpp === --- /dev/null +++ clang/unittests/Interpreter/CodeCompletionTest.cpp @@ -0,0 +1,71 @@ +#include "clang/Interpreter/CodeCompletion.h" +#include "clang/Interpreter/Interpreter.h" + +#include "clang/Frontend/CompilerInstance.h" +#include "llvm/LineEditor/LineEditor.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/raw_ostream.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using namespace clang; +namespace { +auto CB = clang::IncrementalCompilerBuilder(); + +static std::unique_ptr createInterpreter() { + auto CI = cantFail(CB.CreateCpp()); + return cantFail(clang::Interpreter::create(std::move(CI))); +} + +TEST(CodeCompletionTest, Sanity) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Completer = ReplListCompleter(CB, *Interp); + std::vector comps = + Completer(std::string("f"), 1); + EXPECT_EQ((size_t)2, comps.size()); // foo and float + EXPECT_EQ(comps[0].TypedText, std::string("oo")); +} + +TEST(CodeCompletionTest, SanityNoneValid) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Completer = ReplListCompleter(CB, *Interp); + std::vector comps = + Completer(std::string("babanana"), 8); + EXPECT_EQ((size_t)0, comps.size()); // foo and float +} + +TEST(CodeCompletionTest, TwoDecls) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int application = 12;")) { +consumeError(std::move(R)); +return; + } + if (auto R = Interp->ParseAndExecute("int apple = 12;")) { +consumeError(std::move(R)); +return; + } + auto Completer = ReplListCompleter(CB, *Interp); + std::vector comps = + Completer(std::string("app"), 3); + EXPECT_EQ((size_t)2, comps.size()); +} + +TEST(CodeCompletionTest, CompFunDeclsNoError) { + auto Interp = createInterpreter(); + auto Completer = ReplListCompleter(CB, *Interp); + auto Err = llvm::Error::success(); + std::vector comps = + Completer(std::string("void app("), 9, Err); + EXPECT_EQ((bool)Err, false); +} + +} // anonymous namespace Index: clang/unittests/Interpreter/CMakeLists.txt === --- clang/unittests/Interpreter/CMakeLists.txt +++ clang/unittests/Interpreter/CMakeLists.txt @@ -9,6 +9,7 @@ add_clang_unittest(ClangReplInterpreterTests IncrementalProcessingTest.cpp InterpreterTest.cpp + CodeCompletionTest.cpp ) target_link_libraries(ClangReplInterpreterTests PUBLIC clangAST Index: clang/tools/libclang/CIndexCodeCompletion.cpp === --- clang/tools/libclang/CIndexCodeCompletion.cpp +++ clang/tools/libclang/CIndexCodeCompletion.cpp @@ -543,6 +543,7 @@ case CodeCompletionContext::CCC_PreprocessorExpression: case CodeCompletionContext::CCC_PreprocessorDirective: case CodeCompletionContext::CCC_Attribute: +case CodeCompletionContext::CCC_ReplTopLevel: case CodeCompletionContext::CCC_TypeQualifiers: { //Only Clang results should be accepted, so we'll set all of the other //context bits to 0 (i.e. the empty set) Index: clang/tools/clang-repl/ClangRepl.cpp === --- clang/tools/clang-repl/ClangRepl.cpp +++ clang/tools/clang-repl/ClangRepl.cpp @@ -13,6 +13,7 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Interpreter/CodeCompletion.h" #include "clang/Interpreter/Interpreter.h" #include "llvm/ExecutionEngine/Orc/LLJIT.h" @@ -155,8 +156,8
[PATCH] D154382: [ClangRepl] support code completion at a REPL
v.g.vassilev added inline comments. Comment at: clang/unittests/Interpreter/CodeCompletionTest.cpp:71 +Completer(std::string("void app("), 9); + EXPECT_EQ((size_t)0, out.length()); +} capfredf wrote: > @v.g.vassilev The way I fixed this is a bit hacky. Do you have a better idea? Now I think I understand what you were after. Instead of handling the error in the constructor we should handle it in the caller. Here is some information how we could do that: https://llvm.org/docs/ProgrammersManual.html#fallible-constructors Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D154382: [ClangRepl] support code completion at a REPL
capfredf added inline comments. Comment at: clang/unittests/Interpreter/CodeCompletionTest.cpp:71 +Completer(std::string("void app("), 9); + EXPECT_EQ((size_t)0, out.length()); +} @v.g.vassilev The way I fixed this is a bit hacky. Do you have a better idea? Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D154382: [ClangRepl] support code completion at a REPL
capfredf updated this revision to Diff 542622. capfredf added a comment. handle cases where code completion in a function declaration Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 Files: clang/include/clang/Interpreter/CodeCompletion.h clang/include/clang/Interpreter/Interpreter.h clang/include/clang/Sema/CodeCompleteConsumer.h clang/include/clang/Sema/Sema.h clang/lib/Frontend/ASTUnit.cpp clang/lib/Interpreter/CMakeLists.txt clang/lib/Interpreter/CodeCompletion.cpp clang/lib/Interpreter/ExternalSource.cpp clang/lib/Interpreter/ExternalSource.h clang/lib/Interpreter/IncrementalParser.cpp clang/lib/Interpreter/IncrementalParser.h clang/lib/Interpreter/Interpreter.cpp clang/lib/Parse/ParseDecl.cpp clang/lib/Parse/Parser.cpp clang/lib/Sema/CodeCompleteConsumer.cpp clang/lib/Sema/SemaCodeComplete.cpp clang/tools/clang-repl/ClangRepl.cpp clang/tools/libclang/CIndexCodeCompletion.cpp clang/unittests/Interpreter/CMakeLists.txt clang/unittests/Interpreter/CodeCompletionTest.cpp Index: clang/unittests/Interpreter/CodeCompletionTest.cpp === --- /dev/null +++ clang/unittests/Interpreter/CodeCompletionTest.cpp @@ -0,0 +1,74 @@ +#include "clang/Interpreter/CodeCompletion.h" +#include "clang/Interpreter/Interpreter.h" + +#include "llvm/LineEditor/LineEditor.h" +#include "clang/Frontend/CompilerInstance.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/raw_ostream.h" + + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using namespace clang; +namespace { +auto CB = clang::IncrementalCompilerBuilder(); + +static std::unique_ptr createInterpreter() { + auto CI = cantFail(CB.CreateCpp()); + return cantFail(clang::Interpreter::create(std::move(CI))); +} + +TEST(CodeCompletionTest, Sanity) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Completer = ReplListCompleter(CB, *Interp); + std::vector comps = + Completer(std::string("f"), 1); + EXPECT_EQ((size_t)2, comps.size()); // foo and float + EXPECT_EQ(comps[0].TypedText, std::string("oo")); +} + +TEST(CodeCompletionTest, SanityNoneValid) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Completer = ReplListCompleter(CB, *Interp); + std::vector comps = + Completer(std::string("babanana"), 8); + EXPECT_EQ((size_t)0, comps.size()); // foo and float +} + +TEST(CodeCompletionTest, TwoDecls) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int application = 12;")) { +consumeError(std::move(R)); +return; + } + if (auto R = Interp->ParseAndExecute("int apple = 12;")) { +consumeError(std::move(R)); +return; + } + auto Completer = ReplListCompleter(CB, *Interp); + std::vector comps = + Completer(std::string("app"), 3); + EXPECT_EQ((size_t)2, comps.size()); +} + + +TEST(CodeCompletionTest, CompFunDeclsNoError) { + auto Interp = createInterpreter(); + std::string out; + auto rs = llvm::raw_string_ostream(out); + auto Completer = ReplListCompleter(CB, *Interp, rs); + std::vector comps = +Completer(std::string("void app("), 9); + EXPECT_EQ((size_t)0, out.length()); +} + +} // anonymous namespace Index: clang/unittests/Interpreter/CMakeLists.txt === --- clang/unittests/Interpreter/CMakeLists.txt +++ clang/unittests/Interpreter/CMakeLists.txt @@ -9,6 +9,7 @@ add_clang_unittest(ClangReplInterpreterTests IncrementalProcessingTest.cpp InterpreterTest.cpp + CodeCompletionTest.cpp ) target_link_libraries(ClangReplInterpreterTests PUBLIC clangAST Index: clang/tools/libclang/CIndexCodeCompletion.cpp === --- clang/tools/libclang/CIndexCodeCompletion.cpp +++ clang/tools/libclang/CIndexCodeCompletion.cpp @@ -543,6 +543,7 @@ case CodeCompletionContext::CCC_PreprocessorExpression: case CodeCompletionContext::CCC_PreprocessorDirective: case CodeCompletionContext::CCC_Attribute: +case CodeCompletionContext::CCC_ReplTopLevel: case CodeCompletionContext::CCC_TypeQualifiers: { //Only Clang results should be accepted, so we'll set all of the other //context bits to 0 (i.e. the empty set) Index: clang/tools/clang-repl/ClangRepl.cpp === --- clang/tools/clang-repl/ClangRepl.cpp +++ clang/tools/clang-repl/ClangRepl.cpp @@ -13,6 +13,7 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Interpreter/CodeCompletion.h" #include "clang/Interpreter/Interpreter.h" #i
[PATCH] D154382: [ClangRepl] support code completion at a REPL
capfredf updated this revision to Diff 541753. capfredf added a comment. Remove unnecessary braces Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 Files: clang/include/clang/Interpreter/CodeCompletion.h clang/include/clang/Interpreter/Interpreter.h clang/include/clang/Sema/CodeCompleteConsumer.h clang/include/clang/Sema/Sema.h clang/lib/Frontend/ASTUnit.cpp clang/lib/Interpreter/CMakeLists.txt clang/lib/Interpreter/CodeCompletion.cpp clang/lib/Interpreter/ExternalSource.cpp clang/lib/Interpreter/ExternalSource.h clang/lib/Interpreter/IncrementalParser.cpp clang/lib/Interpreter/IncrementalParser.h clang/lib/Interpreter/Interpreter.cpp clang/lib/Parse/Parser.cpp clang/lib/Sema/CodeCompleteConsumer.cpp clang/lib/Sema/SemaCodeComplete.cpp clang/tools/clang-repl/ClangRepl.cpp clang/tools/libclang/CIndexCodeCompletion.cpp clang/unittests/Interpreter/CMakeLists.txt clang/unittests/Interpreter/CodeCompletionTest.cpp Index: clang/unittests/Interpreter/CodeCompletionTest.cpp === --- /dev/null +++ clang/unittests/Interpreter/CodeCompletionTest.cpp @@ -0,0 +1,61 @@ +#include "clang/Interpreter/CodeCompletion.h" +#include "clang/Interpreter/Interpreter.h" + +#include "llvm/LineEditor/LineEditor.h" + +#include "clang/Frontend/CompilerInstance.h" +#include "llvm/Support/Error.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using namespace clang; +namespace { +auto CB = clang::IncrementalCompilerBuilder(); + +static std::unique_ptr createInterpreter() { + auto CI = cantFail(CB.CreateCpp()); + return cantFail(clang::Interpreter::create(std::move(CI))); +} + +TEST(CodeCompletionTest, Sanity) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Completer = ReplListCompleter(CB, *Interp); + std::vector comps = + Completer(std::string("f"), 1); + EXPECT_EQ((size_t)2, comps.size()); // foo and float + EXPECT_EQ(comps[0].TypedText, std::string("oo")); +} + +TEST(CodeCompletionTest, SanityNoneValid) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Completer = ReplListCompleter(CB, *Interp); + std::vector comps = + Completer(std::string("babanana"), 8); + EXPECT_EQ((size_t)0, comps.size()); // foo and float +} + +TEST(CodeCompletionTest, TwoDecls) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int application = 12;")) { +consumeError(std::move(R)); +return; + } + if (auto R = Interp->ParseAndExecute("int apple = 12;")) { +consumeError(std::move(R)); +return; + } + auto Completer = ReplListCompleter(CB, *Interp); + std::vector comps = + Completer(std::string("app"), 3); + EXPECT_EQ((size_t)2, comps.size()); +} +} // anonymous namespace Index: clang/unittests/Interpreter/CMakeLists.txt === --- clang/unittests/Interpreter/CMakeLists.txt +++ clang/unittests/Interpreter/CMakeLists.txt @@ -9,6 +9,7 @@ add_clang_unittest(ClangReplInterpreterTests IncrementalProcessingTest.cpp InterpreterTest.cpp + CodeCompletionTest.cpp ) target_link_libraries(ClangReplInterpreterTests PUBLIC clangAST Index: clang/tools/libclang/CIndexCodeCompletion.cpp === --- clang/tools/libclang/CIndexCodeCompletion.cpp +++ clang/tools/libclang/CIndexCodeCompletion.cpp @@ -543,6 +543,7 @@ case CodeCompletionContext::CCC_PreprocessorExpression: case CodeCompletionContext::CCC_PreprocessorDirective: case CodeCompletionContext::CCC_Attribute: +case CodeCompletionContext::CCC_ReplTopLevel: case CodeCompletionContext::CCC_TypeQualifiers: { //Only Clang results should be accepted, so we'll set all of the other //context bits to 0 (i.e. the empty set) Index: clang/tools/clang-repl/ClangRepl.cpp === --- clang/tools/clang-repl/ClangRepl.cpp +++ clang/tools/clang-repl/ClangRepl.cpp @@ -13,6 +13,7 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Interpreter/CodeCompletion.h" #include "clang/Interpreter/Interpreter.h" #include "llvm/ExecutionEngine/Orc/LLJIT.h" @@ -155,8 +156,8 @@ if (OptInputs.empty()) { llvm::LineEditor LE("clang-repl"); -// FIXME: Add LE.setListCompleter std::string Input; +LE.setListCompleter(clang::ReplListCompleter(CB, *Interp)); while (std::optional Line = LE.readLine()) { llvm::StringRef L = *Line; L = L.trim(); @@ -168,10 +169,10 @@ } Input += L; - if
[PATCH] D154382: [ClangRepl] support code completion at a REPL
capfredf added inline comments. Comment at: clang/lib/Interpreter/CodeCompletion.cpp:102 + std::vector Results; + auto *CConsumer = new ReplCompletionConsumer(Results); + auto Interp = Interpreter::createForCodeCompletion( v.g.vassilev wrote: > Let's move this in `Interpreter::createForCodeCompletion`. The reasons I moved this out of `Interpreter::createForCodeCompletion` are 1. Design-wise, we don't need to expose `ReplCompletionConsumer` to `Interpreter.cpp`. All `createForCodeCompletion` needs is a subclass instance of `CodeCompletionConsumer`. 2. ReplCompletionConsumer has more data members on the type-directed branch than the one on this branch. I'd rather create an instance here than pass all the necessary arguments to one layer down and do that there. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D154382: [ClangRepl] support code completion at a REPL
capfredf added inline comments. Comment at: clang/lib/Interpreter/Interpreter.cpp:304 +llvm::Expected> +Interpreter::createForCodeCompletion( +IncrementalCompilerBuilder &CB, const CompilerInstance *ParentCI, v.g.vassilev wrote: > I still do not entirely understand why we can "just" ask the codecompletion > infrastructure for the possible options at the current position. I know > that's probably easier set than done but I'd like to entertain that idea for > a while.. I'm a bit confused. Can you expand on the suggestion? Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D154382: [ClangRepl] support code completion at a REPL
v.g.vassilev added inline comments. Comment at: clang/include/clang/Sema/CodeCompleteConsumer.h:342 +/// Code completion at a top level in a REPL session. +CCC_ReplTopLevel, }; Comment at: clang/lib/Interpreter/CodeCompletion.cpp:102 + std::vector Results; + auto *CConsumer = new ReplCompletionConsumer(Results); + auto Interp = Interpreter::createForCodeCompletion( Let's move this in `Interpreter::createForCodeCompletion`. Comment at: clang/lib/Interpreter/CodeCompletion.cpp:118 + llvm::StringRef s; + if (space_pos == llvm::StringRef::npos) { +s = Buffer; Please remove the braces around single statement blocks. Comment at: clang/lib/Interpreter/Interpreter.cpp:304 +llvm::Expected> +Interpreter::createForCodeCompletion( +IncrementalCompilerBuilder &CB, const CompilerInstance *ParentCI, I still do not entirely understand why we can "just" ask the codecompletion infrastructure for the possible options at the current position. I know that's probably easier set than done but I'd like to entertain that idea for a while.. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D154382: [ClangRepl] support code completion at a REPL
capfredf updated this revision to Diff 539578. capfredf edited the summary of this revision. capfredf added a comment. @v.g.vassilev I moved the ReplCodeCompletionConsumer class out of the header file, since it is not needed elsewhere. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 Files: clang/include/clang/Interpreter/CodeCompletion.h clang/include/clang/Interpreter/Interpreter.h clang/include/clang/Sema/CodeCompleteConsumer.h clang/include/clang/Sema/Sema.h clang/lib/Frontend/ASTUnit.cpp clang/lib/Interpreter/CMakeLists.txt clang/lib/Interpreter/CodeCompletion.cpp clang/lib/Interpreter/ExternalSource.cpp clang/lib/Interpreter/ExternalSource.h clang/lib/Interpreter/IncrementalParser.cpp clang/lib/Interpreter/IncrementalParser.h clang/lib/Interpreter/Interpreter.cpp clang/lib/Parse/Parser.cpp clang/lib/Sema/CodeCompleteConsumer.cpp clang/lib/Sema/SemaCodeComplete.cpp clang/tools/clang-repl/ClangRepl.cpp clang/tools/libclang/CIndexCodeCompletion.cpp clang/unittests/Interpreter/CMakeLists.txt clang/unittests/Interpreter/CodeCompletionTest.cpp Index: clang/unittests/Interpreter/CodeCompletionTest.cpp === --- /dev/null +++ clang/unittests/Interpreter/CodeCompletionTest.cpp @@ -0,0 +1,61 @@ +#include "clang/Interpreter/CodeCompletion.h" +#include "clang/Interpreter/Interpreter.h" + +#include "llvm/LineEditor/LineEditor.h" + +#include "clang/Frontend/CompilerInstance.h" +#include "llvm/Support/Error.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using namespace clang; +namespace { +auto CB = clang::IncrementalCompilerBuilder(); + +static std::unique_ptr createInterpreter() { + auto CI = cantFail(CB.CreateCpp()); + return cantFail(clang::Interpreter::create(std::move(CI))); +} + +TEST(CodeCompletionTest, Sanity) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Completer = ReplListCompleter(CB, *Interp); + std::vector comps = + Completer(std::string("f"), 1); + EXPECT_EQ((size_t)2, comps.size()); // foo and float + EXPECT_EQ(comps[0].TypedText, std::string("oo")); +} + +TEST(CodeCompletionTest, SanityNoneValid) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Completer = ReplListCompleter(CB, *Interp); + std::vector comps = + Completer(std::string("babanana"), 8); + EXPECT_EQ((size_t)0, comps.size()); // foo and float +} + +TEST(CodeCompletionTest, TwoDecls) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int application = 12;")) { +consumeError(std::move(R)); +return; + } + if (auto R = Interp->ParseAndExecute("int apple = 12;")) { +consumeError(std::move(R)); +return; + } + auto Completer = ReplListCompleter(CB, *Interp); + std::vector comps = + Completer(std::string("app"), 3); + EXPECT_EQ((size_t)2, comps.size()); +} +} // anonymous namespace Index: clang/unittests/Interpreter/CMakeLists.txt === --- clang/unittests/Interpreter/CMakeLists.txt +++ clang/unittests/Interpreter/CMakeLists.txt @@ -9,6 +9,7 @@ add_clang_unittest(ClangReplInterpreterTests IncrementalProcessingTest.cpp InterpreterTest.cpp + CodeCompletionTest.cpp ) target_link_libraries(ClangReplInterpreterTests PUBLIC clangAST Index: clang/tools/libclang/CIndexCodeCompletion.cpp === --- clang/tools/libclang/CIndexCodeCompletion.cpp +++ clang/tools/libclang/CIndexCodeCompletion.cpp @@ -543,6 +543,7 @@ case CodeCompletionContext::CCC_PreprocessorExpression: case CodeCompletionContext::CCC_PreprocessorDirective: case CodeCompletionContext::CCC_Attribute: +case CodeCompletionContext::CCC_ReplTopLevel: case CodeCompletionContext::CCC_TypeQualifiers: { //Only Clang results should be accepted, so we'll set all of the other //context bits to 0 (i.e. the empty set) Index: clang/tools/clang-repl/ClangRepl.cpp === --- clang/tools/clang-repl/ClangRepl.cpp +++ clang/tools/clang-repl/ClangRepl.cpp @@ -13,6 +13,7 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Interpreter/CodeCompletion.h" #include "clang/Interpreter/Interpreter.h" #include "llvm/ExecutionEngine/Orc/LLJIT.h" @@ -155,8 +156,8 @@ if (OptInputs.empty()) { llvm::LineEditor LE("clang-repl"); -// FIXME: Add LE.setListCompleter std::string Input; +LE.setListCompleter(clang::ReplListCompleter(CB, *Interp)); while (std::optional Line
[PATCH] D154382: [ClangRepl] support code completion at a REPL
capfredf updated this revision to Diff 539572. capfredf marked 2 inline comments as done. capfredf edited the summary of this revision. capfredf added a comment. Herald added a subscriber: arphaman. - rename - Do not export ReplCompletionConsumer - remove commented code Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 Files: clang/include/clang/Interpreter/CodeCompletion.h clang/include/clang/Interpreter/Interpreter.h clang/include/clang/Sema/Sema.h clang/lib/Interpreter/CodeCompletion.cpp clang/lib/Interpreter/IncrementalParser.cpp clang/lib/Interpreter/Interpreter.cpp clang/lib/Parse/Parser.cpp clang/lib/Sema/SemaCodeComplete.cpp clang/tools/libclang/CIndexCodeCompletion.cpp Index: clang/tools/libclang/CIndexCodeCompletion.cpp === --- clang/tools/libclang/CIndexCodeCompletion.cpp +++ clang/tools/libclang/CIndexCodeCompletion.cpp @@ -543,6 +543,7 @@ case CodeCompletionContext::CCC_PreprocessorExpression: case CodeCompletionContext::CCC_PreprocessorDirective: case CodeCompletionContext::CCC_Attribute: +case CodeCompletionContext::CCC_ReplTopLevel: case CodeCompletionContext::CCC_TypeQualifiers: { //Only Clang results should be accepted, so we'll set all of the other //context bits to 0 (i.e. the empty set) Index: clang/lib/Sema/SemaCodeComplete.cpp === --- clang/lib/Sema/SemaCodeComplete.cpp +++ clang/lib/Sema/SemaCodeComplete.cpp @@ -1851,7 +1851,7 @@ case Sema::PCC_ObjCInstanceVariableList: case Sema::PCC_Expression: case Sema::PCC_Statement: - case Sema::PCC_ReplTopLevel: + case Sema::PCC_TopLevelStmtDecl: case Sema::PCC_ForInit: case Sema::PCC_Condition: case Sema::PCC_RecoveryInFunction: @@ -1909,7 +1909,7 @@ case Sema::PCC_Type: case Sema::PCC_ParenthesizedExpression: case Sema::PCC_LocalDeclarationSpecifiers: - case Sema::PCC_ReplTopLevel: + case Sema::PCC_TopLevelStmtDecl: return true; case Sema::PCC_Expression: @@ -,7 +,7 @@ break; case Sema::PCC_RecoveryInFunction: - case Sema::PCC_ReplTopLevel: + case Sema::PCC_TopLevelStmtDecl: case Sema::PCC_Statement: { if (SemaRef.getLangOpts().CPlusPlus11) AddUsingAliasResult(Builder, Results); @@ -4212,7 +4212,7 @@ case Sema::PCC_LocalDeclarationSpecifiers: return CodeCompletionContext::CCC_Type; - case Sema::PCC_ReplTopLevel: + case Sema::PCC_TopLevelStmtDecl: return CodeCompletionContext::CCC_ReplTopLevel; } @@ -4354,7 +4354,7 @@ break; case PCC_Statement: - case PCC_ReplTopLevel: + case PCC_TopLevelStmtDecl: case PCC_ParenthesizedExpression: case PCC_Expression: case PCC_ForInit: @@ -4392,7 +4392,7 @@ case PCC_ParenthesizedExpression: case PCC_Expression: case PCC_Statement: - case PCC_ReplTopLevel: + case PCC_TopLevelStmtDecl: case PCC_RecoveryInFunction: if (S->getFnParent()) AddPrettyFunctionResults(getLangOpts(), Results); Index: clang/lib/Parse/Parser.cpp === --- clang/lib/Parse/Parser.cpp +++ clang/lib/Parse/Parser.cpp @@ -928,7 +928,7 @@ if (CurParsedObjCImpl) { PCC = Sema::PCC_ObjCImplementation; } else if (PP.isIncrementalProcessingEnabled()) { - PCC = Sema::PCC_ReplTopLevel; + PCC = Sema::PCC_TopLevelStmtDecl; } else { PCC = Sema::PCC_Namespace; }; Index: clang/lib/Interpreter/Interpreter.cpp === --- clang/lib/Interpreter/Interpreter.cpp +++ clang/lib/Interpreter/Interpreter.cpp @@ -239,12 +239,11 @@ } Interpreter::Interpreter(std::unique_ptr CI, llvm::Error &Err, - std::vector &CompResults, + CodeCompleteConsumer* CConsumer, const CompilerInstance *ParentCI) { llvm::ErrorAsOutParameter EAO(&Err); auto LLVMCtx = std::make_unique(); TSCtx = std::make_unique(std::move(LLVMCtx)); - auto *CConsumer = new ReplCompletionConsumer(CompResults); CI->setCodeCompletionConsumer(CConsumer); IncrParser = std::make_unique( *this, std::move(CI), *TSCtx->getContext(), Err, ParentCI); @@ -304,7 +303,7 @@ llvm::Expected> Interpreter::createForCodeCompletion( IncrementalCompilerBuilder &CB, const CompilerInstance *ParentCI, -std::vector &CompResults) { +CodeCompleteConsumer* CConsumer) { auto CI = CB.CreateCpp(); if (auto Err = CI.takeError()) { return std::move(Err); @@ -315,12 +314,9 @@ (*CI)->getLangOpts().SpellChecking = false; (*CI)->getLangOpts().DelayedTemplateParsing = false; - auto &FrontendOpts = (*CI)->getFrontendOpts(); - FrontendOpts.CodeCompleteOpts = getClangCompleteOpts(); - llvm::Error Err = llvm::Error::success(); auto I
[PATCH] D154382: [ClangRepl] support code completion at a REPL
capfredf marked 5 inline comments as done. capfredf added inline comments. Comment at: clang/include/clang/Interpreter/Interpreter.h:117 ASTContext &getASTContext(); + void CodeComplete(llvm::StringRef Input, size_t Col, size_t Line = 1); const CompilerInstance *getCompilerInstance() const; v.g.vassilev wrote: > I could not find where this interface was used. If it is unused, let'd drop > it. it is used at L86 of CodeCompletion.cpp Comment at: clang/lib/Interpreter/IncrementalParser.cpp:376 // Create FileID for the current buffer. - FileID FID = SM.createFileID(std::move(MB), SrcMgr::C_User, /*LoadedID=*/0, - /*LoadedOffset=*/0, NewLoc); + // FileID FID = SM.createFileID(std::move(MB), SrcMgr::C_User, /*LoadedID=*/0, + // /*LoadedOffset=*/0, NewLoc); v.g.vassilev wrote: > Why we had to comment out this line? This is old code. `FID` is created in a different way. See below. I will remove the commented code Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D154382: [ClangRepl] support code completion at a REPL
v.g.vassilev added a reviewer: aaron.ballman. v.g.vassilev added a subscriber: aaron.ballman. v.g.vassilev added a comment. @capfredf this seems to be heading in a good direction. Please find another round of comments. @aaron.ballman, I could not find a person that's active in that area. Could you help with finding reviewers for this type of patch? Comment at: clang/include/clang/Interpreter/Interpreter.h:117 ASTContext &getASTContext(); + void CodeComplete(llvm::StringRef Input, size_t Col, size_t Line = 1); const CompilerInstance *getCompilerInstance() const; I could not find where this interface was used. If it is unused, let'd drop it. Comment at: clang/include/clang/Sema/Sema.h:13324 +/// Code completion occurs at top-level in a REPL session +PCC_ReplTopLevel, }; Comment at: clang/lib/Interpreter/IncrementalParser.cpp:338 + // return; + // } + if (FE) { Seems that we have stray debug fragments? Can you remove them? Comment at: clang/lib/Interpreter/IncrementalParser.cpp:376 // Create FileID for the current buffer. - FileID FID = SM.createFileID(std::move(MB), SrcMgr::C_User, /*LoadedID=*/0, - /*LoadedOffset=*/0, NewLoc); + // FileID FID = SM.createFileID(std::move(MB), SrcMgr::C_User, /*LoadedID=*/0, + // /*LoadedOffset=*/0, NewLoc); Why we had to comment out this line? Comment at: clang/lib/Interpreter/Interpreter.cpp:248 + auto *CConsumer = new ReplCompletionConsumer(CompResults); + CI->setCodeCompletionConsumer(CConsumer); + IncrParser = std::make_unique( IIUC, `setCodeCompletionConsumer` takes the ownership of `CConsumer`. I'd suggest to drop `CConsumer` member. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D154382: [ClangRepl] support code completion at a REPL
capfredf updated this revision to Diff 537933. capfredf marked an inline comment as not done. capfredf added a comment. get rid of the wrapping Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 Files: clang/include/clang/Interpreter/CodeCompletion.h clang/include/clang/Interpreter/Interpreter.h clang/include/clang/Sema/CodeCompleteConsumer.h clang/include/clang/Sema/Sema.h clang/lib/Frontend/ASTUnit.cpp clang/lib/Interpreter/CMakeLists.txt clang/lib/Interpreter/CodeCompletion.cpp clang/lib/Interpreter/ExternalSource.cpp clang/lib/Interpreter/ExternalSource.h clang/lib/Interpreter/IncrementalParser.cpp clang/lib/Interpreter/IncrementalParser.h clang/lib/Interpreter/Interpreter.cpp clang/lib/Parse/Parser.cpp clang/lib/Sema/CodeCompleteConsumer.cpp clang/lib/Sema/SemaCodeComplete.cpp clang/tools/clang-repl/ClangRepl.cpp clang/unittests/Interpreter/CMakeLists.txt clang/unittests/Interpreter/CodeCompletionTest.cpp Index: clang/unittests/Interpreter/CodeCompletionTest.cpp === --- /dev/null +++ clang/unittests/Interpreter/CodeCompletionTest.cpp @@ -0,0 +1,61 @@ +#include "clang/Interpreter/CodeCompletion.h" +#include "clang/Interpreter/Interpreter.h" + +#include "llvm/LineEditor/LineEditor.h" + +#include "clang/Frontend/CompilerInstance.h" +#include "llvm/Support/Error.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using namespace clang; +namespace { +auto CB = clang::IncrementalCompilerBuilder(); + +static std::unique_ptr createInterpreter() { + auto CI = cantFail(CB.CreateCpp()); + return cantFail(clang::Interpreter::create(std::move(CI))); +} + +TEST(CodeCompletionTest, Sanity) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Completer = ReplListCompleter(CB, *Interp); + std::vector comps = + Completer(std::string("f"), 1); + EXPECT_EQ((size_t)2, comps.size()); // foo and float + EXPECT_EQ(comps[0].TypedText, std::string("oo")); +} + +TEST(CodeCompletionTest, SanityNoneValid) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Completer = ReplListCompleter(CB, *Interp); + std::vector comps = + Completer(std::string("babanana"), 8); + EXPECT_EQ((size_t)0, comps.size()); // foo and float +} + +TEST(CodeCompletionTest, TwoDecls) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int application = 12;")) { +consumeError(std::move(R)); +return; + } + if (auto R = Interp->ParseAndExecute("int apple = 12;")) { +consumeError(std::move(R)); +return; + } + auto Completer = ReplListCompleter(CB, *Interp); + std::vector comps = + Completer(std::string("app"), 3); + EXPECT_EQ((size_t)2, comps.size()); +} +} // anonymous namespace Index: clang/unittests/Interpreter/CMakeLists.txt === --- clang/unittests/Interpreter/CMakeLists.txt +++ clang/unittests/Interpreter/CMakeLists.txt @@ -9,6 +9,7 @@ add_clang_unittest(ClangReplInterpreterTests IncrementalProcessingTest.cpp InterpreterTest.cpp + CodeCompletionTest.cpp ) target_link_libraries(ClangReplInterpreterTests PUBLIC clangAST Index: clang/tools/clang-repl/ClangRepl.cpp === --- clang/tools/clang-repl/ClangRepl.cpp +++ clang/tools/clang-repl/ClangRepl.cpp @@ -13,6 +13,7 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Interpreter/CodeCompletion.h" #include "clang/Interpreter/Interpreter.h" #include "llvm/ExecutionEngine/Orc/LLJIT.h" @@ -155,8 +156,8 @@ if (OptInputs.empty()) { llvm::LineEditor LE("clang-repl"); -// FIXME: Add LE.setListCompleter std::string Input; +LE.setListCompleter(clang::ReplListCompleter(CB, *Interp)); while (std::optional Line = LE.readLine()) { llvm::StringRef L = *Line; L = L.trim(); @@ -168,10 +169,10 @@ } Input += L; - if (Input == R"(%quit)") { break; - } else if (Input == R"(%undo)") { + } + if (Input == R"(%undo)") { if (auto Err = Interp->Undo()) { llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), "error: "); HasError = true; Index: clang/lib/Sema/SemaCodeComplete.cpp === --- clang/lib/Sema/SemaCodeComplete.cpp +++ clang/lib/Sema/SemaCodeComplete.cpp @@ -225,6 +225,7 @@ case CodeCompletionContext::CCC_ObjCMessageReceiver: case CodeCompletionContext::CCC_ParenthesizedExpression: case CodeCompletionContext::CCC_St
[PATCH] D154382: [ClangRepl] support code completion at a REPL
capfredf marked an inline comment as not done. capfredf added inline comments. Comment at: clang/lib/Interpreter/CodeCompletion.cpp:84 + std::string AllCodeText = + MainInterp.getAllInput() + "\nvoid dummy(){\n" + Buffer.str() + "}"; + auto Lines = std::count(AllCodeText.begin(), AllCodeText.end(), '\n') + 1; capfredf wrote: > v.g.vassilev wrote: > > I am not sure why we need to wrap this code. Can we teach the > > `TopLevelStmtDecl` to work with the code completion logic? > I think the problem has less to do with the TopLevelStmtDecl. Usually, a > `TopLevelStmtDecl` instance is a successful result from `ParseX`, but > when `CodeCompletion` is triggered during parsing, nothing meaning comes out > from `Parse`. > > We need to wrap our input because we need `Sema::CodeCompleteOrdinaryName` to > work on code from the REPL in a different completion context than the same > code from a regular source file. > > In a regular C++ file, > > ``` > int foo = 42; > f_ > ``` > > Since top-level expressions are not supported, `foo` should not be an option. > > But in a REPL session, > > ``` > clang-repl> int foo = 42; > clang-repl> f_ > ``` > > we are allowed to use `foo` to make a statement like `foo + 84;`. > > Since the argument for `CompletionContext` to `CodeCompleteOrdinaryName` is > controlled by the parsing process, ie. there is no way to configure it from > outside, I think faking context is a straightforward solution. > > Alternatively, we can check if the compiler is in incremental mode and call > `CodeCompleteOrdinaryName` with the context we want in parsing. Something > like: > > ``` > if (PP.isIncrementalProcessingEnabled() { > Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Statement); > } else { > Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Namespace); > } > ``` > > I personally think both solutions are extensionally equivalent, but the > alternative is a bit intrusive. I think the combination of checking `isIncrementalProcessingEnabled` and adding a new PCC might be better since it is really a different context at the REPL Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D154382: [ClangRepl] support code completion at a REPL
capfredf updated this revision to Diff 537915. capfredf added a comment. remove an unused decl Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 Files: clang/include/clang/Interpreter/CodeCompletion.h clang/include/clang/Interpreter/Interpreter.h clang/lib/Interpreter/CMakeLists.txt clang/lib/Interpreter/CodeCompletion.cpp clang/lib/Interpreter/ExternalSource.cpp clang/lib/Interpreter/ExternalSource.h clang/lib/Interpreter/IncrementalParser.cpp clang/lib/Interpreter/IncrementalParser.h clang/lib/Interpreter/Interpreter.cpp clang/tools/clang-repl/ClangRepl.cpp clang/unittests/Interpreter/CMakeLists.txt clang/unittests/Interpreter/CodeCompletionTest.cpp Index: clang/unittests/Interpreter/CodeCompletionTest.cpp === --- /dev/null +++ clang/unittests/Interpreter/CodeCompletionTest.cpp @@ -0,0 +1,61 @@ +#include "clang/Interpreter/CodeCompletion.h" +#include "clang/Interpreter/Interpreter.h" + +#include "llvm/LineEditor/LineEditor.h" + +#include "clang/Frontend/CompilerInstance.h" +#include "llvm/Support/Error.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using namespace clang; +namespace { +auto CB = clang::IncrementalCompilerBuilder(); + +static std::unique_ptr createInterpreter() { + auto CI = cantFail(CB.CreateCpp()); + return cantFail(clang::Interpreter::create(std::move(CI))); +} + +TEST(CodeCompletionTest, Sanity) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Completer = ReplListCompleter(CB, *Interp); + std::vector comps = + Completer(std::string("f"), 1); + EXPECT_EQ((size_t)2, comps.size()); // foo and float + EXPECT_EQ(comps[0].TypedText, std::string("oo")); +} + +TEST(CodeCompletionTest, SanityNoneValid) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Completer = ReplListCompleter(CB, *Interp); + std::vector comps = + Completer(std::string("babanana"), 8); + EXPECT_EQ((size_t)0, comps.size()); // foo and float +} + +TEST(CodeCompletionTest, TwoDecls) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int application = 12;")) { +consumeError(std::move(R)); +return; + } + if (auto R = Interp->ParseAndExecute("int apple = 12;")) { +consumeError(std::move(R)); +return; + } + auto Completer = ReplListCompleter(CB, *Interp); + std::vector comps = + Completer(std::string("app"), 3); + EXPECT_EQ((size_t)2, comps.size()); +} +} // anonymous namespace Index: clang/unittests/Interpreter/CMakeLists.txt === --- clang/unittests/Interpreter/CMakeLists.txt +++ clang/unittests/Interpreter/CMakeLists.txt @@ -9,6 +9,7 @@ add_clang_unittest(ClangReplInterpreterTests IncrementalProcessingTest.cpp InterpreterTest.cpp + CodeCompletionTest.cpp ) target_link_libraries(ClangReplInterpreterTests PUBLIC clangAST Index: clang/tools/clang-repl/ClangRepl.cpp === --- clang/tools/clang-repl/ClangRepl.cpp +++ clang/tools/clang-repl/ClangRepl.cpp @@ -13,6 +13,7 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Interpreter/CodeCompletion.h" #include "clang/Interpreter/Interpreter.h" #include "llvm/ExecutionEngine/Orc/LLJIT.h" @@ -155,8 +156,8 @@ if (OptInputs.empty()) { llvm::LineEditor LE("clang-repl"); -// FIXME: Add LE.setListCompleter std::string Input; +LE.setListCompleter(clang::ReplListCompleter(CB, *Interp)); while (std::optional Line = LE.readLine()) { llvm::StringRef L = *Line; L = L.trim(); @@ -168,10 +169,10 @@ } Input += L; - if (Input == R"(%quit)") { break; - } else if (Input == R"(%undo)") { + } + if (Input == R"(%undo)") { if (auto Err = Interp->Undo()) { llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), "error: "); HasError = true; Index: clang/lib/Interpreter/Interpreter.cpp === --- clang/lib/Interpreter/Interpreter.cpp +++ clang/lib/Interpreter/Interpreter.cpp @@ -14,6 +14,7 @@ #include "clang/Interpreter/Interpreter.h" #include "DeviceOffload.h" +#include "ExternalSource.h" #include "IncrementalExecutor.h" #include "IncrementalParser.h" @@ -33,6 +34,7 @@ #include "clang/Driver/Tool.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/TextDiagnosticBuffer.h" +#include "clang/Interpreter/CodeCompletion.h" #include "clang/Interpreter/Value.h" #include "clang/Lex/Preproc
[PATCH] D154382: [ClangRepl] support code completion at a REPL
capfredf updated this revision to Diff 537912. capfredf added a comment. move the comment up Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 Files: clang/include/clang/Interpreter/CodeCompletion.h clang/include/clang/Interpreter/Interpreter.h clang/lib/Interpreter/CMakeLists.txt clang/lib/Interpreter/CodeCompletion.cpp clang/lib/Interpreter/ExternalSource.cpp clang/lib/Interpreter/ExternalSource.h clang/lib/Interpreter/IncrementalParser.cpp clang/lib/Interpreter/IncrementalParser.h clang/lib/Interpreter/Interpreter.cpp clang/tools/clang-repl/ClangRepl.cpp clang/unittests/Interpreter/CMakeLists.txt clang/unittests/Interpreter/CodeCompletionTest.cpp Index: clang/unittests/Interpreter/CodeCompletionTest.cpp === --- /dev/null +++ clang/unittests/Interpreter/CodeCompletionTest.cpp @@ -0,0 +1,61 @@ +#include "clang/Interpreter/CodeCompletion.h" +#include "clang/Interpreter/Interpreter.h" + +#include "llvm/LineEditor/LineEditor.h" + +#include "clang/Frontend/CompilerInstance.h" +#include "llvm/Support/Error.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using namespace clang; +namespace { +auto CB = clang::IncrementalCompilerBuilder(); + +static std::unique_ptr createInterpreter() { + auto CI = cantFail(CB.CreateCpp()); + return cantFail(clang::Interpreter::create(std::move(CI))); +} + +TEST(CodeCompletionTest, Sanity) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Completer = ReplListCompleter(CB, *Interp); + std::vector comps = + Completer(std::string("f"), 1); + EXPECT_EQ((size_t)2, comps.size()); // foo and float + EXPECT_EQ(comps[0].TypedText, std::string("oo")); +} + +TEST(CodeCompletionTest, SanityNoneValid) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Completer = ReplListCompleter(CB, *Interp); + std::vector comps = + Completer(std::string("babanana"), 8); + EXPECT_EQ((size_t)0, comps.size()); // foo and float +} + +TEST(CodeCompletionTest, TwoDecls) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int application = 12;")) { +consumeError(std::move(R)); +return; + } + if (auto R = Interp->ParseAndExecute("int apple = 12;")) { +consumeError(std::move(R)); +return; + } + auto Completer = ReplListCompleter(CB, *Interp); + std::vector comps = + Completer(std::string("app"), 3); + EXPECT_EQ((size_t)2, comps.size()); +} +} // anonymous namespace Index: clang/unittests/Interpreter/CMakeLists.txt === --- clang/unittests/Interpreter/CMakeLists.txt +++ clang/unittests/Interpreter/CMakeLists.txt @@ -9,6 +9,7 @@ add_clang_unittest(ClangReplInterpreterTests IncrementalProcessingTest.cpp InterpreterTest.cpp + CodeCompletionTest.cpp ) target_link_libraries(ClangReplInterpreterTests PUBLIC clangAST Index: clang/tools/clang-repl/ClangRepl.cpp === --- clang/tools/clang-repl/ClangRepl.cpp +++ clang/tools/clang-repl/ClangRepl.cpp @@ -13,6 +13,7 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Interpreter/CodeCompletion.h" #include "clang/Interpreter/Interpreter.h" #include "llvm/ExecutionEngine/Orc/LLJIT.h" @@ -155,8 +156,8 @@ if (OptInputs.empty()) { llvm::LineEditor LE("clang-repl"); -// FIXME: Add LE.setListCompleter std::string Input; +LE.setListCompleter(clang::ReplListCompleter(CB, *Interp)); while (std::optional Line = LE.readLine()) { llvm::StringRef L = *Line; L = L.trim(); @@ -168,10 +169,10 @@ } Input += L; - if (Input == R"(%quit)") { break; - } else if (Input == R"(%undo)") { + } + if (Input == R"(%undo)") { if (auto Err = Interp->Undo()) { llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), "error: "); HasError = true; Index: clang/lib/Interpreter/Interpreter.cpp === --- clang/lib/Interpreter/Interpreter.cpp +++ clang/lib/Interpreter/Interpreter.cpp @@ -14,6 +14,7 @@ #include "clang/Interpreter/Interpreter.h" #include "DeviceOffload.h" +#include "ExternalSource.h" #include "IncrementalExecutor.h" #include "IncrementalParser.h" @@ -33,6 +34,7 @@ #include "clang/Driver/Tool.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/TextDiagnosticBuffer.h" +#include "clang/Interpreter/CodeCompletion.h" #include "clang/Interpreter/Value.h" #include "clang/Lex/Preproces
[PATCH] D154382: [ClangRepl] support code completion at a REPL
capfredf updated this revision to Diff 537910. capfredf added a comment. move the comment up Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 Files: clang/lib/Interpreter/CodeCompletion.cpp Index: clang/lib/Interpreter/CodeCompletion.cpp === --- clang/lib/Interpreter/CodeCompletion.cpp +++ clang/lib/Interpreter/CodeCompletion.cpp @@ -81,8 +81,6 @@ return Comps; } - std::string AllCodeText = "void __dummy(){\n" + Buffer.str(); - // We need to wrap our input because we need `Sema::CodeCompleteOrdinaryName` // to work on code from the REPL in a statement completion context. By // default, `Sema::CodeCompleteOrdinaryName` thinks the input is a regular c++ @@ -102,6 +100,7 @@ // Since top-level expressions are not supported, `foo` should not be an // option. But in a REPL session, we should be allowed to use `foo` to make a // statement like `foo + 84;`. + std::string AllCodeText = "void __dummy(){\n" + Buffer.str(); auto Lines = std::count(AllCodeText.begin(), AllCodeText.end(), '\n') + 1; Index: clang/lib/Interpreter/CodeCompletion.cpp === --- clang/lib/Interpreter/CodeCompletion.cpp +++ clang/lib/Interpreter/CodeCompletion.cpp @@ -81,8 +81,6 @@ return Comps; } - std::string AllCodeText = "void __dummy(){\n" + Buffer.str(); - // We need to wrap our input because we need `Sema::CodeCompleteOrdinaryName` // to work on code from the REPL in a statement completion context. By // default, `Sema::CodeCompleteOrdinaryName` thinks the input is a regular c++ @@ -102,6 +100,7 @@ // Since top-level expressions are not supported, `foo` should not be an // option. But in a REPL session, we should be allowed to use `foo` to make a // statement like `foo + 84;`. + std::string AllCodeText = "void __dummy(){\n" + Buffer.str(); auto Lines = std::count(AllCodeText.begin(), AllCodeText.end(), '\n') + 1; ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D154382: [ClangRepl] support code completion at a REPL
capfredf updated this revision to Diff 537883. capfredf edited the summary of this revision. capfredf added a comment. update Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 Files: clang/include/clang/Interpreter/CodeCompletion.h clang/include/clang/Interpreter/Interpreter.h clang/lib/Interpreter/CMakeLists.txt clang/lib/Interpreter/CodeCompletion.cpp clang/lib/Interpreter/ExternalSource.cpp clang/lib/Interpreter/ExternalSource.h clang/lib/Interpreter/IncrementalParser.cpp clang/lib/Interpreter/IncrementalParser.h clang/lib/Interpreter/Interpreter.cpp clang/tools/clang-repl/ClangRepl.cpp clang/unittests/Interpreter/CMakeLists.txt clang/unittests/Interpreter/CodeCompletionTest.cpp Index: clang/unittests/Interpreter/CodeCompletionTest.cpp === --- /dev/null +++ clang/unittests/Interpreter/CodeCompletionTest.cpp @@ -0,0 +1,61 @@ +#include "clang/Interpreter/CodeCompletion.h" +#include "clang/Interpreter/Interpreter.h" + +#include "llvm/LineEditor/LineEditor.h" + +#include "clang/Frontend/CompilerInstance.h" +#include "llvm/Support/Error.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using namespace clang; +namespace { +auto CB = clang::IncrementalCompilerBuilder(); + +static std::unique_ptr createInterpreter() { + auto CI = cantFail(CB.CreateCpp()); + return cantFail(clang::Interpreter::create(std::move(CI))); +} + +TEST(CodeCompletionTest, Sanity) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Completer = ReplListCompleter(CB, *Interp); + std::vector comps = + Completer(std::string("f"), 1); + EXPECT_EQ((size_t)2, comps.size()); // foo and float + EXPECT_EQ(comps[0].TypedText, std::string("oo")); +} + +TEST(CodeCompletionTest, SanityNoneValid) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Completer = ReplListCompleter(CB, *Interp); + std::vector comps = + Completer(std::string("babanana"), 8); + EXPECT_EQ((size_t)0, comps.size()); // foo and float +} + +TEST(CodeCompletionTest, TwoDecls) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int application = 12;")) { +consumeError(std::move(R)); +return; + } + if (auto R = Interp->ParseAndExecute("int apple = 12;")) { +consumeError(std::move(R)); +return; + } + auto Completer = ReplListCompleter(CB, *Interp); + std::vector comps = + Completer(std::string("app"), 3); + EXPECT_EQ((size_t)2, comps.size()); +} +} // anonymous namespace Index: clang/unittests/Interpreter/CMakeLists.txt === --- clang/unittests/Interpreter/CMakeLists.txt +++ clang/unittests/Interpreter/CMakeLists.txt @@ -9,6 +9,7 @@ add_clang_unittest(ClangReplInterpreterTests IncrementalProcessingTest.cpp InterpreterTest.cpp + CodeCompletionTest.cpp ) target_link_libraries(ClangReplInterpreterTests PUBLIC clangAST Index: clang/tools/clang-repl/ClangRepl.cpp === --- clang/tools/clang-repl/ClangRepl.cpp +++ clang/tools/clang-repl/ClangRepl.cpp @@ -13,6 +13,7 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Interpreter/CodeCompletion.h" #include "clang/Interpreter/Interpreter.h" #include "llvm/ExecutionEngine/Orc/LLJIT.h" @@ -155,8 +156,8 @@ if (OptInputs.empty()) { llvm::LineEditor LE("clang-repl"); -// FIXME: Add LE.setListCompleter std::string Input; +LE.setListCompleter(clang::ReplListCompleter(CB, *Interp)); while (std::optional Line = LE.readLine()) { llvm::StringRef L = *Line; L = L.trim(); @@ -168,10 +169,10 @@ } Input += L; - if (Input == R"(%quit)") { break; - } else if (Input == R"(%undo)") { + } + if (Input == R"(%undo)") { if (auto Err = Interp->Undo()) { llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), "error: "); HasError = true; Index: clang/lib/Interpreter/Interpreter.cpp === --- clang/lib/Interpreter/Interpreter.cpp +++ clang/lib/Interpreter/Interpreter.cpp @@ -14,6 +14,7 @@ #include "clang/Interpreter/Interpreter.h" #include "DeviceOffload.h" +#include "ExternalSource.h" #include "IncrementalExecutor.h" #include "IncrementalParser.h" @@ -33,6 +34,7 @@ #include "clang/Driver/Tool.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/TextDiagnosticBuffer.h" +#include "clang/Interpreter/CodeCompletion.h" #include "clang/Interpreter/Value.
[PATCH] D154382: [ClangRepl] support code completion at a REPL
capfredf updated this revision to Diff 537766. capfredf edited the summary of this revision. capfredf added a comment. changes per discussions Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 Files: clang/include/clang/Interpreter/CodeCompletion.h clang/include/clang/Interpreter/Interpreter.h clang/lib/Interpreter/CMakeLists.txt clang/lib/Interpreter/CodeCompletion.cpp clang/lib/Interpreter/ExternalSource.cpp clang/lib/Interpreter/ExternalSource.h clang/lib/Interpreter/IncrementalParser.cpp clang/lib/Interpreter/IncrementalParser.h clang/lib/Interpreter/Interpreter.cpp clang/tools/clang-repl/ClangRepl.cpp clang/unittests/Interpreter/CMakeLists.txt clang/unittests/Interpreter/CodeCompletionTest.cpp Index: clang/unittests/Interpreter/CodeCompletionTest.cpp === --- /dev/null +++ clang/unittests/Interpreter/CodeCompletionTest.cpp @@ -0,0 +1,61 @@ +#include "clang/Interpreter/CodeCompletion.h" +#include "clang/Interpreter/Interpreter.h" + +#include "llvm/LineEditor/LineEditor.h" + +#include "clang/Frontend/CompilerInstance.h" +#include "llvm/Support/Error.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using namespace clang; +namespace { +auto CB = clang::IncrementalCompilerBuilder(); + +static std::unique_ptr createInterpreter() { + auto CI = cantFail(CB.CreateCpp()); + return cantFail(clang::Interpreter::create(std::move(CI))); +} + +TEST(CodeCompletionTest, Sanity) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Completer = ReplListCompleter(CB, *Interp); + std::vector comps = + Completer(std::string("f"), 1); + EXPECT_EQ((size_t)2, comps.size()); // foo and float + EXPECT_EQ(comps[0].TypedText, std::string("oo")); +} + +TEST(CodeCompletionTest, SanityNoneValid) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Completer = ReplListCompleter(CB, *Interp); + std::vector comps = + Completer(std::string("babanana"), 8); + EXPECT_EQ((size_t)0, comps.size()); // foo and float +} + +TEST(CodeCompletionTest, TwoDecls) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int application = 12;")) { +consumeError(std::move(R)); +return; + } + if (auto R = Interp->ParseAndExecute("int apple = 12;")) { +consumeError(std::move(R)); +return; + } + auto Completer = ReplListCompleter(CB, *Interp); + std::vector comps = + Completer(std::string("app"), 3); + EXPECT_EQ((size_t)2, comps.size()); +} +} // anonymous namespace Index: clang/unittests/Interpreter/CMakeLists.txt === --- clang/unittests/Interpreter/CMakeLists.txt +++ clang/unittests/Interpreter/CMakeLists.txt @@ -9,6 +9,7 @@ add_clang_unittest(ClangReplInterpreterTests IncrementalProcessingTest.cpp InterpreterTest.cpp + CodeCompletionTest.cpp ) target_link_libraries(ClangReplInterpreterTests PUBLIC clangAST Index: clang/tools/clang-repl/ClangRepl.cpp === --- clang/tools/clang-repl/ClangRepl.cpp +++ clang/tools/clang-repl/ClangRepl.cpp @@ -13,6 +13,7 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Interpreter/CodeCompletion.h" #include "clang/Interpreter/Interpreter.h" #include "llvm/ExecutionEngine/Orc/LLJIT.h" @@ -155,8 +156,8 @@ if (OptInputs.empty()) { llvm::LineEditor LE("clang-repl"); -// FIXME: Add LE.setListCompleter std::string Input; +LE.setListCompleter(clang::ReplListCompleter(CB, *Interp)); while (std::optional Line = LE.readLine()) { llvm::StringRef L = *Line; L = L.trim(); @@ -168,10 +169,10 @@ } Input += L; - if (Input == R"(%quit)") { break; - } else if (Input == R"(%undo)") { + } + if (Input == R"(%undo)") { if (auto Err = Interp->Undo()) { llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), "error: "); HasError = true; Index: clang/lib/Interpreter/Interpreter.cpp === --- clang/lib/Interpreter/Interpreter.cpp +++ clang/lib/Interpreter/Interpreter.cpp @@ -14,6 +14,7 @@ #include "clang/Interpreter/Interpreter.h" #include "DeviceOffload.h" +#include "ExternalSource.h" #include "IncrementalExecutor.h" #include "IncrementalParser.h" @@ -33,6 +34,7 @@ #include "clang/Driver/Tool.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/TextDiagnosticBuffer.h" +#include "clang/Interpreter/CodeCompletion.h" #include "clang/I
[PATCH] D154382: [ClangRepl] support code completion at a REPL
capfredf added inline comments. Comment at: clang/lib/Interpreter/CodeCompletion.cpp:84 + std::string AllCodeText = + MainInterp.getAllInput() + "\nvoid dummy(){\n" + Buffer.str() + "}"; + auto Lines = std::count(AllCodeText.begin(), AllCodeText.end(), '\n') + 1; v.g.vassilev wrote: > I am not sure why we need to wrap this code. Can we teach the > `TopLevelStmtDecl` to work with the code completion logic? I think the problem has less to do with the TopLevelStmtDecl. Usually, a `TopLevelStmtDecl` instance is a successful result from `ParseX`, but when `CodeCompletion` is triggered during parsing, nothing meaning comes out from `Parse`. We need to wrap our input because we need `Sema::CodeCompleteOrdinaryName` to work on code from the REPL in a different completion context than the same code from a regular source file. In a regular C++ file, ``` int foo = 42; f_ ``` Since top-level expressions are not supported, `foo` should not be an option. But in a REPL session, ``` clang-repl> int foo = 42; clang-repl> f_ ``` we are allowed to use `foo` to make a statement like `foo + 84;`. Since the argument for `CompletionContext` to `CodeCompleteOrdinaryName` is controlled by the parsing process, ie. there is no way to configure it from outside, I think faking context is a straightforward solution. Alternatively, we can check if the compiler is in incremental mode and call `CodeCompleteOrdinaryName` with the context we want in parsing. Something like: ``` if (PP.isIncrementalProcessingEnabled() { Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Statement); } else { Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Namespace); } ``` I personally think both solutions are extensionally equivalent, but the alternative is a bit intrusive. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D154382: [ClangRepl] support code completion at a REPL
v.g.vassilev added a comment. Can you extend the commit log to include a description of how things are currently done? For example, it would be good to read about design and technical decisions, etc. Comment at: clang/lib/Interpreter/CodeCompletion.cpp:79 + if (auto Err = Interp.takeError()) { +llvm::consumeError(std::move(Err)); +return Comps; Why we drop the error on the floor? Comment at: clang/lib/Interpreter/CodeCompletion.cpp:84 + std::string AllCodeText = + MainInterp.getAllInput() + "\nvoid dummy(){\n" + Buffer.str() + "}"; + auto Lines = std::count(AllCodeText.begin(), AllCodeText.end(), '\n') + 1; I am not sure why we need to wrap this code. Can we teach the `TopLevelStmtDecl` to work with the code completion logic? Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D154382/new/ https://reviews.llvm.org/D154382 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D154382: [ClangRepl] support code completion at a REPL
capfredf created this revision. capfredf added a reviewer: v.g.vassilev. Herald added a project: All. capfredf requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits. This patch enabled users to use code completion in a REPL session. The solution is based on LineEditor and Sema/CodeCompletion. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D154382 Files: clang/include/clang/Interpreter/CodeCompletion.h clang/include/clang/Interpreter/Interpreter.h clang/lib/Interpreter/CMakeLists.txt clang/lib/Interpreter/CodeCompletion.cpp clang/lib/Interpreter/ExternalSource.cpp clang/lib/Interpreter/ExternalSource.h clang/lib/Interpreter/IncrementalParser.cpp clang/lib/Interpreter/IncrementalParser.h clang/lib/Interpreter/Interpreter.cpp clang/tools/clang-repl/ClangRepl.cpp clang/unittests/Interpreter/CMakeLists.txt clang/unittests/Interpreter/CodeCompletionTest.cpp Index: clang/unittests/Interpreter/CodeCompletionTest.cpp === --- /dev/null +++ clang/unittests/Interpreter/CodeCompletionTest.cpp @@ -0,0 +1,61 @@ +#include "clang/Interpreter/CodeCompletion.h" +#include "clang/Interpreter/Interpreter.h" + +#include "llvm/LineEditor/LineEditor.h" + +#include "clang/Frontend/CompilerInstance.h" +#include "llvm/Support/Error.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using namespace clang; +namespace { +auto CB = clang::IncrementalCompilerBuilder(); + +static std::unique_ptr createInterpreter() { + auto CI = cantFail(CB.CreateCpp()); + return cantFail(clang::Interpreter::create(std::move(CI))); +} + +TEST(CodeCompletionTest, Sanity) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Completer = ReplListCompleter(CB, *Interp); + std::vector comps = + Completer(std::string("f"), 1); + EXPECT_EQ((size_t)2, comps.size()); // foo and float + EXPECT_EQ(comps[0].TypedText, std::string("oo")); +} + +TEST(CodeCompletionTest, SanityNoneValid) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int foo = 12;")) { +consumeError(std::move(R)); +return; + } + auto Completer = ReplListCompleter(CB, *Interp); + std::vector comps = + Completer(std::string("babanana"), 8); + EXPECT_EQ((size_t)0, comps.size()); // foo and float +} + +TEST(CodeCompletionTest, TwoDecls) { + auto Interp = createInterpreter(); + if (auto R = Interp->ParseAndExecute("int application = 12;")) { +consumeError(std::move(R)); +return; + } + if (auto R = Interp->ParseAndExecute("int apple = 12;")) { +consumeError(std::move(R)); +return; + } + auto Completer = ReplListCompleter(CB, *Interp); + std::vector comps = + Completer(std::string("app"), 3); + EXPECT_EQ((size_t)2, comps.size()); +} +} // anonymous namespace Index: clang/unittests/Interpreter/CMakeLists.txt === --- clang/unittests/Interpreter/CMakeLists.txt +++ clang/unittests/Interpreter/CMakeLists.txt @@ -9,6 +9,7 @@ add_clang_unittest(ClangReplInterpreterTests IncrementalProcessingTest.cpp InterpreterTest.cpp + CodeCompletionTest.cpp ) target_link_libraries(ClangReplInterpreterTests PUBLIC clangAST Index: clang/tools/clang-repl/ClangRepl.cpp === --- clang/tools/clang-repl/ClangRepl.cpp +++ clang/tools/clang-repl/ClangRepl.cpp @@ -13,6 +13,7 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Interpreter/CodeCompletion.h" #include "clang/Interpreter/Interpreter.h" #include "llvm/ExecutionEngine/Orc/LLJIT.h" @@ -155,8 +156,8 @@ if (OptInputs.empty()) { llvm::LineEditor LE("clang-repl"); -// FIXME: Add LE.setListCompleter std::string Input; +LE.setListCompleter(clang::ReplListCompleter(CB, *Interp)); while (std::optional Line = LE.readLine()) { llvm::StringRef L = *Line; L = L.trim(); @@ -168,10 +169,10 @@ } Input += L; - if (Input == R"(%quit)") { break; - } else if (Input == R"(%undo)") { + } + if (Input == R"(%undo)") { if (auto Err = Interp->Undo()) { llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), "error: "); HasError = true; Index: clang/lib/Interpreter/Interpreter.cpp === --- clang/lib/Interpreter/Interpreter.cpp +++ clang/lib/Interpreter/Interpreter.cpp @@ -14,6 +14,7 @@ #include "clang/Interpreter/Interpreter.h" #include "DeviceOffload.h" +#include "ExternalSource.h" #include "IncrementalExecutor.h" #include "IncrementalParser.h" @@ -33,6 +34,7 @@ #include "clang/Driver/Tool.h" #include "clang/Frontend