Completed:

- Align other assignments such as `+=`
- Switch to using `verifyFormat` when possible
- Test multiple assignments on a single line

Still to do:

- Don't align for default parameters
- Ignore assignments within for and if statements

I'm unsure what the best way to detect those two cases are. I thought about 
checking that either the token before (or two before when a type is given) the 
first assignment on a line is at the start of the line. Would that be an 
acceptable solution?


http://reviews.llvm.org/D8821

Files:
  docs/ClangFormatStyleOptions.rst
  include/clang/Format/Format.h
  lib/Format/Format.cpp
  lib/Format/WhitespaceManager.cpp
  lib/Format/WhitespaceManager.h
  unittests/Format/FormatTest.cpp

EMAIL PREFERENCES
  http://reviews.llvm.org/settings/panel/emailpreferences/
Index: docs/ClangFormatStyleOptions.rst
===================================================================
--- docs/ClangFormatStyleOptions.rst
+++ docs/ClangFormatStyleOptions.rst
@@ -160,6 +160,17 @@
   argument2);
   \endcode
 
+**AlignConsecutiveAssignments** (``bool``)
+  If ``true``, aligns consecutive assignments.
+
+  This will align the assignment operators of consecutive lines. This
+  will result in formattings like
+  \code
+  int aaaa = 12;
+  int b    = 23;
+  int ccc  = 23;
+  \endcode
+
 **AlignEscapedNewlinesLeft** (``bool``)
   If ``true``, aligns escaped newlines as far left as possible.
   Otherwise puts them into the right-most column.
Index: include/clang/Format/Format.h
===================================================================
--- include/clang/Format/Format.h
+++ include/clang/Format/Format.h
@@ -247,6 +247,17 @@
   /// \brief If \c true, aligns trailing comments.
   bool AlignTrailingComments;
 
+  /// \brief If \c true, aligns consecutive assignments.
+  ///
+  /// This will align the assignment operators of consecutive lines. This
+  /// will result in formattings like
+  /// \code
+  /// int aaaa = 12;
+  /// int b    = 23;
+  /// int ccc  = 23;
+  /// \endcode
+  bool AlignConsecutiveAssignments;
+
   /// \brief If \c true, aligns escaped newlines as far left as possible.
   /// Otherwise puts them into the right-most column.
   bool AlignEscapedNewlinesLeft;
Index: lib/Format/Format.cpp
===================================================================
--- lib/Format/Format.cpp
+++ lib/Format/Format.cpp
@@ -174,6 +174,7 @@
     IO.mapOptional("AlignEscapedNewlinesLeft", Style.AlignEscapedNewlinesLeft);
     IO.mapOptional("AlignOperands", Style.AlignOperands);
     IO.mapOptional("AlignTrailingComments", Style.AlignTrailingComments);
+    IO.mapOptional("AlignConsecutiveAssignments", Style.AlignConsecutiveAssignments);
     IO.mapOptional("AllowAllParametersOfDeclarationOnNextLine",
                    Style.AllowAllParametersOfDeclarationOnNextLine);
     IO.mapOptional("AllowShortBlocksOnASingleLine",
@@ -329,6 +330,7 @@
   LLVMStyle.AlignAfterOpenBracket = true;
   LLVMStyle.AlignOperands = true;
   LLVMStyle.AlignTrailingComments = true;
+  LLVMStyle.AlignConsecutiveAssignments = false;
   LLVMStyle.AllowAllParametersOfDeclarationOnNextLine = true;
   LLVMStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All;
   LLVMStyle.AllowShortBlocksOnASingleLine = false;
Index: lib/Format/WhitespaceManager.cpp
===================================================================
--- lib/Format/WhitespaceManager.cpp
+++ lib/Format/WhitespaceManager.cpp
@@ -29,13 +29,15 @@
     bool CreateReplacement, const SourceRange &OriginalWhitespaceRange,
     unsigned IndentLevel, int Spaces, unsigned StartOfTokenColumn,
     unsigned NewlinesBefore, StringRef PreviousLinePostfix,
-    StringRef CurrentLinePrefix, tok::TokenKind Kind, bool ContinuesPPDirective)
+    StringRef CurrentLinePrefix, tok::TokenKind Kind, bool ContinuesPPDirective,
+    bool AssignmentToken)
     : CreateReplacement(CreateReplacement),
       OriginalWhitespaceRange(OriginalWhitespaceRange),
       StartOfTokenColumn(StartOfTokenColumn), NewlinesBefore(NewlinesBefore),
       PreviousLinePostfix(PreviousLinePostfix),
       CurrentLinePrefix(CurrentLinePrefix), Kind(Kind),
