This is an archive of the discontinued LLVM Phabricator instance.

[clangd] Desugar template parameter aliases in type hints
ClosedPublic

Authored by zyounan on May 31 2023, 12:26 AM.

Details

Summary

This patch alleviates https://github.com/clangd/clangd/issues/1298.

Containers in C++ such as std::vector or llvm::SmallVector,
introduce a series of type aliases to adapt to generic algorithms.

Currently, If we write an declarator involving expressions with
these containers and auto placeholder, we probably obtain opaque
type alias like following:

std::vector<int> v = {1, 2, 3};
auto value = v[1]; // hint for `value`: value_type
auto *ptr = &v[0]; // hint for `ptr`: value_type *

These hints are useless for most of the time. It would be nice if we
desugar the type of value_type and print int, int * respectively
in this situation. But note we can't always prefer desugared type
since user might introduce type-aliases for brevity, where printing
sugared types makes more sense.

This patch introduces a heuristic method that displays the desugared
type that is an alias of template parameter. It merges
analogous method shouldPrintCanonicalType into maybeDesugar as well.

Previous commit for shouldPrintCanonicalType: dde8a0fe91cc

Diff Detail

Event Timeline

zyounan created this revision.May 31 2023, 12:26 AM
zyounan requested review of this revision.May 31 2023, 12:26 AM

Before

After

(Sorry for posting screenshots directly and bringing any inconvenience for email users.)

zyounan added inline comments.Jun 4 2023, 4:52 AM
clang-tools-extra/clangd/InlayHints.cpp
279

PrintCanonicalTypes turns on printing default template arguments, which would prevent the patch from printing, e.g., std::basic_string<char>, within the default length limitation.

std::map<std::string, int> Map;

for (auto &[Key, Value] : Map) // Key: basic_string<char, char_traits<char>, allocator<char>>, whose length exceeds the default threshold.

Is it safe to drop it now? I believe this patch can handle the case the comment mentioned.

zyounan marked an inline comment as not done.Jun 4 2023, 4:57 AM

Thanks, this is a nice improvement.

A couple of general comments:

  • We have an existing heuristic here, should we move the logic into maybeDesugar() so it's all in one place?
  • I don't think "dependent type" is the right terminology, "dependent type" means "depends on a template parameter whose value is not yet known", for example vector<T>::value_type where we don't know the value of T. But here we are talking about things like vector<int>::value_type. Maybe in place of "dependent type alias" we can say "alias for template parameter"?
clang-tools-extra/clangd/InlayHints.cpp
198

nit: it sounds like this name (PeelQualifier) is using "qualifier" to mean "pointer or reference", which is different from the meaning of the word in "QualType" (where it means "const or volatile")

maybe PeelWrappers would be a better name, since we can think of PointerType and ReferenceType as wrapping an underlying type?

201

a possible reformulation:

QualType Next;
while (!(Next = QT->getPointeeType()).isNull()) {
  QT = Next;
}
return QT;

this seems slightly cleaner to me, but I'll leave it up to you

207

this loop can also be reformulated to avoid repeating the update step:

while (true) {
  QualType Desugared = Peel(...);
  if (Desugared == QT)
    break;
  if (Desugared->getAs<...>)
    return true;
  QT = Desugared;
}
215

The only test case that seems to rely on this BuiltinType heuristic is getting int instead of size_type for array.size().

size_type doesn't seem so bad, maybe we can leave this out for now? Or do you have a more compelling motivating case for it?

235

name suggestion: maybeDesugar

(try sounds like it might fail and return something that needs to be checked like optional or Expected)

279

Unfortunately, I don't think it works in general. I tried commenting out this line and
TypeHints.StructuredBindings_TupleLike failed.

(Note, this was with the BuiltinType heuristic removed. If we keep the BuilinType heuristic, a modified version of the testcase (e.g. struct members are changed from int to a class type) still fails.)

zyounan added inline comments.Jun 7 2023, 1:28 AM
clang-tools-extra/clangd/InlayHints.cpp
279

Thank you for providing me with the case. I think the flag PrintCanonicalTypes actually controls two aspects of styles, if I understand TypePrinter correctly:

  1. For type aliases (a.k.a. typedefs and using alias), the 'canonical' type (i.e., the "most" desugared type) is obtained before printing.
  1. For template arguments, print default parameters even they weren't specified.

