Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[clang-format]: Split alignment of declarations around assignment #69340

Merged
merged 10 commits into from Jan 11, 2024

Conversation

gedare
Copy link
Contributor

@gedare gedare commented Oct 17, 2023

Function pointers are detected as a type of declaration using FunctionTypeLParen. They are aligned based on rules for AlignConsecutiveDeclarations. When a function pointer is on the right-hand side of an assignment, the alignment of the function pointer can result in excessive whitespace padding due to the ordering of alignment, as the alignment processes a line from left-to-right and first aligns the declarations before and after the assignment operator, and then aligns the assignment operator. Injection of whitespace by alignment of declarations after the equal sign followed by alignment of the equal sign results in the excessive whitespace.

Fixes #68079.

@llvmbot
Copy link
Collaborator

llvmbot commented Oct 17, 2023

@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clang-format

Author: Gedare Bloom (gedare)

Changes

Function pointers are detected as a type of declaration using FunctionTypeLParen. They are aligned based on rules for AlignConsecutiveDeclarations. When a function pointer is on the right-hand side of an assignment, the alignment of the function pointer can result in excessive whitespace padding due to the ordering of alignment, as the alignment processes a line from left-to-right and first aligns the declarations before and after the assignment operator, and then aligns the assignment operator. Injection of whitespace by alignment of declarations after the equal sign followed by alignment of the equal sign results in the excessive whitespace.

Fixes #68079.


Full diff: https://github.com/llvm/llvm-project/pull/69340.diff

3 Files Affected:

  • (modified) clang/lib/Format/WhitespaceManager.cpp (+41-2)
  • (modified) clang/lib/Format/WhitespaceManager.h (+2-1)
  • (modified) clang/unittests/Format/FormatTest.cpp (+9)
diff --git a/clang/lib/Format/WhitespaceManager.cpp b/clang/lib/Format/WhitespaceManager.cpp
index dc81060671c1712..e6bc0963b40dc75 100644
--- a/clang/lib/Format/WhitespaceManager.cpp
+++ b/clang/lib/Format/WhitespaceManager.cpp
@@ -108,9 +108,10 @@ const tooling::Replacements &WhitespaceManager::generateReplacements() {
   calculateLineBreakInformation();
   alignConsecutiveMacros();
   alignConsecutiveShortCaseStatements();
-  alignConsecutiveDeclarations();
+  alignConsecutiveDeclarationsPreAssignment();
   alignConsecutiveBitFields();
   alignConsecutiveAssignments();
+  alignConsecutiveDeclarationsPostAssignment();
   alignChainedConditionals();
   alignTrailingComments();
   alignEscapedNewlines();
@@ -973,13 +974,51 @@ void WhitespaceManager::alignConsecutiveShortCaseStatements() {
                              Changes);
 }
 
