This is an archive of the discontinued LLVM Phabricator instance.

[clangd] Don't produce snippets when completion location is followed by parenthesis
ClosedPublic

Authored by kbobyrev on Jun 8 2020, 4:49 AM.

Details

Summary

Prevent a second pair of parenthesis from being added when there already is one
right after cursor.

Related issue and more context: https://github.com/clangd/clangd/issues/387

Diff Detail

Event Timeline

kbobyrev created this revision.Jun 8 2020, 4:49 AM
Herald added a project: Restricted Project. · View Herald TranscriptJun 8 2020, 4:50 AM

Thanks, this is nice!

clang-tools-extra/clangd/CodeComplete.cpp
1240

I'd suggest rather storing the token kind as NextToken, and then deferring the actual "is it l_paren" check until toCodeCompletion.
That way the should-we-generate-snippets logic is more localized and IMO easier to read.

1295

need to decide what to do when it returns none, or add an explicit assert with a message ("code completing in macro?")

1714

This is a bit lengthy for describing an implementation strategy we're *not* using. Do you think we're very likely to do this, and this comment would save a lot of the work of finding out how?

I'd rather add a comment explaining what we *are* doing
e.g. Suppress function argument snippets if args are already present, or not needed (using decl).
And at most // Should we consider sometimes replacing parens with the snippet instead?

1720

how sure are we that paren-after is the right condition in all cases? Does "snippet" cover template snippets (std::vector<{$0}>)?

Don't need to handle this but it'd be nice to cover in tests.

clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
2878

nit: I don't really follow this test name, but it seems to be explaining part of the implementation.

What about FunctionArgsExist which rather explains the scenario?

2890

can we have fo^o(42) as a case as well?

kbobyrev updated this revision to Diff 269430.Jun 9 2020, 1:02 AM
kbobyrev marked 9 inline comments as done.

Make sure snippets are omitted only in the function/method/constructor calls
for safety and extend the testset.

clang-tools-extra/clangd/CodeComplete.cpp
1295

Yeah, forgot about that -_- I think just doing nothing is OK here?

1714

I'd like to do that next patch (this patch is actually a simplified version of what I *wanted* to do, but I figured there are too many corner cases and complications. I would like to get to that very soon but I'm just afraid I'll be distracted or something. I should probably just write this down for myself, that would be fine.

1720

Yeah templates are hard :( The problem here is that this is a heuristic and I was considering suppressing pieces of the CC snippets (e.g. the templated parts) upon having < token ahead but this can also be "less than" sign and the heuristics are probably going to be harder for this. Maybe some semantic analysis would do, but I'm not sure about all the details right now.

I've added a test which shows how the template snippet will be omitted, is that OK with you?

clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
2890

We can, but it wouldn't be handled "as expected" :) The problem would be that the next token is an identifier (o) and hence this wouldn't work. I'd like to fix that too (see if the next token is an identifier and a suffix of inserted text), but I think this should be a separate patch.

Do you want me to add this case with a FIXME?

sammccall accepted this revision.Jun 9 2020, 2:11 AM
sammccall marked 2 inline comments as done.
sammccall added inline comments.
clang-tools-extra/clangd/CodeComplete.cpp
1295

Yup EOF LGTM.

1718

now you've got the "should we generate snippets" logic split a different way :-) No-snippets-for-using-decl is expressed here, but no-args-if-parens-exist is inside the builder.

I think it's slightly neater (less plumbing) to compute it here - it's safe to do so based on the current item because we won't produce a bundle containing functions together with other things.

Also fine to pass in IsUsingDeclaration, but it should be to a parameter called "IsUsingDeclaration" rather than one called GenerateSnippets, as it's only part of the equation.

1720

Yes, adding a test showing we don't handle this edge case is fine.

clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
2890

Yes, no need to handle it, but let's add a test and mark it as bad.

2918

Add a fixme: should be "<${1:typename T}>"

This revision is now accepted and ready to land.Jun 9 2020, 2:11 AM
sammccall added inline comments.Jun 9 2020, 2:17 AM
clang-tools-extra/clangd/CodeComplete.cpp
1720

BTW it might be possible to handle this robustly by having Preprocessor::Lex look ahead once it reaches the CC token and call setCodeCompletionTokenRange appropriately. You'd then have to look for the token at the endpoint of this range, rather than the one after the code completion point.

Clangd is the only (in-tree) user of the code completion token range, we use it to decide what to replace.

kbobyrev updated this revision to Diff 269464.Jun 9 2020, 2:45 AM
kbobyrev marked 4 inline comments as done.

Address most comments.

clang-tools-extra/clangd/CodeComplete.cpp
1718

Also fine to pass in IsUsingDeclaration, but it should be to a parameter called "IsUsingDeclaration" rather than one called GenerateSnippets, as it's only part of the equation.

Yeah I thought it might be a bit confusing to split this up, but couldn't figure out what would be best option. This sounds logical, will do!

I think it's slightly neater (less plumbing) to compute it here - it's safe to do so based on the current item because we won't produce a bundle containing functions together with other things.

I'm a bit confused: I moved the l_brace token detection logic into the builder because it resolves the completion kind, so computing it here would require the completion item kind to be resolved at this point. So are you suggesting moving the completion kind resolution out of the builder here and then passing it to the builder along with GenerateSnippets?

kbobyrev marked an inline comment as not done.Jun 9 2020, 2:45 AM
kbobyrev marked an inline comment as done.
kbobyrev updated this revision to Diff 269471.Jun 9 2020, 3:05 AM
kbobyrev marked 2 inline comments as done.

Don't split the snippet omitting logic between the builder and its caller.

sammccall accepted this revision.Jun 9 2020, 3:50 AM
sammccall marked an inline comment as done.

Ship it!

clang-tools-extra/clangd/CodeComplete.cpp
1718

Yeah, I didn't see that we don't yet have access to the kind here.

This revision was automatically updated to reflect the committed changes.