Index: docs/ClangFormatStyleOptions.rst =================================================================== --- docs/ClangFormatStyleOptions.rst +++ docs/ClangFormatStyleOptions.rst @@ -160,6 +160,9 @@ argument2); \endcode +**AlignAssignmentOperators** (``bool``) + If ``true``, aligns assignment operators. + **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,9 @@ /// \brief If \c true, aligns trailing comments. bool AlignTrailingComments; + /// \brief If \c true, aligns variable assignments. + bool AlignAssignmentOperators; + /// \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("AlignAssignmentOperators", Style.AlignAssignmentOperators); IO.mapOptional("AllowAllParametersOfDeclarationOnNextLine", Style.AllowAllParametersOfDeclarationOnNextLine); IO.mapOptional("AllowShortBlocksOnASingleLine", @@ -329,6 +330,7 @@ LLVMStyle.AlignAfterOpenBracket = true; LLVMStyle.AlignOperands = true; LLVMStyle.AlignTrailingComments = true; + LLVMStyle.AlignAssignmentOperators = false; LLVMStyle.AllowAllParametersOfDeclarationOnNextLine = true; LLVMStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All; LLVMStyle.AllowShortBlocksOnASingleLine = false; @@ -418,6 +420,7 @@ GoogleStyle.AlignAfterOpenBracket = false; GoogleStyle.AlignOperands = false; GoogleStyle.AlignTrailingComments = false; + GoogleStyle.AlignAssignmentOperators = false; GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty; GoogleStyle.AllowShortIfStatementsOnASingleLine = false; GoogleStyle.AlwaysBreakBeforeMultilineStrings = false; @@ -477,6 +480,7 @@ Style.AlignAfterOpenBracket = false; Style.AlignOperands = false; Style.AlignTrailingComments = false; + Style.AlignAssignmentOperators = false; Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All; Style.BreakBeforeBraces = FormatStyle::BS_Stroustrup; Style.BreakConstructorInitializersBeforeComma = true; Index: lib/Format/WhitespaceManager.h =================================================================== --- lib/Format/WhitespaceManager.h +++ lib/Format/WhitespaceManager.h @@ -178,6 +178,13 @@ /// the specified \p Column. void alignEscapedNewlines(unsigned Start, unsigned End, unsigned Column); + /// \brief Align assignment operators over all \c Changes. + void alignAssignmentOperators(); + + /// \brief Align assignment operators from change \p Start to change \p End at + /// the specified \p Column. + void alignAssignmentOperators(unsigned Start, unsigned End, unsigned Column); + /// \brief Fill \c Replaces with the replacements for all effective changes. void generateChanges(); Index: lib/Format/WhitespaceManager.cpp =================================================================== --- lib/Format/WhitespaceManager.cpp +++ lib/Format/WhitespaceManager.cpp @@ -95,6 +95,7 @@ calculateLineBreakInformation(); alignTrailingComments(); alignEscapedNewlines(); + alignAssignmentOperators(); generateChanges(); return Replaces; @@ -263,6 +264,63 @@ } } +void WhitespaceManager::alignAssignmentOperators() { + if (!Style.AlignAssignmentOperators) + return; + + unsigned MinColumn = 0; + unsigned StartOfSequence = 0; + bool FoundEqualOnLine = false; + unsigned CurrentLine = 0; + for (unsigned i = 0, e = Changes.size(); i != e; ++i) { + if (Changes[i].NewlinesBefore == 1) { + CurrentLine += Changes[i].NewlinesBefore; + if (!FoundEqualOnLine && StartOfSequence > 0) { + alignAssignmentOperators(StartOfSequence, i, MinColumn); + MinColumn = 0; + StartOfSequence = 0; + } + FoundEqualOnLine = false; + } else if (Changes[i].NewlinesBefore > 1) { + CurrentLine += Changes[i].NewlinesBefore; + if (StartOfSequence > 0) { + alignAssignmentOperators(StartOfSequence, i, MinColumn); + MinColumn = 0; + StartOfSequence = 0; + } + FoundEqualOnLine = false; + } + + if (Changes[i].Kind != tok::equal) + continue; + + FoundEqualOnLine = true; + if (StartOfSequence == 0) + StartOfSequence = i; + + unsigned ChangeMinColumn = Changes[i].StartOfTokenColumn; + MinColumn = std::max(MinColumn, ChangeMinColumn); + } + + if (StartOfSequence > 0) + alignAssignmentOperators(StartOfSequence, Changes.size(), MinColumn); +} + +void WhitespaceManager::alignAssignmentOperators(unsigned Start, unsigned End, + unsigned Column) { + for (unsigned i = Start; i != End; ++i) { + int Shift = 0; + if (Changes[i].Kind == tok::equal) { + Shift = Column - Changes[i].StartOfTokenColumn; + } + assert(Shift >= 0); + Changes[i].Spaces += Shift; + if (i + 1 != Changes.size()) + Changes[i + 1].PreviousEndOfTokenColumn += Shift; + Changes[i].StartOfTokenColumn += Shift; + } +} + void WhitespaceManager::generateChanges() { for (unsigned i = 0, e = Changes.size(); i != e; ++i) { const Change &C = Changes[i]; Index: unittests/Format/FormatTest.cpp =================================================================== --- unittests/Format/FormatTest.cpp +++ unittests/Format/FormatTest.cpp @@ -8347,6 +8347,59 @@ verifyFormat("a or_eq 8;", Spaces); } +TEST_F(FormatTest, AlignAssignmentOperators) { + FormatStyle Alignment = getLLVMStyle(); + Alignment.AlignAssignmentOperators = false; + verifyFormat("int a = 5;\n" + "int oneTwoThree = 123;", Alignment); + EXPECT_EQ("int a = 5;\n" + "int oneTwoThree = 123;", + format("int a =5;\n" + "int oneTwoThree= 123;", Alignment)); + + Alignment.AlignAssignmentOperators = true; + verifyFormat("int a = 5;\n" + "int oneTwoThree = 123;", Alignment); + EXPECT_EQ("int a = 5;\n" + "int oneTwoThree = 123;", + format("int a= 5;\n" + "int oneTwoThree = 123;", 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)); + EXPECT_EQ("int a = 5;\n" + "int one = 1;\n" + "method();\n" + "int oneTwoThree = 123;\n" + "int oneTwo = 12;", + format("int a = 5;\n" + "int one = 1;\n" + "method();\n" + "int oneTwoThree = 123;\n" + "int oneTwo = 12;", Alignment)); +} + TEST_F(FormatTest, LinuxBraceBreaking) { FormatStyle LinuxBraceStyle = getLLVMStyle(); LinuxBraceStyle.BreakBeforeBraces = FormatStyle::BS_Linux; @@ -8886,6 +8939,7 @@ CHECK_PARSE_BOOL(AlignEscapedNewlinesLeft); CHECK_PARSE_BOOL(AlignOperands); CHECK_PARSE_BOOL(AlignTrailingComments); + CHECK_PARSE_BOOL(AlignAssignmentOperators); CHECK_PARSE_BOOL(AllowAllParametersOfDeclarationOnNextLine); CHECK_PARSE_BOOL(AllowShortBlocksOnASingleLine); CHECK_PARSE_BOOL(AllowShortCaseLabelsOnASingleLine);