+**AlignConsecutiveMacros** (``bool``)
+ If ``true``, aligns consecutive C/C++ preprocessor macros.
+
+ This will align the C/C++ preprocessor macros of consecutive lines. This
+ will result in formattings like
+
+ .. code-block:: c++
+
+ #define SHORT_NAME 42
+ #define LONGER_NAME 0x007f
+ #define EVEN_LONGER_NAME (2)
+ #define foo(x) (x * x)
+ #define bar(y, z) (y + z)
+
**AlignConsecutiveAssignments** (``bool``)
If ``true``, aligns consecutive assignments.
/// brackets.
BracketAlignmentStyle AlignAfterOpenBracket;
+ /// \brief If ``true``, aligns consecutive C/C++ preprocessor macros.
+ ///
+ /// This will align C/C++ preprocessor macros of consecutive lines.
+ /// Will result in formattings like
+ /// \code
+ /// #define SHORT_NAME 42
+ /// #define LONGER_NAME 0x007f
+ /// #define EVEN_LONGER_NAME (2)
+ /// #define foo(x) (x * x)
+ /// #define bar(y, z) (y + z)
+ /// \endcode
+ bool AlignConsecutiveMacros;
+
/// If ``true``, aligns consecutive assignments.
///
/// This will align the assignment operators of consecutive lines. This
IO.mapOptional("AccessModifierOffset", Style.AccessModifierOffset);
IO.mapOptional("AlignAfterOpenBracket", Style.AlignAfterOpenBracket);
+ IO.mapOptional("AlignConsecutiveMacros", Style.AlignConsecutiveMacros);
IO.mapOptional("AlignConsecutiveAssignments",
Style.AlignConsecutiveAssignments);
IO.mapOptional("AlignConsecutiveDeclarations",
LLVMStyle.AlignTrailingComments = true;
LLVMStyle.AlignConsecutiveAssignments = false;
LLVMStyle.AlignConsecutiveDeclarations = false;
+ LLVMStyle.AlignConsecutiveMacros = false;
LLVMStyle.AllowAllArgumentsOnNextLine = true;
LLVMStyle.AllowAllConstructorInitializersOnNextLine = true;
LLVMStyle.AllowAllParametersOfDeclarationOnNextLine = true;
llvm::sort(Changes, Change::IsBeforeInFile(SourceMgr));
calculateLineBreakInformation();
+ alignConsecutiveMacros();
alignConsecutiveDeclarations();
alignConsecutiveAssignments();
alignTrailingComments();
return i;
}
+// Aligns a sequence of matching tokens, on the MinColumn column.
+//
+// Sequences start from the first matching token to align, and end at the
+// first token of the first line that doesn't need to be aligned.
+//
+// We need to adjust the StartOfTokenColumn of each Change that is on a line
+// containing any matching token to be aligned and located after such token.
+static void AlignMacroSequence(
+ unsigned &StartOfSequence, unsigned &EndOfSequence, unsigned &MinColumn,
+ unsigned &MaxColumn, bool &FoundMatchOnLine,
+ std::function<bool(const WhitespaceManager::Change &C)> AlignMacrosMatches,
+ SmallVector<WhitespaceManager::Change, 16> &Changes) {
+ if (StartOfSequence > 0 && StartOfSequence < EndOfSequence) {
+
+ FoundMatchOnLine = false;
+ int Shift = 0;
+
+ for (unsigned I = StartOfSequence; I != EndOfSequence; ++I) {
+ if (Changes[I].NewlinesBefore > 0) {
+ Shift = 0;
+ FoundMatchOnLine = false;
+ }
+
+ // If this is the first matching token to be aligned, remember by how many
+ // spaces it has to be shifted, so the rest of the changes on the line are
+ // shifted by the same amount
+ if (!FoundMatchOnLine && AlignMacrosMatches(Changes[I])) {
+ FoundMatchOnLine = true;
+ Shift = MinColumn - Changes[I].StartOfTokenColumn;
+ Changes[I].Spaces += Shift;
+ }
+
+ assert(Shift >= 0);
+ Changes[I].StartOfTokenColumn += Shift;
+ if (I + 1 != Changes.size())
+ Changes[I + 1].PreviousEndOfTokenColumn += Shift;
+ }
+ }
+
+ MinColumn = 0;
+ MaxColumn = UINT_MAX;
+ StartOfSequence = 0;
+ EndOfSequence = 0;
+}
+
+void WhitespaceManager::alignConsecutiveMacros() {
+ if (!Style.AlignConsecutiveMacros)
+ return;
+
+ auto AlignMacrosMatches = [](const Change &C) {
+ const FormatToken *Current = C.Tok;
+ unsigned SpacesRequiredBefore = 1;
+
+ if (Current->SpacesRequiredBefore == 0 || !Current->Previous)
+ return false;
+
+ Current = Current->Previous;
+
+ // If token is a ")", skip over the parameter list, to the
+ // token that precedes the "("
+ if (Current->is(tok::r_paren) && Current->MatchingParen) {
+ Current = Current->MatchingParen->Previous;
+ SpacesRequiredBefore = 0;
+ }
+
+ if (!Current || !Current->is(tok::identifier))
+ return false;
+
+ if (!Current->Previous || !Current->Previous->is(tok::pp_define))
+ return false;
+
+ // For a macro function, 0 spaces are required between the
+ // identifier and the lparen that opens the parameter list.
+ // For a simple macro, 1 space is required between the
+ // identifier and the first token of the defined value.
+ return Current->Next->SpacesRequiredBefore == SpacesRequiredBefore;
+ };
+
+ unsigned MinColumn = 0;
+ unsigned MaxColumn = UINT_MAX;
+
+ // Start and end of the token sequence we're processing.
+ unsigned StartOfSequence = 0;
+ unsigned EndOfSequence = 0;
+
+ // Whether a matching token has been found on the current line.
+ bool FoundMatchOnLine = false;
+
+ unsigned I = 0;
+ for (unsigned E = Changes.size(); I != E; ++I) {
+ if (Changes[I].NewlinesBefore != 0) {
+ EndOfSequence = I;
+ // If there is a blank line, or if the last line didn't contain any
+ // matching token, the sequence ends here.
+ if (Changes[I].NewlinesBefore > 1 || !FoundMatchOnLine)
+ AlignMacroSequence(StartOfSequence, EndOfSequence, MinColumn, MaxColumn,
+ FoundMatchOnLine, AlignMacrosMatches, Changes);
+
+ FoundMatchOnLine = false;
+ }
+
+ if (!AlignMacrosMatches(Changes[I]))
+ continue;
+
+ FoundMatchOnLine = true;
+
+ if (StartOfSequence == 0)
+ StartOfSequence = I;
+
+ unsigned ChangeMinColumn = Changes[I].StartOfTokenColumn;
+ int LineLengthAfter = -Changes[I].Spaces;
+ for (unsigned j = I; j != E && Changes[j].NewlinesBefore == 0; ++j)
+ LineLengthAfter += Changes[j].Spaces + Changes[j].TokenLength;
+ unsigned ChangeMaxColumn = Style.ColumnLimit - LineLengthAfter;
+
+ MinColumn = std::max(MinColumn, ChangeMinColumn);
+ MaxColumn = std::min(MaxColumn, ChangeMaxColumn);
+ }
+
+ EndOfSequence = I;
+ AlignMacroSequence(StartOfSequence, EndOfSequence, MinColumn, MaxColumn,
+ FoundMatchOnLine, AlignMacrosMatches, Changes);
+}
+
void WhitespaceManager::alignConsecutiveAssignments() {
if (!Style.AlignConsecutiveAssignments)
return;
/// \c EscapedNewlineColumn for the first tokens or token parts in a line.
void calculateLineBreakInformation();
+ /// \brief Align consecutive C/C++ preprocessor macros over all \c Changes.
+ void alignConsecutiveMacros();
+
/// Align consecutive assignments over all \c Changes.
void alignConsecutiveAssignments();
NoSpaceStyle);
}
+TEST_F(FormatTest, AlignConsecutiveMacros) {
+ FormatStyle Style = getLLVMStyle();
+ Style.AlignConsecutiveAssignments = true;
+ Style.AlignConsecutiveDeclarations = true;
+ Style.AlignConsecutiveMacros = false;
+
+ verifyFormat("#define a 3\n"
+ "#define bbbb 4\n"
+ "#define ccc (5)",
+ Style);
+
+ verifyFormat("#define f(x) (x * x)\n"
+ "#define fff(x, y, z) (x * y + z)\n"
+ "#define ffff(x, y) (x - y)",
+ Style);
+
+ verifyFormat("#define foo(x, y) (x + y)\n"
+ "#define bar (5, 6)(2 + 2)",
+ Style);
+
+ verifyFormat("#define a 3\n"
+ "#define bbbb 4\n"
+ "#define ccc (5)\n"
+ "#define f(x) (x * x)\n"
+ "#define fff(x, y, z) (x * y + z)\n"
+ "#define ffff(x, y) (x - y)",
+ Style);
+
+ Style.AlignConsecutiveMacros = true;
+ verifyFormat("#define a 3\n"
+ "#define bbbb 4\n"
+ "#define ccc (5)",
+ Style);
+
+ verifyFormat("#define f(x) (x * x)\n"
+ "#define fff(x, y, z) (x * y + z)\n"
+ "#define ffff(x, y) (x - y)",
+ Style);
+
+ verifyFormat("#define foo(x, y) (x + y)\n"
+ "#define bar (5, 6)(2 + 2)",
+ Style);
+
+ verifyFormat("#define a 3\n"
+ "#define bbbb 4\n"
+ "#define ccc (5)\n"
+ "#define f(x) (x * x)\n"
+ "#define fff(x, y, z) (x * y + z)\n"
+ "#define ffff(x, y) (x - y)",
+ Style);
+
+ verifyFormat("#define a 5\n"
+ "#define foo(x, y) (x + y)\n"
+ "#define CCC (6)\n"
+ "auto lambda = []() {\n"
+ " auto ii = 0;\n"
+ " float j = 0;\n"
+ " return 0;\n"
+ "};\n"
+ "int i = 0;\n"
+ "float i2 = 0;\n"
+ "auto v = type{\n"
+ " i = 1, //\n"
+ " (i = 2), //\n"
+ " i = 3 //\n"
+ "};",
+ Style);
+
+ Style.AlignConsecutiveMacros = false;
+ Style.ColumnLimit = 20;
+
+ verifyFormat("#define a \\\n"
+ " \"aabbbbbbbbbbbb\"\n"
+ "#define D \\\n"
+ " \"aabbbbbbbbbbbb\" \\\n"
+ " \"ccddeeeeeeeee\"\n"
+ "#define B \\\n"
+ " \"QQQQQQQQQQQQQ\" \\\n"
+ " \"FFFFFFFFFFFFF\" \\\n"
+ " \"LLLLLLLL\"\n",
+ Style);
+
+ Style.AlignConsecutiveMacros = true;
+ verifyFormat("#define a \\\n"
+ " \"aabbbbbbbbbbbb\"\n"
+ "#define D \\\n"
+ " \"aabbbbbbbbbbbb\" \\\n"
+ " \"ccddeeeeeeeee\"\n"
+ "#define B \\\n"
+ " \"QQQQQQQQQQQQQ\" \\\n"
+ " \"FFFFFFFFFFFFF\" \\\n"
+ " \"LLLLLLLL\"\n",
+ Style);
+}
+
TEST_F(FormatTest, AlignConsecutiveAssignments) {
FormatStyle Alignment = getLLVMStyle();
+ Alignment.AlignConsecutiveMacros = true;
Alignment.AlignConsecutiveAssignments = false;
verifyFormat("int a = 5;\n"
"int oneTwoThree = 123;",
TEST_F(FormatTest, AlignConsecutiveDeclarations) {
FormatStyle Alignment = getLLVMStyle();
+ Alignment.AlignConsecutiveMacros = true;
Alignment.AlignConsecutiveDeclarations = false;
verifyFormat("float const a = 5;\n"
"int oneTwoThree = 123;",
CHECK_PARSE_BOOL(AlignTrailingComments);
CHECK_PARSE_BOOL(AlignConsecutiveAssignments);
CHECK_PARSE_BOOL(AlignConsecutiveDeclarations);
+ CHECK_PARSE_BOOL(AlignConsecutiveMacros);
CHECK_PARSE_BOOL(AllowAllArgumentsOnNextLine);
CHECK_PARSE_BOOL(AllowAllConstructorInitializersOnNextLine);
CHECK_PARSE_BOOL(AllowAllParametersOfDeclarationOnNextLine);