This is an archive of the discontinued LLVM Phabricator instance.

[clang-format] Improve QualifierAlignment
ClosedPublic

Authored by AlexanderHederstaf on Feb 24 2023, 1:18 AM.

Details

Summary

Qualifiers were not moved for non-pointer non-simple types.
Add additional support for many special cases such as templates,
requires clauses, long qualified names.

Fixes https://github.com/llvm/llvm-project/issues/57154 and
https://github.com/llvm/llvm-project/issues/60898

Diff Detail

Event Timeline

Herald added a project: Restricted Project. · View Herald TranscriptFeb 24 2023, 1:18 AM
AlexanderHederstaf requested review of this revision.Feb 24 2023, 1:18 AM
Herald added a project: Restricted Project. · View Herald TranscriptFeb 24 2023, 1:18 AM
Herald added a subscriber: cfe-commits. · View Herald Transcript

I tried to refactor QualifierAlignmentFixer to handle more types, notably removing the *,&,&& requirement as e.g. const Foo did not work. To avoid moving qualifiers too far, a test for "already east const" is introduced. However, to get the correct order for the east qualifiers Clang-Format must be used twice. I assume it's related to how fixes/replacements are handled. Would you like to have a look and perhaps suggest any improvements?

As it must be used twice, some tests related to volatile/const order fail, but I noticed most of them would also fails previously if the type is not simple.

MyDeveloperDay added a comment.EditedFeb 24 2023, 3:49 AM

Can you please add unit tests for the cases you added, can you please add a link to the github issue you are trying to resolve, or log one if there isn't one.

Also all the existing tests need to pass, otherwise its a mute point.

When I added this, I knew that there were limitations, there is just sometimes things that can't be determined and so to air on the side of caution we don't fixup those

but please bring specific examples to the table so we can review them

AlexanderHederstaf edited the summary of this revision. (Show Details)Feb 24 2023, 4:21 AM

I will add new tests / examples as well as look into the volatile/const ordering.

owenpan added a project: Restricted Project.

Fixed the const/volatile placement. Added a few tests.

Add test with advanced type that would not work before.
Add pointer to member.

I tried to refactor QualifierAlignmentFixer to handle more types, notably removing the *,&,&& requirement as e.g. const Foo did not work. To avoid moving qualifiers too far, a test for "already east const" is introduced. However, to get the correct order for the east qualifiers Clang-Format must be used twice. I assume it's related to how fixes/replacements are handled. Would you like to have a look and perhaps suggest any improvements?

As it must be used twice, some tests related to volatile/const order fail, but I noticed most of them would also fails previously if the type is not simple.

Highlight by me. That is not acceptable, running the output of clang-format through clang-format shall not result in any change. In that case it's better to not touch it in any way.

clang/lib/Format/QualifierAlignmentFixer.cpp
293

In the initial commit concerns were raised that East and West are westcentric terms and should not be used. Thus you should stick here to Left and Right the same terms we use in the configuration.

295

Could you add comments what kind of source code we would have here?

296

No else after return.

297

That may be null, or not?

Highlight by me. That is not acceptable, running the output of clang-format through clang-format shall not result in any change. In that case it's better to not touch it in any way.

That is no longer an issue in the latest patch.

just as a heads up, I'm applying https://reviews.llvm.org/D144537 since it's a quick bug fix; this patch *would* replace that one, but may need more time. (also conflicts may appear)

Add comments for different cases.
Add more tests.
Fix whitespace issue.

Thanks for the review so far!

Passes all tests and works in one shot on my test files as well as 3k+ files repository, i.e. it does not have to be run twice.

As one use-case of this rule is to be able to checkout code and freely swap between left/right. Then the left alignment would also need to handle the same cases as right alignment.

I should also make templates with requires work, though I am not familiar with the variations that syntax may have.

@rymiel Good, this might take a few more iterations.

clang/lib/Format/QualifierAlignmentFixer.cpp
293

Replaced with right/left

295

Added comments for the different source code we may have.

296

removed 'else' preceeding return.

297

I assumed that if the token is identified as a template closer then there will exist an opener. As far as I am aware, something must preceed that opener.

AlexanderHederstaf retitled this revision from [clang-format] Improve west to east const to [clang-format] Improve left to right const.Feb 25 2023, 3:15 AM

