feg208 updated this revision to Diff 347419.
feg208 added a comment.
clang-tidy and clang-format changes
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D101868/new/
https://reviews.llvm.org/D101868
Files:
clang/docs/ClangFormatStyleOptions.rst
clang/docs/ReleaseNotes.rst
clang/include/clang/Format/Format.h
clang/lib/Format/ContinuationIndenter.cpp
clang/lib/Format/ContinuationIndenter.h
clang/lib/Format/Format.cpp
clang/lib/Format/FormatToken.cpp
clang/lib/Format/FormatToken.h
clang/lib/Format/TokenAnnotator.cpp
clang/lib/Format/TokenAnnotator.h
clang/unittests/Format/FormatTest.cpp
Index: clang/unittests/Format/FormatTest.cpp
===================================================================
--- clang/unittests/Format/FormatTest.cpp
+++ clang/unittests/Format/FormatTest.cpp
@@ -16367,6 +16367,162 @@
getLLVMStyle());
}
+TEST_F(FormatTest, CatchAlignArrayOfStructures) {
+ auto Style = getLLVMStyle();
+ Style.AlignArrayOfStructures = true;
+ Style.AlignConsecutiveAssignments =
+ FormatStyle::AlignConsecutiveStyle::ACS_Consecutive;
+ Style.AlignConsecutiveDeclarations =
+ FormatStyle::AlignConsecutiveStyle::ACS_Consecutive;
+ verifyFormat("struct test demo[] = {\n"
+ " {56, 23, \"hello\" },\n"
+ " {-1, 93463, \"world\" },\n"
+ " { 7, 5, \"!!\" }\n"
+ "};\n",
+ Style);
+
+ verifyFormat("struct test demo[] = {\n"
+ " {56, 23, \"hello\" }, // first line\n"
+ " {-1, 93463, \"world\" }, // second line\n"
+ " { 7, 5, \"!!\" } // third line\n"
+ "};\n",
+ Style);
+
+ verifyFormat("struct test demo[4] = {\n"
+ " { 56, 23, 21, \"oh\" }, // first line\n"
+ " { -1, 93463, 22, \"my\" }, // second line\n"
+ " { 7, 5, 1, \"goodness\" } // third line\n"
+ " {234, 5, 1, \"gracious\" } // fourth line\n"
+ "};\n",
+ Style);
+
+ verifyFormat("struct test demo[3] = {\n"
+ " {56, 23, \"hello\" },\n"
+ " {-1, 93463, \"world\" },\n"
+ " { 7, 5, \"!!\" }\n"
+ "};\n",
+ Style);
+ verifyFormat("struct test demo[3] = {\n"
+ " {int{56}, 23, \"hello\" },\n"
+ " {int{-1}, 93463, \"world\" },\n"
+ " { int{7}, 5, \"!!\" }\n"
+ "};\n",
+ Style);
+ verifyFormat("struct test demo[] = {\n"
+ " {56, 23, \"hello\" },\n"
+ " {-1, 93463, \"world\" },\n"
+ " { 7, 5, \"!!\" },\n"
+ "};\n",
+ Style);
+ verifyFormat("test demo[] = {\n"
+ " {56, 23, \"hello\" },\n"
+ " {-1, 93463, \"world\" },\n"
+ " { 7, 5, \"!!\" },\n"
+ "};\n",
+ Style);
+ verifyFormat("demo = std::array<struct test, 3>{\n"
+ " test{56, 23, \"hello\" },\n"
+ " test{-1, 93463, \"world\" },\n"
+ " test{ 7, 5, \"!!\" },\n"
+ "};\n",
+ Style);
+ verifyFormat("test demo[] = {\n"
+ " {56, 23, \"hello\" },\n"
+ "#if X\n"
+ " {-1, 93463, \"world\" },\n"
+ "#endif\n"
+ " { 7, 5, \"!!\" }\n"
+ "};\n",
+ Style);
+
+ verifyFormat("test demo[] = {\n"
+ " { 7, 23,\n"
+ " \"hello world i am a very long line that really, in any\"\n"
+ " \"just world, ought to be split over multiple lines\" },\n"
+ " {-1, 93463, \"world\" },\n"
+ " {56, 5, \"!!\" }\n"
+ "};\n",
+ Style);
+
+ verifyFormat("return GradForUnaryCwise(g, {\n"
+ " {{\"sign\"}, \"Sign\", "
+ "{\"x\", \"dy\"} },\n"
+ " { {\"dx\"}, \"Mul\", {\"dy\""
+ ", \"sign\"} },\n"
+ " });\n",
+ Style);
+
+ Style.ColumnLimit = 0;
+ EXPECT_EQ(
+ "test demo[] = {\n"
+ " {56, 23, \"hello world i am a very long line that really, "
+ "in any just world, ought to be split over multiple lines\" },\n"
+ " {-1, 93463, "
+ " \"world\" },\n"
+ " { 7, 5, "
+ " \"!!\" },\n"
+ "};",
+ format("test demo[] = {{56, 23, \"hello world i am a very long line "
+ "that really, in any just world, ought to be split over multiple "
+ "lines\"},{-1, 93463, \"world\"},{7, 5, \"!!\"},};",
+ Style));
+ Style.ColumnLimit = 20;
+ EXPECT_EQ(
+ "demo = std::array<\n"
+ " struct test, 3>{\n"
+ " test{56, 23,\n"
+ " \"hello \"\n"
+ " \"world i \"\n"
+ " \"am a very \"\n"
+ " \"long line \"\n"
+ " \"that \"\n"
+ " \"really, \"\n"
+ " \"in any \"\n"
+ " \"just \"\n"
+ " \"world, \"\n"
+ " \"ought to \"\n"
+ " \"be split \"\n"
+ " \"over \"\n"
+ " \"multiple \"\n"
+ " \"lines\" },\n"
+ " test{-1, 93463,\n"
+ " \"world\" },\n"
+ " test{ 7, 5,\n"
+ " \"!!\" },\n"
+ "};",
+ format("demo = std::array<struct test, 3>{test{56, 23, \"hello world "
+ "i am a very long line that really, in any just world, ought "
+ "to be split over multiple lines\"},test{-1, 93463, \"world\"},"
+ "test{7, 5, \"!!\"},};",
+ Style));
+ // This caused a core dump by enabling Alignment in the LLVMStyle globally
+ Style = getLLVMStyleWithColumns(50);
+ Style.AlignArrayOfStructures = true;
+ verifyFormat("static A x = {\n"
+ " {{init1, init2, init3, init4},\n"
+ " {init1, init2, init3, init4} }\n"
+ "};",
+ Style);
+
+ // FIXME This is a case where the lines are obviously malformed
+ /*
+ Style.ColumnLimit = 100;
+ EXPECT_EQ(
+ "test demo[] = {\n"
+ " {56, 23,\n"
+ " \"hello world i am a very long line that really, in any just world"
+ ", ought to be split over \"\n"
+ " \"multiple lines\" },\n"
+ " {-1, 93463, \"world\" },\n"
+ " { 7, 5, \"!!\" },\n"
+ "};",
+ format("test demo[] = {{56, 23, \"hello world i am a very long line "
+ "that really, in any just world, ought to be split over multiple "
+ "lines\"},{-1, 93463, \"world\"},{7, 5, \"!!\"},};",
+ Style));
+ */
+}
+
TEST_F(FormatTest, UnderstandsPragmas) {
verifyFormat("#pragma omp reduction(| : var)");
verifyFormat("#pragma omp reduction(+ : var)");
Index: clang/lib/Format/TokenAnnotator.h
===================================================================
--- clang/lib/Format/TokenAnnotator.h
+++ clang/lib/Format/TokenAnnotator.h
@@ -18,6 +18,9 @@
#include "UnwrappedLineParser.h"
#include "clang/Format/Format.h"
+#include <deque>
+#include <vector>
+
namespace clang {
class SourceManager;
@@ -31,7 +34,8 @@
LT_ObjCProperty, // An @property line.
LT_Other,
LT_PreprocessorDirective,
- LT_VirtualFunctionDecl
+ LT_VirtualFunctionDecl,
+ LT_ArrayOfStructInitializer
};
class AnnotatedLine {
@@ -189,6 +193,13 @@
void calculateUnbreakableTailLengths(AnnotatedLine &Line);
+ void calculateArrayInitializerColumnList(AnnotatedLine &Line);
+
+ FormatToken *
+ calculateInitializerColumnList(AnnotatedLine &Line,
+ std::deque<FormatToken *> &&ColumnEntries,
+ FormatToken *CurrentToken, unsigned Depth);
+
const FormatStyle &Style;
const AdditionalKeywords &Keywords;
Index: clang/lib/Format/TokenAnnotator.cpp
===================================================================
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -729,11 +729,21 @@
return false;
}
+ bool couldBeInStructArrayInitializer() const {
+ const auto end = Contexts.rbegin() + 2;
+ auto last = Contexts.rbegin();
+ unsigned Depth = 0;
+ for (; last != end; ++last) {
+ if (last->ContextKind == tok::l_brace)
+ ++Depth;
+ }
+ return Depth == 2 && last->ContextKind != tok::l_brace;
+ }
+
bool parseBrace() {
if (CurrentToken) {
FormatToken *Left = CurrentToken->Previous;
Left->ParentBracket = Contexts.back().ContextKind;
-
if (Contexts.back().CaretFound)
Left->setType(TT_ObjCBlockLBrace);
Contexts.back().CaretFound = false;
@@ -746,10 +756,17 @@
Left->Previous->is(TT_JsTypeColon))
Contexts.back().IsExpression = false;
+ unsigned CommaCount = 0;
while (CurrentToken) {
if (CurrentToken->is(tok::r_brace)) {
Left->MatchingParen = CurrentToken;
CurrentToken->MatchingParen = Left;
+ if (Style.AlignArrayOfStructures) {
+ if (Left->ParentBracket == tok::l_brace &&
+ couldBeInStructArrayInitializer() && CommaCount > 0) {
+ Contexts.back().InStructArrayInitializer = true;
+ }
+ }
next();
return true;
}
@@ -773,9 +790,11 @@
Style.Language == FormatStyle::LK_JavaScript)
Left->setType(TT_DictLiteral);
}
- if (CurrentToken->is(tok::comma) &&
- Style.Language == FormatStyle::LK_JavaScript)
- Left->setType(TT_DictLiteral);
+ if (CurrentToken->is(tok::comma)) {
+ if (Style.Language == FormatStyle::LK_JavaScript)
+ Left->setType(TT_DictLiteral);
+ ++CommaCount;
+ }
if (!consumeToken())
return false;
}
@@ -1339,6 +1358,12 @@
return LT_ObjCMethodDecl;
}
+ for (const auto &ctx : Contexts) {
+ if (ctx.InStructArrayInitializer) {
+ return LT_ArrayOfStructInitializer;
+ }
+ }
+
return LT_Other;
}
@@ -1414,6 +1439,7 @@
bool IsForEachMacro = false;
bool InCpp11AttributeSpecifier = false;
bool InCSharpAttributeSpecifier = false;
+ bool InStructArrayInitializer = false;
};
/// Puts a new \c Context onto the stack \c Contexts for the lifetime
@@ -1429,7 +1455,16 @@
P.Contexts.back().IsExpression));
}
- ~ScopedContextCreator() { P.Contexts.pop_back(); }
+ ~ScopedContextCreator() {
+ if (P.Style.AlignArrayOfStructures) {
+ if (P.Contexts.back().InStructArrayInitializer) {
+ P.Contexts.pop_back();
+ P.Contexts.back().InStructArrayInitializer = true;
+ return;
+ }
+ }
+ P.Contexts.pop_back();
+ }
};
void modifyContext(const FormatToken &Current) {
@@ -2473,6 +2508,11 @@
: Line.FirstStartColumn + Line.First->ColumnWidth;
FormatToken *Current = Line.First->Next;
bool InFunctionDecl = Line.MightBeFunctionDecl;
+ bool AlignArrayOfStructures = (Style.AlignArrayOfStructures &&
+ Line.Type == LT_ArrayOfStructInitializer);
+ if (AlignArrayOfStructures)
+ calculateArrayInitializerColumnList(Line);
+
while (Current) {
if (isFunctionDeclarationName(*Current, Line))
Current->setType(TT_FunctionDeclarationName);
@@ -2592,6 +2632,85 @@
}
}
+void TokenAnnotator::calculateArrayInitializerColumnList(AnnotatedLine &Line) {
+ if (Line.First == Line.Last) {
+ return;
+ }
+ auto *CurrentToken = Line.First;
+ unsigned Depth = 0;
+ while (CurrentToken != nullptr && CurrentToken != Line.Last) {
+ if (CurrentToken->is(tok::l_brace))
+ CurrentToken = calculateInitializerColumnList(
+ Line, std::deque<FormatToken *>{}, CurrentToken->Next, Depth + 1);
+ else
+ CurrentToken = CurrentToken->Next;
+ }
+}
+
+// NOLINTNEXTLINE(misc-no-recursion)
+FormatToken *TokenAnnotator::calculateInitializerColumnList(
+ AnnotatedLine &Line, std::deque<FormatToken *> &&ColumnEntries,
+ FormatToken *CurrentToken, unsigned Depth) {
+ if (Depth == 1) {
+ CurrentToken->MustBreakBefore = true;
+ return calculateInitializerColumnList(Line, std::move(ColumnEntries),
+ CurrentToken, Depth + 1);
+ }
+
+ std::deque<FormatToken *> NextRow;
+ while (CurrentToken != nullptr && CurrentToken != Line.Last) {
+ if (CurrentToken->is(tok::l_brace)) {
+ ++Depth;
+ } else if (CurrentToken->is(tok::r_brace)) {
+ --Depth;
+ }
+ if (CurrentToken->Next != nullptr) {
+ if (CurrentToken->is(tok::r_brace)) {
+ if (Depth == 2) {
+ if (CurrentToken->Next->is(tok::comma)) {
+ auto *NextLBrace = CurrentToken->Next->Next;
+ const auto *StopValue = CurrentToken->Next->getNextNonComment();
+ while (NextLBrace != nullptr && NextLBrace != StopValue)
+ NextLBrace = NextLBrace->Next;
+ if (NextLBrace != nullptr)
+ NextLBrace->MustBreakBefore = true;
+ }
+ CurrentToken->IsRowClosing = true;
+ return calculateInitializerColumnList(Line, std::move(NextRow),
+ CurrentToken->Next, Depth);
+ // NOLINTNEXTLINE(llvm-else-after-return)
+ } else if (Depth == 1) {
+ // We are dropping out of the loop. So in this case take all of the
+ // entries in the last row and point the tails at the heads so we can
+ // loop around the columns ending where we began
+ while (!ColumnEntries.empty()) {
+ auto *LastToken = ColumnEntries.front();
+ if (LastToken->PreviousColumn != nullptr) {
+ auto *StartToken = LastToken->PreviousColumn;
+ while (StartToken->PreviousColumn != nullptr) {
+ StartToken = StartToken->PreviousColumn;
+ }
+ StartToken->PreviousColumn = LastToken;
+ }
+ ColumnEntries.pop_front();
+ }
+ CurrentToken->MustBreakBefore = true;
+ }
+ } else if (Depth == 3 &&
+ CurrentToken->isOneOf(tok::comma, tok::l_brace)) {
+ CurrentToken->Next->ColumnIndex = NextRow.size();
+ NextRow.push_back(CurrentToken->Next);
+ if (!ColumnEntries.empty()) {
+ CurrentToken->Next->PreviousColumn = ColumnEntries.front();
+ ColumnEntries.pop_front();
+ }
+ }
+ }
+ CurrentToken = CurrentToken->Next;
+ }
+ return CurrentToken;
+}
+
unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
const FormatToken &Tok,
bool InFunctionDecl) {
Index: clang/lib/Format/FormatToken.h
===================================================================
--- clang/lib/Format/FormatToken.h
+++ clang/lib/Format/FormatToken.h
@@ -431,6 +431,20 @@
/// The next token in the unwrapped line.
FormatToken *Next = nullptr;
+ /// The previous vertical column element
+ FormatToken *PreviousColumn = nullptr;
+
+ /// Indicates that this is the closing bracket for a row
+ bool IsRowClosing = false;
+
+ /// We we split a token into multiples in the array initializer
+ /// case we need to track the size of the split for other columns
+ unsigned SplitMax = 0U;
+
+ /// For a token in a array initializer we need to track where in the
+ /// row it is so we can set offsets appropriately
+ unsigned ColumnIndex = 0U;
+
/// If this token starts a block, this contains all the unwrapped lines
/// in it.
SmallVector<AnnotatedLine *, 1> Children;
@@ -695,6 +709,17 @@
void copyFrom(const FormatToken &Tok) { *this = Tok; }
+ /// Returns the maximum width of all the columns above and below
+ /// this one
+ unsigned getMaximumColumnWidth(unsigned Limit = 0) const noexcept;
+
+ /// Returns the column width of multiple tokens in a array initializer
+ unsigned getThisColumnWidth(unsigned Limit = 0) const noexcept;
+
+ /// Returns a boolean indicated that a previous column element
+ /// was split
+ bool hasPreviousSplitMax() const noexcept;
+
private:
// Only allow copying via the explicit copyFrom method.
FormatToken(const FormatToken &) = delete;
Index: clang/lib/Format/FormatToken.cpp
===================================================================
--- clang/lib/Format/FormatToken.cpp
+++ clang/lib/Format/FormatToken.cpp
@@ -16,6 +16,7 @@
#include "ContinuationIndenter.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Debug.h"
+#include <algorithm>
#include <climits>
namespace clang {
@@ -69,6 +70,49 @@
}
}
+unsigned FormatToken::getMaximumColumnWidth(unsigned Limit) const noexcept {
+ unsigned MaxWidth = getThisColumnWidth();
+ auto *PColumn = PreviousColumn;
+ while (PColumn != nullptr && PColumn != this) {
+ MaxWidth = std::max(MaxWidth, PColumn->getThisColumnWidth(Limit));
+ PColumn = PColumn->PreviousColumn;
+ }
+ return MaxWidth;
+}
+
+unsigned FormatToken::getThisColumnWidth(unsigned Limit) const noexcept {
+ auto ColWidth =
+ (SplitMax > 0 && SplitMax < ColumnWidth) ? SplitMax : ColumnWidth;
+ const auto *NextColEntry = Next;
+ while (NextColEntry != nullptr &&
+ !NextColEntry->isOneOf(tok::r_brace, tok::comma)) {
+ if (NextColEntry->SplitMax > 0 &&
+ NextColEntry->SplitMax < NextColEntry->ColumnWidth) {
+ ColWidth += NextColEntry->SplitMax;
+ } else if (Limit > 0 && ColWidth + NextColEntry->ColumnWidth >= Limit) {
+ ColWidth = NextColEntry->ColumnWidth;
+ } else {
+ ColWidth += NextColEntry->ColumnWidth;
+ }
+ NextColEntry = NextColEntry->Next;
+ }
+ return ColWidth;
+}
+
+bool FormatToken::hasPreviousSplitMax() const noexcept {
+ if (SplitMax > 0)
+ return true;
+ // We can't recurse here because there is no stopping
+ // condition in the case in which there is no SplitMaximum
+ const auto *PColumn = PreviousColumn;
+ while (PColumn != nullptr && PColumn != this) {
+ if (PColumn->SplitMax > 0)
+ return true;
+ PColumn = PColumn->PreviousColumn;
+ }
+ return false;
+}
+
TokenRole::~TokenRole() {}
void TokenRole::precomputeFormattingInfos(const FormatToken *Token) {}
Index: clang/lib/Format/Format.cpp
===================================================================
--- clang/lib/Format/Format.cpp
+++ clang/lib/Format/Format.cpp
@@ -506,6 +506,7 @@
IO.mapOptional("AccessModifierOffset", Style.AccessModifierOffset);
IO.mapOptional("AlignAfterOpenBracket", Style.AlignAfterOpenBracket);
+ IO.mapOptional("AlignArrayOfStructures", Style.AlignArrayOfStructures);
IO.mapOptional("AlignConsecutiveMacros", Style.AlignConsecutiveMacros);
IO.mapOptional("AlignConsecutiveAssignments",
Style.AlignConsecutiveAssignments);
@@ -941,6 +942,7 @@
LLVMStyle.AccessModifierOffset = -2;
LLVMStyle.AlignEscapedNewlines = FormatStyle::ENAS_Right;
LLVMStyle.AlignAfterOpenBracket = FormatStyle::BAS_Align;
+ LLVMStyle.AlignArrayOfStructures = false;
LLVMStyle.AlignOperands = FormatStyle::OAS_Align;
LLVMStyle.AlignTrailingComments = true;
LLVMStyle.AlignConsecutiveAssignments = FormatStyle::ACS_None;
Index: clang/lib/Format/ContinuationIndenter.h
===================================================================
--- clang/lib/Format/ContinuationIndenter.h
+++ clang/lib/Format/ContinuationIndenter.h
@@ -188,6 +188,9 @@
/// by clang-format and string literals with escaped newlines.
bool nextIsMultilineString(const LineState &State);
+ /// make sure row positions is properly initialized and return the max width
+ unsigned setRowPositions(const FormatToken &Current, LineState &State);
+
FormatStyle Style;
const AdditionalKeywords &Keywords;
const SourceManager &SourceMgr;
@@ -453,6 +456,13 @@
/// Does not need to be considered for memoization because it doesn't change.
const AnnotatedLine *Line;
+ /// The column position of the end of each of the row elements
+ /// for array initializers
+ std::vector<std::pair<unsigned, unsigned>> RowPositions;
+
+ /// Keep track of the current column index in array initializers
+ unsigned CurrentColumnIndex = 0U;
+
/// Comparison operator to be able to used \c LineState in \c map.
bool operator<(const LineState &Other) const {
if (NextToken != Other.NextToken)
@@ -474,6 +484,8 @@
return false;
return Stack < Other.Stack;
}
+
+ unsigned getLBraceDepth() const;
};
} // end namespace format
Index: clang/lib/Format/ContinuationIndenter.cpp
===================================================================
--- clang/lib/Format/ContinuationIndenter.cpp
+++ clang/lib/Format/ContinuationIndenter.cpp
@@ -597,10 +597,37 @@
PPColumnCorrection = -1;
}
- if (!DryRun)
- Whitespaces.replaceWhitespace(Current, /*Newlines=*/0, Spaces,
- State.Column + Spaces + PPColumnCorrection);
-
+ if (!DryRun) {
+ if (Style.AlignArrayOfStructures &&
+ State.Line->Type == LT_ArrayOfStructInitializer) {
+ auto ColumnPos = State.Column;
+ if (Current.PreviousColumn != nullptr) {
+ auto MaxWidth = setRowPositions(Current, State);
+ Spaces = MaxWidth - Current.getThisColumnWidth();
+ Spaces += ((Current.ColumnIndex != 0) ? 1 : 0U);
+ if ((Current.hasPreviousSplitMax() ||
+ MaxWidth < Current.getMaximumColumnWidth()) &&
+ Current.ColumnIndex > 0) {
+ // We had a line get broken so net the previous
+ // column
+ auto LeftPosition =
+ State.RowPositions[Current.ColumnIndex - 1].first +
+ State.RowPositions[Current.ColumnIndex - 1].second - 1;
+ if (Spaces > LeftPosition)
+ Spaces -= LeftPosition;
+ else if (Spaces < LeftPosition)
+ Spaces = 1;
+ }
+ ColumnPos = State.RowPositions[Current.ColumnIndex].first;
+ } else if (Current.IsRowClosing) {
+ Spaces += 1;
+ }
+ Whitespaces.replaceWhitespace(Current, /*Newlines=*/0, Spaces, ColumnPos);
+ } else {
+ Whitespaces.replaceWhitespace(Current, /*Newlines=*/0, Spaces,
+ State.Column + Spaces + PPColumnCorrection);
+ }
+ }
// If "BreakBeforeInheritanceComma" mode, don't break within the inheritance
// declaration unless there is multiple inheritance.
if (Style.BreakInheritanceList == FormatStyle::BILS_BeforeComma &&
@@ -885,9 +912,45 @@
std::max(1u, std::min(Current.NewlinesBefore, MaxEmptyLinesToKeep));
bool ContinuePPDirective =
State.Line->InPPDirective && State.Line->Type != LT_ImportStatement;
- Whitespaces.replaceWhitespace(Current, Newlines, State.Column, State.Column,
- State.Stack.back().IsAligned,
- ContinuePPDirective);
+ bool AlignArrayOfStructures =
+ (Style.AlignArrayOfStructures &&
+ State.Line->Type == LT_ArrayOfStructInitializer);
+ if (AlignArrayOfStructures) {
+ unsigned Depth = State.getLBraceDepth();
+ if (Current.PreviousColumn != nullptr) {
+ auto MaxWidth = setRowPositions(Current, State);
+ auto ColumnPos = State.RowPositions[Current.ColumnIndex].first;
+ auto Spaces = MaxWidth - Current.getThisColumnWidth();
+ // FIXME really we shouldn't have this test here
+ if (Current.ColumnIndex == 0 &&
+ (ColumnPos + Current.getThisColumnWidth()) < Style.ColumnLimit) {
+ Newlines = 0;
+ State.RowPositions[Current.ColumnIndex] =
+ std::make_pair(State.Column + 1, MaxWidth);
+ } else if (Current.ColumnIndex > 0 && Newlines > 0) {
+ // We are linebreaking at a column so set the position to the first
+ State.RowPositions[Current.ColumnIndex] =
+ std::make_pair(State.RowPositions[0].first,
+ State.RowPositions[Current.ColumnIndex].second);
+ ColumnPos = State.RowPositions[Current.ColumnIndex].first;
+ Spaces += ColumnPos - 1;
+ }
+ Whitespaces.replaceWhitespace(Current, Newlines, Spaces, ColumnPos);
+ } else if (!Current.isOneOf(tok::r_brace, tok::comma, tok::l_brace) &&
+ State.RowPositions.size() > State.CurrentColumnIndex &&
+ Depth == 2) {
+ auto ColumnPos = State.RowPositions[State.CurrentColumnIndex].first;
+ Whitespaces.replaceWhitespace(Current, Newlines, ColumnPos - 1,
+ ColumnPos);
+ } else {
+ Whitespaces.replaceWhitespace(Current, Newlines, State.Column,
+ State.Column);
+ }
+ } else {
+ Whitespaces.replaceWhitespace(Current, Newlines, State.Column,
+ State.Column, State.Stack.back().IsAligned,
+ ContinuePPDirective);
+ }
}
if (!Current.isTrailingComment())
@@ -1951,6 +2014,12 @@
unsigned UnbreakableTailLength = (State.NextToken && canBreak(State))
? 0
: Current.UnbreakableTailLength;
+ if (Style.AlignArrayOfStructures &&
+ State.Line->Type == LT_ArrayOfStructInitializer) {
+ if (!State.RowPositions.empty()) {
+ StartColumn = State.RowPositions[0].first - 1;
+ }
+ }
return std::make_unique<BreakableStringLiteral>(
Current, StartColumn, Prefix, Postfix, UnbreakableTailLength,
State.Line->InPPDirective, Encoding, Style);
@@ -2188,10 +2257,24 @@
LLVM_DEBUG(llvm::dbgs() << " Breaking at: " << TailOffset + Split.first
<< ", " << Split.second << "\n");
- if (!DryRun)
+ if (!DryRun) {
+ if (Style.AlignArrayOfStructures &&
+ State.Line->Type == LT_ArrayOfStructInitializer) {
+ // So at this point we have a initializer. We need to make sure the
+ // related column tokens are updated as well as any changes already
+ // inflight linked to those tokens
+ auto *CurrentWritableToken = State.NextToken->Previous;
+ for (; CurrentWritableToken != &Current;
+ CurrentWritableToken = CurrentWritableToken->Previous) {
+ }
+ assert(CurrentWritableToken != nullptr);
+ CurrentWritableToken->SplitMax =
+ CurrentWritableToken->TokenText.substr(TailOffset + Split.first)
+ .size();
+ }
Token->insertBreak(LineIndex, TailOffset, Split, ContentIndent,
Whitespaces);
-
+ }
Penalty += NewBreakPenalty;
TailOffset += Split.first + Split.second;
RemainingTokenColumns = NewRemainingTokenColumns;
@@ -2384,5 +2467,27 @@
return false;
}
+unsigned ContinuationIndenter::setRowPositions(const FormatToken &Current,
+ LineState &State) {
+ auto MaxWidth = Current.getMaximumColumnWidth(Style.ColumnLimit);
+ State.CurrentColumnIndex = Current.ColumnIndex;
+ if (State.RowPositions.size() <= Current.ColumnIndex)
+ State.RowPositions.push_back(std::make_pair(State.Column, MaxWidth));
+ else if (State.RowPositions[Current.ColumnIndex].second != MaxWidth) {
+ State.RowPositions[Current.ColumnIndex] =
+ std::make_pair(State.Column, MaxWidth);
+ }
+ return MaxWidth;
+}
+
+unsigned LineState::getLBraceDepth() const {
+ unsigned Depth = 0U;
+ for (const auto &PState : Stack) {
+ if (PState.Tok != nullptr)
+ Depth += (PState.Tok->is(tok::l_brace)) ? 1 : 0;
+ }
+ return Depth;
+}
+
} // namespace format
} // namespace clang
Index: clang/include/clang/Format/Format.h
===================================================================
--- clang/include/clang/Format/Format.h
+++ clang/include/clang/Format/Format.h
@@ -90,6 +90,18 @@
/// brackets.
BracketAlignmentStyle AlignAfterOpenBracket;
+ /// if ``true``, when using initialization for an array of structs
+ /// aligns the fields into columns
+ /// \code
+ /// struct test demo[] =
+ /// {
+ /// {56, 23, "hello" },
+ /// {-1, 93463, "world" },
+ /// {7, 5, "!!" }
+ /// }
+ /// \endcode
+ bool AlignArrayOfStructures;
+
/// Styles for alignment of consecutive tokens. Tokens can be assignment signs
/// (see
/// ``AlignConsecutiveAssignments``), bitfield member separators (see
@@ -3249,6 +3261,7 @@
bool operator==(const FormatStyle &R) const {
return AccessModifierOffset == R.AccessModifierOffset &&
AlignAfterOpenBracket == R.AlignAfterOpenBracket &&
+ AlignArrayOfStructures == R.AlignArrayOfStructures &&
AlignConsecutiveAssignments == R.AlignConsecutiveAssignments &&
AlignConsecutiveBitFields == R.AlignConsecutiveBitFields &&
AlignConsecutiveDeclarations == R.AlignConsecutiveDeclarations &&
Index: clang/docs/ReleaseNotes.rst
===================================================================
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -251,6 +251,9 @@
- ``git-clang-format`` no longer formats changes to symbolic links. (Fixes
https://llvm.org/PR46992.)
+- Option ``AlignArrayOfStructure`` has been added to allow for ordering array-like
+ initializers.
+
libclang
--------
Index: clang/docs/ClangFormatStyleOptions.rst
===================================================================
--- clang/docs/ClangFormatStyleOptions.rst
+++ clang/docs/ClangFormatStyleOptions.rst
@@ -203,6 +203,17 @@
argument1, argument2);
+**AlignArrayOfStructures** (``bool``)
+ If ``true``, when using initialization for an array
+ of structs aligns the fields into right justified columns
+
+ .. code-block:: c
+ struct test demo[] =
+ {
+ {56, 23, "hello" },
+ {-1, 93463, "world" },
+ { 7, 5, "!!" }
+ }
**AlignConsecutiveAssignments** (``AlignConsecutiveStyle``)
Style of aligning consecutive assignments.
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits