This is an archive of the discontinued LLVM Phabricator instance.

[clangd] support expanding `decltype(expr)`
ClosedPublic

Authored by v1nh1shungry on Jan 8 2023, 8:46 AM.

Details

Summary

Enable the existing tweak ExpandAutoType to expand
decltype(expr), e.g.

decltype(0) i;

will expand to

int i;

Therefore, rename the tweak ExpandAutoType to ExpandDeducedType.

This patch also fixes some nits,

  • avoid replacing reference to a function
  • avoid replacing array types and reference to an array

Diff Detail

Event Timeline

v1nh1shungry created this revision.Jan 8 2023, 8:46 AM
Herald added a project: Restricted Project. · View Herald TranscriptJan 8 2023, 8:46 AM
v1nh1shungry requested review of this revision.Jan 8 2023, 8:46 AM

If this is okay to go ahead, I'm considering renaming the tweak. Does ExpandType or ExpandDeducedType sound good?

rename the tweak ExpandAutoType to ExpandDeducedType

Herald added projects: Restricted Project, Restricted Project. · View Herald TranscriptJan 9 2023, 12:03 PM
  • avoid expanding dependent types
  • avoid expanding reference to a function
  • avoid expanding array type and reference to an array
v1nh1shungry retitled this revision from [WIP][clangd] support expanding `decltype(expr)` to [clangd] support expanding `decltype(expr)`.Jan 9 2023, 10:38 PM
v1nh1shungry edited the summary of this revision. (Show Details)

avoid expanding pointer to an array

Thanks for doing this!

There are a couple of separate logical changes here - I don't think it's a problem per se, but it does mean it takes a bit longer to get the good + obvious stuff reviewed and landed.

clang-tools-extra/clangd/refactor/tweaks/ExpandDeducedType.cpp
56

Maybe "Replace with deduced type" would be clearer for both cases?

Then we don't need to track IsAutoType.
(I have no objection with spending a bit of code to provide better text, but given that the cursor is either on top of "auto" or "decltype" I don't think we're actually adding anything by echoing it back)

124

isDeducedAsLambda is detecting the specific pattern auto x = [&} { ... };, which doesn't occur with decltype.

On the other hand I suspect the DecltypeTypeLoc for decltype(some_lambda) doesn't suffer from the same issue as the AutoTypeLoc in a declaration, and we can simply call getUnderlyingType().

So I think you can simply factor out isLambda(QualType) from isDeducedAsLambda, and call isLambda(DTTL.getType()->getUnderlyingType()) here.

141–142

why not? replacing this with T seems perfectly reasonable.
(The fact that we don't do this with auto t = T{} is just because we're hitting a limitation of clang's AST)

151

these are unrelated to the decltype change (decltype(auto) is an AutoType rather than a DecltypeType and already works/has this bug today).

In future it's best to split unrelated changes into different patches/a patch sequence, though this is simple enough it's probably OK.

153

the commonality between these cases you're excluding (and the function types below) is that they use C-style declarator syntax that may have chunks following the declarator-id. Specifically:

  • array, function, and paren types always have chunks following the declarator
  • pointer and reference types compose inside-out so their pointee types may contain trailing chunks

If we want to make some attempt to detect more cases, we should pull out a function here and do it properly, something like: bool hasTrailingChunks(QualType) which calls recursively for pointertype etc.

But there's a cheaper way: when we call printType() below, we can optionally specify the declarator-id. Then we can simply check whether it's at the end of the string:

std::string PrettyDeclarator = printType(..., "DECLARATOR_ID");
llvm::StringRef PrettyType = PrettyDeclarator;
if (!PrettyType.consume_back("DECLARATOR_ID"))
  return error("could not expand non-contiguous type {0}", PrettyType);
PrettyType = PrettyType.rtrim();

This feels slightly hacky, but it's direct and simple and we shouldn't miss a case.

Thank you for reviewing and giving suggestions!

clang-tools-extra/clangd/refactor/tweaks/ExpandDeducedType.cpp
56

I think your suggestion is better. Thanks!

141–142

I'd like it too. But the printType() would give out a <dependent type>. Though I haven't looked into this, would you mind giving some suggestions about it?

sammccall added inline comments.Jan 11 2023, 7:41 AM
clang-tools-extra/clangd/refactor/tweaks/ExpandDeducedType.cpp
141–142

Ah, there are three subtly different concepts here:

  • is this type usefully printable? There are various reasons why it may not be, it can contain DependentTy, or a canonical template parameter (<template-param-0-0>), or a lambda.
  • is this type dependent in the language sense - an example is some type parameter T. This may or may not be usefully printable. (e.g. try template<class X> std::vector<X> y; and hover on y)
  • is this type specifically DependentTy, the placeholder dependent type which we have no information about. This is never usefully printable: prints as <dependent type>

As a heuristic, I'm happy with saying dependent types (in the language sense) are likely not to print usefully, so don't replace them. But the comment should say so (this is a heuristic for unprintable rather than an end in itself), and probably give examples.

v1nh1shungry added inline comments.Jan 11 2023, 8:20 AM
clang-tools-extra/clangd/refactor/tweaks/ExpandDeducedType.cpp
141–142

Hmm, do you mean it's okay to refuse to replace dependent types but I should leave a comment saying the reason is that they are likely not to print usefully? Sorry if I misunderstood anything! I'm really not a good reader :(

153

TBH, I'm confused about printType() and its placeholder DECLARATOR_ID. Is the code your offered above can be used directly?

If so, I had a try on it and it did refuse to replace types like function and array. But it would give an error message saying "Could not expand non-contiguous type const char (&DECLARATOR_ID)[6]". Is this okay? I mean isn't the "DECLARATOR_ID" in the message a bit confusing?

sammccall added inline comments.Jan 11 2023, 8:59 AM
clang-tools-extra/clangd/refactor/tweaks/ExpandDeducedType.cpp
141–142

Yeah, exactly!

153

That was the idea, but I think you're right the error message is confusing.

We need to strike a balance between being precise, being easy to understand, and being reasonable to maintain.

I think it's probably best to be a bit vague here rather than using precise but obscure language, maybe "could not expand type that isn't a simple string".
Whether to leave out the actual type, include it with DECLARATOR_ID in it, or call printType() again with an empty placeholder is up to you - I don't think any of those are too confusing in context.

address the comments

v1nh1shungry marked 7 inline comments as done.Jan 11 2023, 9:40 AM
sammccall accepted this revision.Jan 11 2023, 10:57 AM

LGTM with a comment nit, thank you!
Do you have commit access?

clang-tools-extra/clangd/refactor/tweaks/ExpandDeducedType.cpp
152

Say why rather than what, e.g.

Some types aren't written as single chunks of text, e.g:
  auto fptr = &func; // auto is void(*)()
==>
  void (*fptr)();

Replacing these requires examining the declarator, we don't support it yet.
This revision is now accepted and ready to land.Jan 11 2023, 10:57 AM
sammccall added inline comments.Jan 11 2023, 10:58 AM
clang-tools-extra/clangd/refactor/tweaks/ExpandDeducedType.cpp
152

oops, that should be void (*fptr)() = &func; of course..

modify the comment

v1nh1shungry marked 2 inline comments as done.Jan 11 2023, 11:16 AM

Thank you for reviewing and giving guidance!

Do you have commit access?

I don't. If this patch is okay to land, could you please help me commit it? Thanks a lot!

This revision was landed with ongoing or failed builds.Jan 12 2023, 6:27 PM
This revision was automatically updated to reflect the committed changes.