This is an archive of the discontinued LLVM Phabricator instance.

[CodeComplete] Basic code completion for attribute names.
ClosedPublic

Authored by sammccall on Aug 7 2021, 9:05 AM.

Details

Summary

Only the bare name is completed, with no args.
For args to be useful we need arg names. These *are* in the tablegen but
not currently emitted in usable form, so left this as future work.

C++11, C2x, GNU, declspec, MS syntax is supported, with the appropriate
spellings of attributes suggested.
#pragma clang attribute is supported but not terribly useful as we
only reach completion if parens are balanced (i.e. the line is not truncated)

There's no filtering of which attributes might make sense in this
grammatical context (e.g. attached to a function). In code-completion context
this is hard to do, and will only work in few cases :-(

There's also no filtering by langopts: this is because currently the
only way of checking is to try to produce diagnostics, which requires a
valid ParsedAttr which is hard to get.
This should be fairly simple to fix but requires some tablegen changes
to expose the logic without the side-effect.

Diff Detail

Event Timeline

sammccall created this revision.Aug 7 2021, 9:05 AM
sammccall requested review of this revision.Aug 7 2021, 9:05 AM
Herald added projects: Restricted Project, Restricted Project. · View Herald TranscriptAug 7 2021, 9:05 AM
Herald added a subscriber: cfe-commits. · View Herald Transcript

Thank you for working on this, I think it's fantastic functionality!

clang/lib/Sema/SemaCodeComplete.cpp
4357

Should we also add some special handling for attributes optionally starting with double underscores? e.g., __attribute__((const)) and __attribute__((__const__))` are both equally useful to complete.

Also, we should add some explicit testing for omp::sequence and omp::directive as those are handled very specially and won't appear in the parsed attribute map. I think the OpenMP code completion would be super useful, but can be handled in a follow-up if you want.

sammccall added inline comments.Aug 9 2021, 8:07 AM
clang/lib/Sema/SemaCodeComplete.cpp
4357

Should we also add some special handling for attributes optionally starting with double underscores?

I think so. Two questions:

  • Do I understand right that this is "just" a matter of adding leading/trailing __ as a second option, for AS_GNU?
  • are there similar rules for other syntaxes I've missed?

Offering both seems potentially confusing for users who don't care (especially in the case of const!). But I guess enough users will care about macros. At least in clangd the underscore versions will get ranked lower for having "internal" names though.

FWIW The no-underscores version appears to be ~3x more common (87k vs 27k hits in third-party code in google's repo). Among headers, no-underscores is "only" 2x more common (40k vs 21k).


Also, we should add some explicit testing for omp::sequence and omp::directive as those are handled very specially and won't appear in the parsed attribute map.

Yeah, I punted on these because it seems they will need special case logic, I'll add some tests that they don't do anything.

aaron.ballman added inline comments.Aug 9 2021, 8:58 AM
clang/lib/Sema/SemaCodeComplete.cpp
4357

Do I understand right that this is "just" a matter of adding leading/trailing __ as a second option, for AS_GNU?
are there similar rules for other syntaxes I've missed?

Clang supports GNU attributes in either __attribute__((foo)) or __attribute__((__foo__)) forms. So I'd say that autocompleting after the second ( should either suggest attributes (preferred) or __ (for the poor folks writing libraries). If the user wants to autocomplete after __attribute__((__, I think it should suggest foo__ as the rest of the attribute name. (Basically, if the user looks like they want underscores, give them all the underscores.)

Clang also supports [[]] attributes but with somewhat different rules. We support [[gnu::attr]], [[__gnu__::attr]], [[gnu::__attr__]], and [[__gnu__::__attr__]] for GCC attributes. We support [[clang::attr]], [[_Clang::attr]], [[clang::__attr__]], and [[_Clang::__attr__]] for Clang attributes. For vendors other than Clang and GCC, we don't support any additional underscores for either the scope or the attribute name. I would say that if the user asked for underscores for the vendor scope, they likely want the underscores for the attribute as well.

I suppose there's a third case. That horrible using syntax that I've never really seen used in the wild. e.g., `[[using clang: attr]`. We do support the underscore behavior there as well.

Offering both seems potentially confusing for users who don't care (especially in the case of const!). But I guess enough users will care about macros.

Yeah, users who are writing portable libraries are far more likely to care than users writing typical application code.

sammccall planned changes to this revision.Aug 9 2021, 10:01 AM

Thanks, I know what to do next!

While I have you here, any thoughts on future patches:

Only the bare name is completed, with no args.
For args to be useful we need arg names. These *are* in the tablegen but
not currently emitted in usable form, so left this as future work.

How do you feel about this plan:

  • add an ArrayRef<const char*> to ParsedAttrInfo for this purpose? (Or a null-terminated char** if we're worried about sizeof).
  • It'd be populated by the names of the tablegen Args.
  • If empty, completions render as now. If nonempty they render as foo(bar, baz) where bar and baz are placeholders - just like function args but without types.

There's also no filtering by langopts: this is because currently the
only way of checking is to try to produce diagnostics, which requires a
valid ParsedAttr which is hard to get.

And for this, WDYT about making diagLangOpts non-virtual and moving the attr-specific test into a virtual bool supportsLangOpts() function with no side-effects?

clang/lib/Sema/SemaCodeComplete.cpp
4357

So I'd say that autocompleting after the second ( should either suggest attributes (preferred) or __ (for the poor folks writing libraries).

This is clever, unfortunately it doesn't really work for other reasons:

  • LSP allows clients to "narrow down" results as an identifier is typed with client-side filtering, and _ is treated as an identifier character.
  • clang's code completion similarly returns all matches and leaves partial-identifier-filtering them to the CodeCompleteConsumer

I can't see a better plan than including both the underscore and non-underscore versions, with the latter downranked. Doesn't seem *too* bad.

Clang also supports [[]] attributes...

Yeah, I think what we should do here is pretend the scoped namespace contains only the scoped attribute and vice versa:

  • When we want qualified attributes, emit gnu::attr and __gnu__::__attr__ but no mixing
  • When we want scopes (after using), emit gnu and __gnu__
  • When we want unqualified attributes (after ns:: or using ns:), emit either attr or __attr__ depending on the scope

That horrible using syntax

I really don't understand why this is worthwhile. Maybe feature parity with XMLNS? :-)
In any case, it happens to be easy to handle.

Thanks, I know what to do next!

While I have you here, any thoughts on future patches:

Only the bare name is completed, with no args.
For args to be useful we need arg names. These *are* in the tablegen but
not currently emitted in usable form, so left this as future work.

How do you feel about this plan:

  • add an ArrayRef<const char*> to ParsedAttrInfo for this purpose? (Or a null-terminated char** if we're worried about sizeof).
  • It'd be populated by the names of the tablegen Args.
  • If empty, completions render as now. If nonempty they render as foo(bar, baz) where bar and baz are placeholders - just like function args but without types.

I think args may be... interesting. Many attributes have arguments that can't really be completed because they're an integer, a string literal, whatever. But there are still quite a few that accept an enumeration, and those enumeration values would be super useful to autocomplete. And still others have arbitrary expressions where autocompletion would be fantastic (like diagnose_if).

I'm not certain that an ArrayRef would be sufficient to the task, but I do think we could probably generate something out of ClangAttrEmitter.cpp to help on an attribute-by-attribute basis.

There's also no filtering by langopts: this is because currently the
only way of checking is to try to produce diagnostics, which requires a
valid ParsedAttr which is hard to get.

And for this, WDYT about making diagLangOpts non-virtual and moving the attr-specific test into a virtual bool supportsLangOpts() function with no side-effects?

I think that'd work fine -- it'll break plugin authors, but that should hopefully be a loud break when they go to recompile their plugin.

sammccall updated this revision to Diff 365490.Aug 10 2021, 8:35 AM

Add support and tests for underscore-guarding.
Add tests that omp attributes are not supported.

aaron.ballman added inline comments.Aug 10 2021, 9:21 AM
clang/lib/Sema/SemaCodeComplete.cpp
4357

I can't see a better plan than including both the underscore and non-underscore versions, with the latter downranked. Doesn't seem *too* bad.

Seems reasonable enough to me!

Yeah, I think what we should do here is pretend the scoped namespace contains only the scoped attribute and vice versa:

+1, that seems good to me.

I really don't understand why this is worthwhile.

IMHO, it absolutely wasn't worthwhile. :-D

4390

Should we also early return if the attribute is ignored? (See IgnoredAttr in Attr.td) I'm assuming that attributes which do nothing are unlikely to be high-value attributes to autocomplete (so maybe they'd go at the end of the list if we wanted to keep them).

4436–4446

This could probably use a Twine and save some typing, but I don't insist.

sammccall added inline comments.Aug 10 2021, 12:52 PM
clang/lib/Sema/SemaCodeComplete.cpp
4390

Hmm, I'm not sure about that.
They do nothing *in clang*, but using clang-based code completion doesn't particularly mean we'll use clang to build the code.
Something must care about the attribute, even if it's just a doc generator or something.

In practice, there are 6 attrs with Ignored = 1:

  • bounded is an openbsd-gcc extension
  • 3 are cuda-specific and probably only used by cuda stdlib headers
  • __w64 is a keyword so not relevant here
  • property is actually supported by clang, it seems Ignored is lying!

So none of these are *terribly* important, but they also don't seem so worthless that it's important to exclude them. (There are other attributes that aren't important too!)

aaron.ballman accepted this revision.Aug 11 2021, 10:26 AM

Btw, I'm not certain why patch application is failing for you in the precommit CI: https://buildkite.com/llvm-project/diff-checks/builds/58571#c186a7d3-f5c9-4ad2-ae27-07408b1c5dad It doesn't seem like your patch is the cause of it, but this review is the only one where I've noticed the issue. Perhaps if you upload a new patch CI will be happier? Otherwise, beware of bot stampedes when you land. :-)

This LGTM (if you want to, feel free to switch to Twine in the one place I called out, but we don't need another round of review for that), thank you for the patch!

clang/lib/Sema/SemaCodeComplete.cpp
4390

Hmm, I'm not sure about that.

I'm convinced by your reasoning, thank you!

This revision is now accepted and ready to land.Aug 11 2021, 10:26 AM

Btw, I'm not certain why patch application is failing for you in the precommit CI: https://buildkite.com/llvm-project/diff-checks/builds/58571#c186a7d3-f5c9-4ad2-ae27-07408b1c5dad It doesn't seem like your patch is the cause of it, but this review is the only one where I've noticed the issue.

Literally the next review I looked at had this same issue (https://reviews.llvm.org/D107095), so I'm more comfortable saying the CI failure is unrelated to anything in your patch. :-)

This revision was landed with ongoing or failed builds.Aug 12 2021, 3:04 PM
This revision was automatically updated to reflect the committed changes.