This is an archive of the discontinued LLVM Phabricator instance.

[clangd] Show lambda signature for lambda autocompletions
ClosedPublic

Authored by kbobyrev on Nov 19 2019, 7:55 AM.

Details

Summary

The original bug report can be found here.

Given the following code:

c++
void function() {
  auto Lambda = [](int a, double &b) {return 1.f;};
  La^
}

Triggering the completion at ^ would show (lambda) before this patch and would show signature (int a, double &b) const, build a snippet etc with this patch.

Diff Detail

Event Timeline

kbobyrev created this revision.Nov 19 2019, 7:55 AM
sammccall added inline comments.Nov 19 2019, 9:25 AM
clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
2506

testing this in clangd is nice to have, but the canonical test for stuff in sema code completion should be a lit test under clang/test/CodeCompletion IIRC

2508

specializing opts shouldn't be needed for this test

2518

auto&

clang/lib/Sema/SemaCodeComplete.cpp
3318

llvm style is to make the function static instead (we don't follow this particlularly closely in clangd, but we should here)

3319

in view of the functor (std::function etc) case, should this be extractFunctorCallOperator()?

3323

VD->getType()->getAsCXXRecordDecl() should be all you need.
getAs() and friends desugar as needed.

3330

can we fix that instead of leaving a FIXME? should only be a couple of lines I think

3330

also FIXME: support other functor types like std::function?

looking at the implementation of getLambdaCallOperatorHelper it looks pretty easy

3357

can you give this a clearer name?
Like AddFunctionTypeAndResult?

I also think making it void would be clearer, rather than mixing adding/building.

3361

why do you want to avoid adding the qualifier in lambda case?

3380

above the return statement to below - why?

kbobyrev updated this revision to Diff 230387.Nov 21 2019, 1:14 AM
kbobyrev marked 12 inline comments as done.

Add initial support for generic lambdas, put more tests into clang/test/CodeCompletion.

kbobyrev added inline comments.Nov 21 2019, 1:17 AM
clang/lib/Sema/SemaCodeComplete.cpp
3323

Could you please elaborate here? VD->getType() would be a QualType, so I first cast it to the pointer and then desugar it (otherwise I might not be able to call ->getAsCXXRecordDecl()), then I do the getAsCXXRecordDecl() as suggested. Is there any way I could simplify this?

3330

I was thinking about it, but decided against it in the end because of possible incomplete support of the generic lambdas. I have added the basic handling which, given

auto foo(auto x, const auto &y) { return &y; }

would show

foo(auto x, const auto &y) -> auto

in code completion.

This should be about exposing some human-readable dummy template types - showing foo<class A, class B>(A a, const B &b) -> B * instead. This is a bit more work: not only should we come up with the classnames (which is somewhat OK), but also connect the dots, so that the same typename is "propagated" from the piece which is responsible for adding <class A, class B> to the following pieces - the arguments and return type. I don't see any simple heuristic here and probably the correct way of doing that would be assigning a dummy typename to every TemplateTypeParmDecl and then propagating this information to AddTemplateParameterChunks, AddFunctionParameterChunks, AddFunctionTypeQualsToCompletionString, but it's certainly not several lines of code and it might be better to leave this for the next patch. This probably requires tweaking Sema::MarkDeducedTemplateParameters or doing something similar.

This kind of increases the scope of the patch (which is probably not a great thing) and also makes it incomplete in some sense, but that might be OK.

What do you think? Should I do that in a separate patch?

3380

For lambdas, ND should be replaced with CallOperator, hence I think it's easier to repeat this line of code in the above function/lambda handler (inserting the correct delcaration) and then simply proceed with the general case (i.e. use ND for the result type).

Does this make sense? Can I simplify this somehow?

Behavior looks good, and I wouldn't extend it any further (other than to non-lambda functors someday).

Implementation can be simplified a bit I think - see comment about the templated function codepath.

(Would like to see one more round if that's OK, if I'm wrong about the simplifications I'd like to understand why)

clang/lib/Sema/SemaCodeComplete.cpp
3323

QualType acts as a smart-pointer to type: QT->foo() is the same as T.foo().
(This is unusual and confusing, but you get used to it...)

You don't need to desugar, because getAsCXXRecordDecl() does the desugaring itself. This isn't clearly documented, but getAsCXXRecordDecl is a variant of (and calls) getAs<T>, which says

Look through sugar for an instance of \<specific type>.

3330

This should be about exposing some human-readable dummy template types - showing foo<class A, class B>(A a, const B &b) -> B * instead. This is a bit more work...

Frankly I'm not sure it's a good idea, so I'd suggest leaving related fixmes out.
While yes, such a signature would be accurate and provide more information, there are downsides:

  • the shown signature is very different from the declaration and may not be clear to the reader
  • it's longer/noisier, and the new information comes at the end
  • there'll be a great deal of complexity in the implementation
  • it's inconsistent with how clang treats generic lambda type params elsewhere, which is to print them as auto (see TypePrinter::printTemplateTypeParmBefore)

The basic support you've added (foo(auto x, const auto &y) -> auto) is what I'd personally like to see here as a user.

3387

I actually think there's no need to modify the "templated function" path at all - you can just take return the templated FunctionDecl from extractFunctorCallOperator and treat it as a regular function.

The template function stuff is about identifying template parameters that need to be spelled, and adding them to the CCS. With generic lambdas the type parameters are always deduced and may not be specified. And this can be assumed the case for general functors as well, as the syntax Functor f; f<int>(); isn't legal.

kbobyrev updated this revision to Diff 230594.Nov 21 2019, 11:39 PM
kbobyrev marked 7 inline comments as done.

Simplified the patch to address the comments.

clang/lib/Sema/SemaCodeComplete.cpp
3387

Good point! I did that because, as I mentioned earlier, my impression was that we would probably want something like foo<class A, class B>(A a, const B &b) -> B * (and probably even more complicated things to print dependent types). But if we don't want to go that direction, this should not be needed, thanks!

sammccall accepted this revision.Nov 22 2019, 1:34 AM

Great, thanks for fixing this!

clang/test/CodeCompletion/lambdas.cpp
66

nit: often preferable to make the examples valid syntax (and set code completion point to interrupt it, to avoid different tests interfering with each other.

(Here the my_ prefix isn't needed - plain completion on an empty line will yield the result you want)

This revision is now accepted and ready to land.Nov 22 2019, 1:34 AM
kbobyrev updated this revision to Diff 230619.Nov 22 2019, 2:36 AM

Get rid of incomplete identifiers in test code.

This revision was automatically updated to reflect the committed changes.