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