summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang-tools-extra/clangd/ClangdUnit.cpp4
-rw-r--r--clang-tools-extra/clangd/CodeComplete.cpp35
-rw-r--r--clang-tools-extra/unittests/clangd/CodeCompleteTests.cpp20
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
OpenPOWER on IntegriCloud