-      ContinuesPPDirective(ContinuesPPDirective), IndentLevel(IndentLevel),
+      ContinuesPPDirective(ContinuesPPDirective),
+      IsAssignmentToken(AssignmentToken), IndentLevel(IndentLevel),
       Spaces(Spaces), IsTrailingComment(false), TokenLength(0),
       PreviousEndOfTokenColumn(0), EscapedNewlineColumn(0),
       StartOfBlockComment(nullptr), IndentationOffset(0) {}
@@ -54,7 +56,8 @@
   Tok.Decision = (Newlines > 0) ? FD_Break : FD_Continue;
   Changes.push_back(Change(true, Tok.WhitespaceRange, IndentLevel, Spaces,
                            StartOfTokenColumn, Newlines, "", "",
-                           Tok.Tok.getKind(), InPPDirective && !Tok.IsFirst));
+                           Tok.Tok.getKind(), InPPDirective && !Tok.IsFirst,
+                           isAssignmentToken(Tok.Tok.getKind())));
 }
 
 void WhitespaceManager::addUntouchableToken(const FormatToken &Tok,
@@ -64,7 +67,8 @@
   Changes.push_back(Change(false, Tok.WhitespaceRange, /*IndentLevel=*/0,
                            /*Spaces=*/0, Tok.OriginalColumn, Tok.NewlinesBefore,
                            "", "", Tok.Tok.getKind(),
-                           InPPDirective && !Tok.IsFirst));
+                           InPPDirective && !Tok.IsFirst,
+                           isAssignmentToken(Tok.Tok.getKind())));
 }
 
 void WhitespaceManager::replaceWhitespaceInToken(
@@ -84,15 +88,16 @@
       // calculate the new length of the comment and to calculate the changes
       // for which to do the alignment when aligning comments.
       Tok.is(TT_LineComment) && Newlines > 0 ? tok::comment : tok::unknown,
-      InPPDirective && !Tok.IsFirst));
+      InPPDirective && !Tok.IsFirst, isAssignmentToken(Tok.Tok.getKind())));
 }
 
 const tooling::Replacements &WhitespaceManager::generateReplacements() {
   if (Changes.empty())
     return Replaces;
 
   std::sort(Changes.begin(), Changes.end(), Change::IsBeforeInFile(SourceMgr));
   calculateLineBreakInformation();
+  alignConsecutiveAssignments();
   alignTrailingComments();
   alignEscapedNewlines();
   generateChanges();
@@ -141,6 +146,83 @@
   }
 }
 
+bool WhitespaceManager::isAssignmentToken(tok::TokenKind Kind) {
+  return (Kind == tok::ampequal || Kind == tok::starequal ||
+          Kind == tok::plusequal || Kind == tok::minusequal ||
+          Kind == tok::slashequal || Kind == tok::percentequal ||
+          Kind == tok::caretequal || Kind == tok::pipeequal ||
+          Kind == tok::equal);
+}
+
+void WhitespaceManager::alignConsecutiveAssignments() {
+  if (!Style.AlignConsecutiveAssignments)
+    return;
+
+  unsigned MinColumn = 0;
+  unsigned StartOfSequence = 0;
+  bool FoundAssignmentOnLine = false;
+  unsigned CurrentLine = 0;
+  for (unsigned i = 0, e = Changes.size(); i != e; ++i) {
+    if (Changes[i].NewlinesBefore == 1) {
+      CurrentLine += Changes[i].NewlinesBefore;
+      if (!FoundAssignmentOnLine && StartOfSequence > 0) {
+        alignConsecutiveAssignments(StartOfSequence, i, MinColumn);
+        MinColumn = 0;
+        StartOfSequence = 0;
+      }
+      FoundAssignmentOnLine = false;
+    } else if (Changes[i].NewlinesBefore > 1) {
+      CurrentLine += Changes[i].NewlinesBefore;
+      if (StartOfSequence > 0) {
+        alignConsecutiveAssignments(StartOfSequence, i, MinColumn);
+        MinColumn = 0;
+        StartOfSequence = 0;
+      }
+      FoundAssignmentOnLine = false;
+    }
+
+    if (FoundAssignmentOnLine || !Changes[i].IsAssignmentToken)
+      continue;
+
+    FoundAssignmentOnLine = true;
+    if (StartOfSequence == 0)
+      StartOfSequence = i;
+
+    unsigned ChangeMinColumn = Changes[i].StartOfTokenColumn;
+    MinColumn = std::max(MinColumn, ChangeMinColumn);
+  }
+
+  if (StartOfSequence > 0)
+    alignConsecutiveAssignments(StartOfSequence, Changes.size(), MinColumn);
+}
+
+void WhitespaceManager::alignConsecutiveAssignments(unsigned Start,
+                                                    unsigned End,
+                                                    unsigned Column) {
+  bool AlignedAssignment = false;
+  int PreviousShift = 0;
+  for (unsigned i = Start; i != End; ++i) {
+    int Shift = 0;
+    if (Changes[i].NewlinesBefore > 0)
+      AlignedAssignment = false;
+    if (!AlignedAssignment && Changes[i].IsAssignmentToken) {
+      Shift = Column - Changes[i].StartOfTokenColumn;
+      AlignedAssignment = true;
+      PreviousShift = Shift;
+    }
+    assert(Shift >= 0);
+    Changes[i].Spaces += Shift;
+    if (i + 1 != Changes.size())
+      Changes[i + 1].PreviousEndOfTokenColumn += Shift;
+    Changes[i].StartOfTokenColumn += Shift;
+    if (AlignedAssignment) {
+      Changes[i].StartOfTokenColumn += PreviousShift;
+      if (i + 1 != Changes.size())
+        Changes[i + 1].PreviousEndOfTokenColumn += PreviousShift;
+    }
+  }
+}
+
 void WhitespaceManager::alignTrailingComments() {
   unsigned MinColumn = 0;
   unsigned MaxColumn = UINT_MAX;
Index: lib/Format/WhitespaceManager.h
===================================================================
--- lib/Format/WhitespaceManager.h
+++ lib/Format/WhitespaceManager.h
@@ -106,11 +106,13 @@
     ///
     /// \p StartOfTokenColumn and \p InPPDirective will be used to lay out
     /// trailing comments and escaped newlines.
+    ///
+    /// \p AssignmentToken will be used to align consecutive assignments.
     Change(bool CreateReplacement, const SourceRange &OriginalWhitespaceRange,
            unsigned IndentLevel, int Spaces, unsigned StartOfTokenColumn,
            unsigned NewlinesBefore, StringRef PreviousLinePostfix,
            StringRef CurrentLinePrefix, tok::TokenKind Kind,
-           bool ContinuesPPDirective);
+           bool ContinuesPPDirective, bool AssignmentToken);
 
     bool CreateReplacement;
     // Changes might be in the middle of a token, so we cannot just keep the
@@ -126,6 +128,7 @@
     // the \c BreakableToken is still doing its own alignment.
     tok::TokenKind Kind;
     bool ContinuesPPDirective;
+    bool IsAssignmentToken;
 
     // The number of nested blocks the token is in. This is used to add tabs
     // only for the indentation, and not for alignment, when
@@ -164,6 +167,16 @@
   /// \c EscapedNewlineColumn for the first tokens or token parts in a line.
   void calculateLineBreakInformation();
 
+  /// \brief Returns true if the FormatToken passed in is an assignment token.
+  bool isAssignmentToken(tok::TokenKind Kind);
+
+  /// \brief Align consecutive assignments over all \c Changes.
+  void alignConsecutiveAssignments();
+
+  /// \brief Align consecutive assignments from change \p Start to change \p End at
+  /// the specified \p Column.
+  void alignConsecutiveAssignments(unsigned Start, unsigned End, unsigned Column);
+
   /// \brief Align trailing comments over all \c Changes.
   void alignTrailingComments();
 
Index: unittests/Format/FormatTest.cpp
===================================================================
--- unittests/Format/FormatTest.cpp
+++ unittests/Format/FormatTest.cpp
@@ -8347,6 +8347,77 @@
   verifyFormat("a or_eq 8;", Spaces);
 }
 