when I originally did this work, I checked out the whole fresh area of LLVM and applied the both east then back to west const and built both to ensure I didn't break anything. Please ensure you do the same, I'm going to be honest you are changing it massively, I'm going to need some time to understand the changes.

can you rebase please

Highlight by me. That is not acceptable, running the output of clang-format through clang-format shall not result in any change. In that case it's better to not touch it in any way.

That is no longer an issue in the latest patch.

Great!

Please mark comments as done.

when I originally did this work, I checked out the whole fresh area of LLVM and applied the both east then back to west const and built both to ensure I didn't break anything. Please ensure you do the same, I'm going to be honest you are changing it massively, I'm going to need some time to understand the changes.

From my point this looks okay, but I did not look very deeply into it, I'll let @MyDeveloperDay do that.

clang/lib/Format/QualifierAlignmentFixer.cpp
252–253

clang-format did wrap your comment ;)

297

Then please add an assertion. So we would get a nice message if your assumption is wrong.

Rebase after change to pointer to member was merged.
Add case for typename used for nested dependent names.
Add assertions for template closers/openers.

Add commented-out tests for two cases where right to left
produces code that does not compile.

AlexanderHederstaf marked 6 inline comments as done.Feb 27 2023, 1:15 AM

Fixed comments and rebased. Tested right to left on the output of left to right and discovered two cases where the output code would not compile. Added new tests for those cases and I am working on improvements for right to left.

clang/lib/Format/QualifierAlignmentFixer.cpp
252–253

Re-arranged the comments.

297

Added assertions.

AlexanderHederstaf marked 2 inline comments as done.Feb 27 2023, 1:18 AM

Fix simple types not moving all the way right.

Update right to left analyzer
Add support for requires clauses
Ignore usages of struct/class keyword

Add new, and uncomment old tests
Fix invalid tests with 'const Foo b* const;'

AlexanderHederstaf added a comment.EditedFeb 27 2023, 8:02 AM

There are a lot of complicated cases when trying to extend this functionality. I addressed a few more and thought that it might be acceptable to avoid adjusting the qualifiers for variable declared as

struct Foo const; -> const struct Foo;
const struct Foo; -> struct Foo const;

const struct {
  int a;
} foo = {5};
 -> 
struct {
  int a;
} const foo = {5};

as they are difficult to distinguish from

const struct Foo {
  int a;
} foo = {5};

where this is not valid code

struct const Foo {
  int a;
} foo = {5};
struct Foo const {
  int a;
} foo = {5};

I have still not tested left->right->left on the llvm codebase, I'll update you when it's done.

AlexanderHederstaf retitled this revision from [clang-format] Improve left to right const to [clang-format] Improve QualifierAlignment.Feb 27 2023, 8:06 AM
AlexanderHederstaf edited the summary of this revision. (Show Details)

Update commit message

Simplify insertQualifierAfter.
Ignore decltype, typeof, and _Atomic.
Set length of TT_TemplateCloser to 1.

AlexanderHederstaf added a comment.EditedFeb 28 2023, 7:45 AM

Discovered incorrect code generation for llvm/include/llvm/ADT/StringMap.h.

using base = StringMapIterBase<StringMapConstIterator<ValueTy>,
                               const StringMapEntry<ValueTy>>;

was converted to, removing two characters. I checked the Token length in InsertQualifierAfter and found that it was not 1. How should I proceed with this particular issue @MyDeveloperDay

using base = StringMapIterBase<StringMapConstIterator<ValueTy>,
                               StringMapEntry<ValueTy> const

I commited the change to SetLength(1) but that looks a bit much like a hack, perhaps anyone more familiar with the codebase can have a look at this issue.

Discovered incorrect code generation for llvm/include/llvm/ADT/StringMap.h.

using base = StringMapIterBase<StringMapConstIterator<ValueTy>,
                               const StringMapEntry<ValueTy>>;

was converted to, removing two characters. I checked the Token length in InsertQualifierAfter and found that it was not 1. How should I proceed with this particular issue @MyDeveloperDay

using base = StringMapIterBase<StringMapConstIterator<ValueTy>,
                               StringMapEntry<ValueTy> const

I commited the change to SetLength(1) but that looks a bit much like a hack, perhaps anyone more familiar with the codebase can have a look at this issue.

Looks like https://github.com/llvm/llvm-project/issues/56111

As tests currently fail can you set it to "planned changes" until they pass

