Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 84 additions & 35 deletions clang/lib/Format/ContinuationIndenter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,45 @@ RawStringFormatStyleManager::getEnclosingFunctionStyle(
return It->second;
}

IndentationAndAlignment
IndentationAndAlignment::addPadding(unsigned Spaces) const {
return IndentationAndAlignment(Total + Spaces, IndentedFrom);
}

IndentationAndAlignment
IndentationAndAlignment::operator+(unsigned Spaces) const {
return IndentationAndAlignment(Total + Spaces, Total);
}

IndentationAndAlignment
IndentationAndAlignment::operator-(unsigned Spaces) const {
return IndentationAndAlignment(Total - Spaces, Total);
}

IndentationAndAlignment &IndentationAndAlignment::operator+=(unsigned Spaces) {
*this = *this + Spaces;
return *this;
}

IndentationAndAlignment::IndentationAndAlignment(unsigned Total,
unsigned IndentedFrom)
: Total(Total), IndentedFrom(IndentedFrom) {}

IndentationAndAlignment::IndentationAndAlignment(unsigned Spaces)
: Total(Spaces), IndentedFrom(Spaces) {}

bool IndentationAndAlignment::operator<(
const IndentationAndAlignment &Other) const {
if (Total != Other.Total)
return Total < Other.Total;
// The sign to use here was decided arbitrarily. This operator is mostly used
// when a line's indentation should be the max of 2 things. Using this sign
// here makes the program prefer alignment over continuation indentation. That
// is, it makes the alignment step that follows prefer to move the line when
// aligning the previous line.
return IndentedFrom > Other.IndentedFrom;
}

ContinuationIndenter::ContinuationIndenter(const FormatStyle &Style,
const AdditionalKeywords &Keywords,
const SourceManager &SourceMgr,
Expand Down Expand Up @@ -491,7 +530,7 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
return true;
}

unsigned NewLineColumn = getNewLineColumn(State);
unsigned NewLineColumn = getNewLineColumn(State).Total;
if (Current.isMemberAccess() && Style.ColumnLimit != 0 &&
State.Column + getLengthToNextOperator(Current) > Style.ColumnLimit &&
(State.Column > NewLineColumn ||
Expand Down Expand Up @@ -819,8 +858,9 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
}

if (Current.is(TT_SelectorName) && !CurrentState.ObjCSelectorNameFound) {
unsigned MinIndent = std::max(
State.FirstIndent + Style.ContinuationIndentWidth, CurrentState.Indent);
unsigned MinIndent =
std::max(State.FirstIndent + Style.ContinuationIndentWidth,
CurrentState.Indent.Total);
unsigned FirstColonPos = State.Column + Spaces + Current.ColumnWidth;
if (Current.LongestObjCSelectorName == 0)
CurrentState.AlignColons = false;
Expand Down Expand Up @@ -910,7 +950,8 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
return !Next || Next->isMemberAccess() ||
Next->is(TT_FunctionDeclarationLParen) || IsFunctionCallParen(*Next);
};
if (IsOpeningBracket(Previous) && State.Column > getNewLineColumn(State) &&
if (IsOpeningBracket(Previous) &&
State.Column > getNewLineColumn(State).Total &&
// Don't do this for simple (no expressions) one-argument function calls
// as that feels like needlessly wasting whitespace, e.g.:
//
Expand Down Expand Up @@ -955,7 +996,7 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
CurrentState.NoLineBreak = true;

if (startsSegmentOfBuilderTypeCall(Current) &&
State.Column > getNewLineColumn(State)) {
State.Column > getNewLineColumn(State).Total) {
CurrentState.ContainsUnwrappedBuilder = true;
}

Expand Down Expand Up @@ -1086,7 +1127,8 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
Penalty += Style.PenaltyBreakFirstLessLess;
}

State.Column = getNewLineColumn(State);
const auto [TotalColumn, IndentedFromColumn] = getNewLineColumn(State);
State.Column = TotalColumn;

// Add Penalty proportional to amount of whitespace away from FirstColumn
// This tends to penalize several lines that are far-right indented,
Expand Down Expand Up @@ -1132,9 +1174,9 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
} else {
CurrentState.ColonPos =
(shouldIndentWrappedSelectorName(Style, State.Line->Type)
? std::max(CurrentState.Indent,
? std::max(CurrentState.Indent.Total,
State.FirstIndent + Style.ContinuationIndentWidth)
: CurrentState.Indent) +
: CurrentState.Indent.Total) +
std::max(NextNonComment->LongestObjCSelectorName,
NextNonComment->ColumnWidth);
}
Expand All @@ -1155,7 +1197,7 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
// when we consume all of the "}"'s FakeRParens at the "{".
if (State.Stack.size() > 1) {
State.Stack[State.Stack.size() - 2].LastSpace =
std::max(CurrentState.LastSpace, CurrentState.Indent) +
std::max(CurrentState.LastSpace, CurrentState.Indent.Total) +
Style.ContinuationIndentWidth;
}
}
Expand Down Expand Up @@ -1196,7 +1238,8 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
State.Line->Type != LT_ImportStatement &&
Current.isNot(TT_LineComment);
Whitespaces.replaceWhitespace(Current, Newlines, State.Column, State.Column,
CurrentState.IsAligned, ContinuePPDirective);
CurrentState.IsAligned, ContinuePPDirective,
IndentedFromColumn);
}

if (!Current.isTrailingComment())
Expand Down Expand Up @@ -1340,7 +1383,8 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
return Penalty;
}

unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
IndentationAndAlignment
ContinuationIndenter::getNewLineColumn(const LineState &State) {
if (!State.NextToken || !State.NextToken->Previous)
return 0;

Expand All @@ -1354,8 +1398,9 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {

const FormatToken &Previous = *Current.Previous;
// If we are continuing an expression, we want to use the continuation indent.
unsigned ContinuationIndent =
std::max(CurrentState.LastSpace, CurrentState.Indent) +
const auto ContinuationIndent =
std::max(IndentationAndAlignment(CurrentState.LastSpace),
CurrentState.Indent) +
Style.ContinuationIndentWidth;
const FormatToken *PreviousNonComment = Current.getPreviousNonComment();
const FormatToken *NextNonComment = Previous.getNextNonComment();
Expand All @@ -1365,7 +1410,7 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
// Java specific bits.
if (Style.isJava() &&
Current.isOneOf(Keywords.kw_implements, Keywords.kw_extends)) {
return std::max(CurrentState.LastSpace,
return std::max(IndentationAndAlignment(CurrentState.LastSpace),
CurrentState.Indent + Style.ContinuationIndentWidth);
}

Expand All @@ -1378,7 +1423,8 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {

if (Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths &&
State.Line->First->is(tok::kw_enum)) {
return (Style.IndentWidth * State.Line->First->IndentLevel) +
return IndentationAndAlignment(Style.IndentWidth *
State.Line->First->IndentLevel) +
Style.IndentWidth;
}

Expand Down Expand Up @@ -1497,7 +1543,7 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
// * not remove the 'lead' ContinuationIndentWidth
// * always un-indent by the operator when
// BreakBeforeTernaryOperators=true
unsigned Indent = CurrentState.Indent;
unsigned Indent = CurrentState.Indent.Total;
if (Style.AlignOperands != FormatStyle::OAS_DontAlign)
Indent -= Style.ContinuationIndentWidth;
if (Style.BreakBeforeTernaryOperators && CurrentState.UnindentOperator)
Expand Down Expand Up @@ -1537,14 +1583,16 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
TT_LeadingJavaAnnotation))) ||
(!Style.IndentWrappedFunctionNames &&
NextNonComment->isOneOf(tok::kw_operator, TT_FunctionDeclarationName))) {
return std::max(CurrentState.LastSpace, CurrentState.Indent);
return std::max(IndentationAndAlignment(CurrentState.LastSpace),
CurrentState.Indent);
}
if (NextNonComment->is(TT_SelectorName)) {
if (!CurrentState.ObjCSelectorNameFound) {
unsigned MinIndent = CurrentState.Indent;
auto MinIndent = CurrentState.Indent;
if (shouldIndentWrappedSelectorName(Style, State.Line->Type)) {
MinIndent = std::max(MinIndent,
State.FirstIndent + Style.ContinuationIndentWidth);
MinIndent =
std::max(MinIndent, IndentationAndAlignment(State.FirstIndent) +
Style.ContinuationIndentWidth);
}
// If LongestObjCSelectorName is 0, we are indenting the first
// part of an ObjC selector (or a selector component which is
Expand All @@ -1555,10 +1603,10 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
// component of the ObjC selector.
//
// In either case, we want to respect Style.IndentWrappedFunctionNames.
return MinIndent +
std::max(NextNonComment->LongestObjCSelectorName,
NextNonComment->ColumnWidth) -
NextNonComment->ColumnWidth;
return MinIndent.addPadding(
std::max(NextNonComment->LongestObjCSelectorName,
NextNonComment->ColumnWidth) -
NextNonComment->ColumnWidth);
}
if (!CurrentState.AlignColons)
return CurrentState.Indent;
Expand Down Expand Up @@ -1628,7 +1676,7 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
return CurrentState.Indent - NextNonComment->Tok.getLength() -
NextNonComment->SpacesRequiredBefore;
}
if (CurrentState.Indent == State.FirstIndent && PreviousNonComment &&
if (CurrentState.Indent.Total == State.FirstIndent && PreviousNonComment &&
PreviousNonComment->isNoneOf(tok::r_brace, TT_CtorInitializerComma)) {
// Ensure that we fall back to the continuation indent width instead of
// just flushing continuations left.
Expand Down Expand Up @@ -1718,7 +1766,7 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
FormatStyle::BCIS_BeforeComma
? 0
: 2);
CurrentState.NestedBlockIndent = CurrentState.Indent;
CurrentState.NestedBlockIndent = CurrentState.Indent.Total;
if (Style.PackConstructorInitializers > FormatStyle::PCIS_BinPack) {
CurrentState.AvoidBinPacking = true;
CurrentState.BreakBeforeParameter =
Expand All @@ -1733,7 +1781,7 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
Style.BreakConstructorInitializers == FormatStyle::BCIS_AfterColon) {
CurrentState.Indent =
State.FirstIndent + Style.ConstructorInitializerIndentWidth;
CurrentState.NestedBlockIndent = CurrentState.Indent;
CurrentState.NestedBlockIndent = CurrentState.Indent.Total;
if (Style.PackConstructorInitializers > FormatStyle::PCIS_BinPack)
CurrentState.AvoidBinPacking = true;
else
Expand Down Expand Up @@ -1878,7 +1926,8 @@ void ContinuationIndenter::moveStatePastFakeLParens(LineState &State,
(Previous && Previous->isOneOf(TT_TableGenDAGArgListComma,
TT_TableGenDAGArgListCommaToBreak)))) {
NewParenState.Indent = std::max(
std::max(State.Column, NewParenState.Indent), CurrentState.LastSpace);
std::max(IndentationAndAlignment(State.Column), NewParenState.Indent),
IndentationAndAlignment(CurrentState.LastSpace));
Comment on lines 1928 to +1930
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
NewParenState.Indent = std::max(
std::max(State.Column, NewParenState.Indent), CurrentState.LastSpace);
std::max(IndentationAndAlignment(State.Column), NewParenState.Indent),
IndentationAndAlignment(CurrentState.LastSpace));
NewParenState.Indent = std::max({
IndentationAndAlignment(State.Column), NewParenState.Indent,
IndentationAndAlignment(CurrentState.LastSpace)});

}