+TEST_F(FormatTest, AlignConsecutiveAssignments) {
+  FormatStyle Alignment = getLLVMStyle();
+  Alignment.AlignConsecutiveAssignments = false;
+  verifyFormat("int a = 5;\n"
+               "int oneTwoThree = 123;", Alignment);
+  verifyFormat("int a = 5;\n"
+               "int oneTwoThree = 123;", Alignment);
+
+  Alignment.AlignConsecutiveAssignments = true;
+  verifyFormat("int a           = 5;\n"
+               "int oneTwoThree = 123;", Alignment);
+  verifyFormat("int a           = 5;\n"
+               "int oneTwoThree = 123;", Alignment);
+  verifyFormat("a               &= 5;\n"
+               "bcd             *= 5;\n"
+               "ghtyf           += 5;\n"
+               "dvfvdb          -= 5;\n"
+               "a               /= 5;\n"
+               "vdsvsv          %= 5;\n"
+               "sfdbddfbdfbb    ^= 5;\n"
+               "dvsdsv          |= 5;\n"
+               "int dsvvdvsdvvv = 123;", Alignment);
+  verifyFormat("int i     = 1, j = 10;\n"
+               "something = 2000;", Alignment);
+  verifyFormat("something = 2000;\n"
+               "int i     = 1, j = 10;\n", Alignment);
+  verifyFormat("int a   = 5;\n"
+               "int one = 1;\n"
+               "method();\n"
+               "int oneTwoThree = 123;\n"
+               "int oneTwo      = 12;", Alignment);
+  verifyFormat("int oneTwoThree = 123; // comment\n"
+               "int oneTwo      = 12;  // comment", Alignment);
+  EXPECT_EQ("int a = 5;\n"
+            "\n"
+            "int oneTwoThree = 123;",
+            format("int a       = 5;\n"
+                   "\n"
+                   "int oneTwoThree= 123;", Alignment));
+  EXPECT_EQ("int a   = 5;\n"
+            "int one = 1;\n"
+            "\n"
+            "int oneTwoThree = 123;",
+            format("int a = 5;\n"
+                   "int one = 1;\n"
+                   "\n"
+                   "int oneTwoThree = 123;", Alignment));
+  EXPECT_EQ("int a   = 5;\n"
+            "int one = 1;\n"
+            "\n"
+            "int oneTwoThree = 123;\n"
+            "int oneTwo      = 12;",
+            format("int a = 5;\n"
+                   "int one = 1;\n"
+                   "\n"
+                   "int oneTwoThree = 123;\n"
+                   "int oneTwo = 12;", Alignment));
+  Alignment.AlignEscapedNewlinesLeft = true;
+  verifyFormat("#define A              \\\n"
+               "  int aaaa       = 12; \\\n"
+               "  int b          = 23; \\\n"
+               "  int ccc        = 23; \\\n"
+               "  int dddddddddd = 2345;", Alignment);
+  Alignment.AlignEscapedNewlinesLeft = false;
+  verifyFormat("#define A                                                                      \\\n"
+               "  int aaaa       = 12;                                                         \\\n"
+               "  int b          = 23;                                                         \\\n"
+               "  int ccc        = 23;                                                         \\\n"
+               "  int dddddddddd = 2345;", Alignment);
+}
+
 TEST_F(FormatTest, LinuxBraceBreaking) {
   FormatStyle LinuxBraceStyle = getLLVMStyle();
   LinuxBraceStyle.BreakBeforeBraces = FormatStyle::BS_Linux;
@@ -8886,6 +8957,7 @@
   CHECK_PARSE_BOOL(AlignEscapedNewlinesLeft);
   CHECK_PARSE_BOOL(AlignOperands);
   CHECK_PARSE_BOOL(AlignTrailingComments);
+  CHECK_PARSE_BOOL(AlignConsecutiveAssignments);
   CHECK_PARSE_BOOL(AllowAllParametersOfDeclarationOnNextLine);
   CHECK_PARSE_BOOL(AllowShortBlocksOnASingleLine);
   CHECK_PARSE_BOOL(AllowShortCaseLabelsOnASingleLine);
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to