For 1, we could achieve the same goal at the caller site: For DecompositionDecl, instead of creating another different printing policy, call QualType::getCanonicalType() to get the QualType to be passed into addTypeHint. I did a modification and found that test cases from TypeHints are all passed even we disable StructuredBindingPolicy.PrintCanonicalTypes.

For 2, I think for most of the cases, printing default template parameters is an unexpected side effect. (I didn't see any test cases requiring default template parameters on structure bindings, but please correct me if I'm missing something.)

What do you think? I'd like to submit another review addressing this if it looks fine to you.

nridge added inline comments.Jun 7 2023, 9:58 PM
clang-tools-extra/clangd/InlayHints.cpp
279

What do you think? I'd like to submit another review addressing this if it looks fine to you.

+1, it sounds reasonable to me

Trass3r added a subscriber: Trass3r.Jun 9 2023, 5:37 PM
zyounan updated this revision to Diff 530201.Jun 10 2023, 6:21 AM
zyounan marked 7 inline comments as done.

Address many comments

Thank you very much for the insightful review! Regarding to your suggestion,

We have an existing heuristic here, should we move the logic into maybeDesugar() so it's all in one place?

once we merge these two functions, the overloaded addTypeHint without a PrintingPolicy parameter will merely remains one line for forwarding. As we're going to use a single PrintingPolicy after D152520, I think it would be better to eventually drop the parameter PrintingPolicy in addTypeHint in that patch.

clang-tools-extra/clangd/InlayHints.cpp
198

Good catch! I looked up the standard and found out that pointers or references are of compound types, and that 'qualified' usually goes along with 'const or volatile'.

201

Rephrased as the suggestion. (TBH, I didn't realize storing the Next instead of the Prev could make it more terse. Thanks for the hint!)

207

Cool.

215

Not that I could think of except that case. It's possible that size_type varies across different platforms, so it seems okay to remove it.

235

Frankly speaking I used to mix up these two and just learned the differences. Thank you!

279

Link to the proposed review.

zyounan retitled this revision from [clangd] Desugar dependent type aliases for auto type hints to [clangd] Desugar template parameter aliases in type hints.Jun 10 2023, 6:25 AM
zyounan edited the summary of this revision. (Show Details)
zyounan edited the summary of this revision. (Show Details)
nridge accepted this revision.Jun 13 2023, 12:05 AM

Thanks, LGTM!

clang-tools-extra/clangd/InlayHints.cpp
196

nit: "of substituted template parameter" --> "a substituted template parmeter"

(or "of substituted template parameter type")

This revision is now accepted and ready to land.Jun 13 2023, 12:05 AM
zyounan updated this revision to Diff 530850.Jun 13 2023, 3:39 AM
zyounan marked an inline comment as done.

Final update

zyounan updated this revision to Diff 530851.Jun 13 2023, 3:41 AM

Oops. Remove extra debugging statement

This revision was landed with ongoing or failed builds.Jun 13 2023, 4:15 AM
This revision was automatically updated to reflect the committed changes.

Looks like this might have broken a couple of sanitizer builds. Here is one of them: https://lab.llvm.org/buildbot/#/builders/5/builds/34387. Could you please revert or fix?
Thanks!

Looks like this might have broken a couple of sanitizer builds. Here is one of them: https://lab.llvm.org/buildbot/#/builders/5/builds/34387. Could you please revert or fix?
Thanks!

Sorry for the inconvenience. I think this issue had been fixed by https://github.com/llvm/llvm-project/commit/0e8384a0fe4f03d60cd92aba1cae074512481ca2. Does it work now? Please let me know if we still have problems.

Looks like this might have broken a couple of sanitizer builds. Here is one of them: https://lab.llvm.org/buildbot/#/builders/5/builds/34387. Could you please revert or fix?
Thanks!

Sorry for the inconvenience. I think this issue had been fixed by https://github.com/llvm/llvm-project/commit/0e8384a0fe4f03d60cd92aba1cae074512481ca2. Does it work now? Please let me know if we still have problems.

The bot went green after the fix. Thanks.