[clangd] Expose completion range in code completion results (C++ API)

Summary:
Informative only, useful for positioning UI, interacting with other sources of
completion etc. As requested by an embedder of clangd.

Reviewers: usaxena95

Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D74305
This commit is contained in:
Sam McCall 2020-02-10 11:52:42 +01:00
parent 890d5e2dd2
commit d4df372559
3 changed files with 29 additions and 0 deletions

@ -1473,6 +1473,7 @@ private:
}
Output.HasMore = Incomplete;
Output.Context = CCContextKind;
Output.CompletionRange = ReplacedRange;
return Output;
}

@ -216,6 +216,11 @@ struct CodeCompleteResult {
std::vector<CodeCompletion> Completions;
bool HasMore = false;
CodeCompletionContext::Kind Context = CodeCompletionContext::CCC_Other;
// The text that is being directly completed.
// Example: foo.pb^ -> foo.push_back()
// ~~
// Typically matches the textEdit.range of Completions, but not guaranteed to.
llvm::Optional<Range> CompletionRange;
// Usually the source will be parsed with a real C++ parser.
// But heuristics may be used instead if e.g. the preamble is not ready.
bool RanParser = true;

@ -2134,6 +2134,7 @@ TEST(GuessCompletionPrefix, Filters) {
"some text [[scope::more::]][[identif]]^ier",
"some text [[scope::]][[mor]]^e::identifier",
"weird case foo::[[::bar::]][[baz]]^",
"/* [[]][[]]^ */",
}) {
Annotations F(Case);
auto Offset = cantFail(positionToOffset(F.code(), F.point()));
@ -2675,6 +2676,28 @@ TEST(CompletionTest, NoCrashWithIncompleteLambda) {
EXPECT_THAT(Signatures, Contains(Sig("x() -> auto")));
}
TEST(CompletionTest, CompletionRange) {
const char *WithRange = "auto x = [[abc]]^";
auto Completions = completions(WithRange);
EXPECT_EQ(Completions.CompletionRange, Annotations(WithRange).range());
Completions = completionsNoCompile(WithRange);
EXPECT_EQ(Completions.CompletionRange, Annotations(WithRange).range());
const char *EmptyRange = "auto x = [[]]^";
Completions = completions(EmptyRange);
EXPECT_EQ(Completions.CompletionRange, Annotations(EmptyRange).range());
Completions = completionsNoCompile(EmptyRange);
EXPECT_EQ(Completions.CompletionRange, Annotations(EmptyRange).range());
// Sema doesn't trigger at all here, while the no-sema completion runs
// heuristics as normal and reports a range. It'd be nice to be consistent.
const char *NoCompletion = "/* [[]]^ */";
Completions = completions(NoCompletion);
EXPECT_EQ(Completions.CompletionRange, llvm::None);
Completions = completionsNoCompile(NoCompletion);
EXPECT_EQ(Completions.CompletionRange, Annotations(NoCompletion).range());
}
TEST(NoCompileCompletionTest, Basic) {
auto Results = completionsNoCompile(R"cpp(
void func() {