[  FAILED  ] 5 tests, listed below:
[  FAILED  ] QualifierFixerTest.RightQualifier
[  FAILED  ] QualifierFixerTest.LeftQualifier
[  FAILED  ] QualifierFixerTest.ConstVolatileQualifiersOrder
[  FAILED  ] QualifierFixerTest.MoveConstBeyondType
[  FAILED  ] QualifierFixerTest.TemplatesRight

Distinguish configured qualifiers from other qualifiers.

AlexanderHederstaf added a comment.EditedMar 1 2023, 1:50 AM

This code from llvm/tools/llvm-exegesis/lib/SerialSnippetGenerator.cpp failed with Right but without a full list of specifiers. As static was not configured, the } was not discovered by IsRightQualifier. Changed some of the qualifier tests to check against the full list instead.

struct ExecutionClass {
  ExecutionMode Mask;
  const char *Description;
} static const kExecutionClasses[] = {
    {ExecutionMode::ALWAYS_SERIAL_IMPLICIT_REGS_ALIAS |
         ExecutionMode::ALWAYS_SERIAL_TIED_REGS_ALIAS,
     "Repeating a single implicitly serial instruction"},
    {ExecutionMode::SERIAL_VIA_EXPLICIT_REGS,
     "Repeating a single explicitly serial instruction"},
    {ExecutionMode::SERIAL_VIA_MEMORY_INSTR |
         ExecutionMode::SERIAL_VIA_NON_MEMORY_INSTR,
     "Repeating two instructions"},
};

Resulted in

} static kExecutionClasses const[] = {

Which is now fixed. This struct will be left unchanged as with other structs.

I used clang-format on all files in clang/ and llvm/, where I had added QualifierAlignment: Right to any .clang-format. I built with

cmake -S llvm -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS="clang"
cmake --build build

Is that sufficient or did you imagine some other build?

As tests currently fail can you set it to "planned changes" until they pass

[  FAILED  ] 5 tests, listed below:
[  FAILED  ] QualifierFixerTest.RightQualifier
[  FAILED  ] QualifierFixerTest.LeftQualifier
[  FAILED  ] QualifierFixerTest.ConstVolatileQualifiersOrder
[  FAILED  ] QualifierFixerTest.MoveConstBeyondType
[  FAILED  ] QualifierFixerTest.TemplatesRight

Tests should pass now, but how/where do I set that setting?

Change order for typename and :: as
const typename ::Bar b; is valid code.

Add code for handling ::template.

AlexanderHederstaf added a comment.EditedMar 1 2023, 8:09 AM

I used clang-format on all files in clang/ and llvm/, where I had added QualifierAlignment: Right to any .clang-format. I built with

cmake -S llvm -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS="clang"
cmake --build build

Is that sufficient or did you imagine some other build?

Performed the test for
Original -> Right -> compiles
Right -> Left -> compiles

As tests currently fail can you set it to "planned changes" until they pass

[  FAILED  ] 5 tests, listed below:
[  FAILED  ] QualifierFixerTest.RightQualifier
[  FAILED  ] QualifierFixerTest.LeftQualifier
[  FAILED  ] QualifierFixerTest.ConstVolatileQualifiersOrder
[  FAILED  ] QualifierFixerTest.MoveConstBeyondType
[  FAILED  ] QualifierFixerTest.TemplatesRight

Tests should pass now, but how/where do I set that setting?

Right down here where you post your reply. The "Add Action..." has "Plan Changes" to set the state.

AlexanderHederstaf planned changes to this revision.Mar 1 2023, 12:48 PM
AlexanderHederstaf requested review of this revision.
MyDeveloperDay accepted this revision.Mar 2 2023, 3:23 PM

Firstly let me say thank you for this review, your perseverance demonstrates to me that there is a desire to make this capability better, which tells me that a feature that ultimately took 1+ year to get landed in the first place was perhaps worth it. My hope is that these changes will help to further demonstrate that its ok for clang-format to make modifications (which was a major discussion point at the time it first landed)

From a personal perspective I feel you've heavily changed my original implementation quite a bit. ( Its ok I'm not precious ), but I feel you've commented this code nicely and I feel that likely this is now easier to read. For which I thank you.

I also appreciate the extensive testing and the efforts you've made to fix other issue that were ultimately contained originally.

I'm inclined to accept the revision , get it into trunk so it can live for sometime before the next branch. (i.e. it wouldn't land in mainstream releases until 17.0 which could be ~6 months away)

