This is an archive of the discontinued LLVM Phabricator instance.

[clangd] Refine logic on $0 in completion snippets
ClosedPublic

Authored by zyounan on Mar 5 2023, 4:02 AM.

Details

Summary

We have a workaround from D128621 that makes $0 no longer being
a placeholder to conform a vscode feature. However, we have to
refine the logic as it may suppress the last parameter placeholder
for constructor of base class because not all patterns of completion
are compound statements.

This fixes clangd/clangd#1479

Diff Detail

Event Timeline

zyounan created this revision.Mar 5 2023, 4:02 AM
Herald added a project: Restricted Project. · View Herald TranscriptMar 5 2023, 4:02 AM
zyounan published this revision for review.Mar 5 2023, 4:24 AM
zyounan added inline comments.
clang-tools-extra/clangd/CodeCompletionStrings.cpp
153

I was cringed that if we should refine the logic based on CursorKind: It is from libclang; The meaning is sometimes kind of opaque (to me, I don't know it very clearly TBH) like CXCursor_NotImplemented...

Thanks for the patch!

In the future we may want to add other cursor kinds for which ShouldPatchPlaceholder0 should be false, but I think this is a good start which addresses the case from the bug.

clang-tools-extra/clangd/CodeComplete.cpp
439–440

Since we are now passing in the entire C.SemaResult, can we remove the CompletingPattern parameter, and compute that boolean inside the function instead?

clang-tools-extra/clangd/CodeCompletionStrings.cpp
124–125

Can we move this check after the declaration of ShouldPatchPlaceholder0, and change the condition to if (ShouldPatchPlaceholder0)?

(And at the usage site, swap the operands to if (ShouldPatchPlaceholder0 && SnippetArg == CursorSnippetArg)?)

This would avoid doing the count_if when not necessary.

153

It does seem like a layering violation that a libSema interface (CodeCompletionResult) uses a libclang type (CXCursorKind), but that's a pre-existing issue.

zyounan updated this revision to Diff 504947.Mar 13 2023, 11:12 PM
zyounan marked 3 inline comments as done.

Address the comments. Revise parameters of getSignature to avoid passing CCR

clang-tools-extra/clangd/CodeComplete.cpp
439–440

Revise the parameters of getSignature to circumvent CCR now -- Tests for CodeCompletionStrings do not construct any CCR and I don't think it necessary to add that logic.

clang-tools-extra/clangd/CodeCompletionStrings.cpp
124–125

Nice catch! thanks!

153

It does seem like a layering violation that a libSema interface (CodeCompletionResult) uses a libclang type (CXCursorKind), but that's a pre-existing issue.

153

Thanks for clarifying.

zyounan updated this revision to Diff 504950.Mar 13 2023, 11:23 PM

Update doxygen comments

clang-tools-extra/clangd/CodeCompletionStrings.h
44–45

Sorry, I forget to revise the comments :(

Thanks for the update! I have a couple of more minor suggestions, hope you don't mind; I'm trying to make sure the next person to look at this will easily understand what the code is trying to do.

clang-tools-extra/clangd/CodeCompletionStrings.cpp
131

Can we factor this out to a namespace scope function bool shouldPatchPlaceholder0(CodeCompletionResult::ResultKind ResultKind, CXCursorKind CursorKind)?

Then the code here becomes pretty simple:

unsigned CursorSnippetArg = std::numeric_limits<unsigned>::max();
if (shouldPatchPlaceholder0(ResultKind, CursorKind)) {
  CursorSnippetArg = count_if(...);
}

And we can combine some of the comments here into a single comment that explains what we are doing:

// By default, the final cursor position is at the end of the snippet,
// but we have the option to place it somewhere else using $0.
// If the snippet contains a group of statements, we replace the
// last placeholder with $0 to leave the cursor there, e.g.
//    namespace ${1:name} {
//      ${0:decls}
//    }
// We try to identify such cases using the ResultKind and CursorKind.
219

I realized the first part of the condition is now redundant: if ShouldPatchPlaceholder0 == false, then CursorSnippetArg will have value std::numeric_limits<unsigned>::max() and SnippetArg == CursorSnippetArg will never be true.

clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp
31–33

Suggestion: it may be easier to understand if we change the bool CompletingPattern = false parameter of this function to CodeCompletionResult::ResultKind ResultKind = CodeCompletionResult::ResultKind::RK_Declaration.

(And the call site which passed CompletingPattern=true can now pass ResultKind=RK_Pattern.)

Then we don't need to refer to historical behaviour.

zyounan updated this revision to Diff 505420.Mar 15 2023, 3:01 AM
zyounan marked 3 inline comments as done.

Address comments

Updated now. Thank you again for your patient review. :)

clang-tools-extra/clangd/CodeCompletionStrings.cpp
219

Aha, yes. Almost forget that.

nridge accepted this revision.Mar 17 2023, 12:38 AM

Thanks! I have just one final nit, then please feel free to merge.

clang-tools-extra/clangd/CodeCompletionStrings.cpp
60

nit: let's add a short comment to describe the function, such as:

// Determine whether the completion string should be patched
// to replace the last placeholder with $0
This revision is now accepted and ready to land.Mar 17 2023, 12:38 AM
zyounan updated this revision to Diff 506001.Mar 17 2023, 1:24 AM
zyounan marked an inline comment as done.

Add description to shouldPatchPlaceholder0

clang-tools-extra/clangd/CodeCompletionStrings.cpp
60

Sure!

This revision was automatically updated to reflect the committed changes.