// Special case for generic selection expressions, its comma-separated
Expand Down Expand Up @@ -1986,7 +2035,7 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State,
return Prev->is(tok::comma);
}(Current.MatchingParen);

unsigned NewIndent;
IndentationAndAlignment NewIndent = 0;
unsigned LastSpace = CurrentState.LastSpace;
bool AvoidBinPacking;
bool BreakBeforeParameter = false;
Expand All @@ -1999,7 +2048,7 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State,
std::min(State.Column, CurrentState.NestedBlockIndent);
} else if (Current.is(tok::l_brace)) {
const auto Width = Style.BracedInitializerIndentWidth;
NewIndent = CurrentState.LastSpace +
NewIndent = IndentationAndAlignment(CurrentState.LastSpace) +
(Width < 0 ? Style.ContinuationIndentWidth : Width);
} else {
NewIndent = CurrentState.LastSpace + Style.ContinuationIndentWidth;
Expand All @@ -2014,9 +2063,9 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State,
if (Current.ParameterCount > 1)
NestedBlockIndent = std::max(NestedBlockIndent, State.Column + 1);
} else {
NewIndent =
Style.ContinuationIndentWidth +
std::max(CurrentState.LastSpace, CurrentState.StartOfFunctionCall);
NewIndent = IndentationAndAlignment(std::max(
CurrentState.LastSpace, CurrentState.StartOfFunctionCall)) +
Style.ContinuationIndentWidth;

if (Style.isTableGen() && Current.is(TT_TableGenDAGArgOpenerToBreak) &&
Style.TableGenBreakInsideDAGArg == FormatStyle::DAS_BreakElements) {
Expand All @@ -2035,7 +2084,7 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State,
// FIXME: We likely want to do this for more combinations of brackets.
if (Current.is(tok::less) && Current.ParentBracket == tok::l_paren) {
NewIndent = std::max(NewIndent, CurrentState.Indent);
LastSpace = std::max(LastSpace, CurrentState.Indent);
LastSpace = std::max(LastSpace, CurrentState.Indent.Total);
}

// If ObjCBinPackProtocolList is unspecified, fall back to BinPackParameters
Expand Down Expand Up @@ -2281,7 +2330,7 @@ unsigned ContinuationIndenter::reformatRawStringLiteral(
unsigned CurrentIndent =
(!Newline && Current.Next && Current.Next->is(tok::r_paren))
? State.Stack.back().NestedBlockIndent
: State.Stack.back().Indent;
: State.Stack.back().Indent.Total;
unsigned NextStartColumn = ContentStartsOnNewline
? CurrentIndent + Style.IndentWidth
: FirstStartColumn;
Expand Down
51 changes: 43 additions & 8 deletions clang/lib/Format/ContinuationIndenter.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,41 @@ struct RawStringFormatStyleManager {
getEnclosingFunctionStyle(StringRef EnclosingFunction) const;
};

/// Represents the spaces at the start of a line, keeping track of what the
/// spaces are for.
struct IndentationAndAlignment {
unsigned Total;

/// The column that the position of the start of the line is calculated
/// from. It can be more than Total.
unsigned IndentedFrom;

/// Add spaces for right-justifying the token. The IndentedFrom field does not
/// change.
///
/// This example in Objective-C shows why the field should not change. The
/// token `xx` is right-justified with this method to align the `:`
/// symbols. The `:` symbols should remain aligned through the step that
/// aligns assignments. That step uses the IndentedFrom field to tell what
/// lines to move. Not changing the field in this method ensures that the 2
/// lines move together.
///
/// [x //
/// xxxx:0
/// xx:0];
IndentationAndAlignment addPadding(unsigned Spaces) const;
/// Adding indentation is more common than padding. So the operator does that.
IndentationAndAlignment operator+(unsigned Spaces) const;
IndentationAndAlignment operator-(unsigned Spaces) const;
IndentationAndAlignment &operator+=(unsigned Spaces);

IndentationAndAlignment(unsigned Total, unsigned IndentedFrom);

IndentationAndAlignment(unsigned Spaces);

bool operator<(const IndentationAndAlignment &Other) const;
};

class ContinuationIndenter {
public:
/// Constructs a \c ContinuationIndenter to format \p Line starting in
Expand Down Expand Up @@ -168,7 +203,7 @@ class ContinuationIndenter {
unsigned addTokenOnNewLine(LineState &State, bool DryRun);

/// Calculate the new column for a line wrap before the next token.
unsigned getNewLineColumn(const LineState &State);
IndentationAndAlignment getNewLineColumn(const LineState &State);

/// Adds a multiline token to the \p State.
///
Expand All @@ -195,10 +230,10 @@ class ContinuationIndenter {
};

struct ParenState {
ParenState(const FormatToken *Tok, unsigned Indent, unsigned LastSpace,
bool AvoidBinPacking, bool NoLineBreak)
ParenState(const FormatToken *Tok, IndentationAndAlignment Indent,
unsigned LastSpace, bool AvoidBinPacking, bool NoLineBreak)
: Tok(Tok), Indent(Indent), LastSpace(LastSpace),
NestedBlockIndent(Indent), IsAligned(false),
NestedBlockIndent(Indent.Total), IsAligned(false),
BreakBeforeClosingBrace(false), BreakBeforeClosingParen(false),
BreakBeforeClosingAngle(false), AvoidBinPacking(AvoidBinPacking),
BreakBeforeParameter(false), NoLineBreak(NoLineBreak),
Expand All @@ -219,7 +254,7 @@ struct ParenState {

/// The position to which a specific parenthesis level needs to be
/// indented.
unsigned Indent;
IndentationAndAlignment Indent;

/// The position of the last space on each level.
///
Expand Down Expand Up @@ -356,8 +391,8 @@ struct ParenState {
bool UnindentOperator : 1;

bool operator<(const ParenState &Other) const {
if (Indent != Other.Indent)
return Indent < Other.Indent;
if (Indent.Total != Other.Indent.Total)
return Indent.Total < Other.Indent.Total;
if (LastSpace != Other.LastSpace)
return LastSpace < Other.LastSpace;
if (NestedBlockIndent != Other.NestedBlockIndent)
Expand Down Expand Up @@ -406,7 +441,7 @@ struct ParenState {
return IsWrappedConditional;
if (UnindentOperator != Other.UnindentOperator)
return UnindentOperator;
return false;
return Indent < Other.Indent;
}
};

Expand Down
Loading
Loading