diff options
| -rw-r--r-- | clang-tools-extra/clangd/ClangdUnit.cpp | 4 | ||||
| -rw-r--r-- | clang-tools-extra/clangd/CodeComplete.cpp | 35 | ||||
| -rw-r--r-- | clang-tools-extra/unittests/clangd/CodeCompleteTests.cpp | 20 |
3 files changed, 41 insertions, 18 deletions
diff --git a/clang-tools-extra/clangd/ClangdUnit.cpp b/clang-tools-extra/clangd/ClangdUnit.cpp index 41f2df3669e..105bdb1fe8e 100644 --- a/clang-tools-extra/clangd/ClangdUnit.cpp +++ b/clang-tools-extra/clangd/ClangdUnit.cpp @@ -153,6 +153,10 @@ ParsedAST::Build(std::unique_ptr<clang::CompilerInvocation> CI, std::unique_ptr<llvm::MemoryBuffer> Buffer, std::shared_ptr<PCHContainerOperations> PCHs, IntrusiveRefCntPtr<vfs::FileSystem> VFS) { + assert(CI); + // Command-line parsing sets DisableFree to true by default, but we don't want + // to leak memory in clangd. + CI->getFrontendOpts().DisableFree = false; const PrecompiledPreamble *PreamblePCH = Preamble ? &Preamble->Preamble : nullptr; diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp index 4adb80c8470..cfebb3e3c94 100644 --- a/clang-tools-extra/clangd/CodeComplete.cpp +++ b/clang-tools-extra/clangd/CodeComplete.cpp @@ -699,26 +699,13 @@ bool semaCodeComplete(std::unique_ptr<CodeCompleteConsumer> Consumer, log("Couldn't create CompilerInvocation");; return false; } - CI->getFrontendOpts().DisableFree = false; + auto &FrontendOpts = CI->getFrontendOpts(); + FrontendOpts.DisableFree = false; + FrontendOpts.SkipFunctionBodies = true; CI->getLangOpts()->CommentOpts.ParseAllComments = true; - - std::unique_ptr<llvm::MemoryBuffer> ContentsBuffer = - llvm::MemoryBuffer::getMemBufferCopy(Input.Contents, Input.FileName); - - // The diagnostic options must be set before creating a CompilerInstance. - CI->getDiagnosticOpts().IgnoreWarnings = true; - // We reuse the preamble whether it's valid or not. This is a - // correctness/performance tradeoff: building without a preamble is slow, and - // completion is latency-sensitive. - auto Clang = prepareCompilerInstance( - std::move(CI), Input.Preamble, std::move(ContentsBuffer), - std::move(Input.PCHs), std::move(Input.VFS), DummyDiagsConsumer); - // Disable typo correction in Sema. - Clang->getLangOpts().SpellChecking = false; - - auto &FrontendOpts = Clang->getFrontendOpts(); - FrontendOpts.SkipFunctionBodies = true; + CI->getLangOpts()->SpellChecking = false; + // Setup code completion. FrontendOpts.CodeCompleteOpts = Options; FrontendOpts.CodeCompletionAt.FileName = Input.FileName; auto Offset = positionToOffset(Input.Contents, Input.Pos); @@ -731,6 +718,18 @@ bool semaCodeComplete(std::unique_ptr<CodeCompleteConsumer> Consumer, FrontendOpts.CodeCompletionAt.Column) = offsetToClangLineColumn(Input.Contents, *Offset); + std::unique_ptr<llvm::MemoryBuffer> ContentsBuffer = + llvm::MemoryBuffer::getMemBufferCopy(Input.Contents, Input.FileName); + // The diagnostic options must be set before creating a CompilerInstance. + CI->getDiagnosticOpts().IgnoreWarnings = true; + // We reuse the preamble whether it's valid or not. This is a + // correctness/performance tradeoff: building without a preamble is slow, and + // completion is latency-sensitive. + // NOTE: we must call BeginSourceFile after prepareCompilerInstance. Otherwise + // the remapped buffers do not get freed. + auto Clang = prepareCompilerInstance( + std::move(CI), Input.Preamble, std::move(ContentsBuffer), + std::move(Input.PCHs), std::move(Input.VFS), DummyDiagsConsumer); Clang->setCodeCompletionConsumer(Consumer.release()); SyntaxOnlyAction Action; diff --git a/clang-tools-extra/unittests/clangd/CodeCompleteTests.cpp b/clang-tools-extra/unittests/clangd/CodeCompleteTests.cpp index 6ebc8f81c99..d78b4bdd579 100644 --- a/clang-tools-extra/unittests/clangd/CodeCompleteTests.cpp +++ b/clang-tools-extra/unittests/clangd/CodeCompleteTests.cpp @@ -18,6 +18,7 @@ #include "TestFS.h" #include "index/MemIndex.h" #include "llvm/Support/Error.h" +#include "llvm/Testing/Support/Error.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -1040,6 +1041,25 @@ TEST(CompletionTest, DocumentationFromChangedFileCrash) { Contains(AllOf(Not(IsDocumented()), Named("func")))); } +TEST(CompletionTest, CompleteOnInvalidLine) { + auto FooCpp = testPath("foo.cpp"); + + MockCompilationDatabase CDB; + IgnoreDiagnostics DiagConsumer; + MockFSProvider FS; + FS.Files[FooCpp] = "// empty file"; + + ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest()); + // Run completion outside the file range. + Position Pos; + Pos.line = 100; + Pos.character = 0; + EXPECT_THAT_EXPECTED( + runCodeComplete(Server, FooCpp, Pos, clangd::CodeCompleteOptions()), + Failed()); +} + + } // namespace } // namespace clangd } // namespace clang |

