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 <cstdlib> #include <string> - #ifdef UDP_CODE_COMPLETION_LOGGER #include "clang/Basic/Version.h" #include <arpa/inet.h> @@ -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<llvm::LineEditor::Completion> operator()(llvm::StringRef Buffer, + size_t Pos) const; + std::vector<llvm::LineEditor::Completion> + operator()(llvm::StringRef Buffer, size_t Pos, llvm::Error &ErrRes) const; +}; + +std::vector<llvm::LineEditor::Completion> +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<llvm::LineEditor::Completion> +ReplListCompleter::operator()(llvm::StringRef Buffer, size_t Pos, + llvm::Error &ErrRes) const { + std::vector<llvm::LineEditor::Completion> Comps; + std::vector<std::string> 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<clang::CompilerInstance *>((*Interp)->getCompilerInstance()), + Buffer, Lines, Pos + 1, MainInterp.getCompilerInstance(), Results); + + size_t space_pos = Buffer.rfind(" "); + llvm::StringRef Prefix; + if (space_pos == llvm::StringRef::npos) { + Prefix = Buffer; + } else { + Prefix = Buffer.substr(space_pos + 1); + } + + for (auto c : Results) { + if (c.find(Prefix) == 0) + Comps.push_back(llvm::LineEditor::Completion(c.substr(Prefix.size()), c)); + } + return Comps; +} + llvm::ExitOnError ExitOnErr; int main(int argc, const char **argv) { ExitOnErr.setBanner("clang-repl: "); @@ -135,6 +200,7 @@ DeviceCI->LoadRequestedPlugins(); std::unique_ptr<clang::Interpreter> Interp; + if (CudaEnabled) { Interp = ExitOnErr( clang::Interpreter::createWithCUDA(std::move(CI), std::move(DeviceCI))); @@ -157,8 +223,8 @@ if (OptInputs.empty()) { llvm::LineEditor LE("clang-repl"); - // FIXME: Add LE.setListCompleter std::string Input; + LE.setListCompleter(ReplListCompleter(CB, *Interp)); while (std::optional<std::string> Line = LE.readLine()) { llvm::StringRef L = *Line; L = L.trim(); @@ -170,10 +236,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_Statement: + case CodeCompletionContext::CCC_TopLevelOrExpression: case CodeCompletionContext::CCC_Recovery: if (ObjCMethodDecl *Method = SemaRef.getCurMethodDecl()) if (Method->isInstanceMethod()) @@ -1850,6 +1851,7 @@ case Sema::PCC_ObjCInstanceVariableList: case Sema::PCC_Expression: case Sema::PCC_Statement: + case Sema::PCC_TopLevelOrExpression: case Sema::PCC_ForInit: case Sema::PCC_Condition: case Sema::PCC_RecoveryInFunction: @@ -1907,6 +1909,7 @@ case Sema::PCC_Type: case Sema::PCC_ParenthesizedExpression: case Sema::PCC_LocalDeclarationSpecifiers: + case Sema::PCC_TopLevelOrExpression: return true; case Sema::PCC_Expression: @@ -2219,6 +2222,7 @@ break; case Sema::PCC_RecoveryInFunction: + case Sema::PCC_TopLevelOrExpression: case Sema::PCC_Statement: { if (SemaRef.getLangOpts().CPlusPlus11) AddUsingAliasResult(Builder, Results); @@ -4208,6 +4212,8 @@ case Sema::PCC_LocalDeclarationSpecifiers: return CodeCompletionContext::CCC_Type; + case Sema::PCC_TopLevelOrExpression: + return CodeCompletionContext::CCC_TopLevelOrExpression; } llvm_unreachable("Invalid ParserCompletionContext!"); @@ -4348,6 +4354,7 @@ break; case PCC_Statement: + case PCC_TopLevelOrExpression: case PCC_ParenthesizedExpression: case PCC_Expression: case PCC_ForInit: @@ -4385,6 +4392,7 @@ case PCC_ParenthesizedExpression: case PCC_Expression: case PCC_Statement: + case PCC_TopLevelOrExpression: case PCC_RecoveryInFunction: if (S->getFnParent()) AddPrettyFunctionResults(getLangOpts(), Results); Index: clang/lib/Sema/CodeCompleteConsumer.cpp =================================================================== --- clang/lib/Sema/CodeCompleteConsumer.cpp +++ clang/lib/Sema/CodeCompleteConsumer.cpp @@ -51,6 +51,7 @@ case CCC_ParenthesizedExpression: case CCC_Symbol: case CCC_SymbolOrNewName: + case CCC_TopLevelOrExpression: return true; case CCC_TopLevel: @@ -169,6 +170,8 @@ return "Recovery"; case CCKind::CCC_ObjCClassForwardDecl: return "ObjCClassForwardDecl"; + case CCKind::CCC_TopLevelOrExpression: + return "ReplTopLevel"; } llvm_unreachable("Invalid CodeCompletionContext::Kind!"); } Index: clang/lib/Parse/Parser.cpp =================================================================== --- clang/lib/Parse/Parser.cpp +++ clang/lib/Parse/Parser.cpp @@ -923,9 +923,16 @@ /*IsInstanceMethod=*/std::nullopt, /*ReturnType=*/nullptr); } - Actions.CodeCompleteOrdinaryName( - getCurScope(), - CurParsedObjCImpl ? Sema::PCC_ObjCImplementation : Sema::PCC_Namespace); + + Sema::ParserCompletionContext PCC; + if (CurParsedObjCImpl) { + PCC = Sema::PCC_ObjCImplementation; + } else if (PP.isIncrementalProcessingEnabled()) { + PCC = Sema::PCC_TopLevelOrExpression; + } else { + PCC = Sema::PCC_Namespace; + }; + Actions.CodeCompleteOrdinaryName(getCurScope(), PCC); return nullptr; case tok::kw_import: { Sema::ModuleImportState IS = Sema::ModuleImportState::NotACXX20Module; Index: clang/lib/Parse/ParseDecl.cpp =================================================================== --- clang/lib/Parse/ParseDecl.cpp +++ clang/lib/Parse/ParseDecl.cpp @@ -18,6 +18,7 @@ #include "clang/Basic/Attributes.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TokenKinds.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" #include "clang/Parse/RAIIObjectsForParser.h" Index: clang/lib/Interpreter/Interpreter.cpp =================================================================== --- clang/lib/Interpreter/Interpreter.cpp +++ clang/lib/Interpreter/Interpreter.cpp @@ -11,13 +11,11 @@ // //===----------------------------------------------------------------------===// -#include "clang/Interpreter/Interpreter.h" - #include "DeviceOffload.h" #include "IncrementalExecutor.h" #include "IncrementalParser.h" - #include "InterpreterUtils.h" + #include "clang/AST/ASTContext.h" #include "clang/AST/Mangle.h" #include "clang/AST/TypeVisitor.h" @@ -33,6 +31,7 @@ #include "clang/Driver/Tool.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/TextDiagnosticBuffer.h" +#include "clang/Interpreter/Interpreter.h" #include "clang/Interpreter/Value.h" #include "clang/Lex/PreprocessorOptions.h" #include "clang/Sema/Lookup.h" @@ -127,7 +126,6 @@ Clang->getFrontendOpts().DisableFree = false; Clang->getCodeGenOpts().DisableFree = false; - return std::move(Clang); } @@ -276,6 +274,7 @@ std::unique_ptr<Interpreter>(new Interpreter(std::move(CI), Err)); if (Err) return std::move(Err); + auto PTU = Interp->Parse(Runtimes); if (!PTU) return PTU.takeError(); Index: clang/lib/Interpreter/IncrementalParser.h =================================================================== --- clang/lib/Interpreter/IncrementalParser.h +++ clang/lib/Interpreter/IncrementalParser.h @@ -13,9 +13,9 @@ #ifndef LLVM_CLANG_LIB_INTERPRETER_INCREMENTALPARSER_H #define LLVM_CLANG_LIB_INTERPRETER_INCREMENTALPARSER_H +#include "clang/AST/GlobalDecl.h" #include "clang/Interpreter/PartialTranslationUnit.h" -#include "clang/AST/GlobalDecl.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" @@ -24,7 +24,7 @@ #include <memory> namespace llvm { class LLVMContext; -} +} // namespace llvm namespace clang { class ASTConsumer; Index: clang/lib/Interpreter/IncrementalParser.cpp =================================================================== --- clang/lib/Interpreter/IncrementalParser.cpp +++ clang/lib/Interpreter/IncrementalParser.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "IncrementalParser.h" + #include "clang/AST/DeclContextInternals.h" #include "clang/CodeGen/BackendUtil.h" #include "clang/CodeGen/CodeGenAction.h" @@ -157,16 +158,11 @@ TranslationUnitKind getTranslationUnitKind() override { return TU_Incremental; } + void ExecuteAction() override { CompilerInstance &CI = getCompilerInstance(); assert(CI.hasPreprocessor() && "No PP!"); - // FIXME: Move the truncation aspect of this into Sema, we delayed this till - // here so the source manager would be initialized. - if (hasCodeCompletionSupport() && - !CI.getFrontendOpts().CodeCompletionAt.FileName.empty()) - CI.createCodeCompletionConsumer(); - // Use a code completion consumer? CodeCompleteConsumer *CompletionConsumer = nullptr; if (CI.hasCodeCompletionConsumer()) @@ -398,5 +394,4 @@ assert(CG); return CG->GetMangledName(GD); } - } // end namespace clang Index: clang/lib/Interpreter/CMakeLists.txt =================================================================== --- clang/lib/Interpreter/CMakeLists.txt +++ clang/lib/Interpreter/CMakeLists.txt @@ -13,6 +13,7 @@ add_clang_library(clangInterpreter DeviceOffload.cpp + CodeCompletion.cpp IncrementalExecutor.cpp IncrementalParser.cpp Interpreter.cpp Index: clang/lib/Frontend/ASTUnit.cpp =================================================================== --- clang/lib/Frontend/ASTUnit.cpp +++ clang/lib/Frontend/ASTUnit.cpp @@ -2008,7 +2008,8 @@ case CodeCompletionContext::CCC_SymbolOrNewName: case CodeCompletionContext::CCC_ParenthesizedExpression: case CodeCompletionContext::CCC_ObjCInterfaceName: - break; + case CodeCompletionContext::CCC_TopLevelOrExpression: + break; case CodeCompletionContext::CCC_EnumTag: case CodeCompletionContext::CCC_UnionTag: @@ -2167,7 +2168,8 @@ std::shared_ptr<PCHContainerOperations> PCHContainerOps, DiagnosticsEngine &Diag, LangOptions &LangOpts, SourceManager &SourceMgr, FileManager &FileMgr, SmallVectorImpl<StoredDiagnostic> &StoredDiagnostics, - SmallVectorImpl<const llvm::MemoryBuffer *> &OwnedBuffers) { + SmallVectorImpl<const llvm::MemoryBuffer *> &OwnedBuffers, + std::unique_ptr<SyntaxOnlyAction> Act) { if (!Invocation) return; @@ -2304,8 +2306,9 @@ if (!Clang->getLangOpts().Modules) PreprocessorOpts.DetailedRecord = false; - std::unique_ptr<SyntaxOnlyAction> Act; - Act.reset(new SyntaxOnlyAction); + if (!Act) + Act.reset(new SyntaxOnlyAction); + if (Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0])) { if (llvm::Error Err = Act->Execute()) { consumeError(std::move(Err)); // FIXME this drops errors on the floor. Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -13456,7 +13456,9 @@ PCC_ParenthesizedExpression, /// Code completion occurs within a sequence of declaration /// specifiers within a function, method, or block. - PCC_LocalDeclarationSpecifiers + PCC_LocalDeclarationSpecifiers, + /// Code completion occurs at top-level in a REPL session + PCC_TopLevelOrExpression, }; void CodeCompleteModuleImport(SourceLocation ImportLoc, ModuleIdPath Path); Index: clang/include/clang/Sema/CodeCompleteConsumer.h =================================================================== --- clang/include/clang/Sema/CodeCompleteConsumer.h +++ clang/include/clang/Sema/CodeCompleteConsumer.h @@ -336,7 +336,12 @@ CCC_Recovery, /// Code completion in a @class forward declaration. - CCC_ObjCClassForwardDecl + CCC_ObjCClassForwardDecl, + + /// Code completion at a top level, i.e. in a namespace or global scope, + /// but also in expression statements. This is because REPL inputs can be + /// declarations or expression statements. + CCC_TopLevelOrExpression, }; using VisitedContextSet = llvm::SmallPtrSet<DeclContext *, 8>; Index: clang/include/clang/Frontend/ASTUnit.h =================================================================== --- clang/include/clang/Frontend/ASTUnit.h +++ clang/include/clang/Frontend/ASTUnit.h @@ -77,6 +77,7 @@ class PreprocessorOptions; class Sema; class TargetInfo; +class SyntaxOnlyAction; /// \brief Enumerates the available scopes for skipping function bodies. enum class SkipFunctionBodiesScope { None, Preamble, PreambleAndMainFile }; @@ -887,6 +888,10 @@ /// \param IncludeBriefComments Whether to include brief documentation within /// the set of code completions returned. /// + /// \param Act If supplied, this argument is used to parse the input file, + /// allowing customized parsing by overriding SyntaxOnlyAction lifecycle + /// methods. + /// /// FIXME: The Diag, LangOpts, SourceMgr, FileMgr, StoredDiagnostics, and /// OwnedBuffers parameters are all disgusting hacks. They will go away. void CodeComplete(StringRef File, unsigned Line, unsigned Column, @@ -897,7 +902,8 @@ DiagnosticsEngine &Diag, LangOptions &LangOpts, SourceManager &SourceMgr, FileManager &FileMgr, SmallVectorImpl<StoredDiagnostic> &StoredDiagnostics, - SmallVectorImpl<const llvm::MemoryBuffer *> &OwnedBuffers); + SmallVectorImpl<const llvm::MemoryBuffer *> &OwnedBuffers, + std::unique_ptr<SyntaxOnlyAction> Act = nullptr); /// Save this translation unit to a file with the given name. /// Index: clang-tools-extra/clangd/CodeComplete.cpp =================================================================== --- clang-tools-extra/clangd/CodeComplete.cpp +++ clang-tools-extra/clangd/CodeComplete.cpp @@ -821,6 +821,7 @@ case CodeCompletionContext::CCC_Symbol: case CodeCompletionContext::CCC_SymbolOrNewName: case CodeCompletionContext::CCC_ObjCClassForwardDecl: + case CodeCompletionContext::CCC_TopLevelOrExpression: return true; case CodeCompletionContext::CCC_OtherWithMacros: case CodeCompletionContext::CCC_DotMemberAccess:
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits