bbb >>= 2;
-.. _AlignConsecutiveShortCaseStatements:
-
-**AlignConsecutiveShortCaseStatements** (``ShortCaseStatementsAlignmentStyle``) :versionbadge:`clang-format 17` :ref:`¶ <AlignConsecutiveShortCaseStatements>`
- Style of aligning consecutive short case labels.
- Only applies if ``AllowShortCaseLabelsOnASingleLine`` is ``true``.
-
-
- .. code-block:: yaml
-
- # Example of usage:
- AlignConsecutiveShortCaseStatements:
- Enabled: true
- AcrossEmptyLines: true
- AcrossComments: true
- AlignCaseColons: false
-
- Nested configuration flags:
-
- Alignment options.
-
- * ``bool Enabled`` Whether aligning is enabled.
-
- .. code-block:: c++
-
- true:
- switch (level) {
- case log::info: return "info:";
- case log::warning: return "warning:";
- default: return "";
- }
-
- false:
- switch (level) {
- case log::info: return "info:";
- case log::warning: return "warning:";
- default: return "";
- }
-
- * ``bool AcrossEmptyLines`` Whether to align across empty lines.
-
- .. code-block:: c++
-
- true:
- switch (level) {
- case log::info: return "info:";
- case log::warning: return "warning:";
-
- default: return "";
- }
-
- false:
- switch (level) {
- case log::info: return "info:";
- case log::warning: return "warning:";
-
- default: return "";
- }
-
- * ``bool AcrossComments`` Whether to align across comments.
-
- .. code-block:: c++
-
- true:
- switch (level) {
- case log::info: return "info:";
- case log::warning: return "warning:";
- /* A comment. */
- default: return "";
- }
-
- false:
- switch (level) {
- case log::info: return "info:";
- case log::warning: return "warning:";
- /* A comment. */
- default: return "";
- }
-
- * ``bool AlignCaseColons`` Whether aligned case labels are aligned on the colon, or on the
- , or on the tokens after the colon.
-
- .. code-block:: c++
-
- true:
- switch (level) {
- case log::info : return "info:";
- case log::warning: return "warning:";
- default : return "";
- }
-
- false:
- switch (level) {
- case log::info: return "info:";
- case log::warning: return "warning:";
- default: return "";
- }
-
-
.. _AlignEscapedNewlines:
**AlignEscapedNewlines** (``EscapedNewlineAlignmentStyle``) :versionbadge:`clang-format 5` :ref:`¶ <AlignEscapedNewlines>`
- Add ``KeepEmptyLinesAtEOF`` to keep empty lines at end of file.
- Add ``RemoveParentheses`` to remove redundant parentheses.
- Add ``TypeNames`` to treat listed non-keyword identifiers as type names.
-- Add ``AlignConsecutiveShortCaseStatements`` which can be used to align case
- labels in conjunction with ``AllowShortCaseLabelsOnASingleLine``.
libclang
--------
/// \version 3.8
AlignConsecutiveStyle AlignConsecutiveDeclarations;
- /// Alignment options.
- ///
- struct ShortCaseStatementsAlignmentStyle {
- /// Whether aligning is enabled.
- /// \code
- /// true:
- /// switch (level) {
- /// case log::info: return "info:";
- /// case log::warning: return "warning:";
- /// default: return "";
- /// }
- ///
- /// false:
- /// switch (level) {
- /// case log::info: return "info:";
- /// case log::warning: return "warning:";
- /// default: return "";
- /// }
- /// \endcode
- bool Enabled;
- /// Whether to align across empty lines.
- /// \code
- /// true:
- /// switch (level) {
- /// case log::info: return "info:";
- /// case log::warning: return "warning:";
- ///
- /// default: return "";
- /// }
- ///
- /// false:
- /// switch (level) {
- /// case log::info: return "info:";
- /// case log::warning: return "warning:";
- ///
- /// default: return "";
- /// }
- /// \endcode
- bool AcrossEmptyLines;
- /// Whether to align across comments.
- /// \code
- /// true:
- /// switch (level) {
- /// case log::info: return "info:";
- /// case log::warning: return "warning:";
- /// /* A comment. */
- /// default: return "";
- /// }
- ///
- /// false:
- /// switch (level) {
- /// case log::info: return "info:";
- /// case log::warning: return "warning:";
- /// /* A comment. */
- /// default: return "";
- /// }
- /// \endcode
- bool AcrossComments;
- /// Whether aligned case labels are aligned on the colon, or on the
- /// , or on the tokens after the colon.
- /// \code
- /// true:
- /// switch (level) {
- /// case log::info : return "info:";
- /// case log::warning: return "warning:";
- /// default : return "";
- /// }
- ///
- /// false:
- /// switch (level) {
- /// case log::info: return "info:";
- /// case log::warning: return "warning:";
- /// default: return "";
- /// }
- /// \endcode
- bool AlignCaseColons;
- bool operator==(const ShortCaseStatementsAlignmentStyle &R) const {
- return Enabled == R.Enabled && AcrossEmptyLines == R.AcrossEmptyLines &&
- AcrossComments == R.AcrossComments &&
- AlignCaseColons == R.AlignCaseColons;
- }
- };
-
- /// Style of aligning consecutive short case labels.
- /// Only applies if ``AllowShortCaseLabelsOnASingleLine`` is ``true``.
- ///
- /// \code{.yaml}
- /// # Example of usage:
- /// AlignConsecutiveShortCaseStatements:
- /// Enabled: true
- /// AcrossEmptyLines: true
- /// AcrossComments: true
- /// AlignCaseColons: false
- /// \endcode
- /// \version 17
- ShortCaseStatementsAlignmentStyle AlignConsecutiveShortCaseStatements;
-
/// Different styles for aligning escaped newlines.
enum EscapedNewlineAlignmentStyle : int8_t {
/// Don't align escaped newlines.
AlignConsecutiveBitFields == R.AlignConsecutiveBitFields &&
AlignConsecutiveDeclarations == R.AlignConsecutiveDeclarations &&
AlignConsecutiveMacros == R.AlignConsecutiveMacros &&
- AlignConsecutiveShortCaseStatements ==
- R.AlignConsecutiveShortCaseStatements &&
AlignEscapedNewlines == R.AlignEscapedNewlines &&
AlignOperands == R.AlignOperands &&
AlignTrailingComments == R.AlignTrailingComments &&
}
};
-template <>
-struct MappingTraits<FormatStyle::ShortCaseStatementsAlignmentStyle> {
- static void mapping(IO &IO,
- FormatStyle::ShortCaseStatementsAlignmentStyle &Value) {
- IO.mapOptional("Enabled", Value.Enabled);
- IO.mapOptional("AcrossEmptyLines", Value.AcrossEmptyLines);
- IO.mapOptional("AcrossComments", Value.AcrossComments);
- IO.mapOptional("AlignCaseColons", Value.AlignCaseColons);
- }
-};
-
template <>
struct ScalarEnumerationTraits<FormatStyle::AttributeBreakingStyle> {
static void enumeration(IO &IO, FormatStyle::AttributeBreakingStyle &Value) {
IO.mapOptional("AlignConsecutiveDeclarations",
Style.AlignConsecutiveDeclarations);
IO.mapOptional("AlignConsecutiveMacros", Style.AlignConsecutiveMacros);
- IO.mapOptional("AlignConsecutiveShortCaseStatements",
- Style.AlignConsecutiveShortCaseStatements);
IO.mapOptional("AlignEscapedNewlines", Style.AlignEscapedNewlines);
IO.mapOptional("AlignOperands", Style.AlignOperands);
IO.mapOptional("AlignTrailingComments", Style.AlignTrailingComments);
LLVMStyle.AlignConsecutiveBitFields = {};
LLVMStyle.AlignConsecutiveDeclarations = {};
LLVMStyle.AlignConsecutiveMacros = {};
- LLVMStyle.AlignConsecutiveShortCaseStatements = {};
LLVMStyle.AlignTrailingComments = {};
LLVMStyle.AlignTrailingComments.Kind = FormatStyle::TCAS_Always;
LLVMStyle.AlignTrailingComments.OverEmptyLines = 0;
llvm::sort(Changes, Change::IsBeforeInFile(SourceMgr));
calculateLineBreakInformation();
alignConsecutiveMacros();
- alignConsecutiveShortCaseStatements();
alignConsecutiveDeclarations();
alignConsecutiveBitFields();
alignConsecutiveAssignments();
//
// 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 AlignMatchingTokenSequence(
+static void AlignMacroSequence(
unsigned &StartOfSequence, unsigned &EndOfSequence, unsigned &MinColumn,
- std::function<bool(const WhitespaceManager::Change &C)> Matches,
+ unsigned &MaxColumn, bool &FoundMatchOnLine,
+ std::function<bool(const WhitespaceManager::Change &C)> AlignMacrosMatches,
SmallVector<WhitespaceManager::Change, 16> &Changes) {
if (StartOfSequence > 0 && StartOfSequence < EndOfSequence) {
- bool FoundMatchOnLine = false;
+
+ FoundMatchOnLine = false;
int Shift = 0;
for (unsigned I = StartOfSequence; I != EndOfSequence; ++I) {
// 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 && Matches(Changes[I])) {
+ // shifted by the same amount
+ if (!FoundMatchOnLine && AlignMacrosMatches(Changes[I])) {
FoundMatchOnLine = true;
Shift = MinColumn - Changes[I].StartOfTokenColumn;
Changes[I].Spaces += Shift;
}
MinColumn = 0;
+ MaxColumn = UINT_MAX;
StartOfSequence = 0;
EndOfSequence = 0;
}
};
unsigned MinColumn = 0;
+ unsigned MaxColumn = UINT_MAX;
// Start and end of the token sequence we're processing.
unsigned StartOfSequence = 0;
!(LineIsComment && Style.AlignConsecutiveMacros.AcrossComments);
if (EmptyLineBreak || NoMatchBreak) {
- AlignMatchingTokenSequence(StartOfSequence, EndOfSequence, MinColumn,
- AlignMacrosMatches, Changes);
+ AlignMacroSequence(StartOfSequence, EndOfSequence, MinColumn, MaxColumn,
+ FoundMatchOnLine, AlignMacrosMatches, Changes);
}
// A new line starts, re-initialize line status tracking bools.
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;
- AlignMatchingTokenSequence(StartOfSequence, EndOfSequence, MinColumn,
- AlignMacrosMatches, Changes);
+ AlignMacroSequence(StartOfSequence, EndOfSequence, MinColumn, MaxColumn,
+ FoundMatchOnLine, AlignMacrosMatches, Changes);
}
void WhitespaceManager::alignConsecutiveAssignments() {
Changes, /*StartAt=*/0, Style.AlignConsecutiveBitFields);
}
-void WhitespaceManager::alignConsecutiveShortCaseStatements() {
- if (!Style.AlignConsecutiveShortCaseStatements.Enabled ||
- !Style.AllowShortCaseLabelsOnASingleLine) {
- return;
- }
-
- auto Matches = [&](const Change &C) {
- if (Style.AlignConsecutiveShortCaseStatements.AlignCaseColons)
- return C.Tok->is(TT_CaseLabelColon);
-
- // Ignore 'IsInsideToken' to allow matching trailing comments which
- // need to be reflowed as that causes the token to appear in two
- // different changes, which will cause incorrect alignment as we'll
- // reflow early due to detecting multiple aligning tokens per line.
- return !C.IsInsideToken && C.Tok->Previous &&
- C.Tok->Previous->is(TT_CaseLabelColon);
- };
-
- unsigned MinColumn = 0;
-
- // Empty case statements don't break the alignment, but don't necessarily
- // match our predicate, so we need to track their column so they can push out
- // our alignment.
- unsigned MinEmptyCaseColumn = 0;
-
- // 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;
-
- bool LineIsComment = true;
- bool LineIsEmptyCase = false;
-
- unsigned I = 0;
- for (unsigned E = Changes.size(); I != E; ++I) {
- if (Changes[I].NewlinesBefore != 0) {
- // Whether to break the alignment sequence because of an empty line.
- bool EmptyLineBreak =
- (Changes[I].NewlinesBefore > 1) &&
- !Style.AlignConsecutiveShortCaseStatements.AcrossEmptyLines;
-
- // Whether to break the alignment sequence because of a line without a
- // match.
- bool NoMatchBreak =
- !FoundMatchOnLine &&
- !(LineIsComment &&
- Style.AlignConsecutiveShortCaseStatements.AcrossComments) &&
- !LineIsEmptyCase;
-
- if (EmptyLineBreak || NoMatchBreak) {
- AlignMatchingTokenSequence(StartOfSequence, EndOfSequence, MinColumn,
- Matches, Changes);
- MinEmptyCaseColumn = 0;
- }
-
- // A new line starts, re-initialize line status tracking bools.
- FoundMatchOnLine = false;
- LineIsComment = true;
- LineIsEmptyCase = false;
- }
-
- if (Changes[I].Tok->isNot(tok::comment))
- LineIsComment = false;
-
- if (Changes[I].Tok->is(TT_CaseLabelColon)) {
- LineIsEmptyCase =
- !Changes[I].Tok->Next || Changes[I].Tok->Next->isTrailingComment();
-
- if (LineIsEmptyCase) {
- if (Style.AlignConsecutiveShortCaseStatements.AlignCaseColons) {
- MinEmptyCaseColumn =
- std::max(MinEmptyCaseColumn, Changes[I].StartOfTokenColumn);
- } else {
- MinEmptyCaseColumn =
- std::max(MinEmptyCaseColumn, Changes[I].StartOfTokenColumn + 2);
- }
- }
- }
-
- if (!Matches(Changes[I]))
- continue;
-
- if (LineIsEmptyCase)
- continue;
-
- FoundMatchOnLine = true;
-
- if (StartOfSequence == 0)
- StartOfSequence = I;
-
- EndOfSequence = I + 1;
-
- MinColumn = std::max(MinColumn, Changes[I].StartOfTokenColumn);
-
- // Allow empty case statements to push out our alignment.
- MinColumn = std::max(MinColumn, MinEmptyCaseColumn);
- }
-
- AlignMatchingTokenSequence(StartOfSequence, EndOfSequence, MinColumn, Matches,
- Changes);
-}
-
void WhitespaceManager::alignConsecutiveDeclarations() {
if (!Style.AlignConsecutiveDeclarations.Enabled)
return;
/// Align consecutive declarations over all \c Changes.
void alignChainedConditionals();
- /// Align consecutive short case statements over all \c Changes.
- void alignConsecutiveShortCaseStatements();
-
/// Align trailing comments over all \c Changes.
void alignTrailingComments();
CHECK_PARSE_BOOL(SpaceBeforeSquareBrackets);
CHECK_PARSE_BOOL(VerilogBreakBetweenInstancePorts);
- CHECK_PARSE_NESTED_BOOL(AlignConsecutiveShortCaseStatements, Enabled);
- CHECK_PARSE_NESTED_BOOL(AlignConsecutiveShortCaseStatements,
- AcrossEmptyLines);
- CHECK_PARSE_NESTED_BOOL(AlignConsecutiveShortCaseStatements, AcrossComments);
- CHECK_PARSE_NESTED_BOOL(AlignConsecutiveShortCaseStatements, AlignCaseColons);
CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterCaseLabel);
CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterClass);
CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterEnum);
BracedAlign);
}
-TEST_F(FormatTest, AlignConsecutiveShortCaseStatements) {
- FormatStyle Alignment = getLLVMStyle();
- Alignment.AllowShortCaseLabelsOnASingleLine = true;
- Alignment.AlignConsecutiveShortCaseStatements.Enabled = true;
-
- verifyFormat("switch (level) {\n"
- "case log::info: return \"info\";\n"
- "case log::warning: return \"warning\";\n"
- "default: return \"default\";\n"
- "}",
- Alignment);
-
- verifyFormat("switch (level) {\n"
- "case log::info: return \"info\";\n"
- "case log::warning: return \"warning\";\n"
- "}",
- "switch (level) {\n"
- "case log::info: return \"info\";\n"
- "case log::warning:\n"
- " return \"warning\";\n"
- "}",
- Alignment);
-
- // Empty case statements push out the alignment, but non-short case labels
- // don't.
- verifyFormat("switch (level) {\n"
- "case log::info: return \"info\";\n"
- "case log::critical:\n"
- "case log::warning:\n"
- "case log::severe: return \"severe\";\n"
- "case log::extra_severe:\n"
- " // comment\n"
- " return \"extra_severe\";\n"
- "}",
- Alignment);
-
- // Verify comments and empty lines break the alignment.
- verifyNoChange("switch (level) {\n"
- "case log::info: return \"info\";\n"
- "case log::warning: return \"warning\";\n"
- "// comment\n"
- "case log::critical: return \"critical\";\n"
- "default: return \"default\";\n"
- "\n"
- "case log::severe: return \"severe\";\n"
- "}",
- Alignment);
-
- // Empty case statements don't break the alignment, and potentially push it
- // out.
- verifyFormat("switch (level) {\n"
- "case log::info: return \"info\";\n"
- "case log::warning:\n"
- "case log::critical:\n"
- "default: return \"default\";\n"
- "}",
- Alignment);
-
- // Implicit fallthrough cases can be aligned with either a comment or
- // [[fallthrough]]
- verifyFormat("switch (level) {\n"
- "case log::info: return \"info\";\n"
- "case log::warning: // fallthrough\n"
- "case log::error: return \"error\";\n"
- "case log::critical: /*fallthrough*/\n"
- "case log::severe: return \"severe\";\n"
- "case log::diag: [[fallthrough]];\n"
- "default: return \"default\";\n"
- "}",
- Alignment);
-
- // Verify trailing comment that needs a reflow also gets aligned properly.
- verifyFormat("switch (level) {\n"
- "case log::info: return \"info\";\n"
- "case log::warning: // fallthrough\n"
- "case log::error: return \"error\";\n"
- "}",
- "switch (level) {\n"
- "case log::info: return \"info\";\n"
- "case log::warning: //fallthrough\n"
- "case log::error: return \"error\";\n"
- "}",
- Alignment);
-
- // Verify adjacent non-short case statements don't change the alignment, and
- // properly break the set of consecutive statements.
- verifyFormat("switch (level) {\n"
- "case log::critical:\n"
- " // comment\n"
- " return \"critical\";\n"
- "case log::info: return \"info\";\n"
- "case log::warning: return \"warning\";\n"
- "default:\n"
- " // comment\n"
- " return \"\";\n"
- "case log::error: return \"error\";\n"
- "case log::severe: return \"severe\";\n"
- "case log::extra_critical:\n"
- " // comment\n"
- " return \"extra critical\";\n"
- "}",
- Alignment);
-
- Alignment.SpaceBeforeCaseColon = true;
- verifyFormat("switch (level) {\n"
- "case log::info : return \"info\";\n"
- "case log::warning : return \"warning\";\n"
- "default : return \"default\";\n"
- "}",
- Alignment);
- Alignment.SpaceBeforeCaseColon = false;
-
- // Make sure we don't incorrectly align correctly across nested switch cases.
- verifyFormat("switch (level) {\n"
- "case log::info: return \"info\";\n"
- "case log::warning: return \"warning\";\n"
- "case log::other:\n"
- " switch (sublevel) {\n"
- " case log::info: return \"info\";\n"
- " case log::warning: return \"warning\";\n"
- " }\n"
- " break;\n"
- "case log::error: return \"error\";\n"
- "default: return \"default\";\n"
- "}",
- "switch (level) {\n"
- "case log::info: return \"info\";\n"
- "case log::warning: return \"warning\";\n"
- "case log::other: switch (sublevel) {\n"
- " case log::info: return \"info\";\n"
- " case log::warning: return \"warning\";\n"
- "}\n"
- "break;\n"
- "case log::error: return \"error\";\n"
- "default: return \"default\";\n"
- "}",
- Alignment);
-
- Alignment.AlignConsecutiveShortCaseStatements.AcrossEmptyLines = true;
-
- verifyFormat("switch (level) {\n"
- "case log::info: return \"info\";\n"
- "\n"
- "case log::warning: return \"warning\";\n"
- "}",
- "switch (level) {\n"
- "case log::info: return \"info\";\n"
- "\n"
- "case log::warning: return \"warning\";\n"
- "}",
- Alignment);
-
- Alignment.AlignConsecutiveShortCaseStatements.AcrossComments = true;
-
- verifyNoChange("switch (level) {\n"
- "case log::info: return \"info\";\n"
- "\n"
- "/* block comment */\n"
- "\n"
- "// line comment\n"
- "case log::warning: return \"warning\";\n"
- "}",
- Alignment);
-
- Alignment.AlignConsecutiveShortCaseStatements.AcrossEmptyLines = false;
-
- verifyFormat("switch (level) {\n"
- "case log::info: return \"info\";\n"
- "//\n"
- "case log::warning: return \"warning\";\n"
- "}",
- Alignment);
-
- Alignment.AlignConsecutiveShortCaseStatements.AlignCaseColons = true;
-
- verifyFormat("switch (level) {\n"
- "case log::info : return \"info\";\n"
- "case log::warning: return \"warning\";\n"
- "default : return \"default\";\n"
- "}",
- Alignment);
-
- // With AlignCaseColons, empty case statements don't break alignment of
- // consecutive case statements (and are aligned).
- verifyFormat("switch (level) {\n"
- "case log::info : return \"info\";\n"
- "case log::warning :\n"
- "case log::critical:\n"
- "default : return \"default\";\n"
- "}",
- Alignment);
-
- // Final non-short case labels shouldn't have their colon aligned
- verifyFormat("switch (level) {\n"
- "case log::info : return \"info\";\n"
- "case log::warning :\n"
- "case log::critical:\n"
- "case log::severe : return \"severe\";\n"
- "default:\n"
- " // comment\n"
- " return \"default\";\n"
- "}",
- Alignment);
-
- // Verify adjacent non-short case statements break the set of consecutive
- // alignments and aren't aligned with adjacent non-short case statements if
- // AlignCaseColons is set.
- verifyFormat("switch (level) {\n"
- "case log::critical:\n"
- " // comment\n"
- " return \"critical\";\n"
- "case log::info : return \"info\";\n"
- "case log::warning: return \"warning\";\n"
- "default:\n"
- " // comment\n"
- " return \"\";\n"
- "case log::error : return \"error\";\n"
- "case log::severe: return \"severe\";\n"
- "case log::extra_critical:\n"
- " // comment\n"
- " return \"extra critical\";\n"
- "}",
- Alignment);
-
- Alignment.SpaceBeforeCaseColon = true;
- verifyFormat("switch (level) {\n"
- "case log::info : return \"info\";\n"
- "case log::warning : return \"warning\";\n"
- "case log::error :\n"
- "default : return \"default\";\n"
- "}",
- Alignment);
-}
-
TEST_F(FormatTest, AlignWithLineBreaks) {
auto Style = getLLVMStyleWithColumns(120);