-void WhitespaceManager::alignConsecutiveDeclarations() {
+void WhitespaceManager::alignConsecutiveDeclarationsPreAssignment() {
   if (!Style.AlignConsecutiveDeclarations.Enabled)
     return;
 
   AlignTokens(
       Style,
       [](Change const &C) {
+        for (FormatToken *Prev = C.Tok->Previous; Prev; Prev = Prev->Previous)
+          if (Prev->is(tok::equal))
+            return false;
+        if (C.Tok->isOneOf(TT_FunctionDeclarationName, TT_FunctionTypeLParen))
+          return true;
+        if (C.Tok->isNot(TT_StartOfName))
+          return false;
+        if (C.Tok->Previous &&
+            C.Tok->Previous->is(TT_StatementAttributeLikeMacro))
+          return false;
+        // Check if there is a subsequent name that starts the same declaration.
+        for (FormatToken *Next = C.Tok->Next; Next; Next = Next->Next) {
+          if (Next->is(tok::comment))
+            continue;
+          if (Next->is(TT_PointerOrReference))
+            return false;
+          if (!Next->Tok.getIdentifierInfo())
+            break;
+          if (Next->isOneOf(TT_StartOfName, TT_FunctionDeclarationName,
+                            tok::kw_operator)) {
+            return false;
+          }
+        }
+        return true;
+      },
+      Changes, /*StartAt=*/0, Style.AlignConsecutiveDeclarations);
+}
+
+void WhitespaceManager::alignConsecutiveDeclarationsPostAssignment() {
+  if (!Style.AlignConsecutiveDeclarations.Enabled)
+    return;
+
+  AlignTokens(
+      Style,
+      [](Change const &C) {
+        for (FormatToken *Next = C.Tok->Next; Next; Next = Next->Next)
+          if (Next->is(tok::equal))
+            return false;
         if (C.Tok->isOneOf(TT_FunctionDeclarationName, TT_FunctionTypeLParen))
           return true;
         if (C.Tok->isNot(TT_StartOfName))
diff --git a/clang/lib/Format/WhitespaceManager.h b/clang/lib/Format/WhitespaceManager.h
index df7e9add1cd446f..19bd4a3a6f7791f 100644
--- a/clang/lib/Format/WhitespaceManager.h
+++ b/clang/lib/Format/WhitespaceManager.h
@@ -227,7 +227,8 @@ class WhitespaceManager {
   void alignConsecutiveBitFields();
 
   /// Align consecutive declarations over all \c Changes.
-  void alignConsecutiveDeclarations();
+  void alignConsecutiveDeclarationsPreAssignment();
+  void alignConsecutiveDeclarationsPostAssignment();
 
   /// Align consecutive declarations over all \c Changes.
   void alignChainedConditionals();
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 963fb8f4d441618..1dc05ff9de5f0fa 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -18783,6 +18783,15 @@ TEST_F(FormatTest, AlignConsecutiveDeclarations) {
                "                 \"bb\"};\n"
                "int   bbbbbbb = 0;",
                Alignment);
+  // http://llvm.org/PR68079
+  verifyFormat("using Fn   = int (A::*)();\n"
+               "using RFn  = int (A::*)() &;\n"
+               "using RRFn = int (A::*)() &&;",
+               Alignment);
+  verifyFormat("using Fn   = int    (A::*)();\n"
+               "using RFn  = int   *(A::*)() &;\n"
+               "using RRFn = double (A::*)() &&;",
+               Alignment);
 
   // PAS_Right
   verifyFormat("void SomeFunction(int parameter = 0) {\n"

@tru
Copy link
Collaborator

tru commented Oct 27, 2023

@gedare can you fix the merge conflict on this one?

@owenca
Copy link
Contributor

owenca commented Oct 27, 2023

@gedare can you fix the merge conflict on this one?

We don't want to merge this yet. See here.

Copy link
Contributor

@owenca owenca left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please see here.

@gedare
Copy link
Contributor Author

gedare commented Nov 9, 2023

force push was required to layer the revert commit correctly.

Copy link
Contributor

@owenca owenca left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #66857 (comment). Can you make this a suboption, e.g. AlignFunctionPointers? We can add another (e.g. AlignConstructorsDestructors) for ctors and dtors in the future.

@gedare
Copy link
Contributor Author

gedare commented Nov 10, 2023

See #66857 (comment). Can you make this a suboption, e.g. AlignFunctionPointers? We can add another (e.g. AlignConstructorsDestructors) for ctors and dtors in the future.

Yes, I will work on this.

@gedare gedare requested a review from owenca December 19, 2023 22:13
@llvmbot llvmbot added the clang Clang issues not falling into any other category label Dec 19, 2023
@gedare
Copy link
Contributor Author

gedare commented Jan 5, 2024

@owenca this waits for re-review

@owenca
Copy link
Contributor

owenca commented Jan 6, 2024

@owenca this waits for re-review

Can you rebase the patch?

@gedare
Copy link
Contributor Author

gedare commented Jan 6, 2024

@owenca this waits for re-review

Can you rebase the patch?

done

Copy link
Contributor

@owenca owenca left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please also update the release notes. LGTM otherwise.

clang/include/clang/Format/Format.h Outdated Show resolved Hide resolved
clang/lib/Format/Format.cpp Outdated Show resolved Hide resolved
clang/lib/Format/Format.cpp Outdated Show resolved Hide resolved
clang/lib/Format/Format.cpp Outdated Show resolved Hide resolved
clang/lib/Format/Format.cpp Outdated Show resolved Hide resolved
clang/lib/Format/Format.cpp Outdated Show resolved Hide resolved
clang/lib/Format/WhitespaceManager.cpp Outdated Show resolved Hide resolved
Function pointers are detected as a type of declaration using
FunctionTypeLParen. They are aligned based on rules for
AlignConsecutiveDeclarations. When a function pointer is on the
right-hand side of an assignment, the alignment of the function pointer
can result in excessive whitespace padding due to the ordering of
alignment, as the alignment processes a line from left-to-right and
first aligns the declarations before and after the assignment operator,
and then aligns the assignment operator. Injection of whitespace by
alignment of declarations after the equal sign followed by alignment
of the equal sign results in the excessive whitespace.

Fixes llvm#68079.
@gedare
Copy link
Contributor Author

gedare commented Jan 9, 2024

Please also update the release notes. LGTM otherwise.

Fixed the comments and added a release note.

clang/docs/ReleaseNotes.rst Outdated Show resolved Hide resolved
Co-authored-by: Owen Pan <owenpiano@gmail.com>
@owenca owenca merged commit b2c0c6f into llvm:main Jan 11, 2024
4 of 5 checks passed
@gedare gedare deleted the 68079 branch January 12, 2024 01:06
justinfargnoli pushed a commit to justinfargnoli/llvm-project that referenced this pull request Jan 28, 2024
…vm#69340)

Function pointers are detected as a type of declaration using
FunctionTypeLParen. They are aligned based on rules for
AlignConsecutiveDeclarations. When a function pointer is on the
right-hand side of an assignment, the alignment of the function pointer
can result in excessive whitespace padding due to the ordering of
alignment, as the alignment processes a line from left-to-right and
first aligns the declarations before and after the assignment operator,
and then aligns the assignment operator. Injection of whitespace by
alignment of declarations after the equal sign followed by alignment of
the equal sign results in the excessive whitespace.

Fixes llvm#68079.
@owenca owenca removed the clang Clang issues not falling into any other category label May 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[clang-format] Formatting regression for member function pointers using aligned assignment and declaration
6 participants