Commit d4df3725 authored by Sam McCall's avatar Sam McCall
Browse files

[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
parent 890d5e2d
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1473,6 +1473,7 @@ private:
    }
    Output.HasMore = Incomplete;
    Output.Context = CCContextKind;
    Output.CompletionRange = ReplacedRange;
    return Output;
  }

+5 −0
Original line number Diff line number Diff line
@@ -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;
+23 −0
Original line number Diff line number Diff line
@@ -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() {