This revision is now accepted and ready to land.Mar 2 2023, 3:23 PM

Thanks for the comments and help on this review. There are a lot of special cases I had not considered before, and while it works on the clang/ and llvm/ subfolders as well as tests and the other repository I tested on, I suppose there could still be some hidden issues. Allowing any identifier without the requirement that it is a pointer type adds a lot of complexity.

It sounds good to close the existing issues, let this version live some time and watch out for new issues.

rymiel added a comment.EditedMar 4 2023, 6:31 AM

This patch also fixes: https://github.com/llvm/llvm-project/issues/56111, https://github.com/llvm/llvm-project/issues/58696, and https://github.com/llvm/llvm-project/issues/54730 (some of those could probably be made duplicates but it seems they're all going down in one blow anyway)

Firstly let me say thank you for this review, your perseverance demonstrates to me that there is a desire to make this capability better

+1, I certainly wouldn't have such perseverance, which is why I stick to bug reports

rymiel added inline comments.Mar 4 2023, 6:37 AM
clang/unittests/Format/QualifierFixerTest.cpp
523

(see below)

716

This... isn't valid syntax? an opening < is missing.
Perhaps you could adapt https://github.com/llvm/llvm-project/issues/56111 into a test, it seems to be fixed by the patch, but there might still be corner-cases

MyDeveloperDay added a comment.EditedMar 4 2023, 6:37 AM

This patch also fixes: https://github.com/llvm/llvm-project/issues/56111, https://github.com/llvm/llvm-project/issues/58696, and https://github.com/llvm/llvm-project/issues/54730 (some of those could probably be made duplicates but it seems they're all going down in one blow anyway)

Firstly let me say thank you for this review, your perseverance demonstrates to me that there is a desire to make this capability better

+1, I certainly wouldn't have such perseverance, which is why I stick to bug reports

and @rymiel we thank you for those efforts too! it just as important.

clang/unittests/Format/QualifierFixerTest.cpp
716

Right, I must've focused too much on the missing right >. What is the procedure now that the review is accepted. Can I still upload a fix to this and to include that issue in the tests?

rymiel added inline comments.Mar 4 2023, 8:55 AM
clang/unittests/Format/QualifierFixerTest.cpp
716

What is the procedure now that the review is accepted

No different to the usual! The patch will stay accepted, and reviewers can just re-approve anyways.

AlexanderHederstaf planned changes to this revision.Mar 6 2023, 1:26 AM

Missed right->left in the fix. Also looking a bit at comments, e.g.

ns::/*ns2::*/vector v;

Handle /*c*/ comments inside types.
Add >> test to right->left.

This revision is now accepted and ready to land.Mar 6 2023, 2:38 AM
MyDeveloperDay accepted this revision.Mar 6 2023, 4:10 AM

I might have been tempted to handle the comments in a separate commit, I don't like to do too much in one go or the review gets hard to manage.

AlexanderHederstaf requested review of this revision.EditedMar 6 2023, 4:12 AM

I might have been tempted to handle the comments in a separate commit, I don't like to do too much in one go or the review gets hard to manage.

I had the same thought but as the comments change is not only an extension of the capability I included it to be safe. Without the change it would lead to code that doesn't compile.

This revision is now accepted and ready to land.Mar 6 2023, 12:27 PM

What is the next step in the process? Anything I should do?

What is the next step in the process? Anything I should do?

If you have commit access you can go ahead and commit, if not and you want one of us to do it, we need your name and email address

What is the next step in the process? Anything I should do?

If you have commit access you can go ahead and commit, if not and you want one of us to do it, we need your name and email address

I don't have commit access. Please go ahead if you'd wish to do it for me. Should I share my email in some other forum than posting it in this comment section?

What is the next step in the process? Anything I should do?

If you have commit access you can go ahead and commit, if not and you want one of us to do it, we need your name and email address

I don't have commit access. Please go ahead if you'd wish to do it for me. Should I share my email in some other forum than posting it in this comment section?

It will be public on GitHub (and any fork), so you should choose one you are comfortable to share here. ;)
(And in contrast to some other lists where I put my mail, I didn't notice any more spam after becoming active here.)

Okay thanks. If the + options works let's go with
alexanderhederstaf+llvm@gmail.com

Thanks again for the review and answers.

This revision was landed with ongoing or failed builds.Mar 27 2023, 7:20 AM
This revision was automatically updated to reflect the committed changes.