Skip to content

Commit

Permalink
[clang-format] use spaces for alignment with UT_ForContinuationAndInd…
Browse files Browse the repository at this point in the history
…entation

Summary:
Use spaces instead of tabs for alignment with UT_ForContinuationAndIndentation to make the code aligned for any tab/indent width.

Fixes https://bugs.llvm.org/show_bug.cgi?id=38381

Reviewed By: MyDeveloperDay

Patch By: fickert

Tags: #clang-format

Differential Revision: https://reviews.llvm.org/D75034
  • Loading branch information
mydeveloperday committed Apr 13, 2020
1 parent 3b37924 commit e811150
Show file tree
Hide file tree
Showing 10 changed files with 363 additions and 51 deletions.
6 changes: 5 additions & 1 deletion clang/docs/ClangFormatStyleOptions.rst
Expand Up @@ -2534,7 +2534,11 @@ the configuration (without a prefix: ``Auto``).
Use tabs only for indentation.

* ``UT_ForContinuationAndIndentation`` (in configuration: ``ForContinuationAndIndentation``)
Use tabs only for line continuation and indentation.
Fill all leading whitespace with tabs, and use spaces for alignment that
appears within a line (e.g. consecutive assignments and declarations).

* ``UT_AlignWithSpaces`` (in configuration: ``AlignWithSpaces``)
Use tabs for line continuation and indentation, and spaces for alignment.

* ``UT_Always`` (in configuration: ``Always``)
Use tabs whenever we need to fill whitespace that spans at least from
Expand Down
6 changes: 5 additions & 1 deletion clang/include/clang/Format/Format.h
Expand Up @@ -2129,8 +2129,12 @@ struct FormatStyle {
UT_Never,
/// Use tabs only for indentation.
UT_ForIndentation,
/// Use tabs only for line continuation and indentation.
/// Fill all leading whitespace with tabs, and use spaces for alignment that
/// appears within a line (e.g. consecutive assignments and declarations).
UT_ForContinuationAndIndentation,
/// Use tabs for line continuation and indentation, and spaces for
/// alignemnt.
UT_AlignWithSpaces,
/// Use tabs whenever we need to fill whitespace that spans at least from
/// one tab stop to the next one.
UT_Always
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/Format/BreakableToken.cpp
Expand Up @@ -863,7 +863,8 @@ void BreakableLineCommentSection::reflow(unsigned LineIndex,
// tokens by the empty string.
Whitespaces.replaceWhitespace(
*Tokens[LineIndex], /*Newlines=*/0, /*Spaces=*/0,
/*StartOfTokenColumn=*/StartColumn, /*InPPDirective=*/false);
/*StartOfTokenColumn=*/StartColumn, /*IsAligned=*/true,
/*InPPDirective=*/false);
} else if (LineIndex > 0) {
// In case we're reflowing after the '\' in:
//
Expand Down Expand Up @@ -931,6 +932,7 @@ void BreakableLineCommentSection::adaptStartOfLine(
/*Newlines=*/1,
/*Spaces=*/LineColumn,
/*StartOfTokenColumn=*/LineColumn,
/*IsAligned=*/true,
/*InPPDirective=*/false);
}
if (OriginalPrefix[LineIndex] != Prefix[LineIndex]) {
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/Format/ContinuationIndenter.cpp
Expand Up @@ -642,8 +642,10 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
if (Style.AlignAfterOpenBracket != FormatStyle::BAS_DontAlign &&
!State.Stack.back().IsCSharpGenericTypeConstraint &&
Previous.opensScope() && Previous.isNot(TT_ObjCMethodExpr) &&
(Current.isNot(TT_LineComment) || Previous.BlockKind == BK_BracedInit))
(Current.isNot(TT_LineComment) || Previous.BlockKind == BK_BracedInit)) {
State.Stack.back().Indent = State.Column + Spaces;
State.Stack.back().IsAligned = true;
}
if (State.Stack.back().AvoidBinPacking && startsNextParameter(Current, Style))
State.Stack.back().NoLineBreak = true;
if (startsSegmentOfBuilderTypeCall(Current) &&
Expand Down Expand Up @@ -858,6 +860,7 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
bool ContinuePPDirective =
State.Line->InPPDirective && State.Line->Type != LT_ImportStatement;
Whitespaces.replaceWhitespace(Current, Newlines, State.Column, State.Column,
State.Stack.back().IsAligned,
ContinuePPDirective);
}

Expand Down
21 changes: 13 additions & 8 deletions clang/lib/Format/ContinuationIndenter.h
Expand Up @@ -202,14 +202,14 @@ struct ParenState {
ParenState(const FormatToken *Tok, unsigned Indent, unsigned LastSpace,
bool AvoidBinPacking, bool NoLineBreak)
: Tok(Tok), Indent(Indent), LastSpace(LastSpace),
NestedBlockIndent(Indent), BreakBeforeClosingBrace(false),
AvoidBinPacking(AvoidBinPacking), BreakBeforeParameter(false),
NoLineBreak(NoLineBreak), NoLineBreakInOperand(false),
LastOperatorWrapped(true), ContainsLineBreak(false),
ContainsUnwrappedBuilder(false), AlignColons(true),
ObjCSelectorNameFound(false), HasMultipleNestedBlocks(false),
NestedBlockInlined(false), IsInsideObjCArrayLiteral(false),
IsCSharpGenericTypeConstraint(false) {}
NestedBlockIndent(Indent), IsAligned(false),
BreakBeforeClosingBrace(false), AvoidBinPacking(AvoidBinPacking),
BreakBeforeParameter(false), NoLineBreak(NoLineBreak),
NoLineBreakInOperand(false), LastOperatorWrapped(true),
ContainsLineBreak(false), ContainsUnwrappedBuilder(false),
AlignColons(true), ObjCSelectorNameFound(false),
HasMultipleNestedBlocks(false), NestedBlockInlined(false),
IsInsideObjCArrayLiteral(false), IsCSharpGenericTypeConstraint(false) {}

/// \brief The token opening this parenthesis level, or nullptr if this level
/// is opened by fake parenthesis.
Expand Down Expand Up @@ -265,6 +265,9 @@ struct ParenState {
/// Used to align further variables if necessary.
unsigned VariablePos = 0;

/// Whether this block's indentation is used for alignment.
bool IsAligned : 1;

/// Whether a newline needs to be inserted before the block's closing
/// brace.
///
Expand Down Expand Up @@ -341,6 +344,8 @@ struct ParenState {
return NestedBlockIndent < Other.NestedBlockIndent;
if (FirstLessLess != Other.FirstLessLess)
return FirstLessLess < Other.FirstLessLess;
if (IsAligned != Other.IsAligned)
return IsAligned;
if (BreakBeforeClosingBrace != Other.BreakBeforeClosingBrace)
return BreakBeforeClosingBrace;
if (QuestionColumn != Other.QuestionColumn)
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Format/Format.cpp
Expand Up @@ -93,6 +93,7 @@ template <> struct ScalarEnumerationTraits<FormatStyle::UseTabStyle> {
IO.enumCase(Value, "ForIndentation", FormatStyle::UT_ForIndentation);
IO.enumCase(Value, "ForContinuationAndIndentation",
FormatStyle::UT_ForContinuationAndIndentation);
IO.enumCase(Value, "AlignWithSpaces", FormatStyle::UT_AlignWithSpaces);
}
};

Expand Down
4 changes: 3 additions & 1 deletion clang/lib/Format/UnwrappedLineFormatter.cpp
Expand Up @@ -888,7 +888,8 @@ class LineFormatter {
if (!DryRun) {
Whitespaces->replaceWhitespace(
*Child->First, /*Newlines=*/0, /*Spaces=*/1,
/*StartOfTokenColumn=*/State.Column, State.Line->InPPDirective);
/*StartOfTokenColumn=*/State.Column, /*IsAligned=*/false,
State.Line->InPPDirective);
}
Penalty +=
formatLine(*Child, State.Column + 1, /*FirstStartColumn=*/0, DryRun);
Expand Down Expand Up @@ -1320,6 +1321,7 @@ void UnwrappedLineFormatter::formatFirstToken(
Indent = 0;

Whitespaces->replaceWhitespace(RootToken, Newlines, Indent, Indent,
/*IsAligned=*/false,
Line.InPPDirective &&
!RootToken.HasUnescapedNewline);
}
Expand Down
59 changes: 36 additions & 23 deletions clang/lib/Format/WhitespaceManager.cpp
Expand Up @@ -30,13 +30,13 @@ WhitespaceManager::Change::Change(const FormatToken &Tok,
int Spaces, unsigned StartOfTokenColumn,
unsigned NewlinesBefore,
StringRef PreviousLinePostfix,
StringRef CurrentLinePrefix,
StringRef CurrentLinePrefix, bool IsAligned,
bool ContinuesPPDirective, bool IsInsideToken)
: Tok(&Tok), CreateReplacement(CreateReplacement),
OriginalWhitespaceRange(OriginalWhitespaceRange),
StartOfTokenColumn(StartOfTokenColumn), NewlinesBefore(NewlinesBefore),
PreviousLinePostfix(PreviousLinePostfix),
CurrentLinePrefix(CurrentLinePrefix),
CurrentLinePrefix(CurrentLinePrefix), IsAligned(IsAligned),
ContinuesPPDirective(ContinuesPPDirective), Spaces(Spaces),
IsInsideToken(IsInsideToken), IsTrailingComment(false), TokenLength(0),
PreviousEndOfTokenColumn(0), EscapedNewlineColumn(0),
Expand All @@ -45,13 +45,13 @@ WhitespaceManager::Change::Change(const FormatToken &Tok,
void WhitespaceManager::replaceWhitespace(FormatToken &Tok, unsigned Newlines,
unsigned Spaces,
unsigned StartOfTokenColumn,
bool InPPDirective) {
bool IsAligned, bool InPPDirective) {
if (Tok.Finalized)
return;
Tok.Decision = (Newlines > 0) ? FD_Break : FD_Continue;
Changes.push_back(Change(Tok, /*CreateReplacement=*/true, Tok.WhitespaceRange,
Spaces, StartOfTokenColumn, Newlines, "", "",
InPPDirective && !Tok.IsFirst,
IsAligned, InPPDirective && !Tok.IsFirst,
/*IsInsideToken=*/false));
}

Expand All @@ -62,7 +62,7 @@ void WhitespaceManager::addUntouchableToken(const FormatToken &Tok,
Changes.push_back(Change(Tok, /*CreateReplacement=*/false,
Tok.WhitespaceRange, /*Spaces=*/0,
Tok.OriginalColumn, Tok.NewlinesBefore, "", "",
InPPDirective && !Tok.IsFirst,
/*IsAligned=*/false, InPPDirective && !Tok.IsFirst,
/*IsInsideToken=*/false));
}

Expand All @@ -82,7 +82,8 @@ void WhitespaceManager::replaceWhitespaceInToken(
Change(Tok, /*CreateReplacement=*/true,
SourceRange(Start, Start.getLocWithOffset(ReplaceChars)), Spaces,
std::max(0, Spaces), Newlines, PreviousPostfix, CurrentPrefix,
InPPDirective && !Tok.IsFirst, /*IsInsideToken=*/true));
/*IsAligned=*/true, InPPDirective && !Tok.IsFirst,
/*IsInsideToken=*/true));
}

const tooling::Replacements &WhitespaceManager::generateReplacements() {
Expand Down Expand Up @@ -761,9 +762,9 @@ void WhitespaceManager::generateChanges() {
C.EscapedNewlineColumn);
else
appendNewlineText(ReplacementText, C.NewlinesBefore);
appendIndentText(ReplacementText, C.Tok->IndentLevel,
std::max(0, C.Spaces),
C.StartOfTokenColumn - std::max(0, C.Spaces));
appendIndentText(
ReplacementText, C.Tok->IndentLevel, std::max(0, C.Spaces),
C.StartOfTokenColumn - std::max(0, C.Spaces), C.IsAligned);
ReplacementText.append(C.CurrentLinePrefix);
storeReplacement(C.OriginalWhitespaceRange, ReplacementText);
}
Expand Down Expand Up @@ -809,7 +810,8 @@ void WhitespaceManager::appendEscapedNewlineText(

void WhitespaceManager::appendIndentText(std::string &Text,
unsigned IndentLevel, unsigned Spaces,
unsigned WhitespaceStartColumn) {
unsigned WhitespaceStartColumn,
bool IsAligned) {
switch (Style.UseTab) {
case FormatStyle::UT_Never:
Text.append(Spaces, ' ');
Expand Down Expand Up @@ -838,28 +840,39 @@ void WhitespaceManager::appendIndentText(std::string &Text,
case FormatStyle::UT_ForIndentation:
if (WhitespaceStartColumn == 0) {
unsigned Indentation = IndentLevel * Style.IndentWidth;
// This happens, e.g. when a line in a block comment is indented less than
// the first one.
if (Indentation > Spaces)
Indentation = Spaces;
if (Style.TabWidth) {
unsigned Tabs = Indentation / Style.TabWidth;
Text.append(Tabs, '\t');
Spaces -= Tabs * Style.TabWidth;
}
Spaces = appendTabIndent(Text, Spaces, Indentation);
}
Text.append(Spaces, ' ');
break;
case FormatStyle::UT_ForContinuationAndIndentation:
if (WhitespaceStartColumn == 0 && Style.TabWidth) {
unsigned Tabs = Spaces / Style.TabWidth;
Text.append(Tabs, '\t');
Spaces -= Tabs * Style.TabWidth;
if (WhitespaceStartColumn == 0)
Spaces = appendTabIndent(Text, Spaces, Spaces);
Text.append(Spaces, ' ');
break;
case FormatStyle::UT_AlignWithSpaces:
if (WhitespaceStartColumn == 0) {
unsigned Indentation =
IsAligned ? IndentLevel * Style.IndentWidth : Spaces;
Spaces = appendTabIndent(Text, Spaces, Indentation);
}
Text.append(Spaces, ' ');
break;
}
}

unsigned WhitespaceManager::appendTabIndent(std::string &Text, unsigned Spaces,
unsigned Indentation) {
// This happens, e.g. when a line in a block comment is indented less than the
// first one.
if (Indentation > Spaces)
Indentation = Spaces;
if (Style.TabWidth) {
unsigned Tabs = Indentation / Style.TabWidth;
Text.append(Tabs, '\t');
Spaces -= Tabs * Style.TabWidth;
}
return Spaces;
}

} // namespace format
} // namespace clang
10 changes: 7 additions & 3 deletions clang/lib/Format/WhitespaceManager.h
Expand Up @@ -49,7 +49,7 @@ class WhitespaceManager {
/// this replacement. It is needed for determining how \p Spaces is turned
/// into tabs and spaces for some format styles.
void replaceWhitespace(FormatToken &Tok, unsigned Newlines, unsigned Spaces,
unsigned StartOfTokenColumn,
unsigned StartOfTokenColumn, bool isAligned = false,
bool InPPDirective = false);

/// Adds information about an unchangeable token's whitespace.
Expand Down Expand Up @@ -109,7 +109,7 @@ class WhitespaceManager {
SourceRange OriginalWhitespaceRange, int Spaces,
unsigned StartOfTokenColumn, unsigned NewlinesBefore,
StringRef PreviousLinePostfix, StringRef CurrentLinePrefix,
bool ContinuesPPDirective, bool IsInsideToken);
bool IsAligned, bool ContinuesPPDirective, bool IsInsideToken);

// The kind of the token whose whitespace this change replaces, or in which
// this change inserts whitespace.
Expand All @@ -125,6 +125,7 @@ class WhitespaceManager {
unsigned NewlinesBefore;
std::string PreviousLinePostfix;
std::string CurrentLinePrefix;
bool IsAligned;
bool ContinuesPPDirective;

// The number of spaces in front of the token or broken part of the token.
Expand Down Expand Up @@ -204,7 +205,10 @@ class WhitespaceManager {
unsigned PreviousEndOfTokenColumn,
unsigned EscapedNewlineColumn);
void appendIndentText(std::string &Text, unsigned IndentLevel,
unsigned Spaces, unsigned WhitespaceStartColumn);
unsigned Spaces, unsigned WhitespaceStartColumn,
bool IsAligned);
unsigned appendTabIndent(std::string &Text, unsigned Spaces,
unsigned Indentation);

SmallVector<Change, 16> Changes;
const SourceManager &SourceMgr;
Expand Down

0 comments on commit e811150

Please sign in to comment.