diff --git a/clang/lib/Format/CMakeLists.txt b/clang/lib/Format/CMakeLists.txt --- a/clang/lib/Format/CMakeLists.txt +++ b/clang/lib/Format/CMakeLists.txt @@ -6,6 +6,7 @@ ContinuationIndenter.cpp DefinitionBlockSeparator.cpp Format.cpp + FormatDebug.cpp FormatToken.cpp FormatTokenLexer.cpp IntegerLiteralSeparatorFixer.cpp diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp --- a/clang/lib/Format/ContinuationIndenter.cpp +++ b/clang/lib/Format/ContinuationIndenter.cpp @@ -13,6 +13,7 @@ #include "ContinuationIndenter.h" #include "BreakableToken.h" +#include "FormatDebug.h" #include "FormatInternal.h" #include "FormatToken.h" #include "WhitespaceManager.h" @@ -285,6 +286,7 @@ assert(&Previous == Current.Previous); if (!Current.CanBreakBefore && !(CurrentState.BreakBeforeClosingBrace && Current.closesBlockOrBlockTypeList(Style))) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "!canBreak"); return false; } // The opening "{" of a braced list has to be on the same line as the first @@ -293,6 +295,7 @@ Previous.isNot(TT_DictLiteral) && Previous.is(BK_BracedInit) && Previous.Previous && Previous.Previous->isOneOf(tok::l_brace, tok::l_paren, tok::comma)) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "!canBreak"); return false; } // This prevents breaks like: @@ -303,35 +306,44 @@ if (Previous.opensScope() && Previous.isNot(tok::l_brace) && State.LowestLevelOnLine < State.StartOfLineLevel && State.LowestLevelOnLine < Current.NestingLevel) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "!canBreak"); return false; } - if (Current.isMemberAccess() && CurrentState.ContainsUnwrappedBuilder) + if (Current.isMemberAccess() && CurrentState.ContainsUnwrappedBuilder) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "!canBreak"); return false; + } // Don't create a 'hanging' indent if there are multiple blocks in a single // statement. if (Previous.is(tok::l_brace) && State.Stack.size() > 1 && State.Stack[State.Stack.size() - 2].NestedBlockInlined && State.Stack[State.Stack.size() - 2].HasMultipleNestedBlocks) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "!canBreak"); return false; } // Don't break after very short return types (e.g. "void") as that is often // unexpected. if (Current.is(TT_FunctionDeclarationName) && State.Column < 6) { - if (Style.AlwaysBreakAfterReturnType == FormatStyle::RTBS_None) + if (Style.AlwaysBreakAfterReturnType == FormatStyle::RTBS_None) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "!canBreak"); return false; + } } // If binary operators are moved to the next line (including commas for some // styles of constructor initializers), that's always ok. if (!Current.isOneOf(TT_BinaryOperator, tok::comma) && CurrentState.NoLineBreakInOperand) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "!canBreak"); return false; } - if (Previous.is(tok::l_square) && Previous.is(TT_ObjCMethodExpr)) + if (Previous.is(tok::l_square) && Previous.is(TT_ObjCMethodExpr)) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "!canBreak"); return false; + } if (Current.is(TT_ConditionalExpr) && Previous.is(tok::r_paren) && Previous.MatchingParen && Previous.MatchingParen->Previous && @@ -339,9 +351,12 @@ Previous.MatchingParen->Previous->MatchingParen->is(TT_LambdaLBrace)) { // We have a lambda within a conditional expression, allow breaking here. assert(Previous.MatchingParen->Previous->is(tok::r_brace)); + DEBUG_FORMAT_TRACE_TOKEN(Current, "canBreak"); return true; } + DEBUG_FORMAT_TRACE_TOKEN(Current, (CurrentState.NoLineBreak ? "!" : "") + << "canBreak"); return !CurrentState.NoLineBreak; } @@ -352,30 +367,39 @@ if (Style.BraceWrapping.BeforeLambdaBody && Current.CanBreakBefore && Current.is(TT_LambdaLBrace) && Previous.isNot(TT_LineComment)) { auto LambdaBodyLength = getLengthToMatchingParen(Current, State.Stack); + DEBUG_FORMAT_TRACE_TOKEN( + Current, (LambdaBodyLength <= getColumnLimit(State) ? "!" : "") + << "mustBreak"); return LambdaBodyLength > getColumnLimit(State); } if (Current.MustBreakBefore || (Current.is(TT_InlineASMColon) && (Style.BreakBeforeInlineASMColon == FormatStyle::BBIAS_Always || Style.BreakBeforeInlineASMColon == FormatStyle::BBIAS_OnlyMultiline))) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "mustBreak"); return true; } if (CurrentState.BreakBeforeClosingBrace && Current.closesBlockOrBlockTypeList(Style)) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "mustBreak"); return true; } - if (CurrentState.BreakBeforeClosingParen && Current.is(tok::r_paren)) + if (CurrentState.BreakBeforeClosingParen && Current.is(tok::r_paren)) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "mustBreak"); return true; + } if (Style.Language == FormatStyle::LK_ObjC && Style.ObjCBreakBeforeNestedBlockParam && Current.ObjCSelectorNameParts > 1 && Current.startsSequence(TT_SelectorName, tok::colon, tok::caret)) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "mustBreak"); return true; } // Avoid producing inconsistent states by requiring breaks where they are not // permitted for C# generic type constraints. if (CurrentState.IsCSharpGenericTypeConstraint && Previous.isNot(TT_CSharpGenericTypeConstraintComma)) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "mustBreak"); return false; } if ((startsNextParameter(Current, Style) || Previous.is(tok::semi) || @@ -392,6 +416,7 @@ Previous.is(TT_ConditionalExpr))) && CurrentState.BreakBeforeParameter && !Current.isTrailingComment() && !Current.isOneOf(tok::r_paren, tok::r_brace)) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "mustBreak"); return true; } if (CurrentState.IsChainedConditional && @@ -399,6 +424,7 @@ Current.is(tok::colon)) || (!Style.BreakBeforeTernaryOperators && Previous.is(TT_ConditionalExpr) && Previous.is(tok::colon)))) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "mustBreak"); return true; } if (((Previous.is(TT_DictLiteral) && Previous.is(tok::l_brace)) || @@ -408,6 +434,7 @@ Style.ColumnLimit > 0 && getLengthToMatchingParen(Previous, State.Stack) + State.Column - 1 > getColumnLimit(State)) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "mustBreak"); return true; } @@ -423,17 +450,20 @@ (Style.AllowShortFunctionsOnASingleLine != FormatStyle::SFS_All || Style.BreakConstructorInitializers != FormatStyle::BCIS_BeforeColon || Style.ColumnLimit != 0)) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "mustBreak"); return true; } if (Current.is(TT_ObjCMethodExpr) && !Previous.is(TT_SelectorName) && State.Line->startsWith(TT_ObjCMethodSpecifier)) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "mustBreak"); return true; } if (Current.is(TT_SelectorName) && !Previous.is(tok::at) && CurrentState.ObjCSelectorNameFound && CurrentState.BreakBeforeParameter && (Style.ObjCBreakBeforeNestedBlockParam || !Current.startsSequence(TT_SelectorName, tok::colon, tok::caret))) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "mustBreak"); return true; } @@ -442,6 +472,7 @@ State.Column + getLengthToNextOperator(Current) > Style.ColumnLimit && (State.Column > NewLineColumn || Current.NestingLevel < State.StartOfLineLevel)) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "mustBreak"); return true; } @@ -455,6 +486,7 @@ // FIXME: We should find a more generic solution to this problem. !(State.Column <= NewLineColumn && Style.isJavaScript()) && !(Previous.closesScopeAfterBlock() && State.Column <= NewLineColumn)) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "mustBreak"); return true; } @@ -462,11 +494,14 @@ // function/class declaration. if (Previous.ClosesTemplateDeclaration && CurrentState.BreakBeforeParameter && Current.CanBreakBefore) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "mustBreak"); return true; } - if (!State.Line->First->is(tok::kw_enum) && State.Column <= NewLineColumn) + if (!State.Line->First->is(tok::kw_enum) && State.Column <= NewLineColumn) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "mustBreak"); return false; + } if (Style.AlwaysBreakBeforeMultilineStrings && (NewLineColumn == State.FirstIndent + Style.ContinuationIndentWidth || @@ -475,6 +510,7 @@ Keywords.kw_dollar) && !Previous.isOneOf(TT_InlineASMColon, TT_ConditionalExpr) && nextIsMultilineString(State)) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "mustBreak"); return true; } @@ -487,8 +523,10 @@ CurrentState.BreakBeforeParameter && !Current.isTrailingComment()) { const bool LHSIsBinaryExpr = Previous.Previous && Previous.Previous->EndsBinaryExpression; - if (LHSIsBinaryExpr) + if (LHSIsBinaryExpr) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "mustBreak"); return true; + } // If we need to break somewhere inside the LHS of a binary expression, we // should also break after the operator. Otherwise, the formatting would // hide the operator precedence, e.g. in: @@ -504,17 +542,21 @@ PreviousPrecedence == prec::Spaceship) && Previous.Previous && Previous.Previous->isNot(TT_BinaryOperator); // For >>. - if (!IsComparison) + if (!IsComparison) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "mustBreak"); return true; + } } } else if (Current.is(TT_BinaryOperator) && Current.CanBreakBefore && CurrentState.BreakBeforeParameter) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "mustBreak"); return true; } // Same as above, but for the first "<<" operator. if (Current.is(tok::lessless) && Current.isNot(TT_OverloadedOperator) && CurrentState.BreakBeforeParameter && CurrentState.FirstLessLess == 0) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "mustBreak"); return true; } @@ -529,8 +571,10 @@ case FormatStyle::BBCDS_Allowed: break; case FormatStyle::BBCDS_Always: + DEBUG_FORMAT_TRACE_TOKEN(Current, "mustBreak"); return true; case FormatStyle::BBCDS_Never: + DEBUG_FORMAT_TRACE_TOKEN(Current, "!mustBreak"); return false; } } @@ -538,8 +582,10 @@ switch (Style.RequiresClausePosition) { case FormatStyle::RCPS_SingleLine: case FormatStyle::RCPS_WithPreceding: + DEBUG_FORMAT_TRACE_TOKEN(Current, "!mustBreak"); return false; default: + DEBUG_FORMAT_TRACE_TOKEN(Current, "mustBreak"); return true; } } @@ -547,10 +593,12 @@ } if (Previous.is(TT_FunctionAnnotationRParen) && State.Line->Type != LT_PreprocessorDirective) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "mustBreak"); return true; } if (Previous.is(TT_LeadingJavaAnnotation) && Current.isNot(tok::l_paren) && Current.isNot(TT_LeadingJavaAnnotation)) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "mustBreak"); return true; } } @@ -561,8 +609,10 @@ // functions, getters and setters. static const llvm::StringSet<> BreakBeforeDecoratedTokens = {"get", "set", "function"}; - if (BreakBeforeDecoratedTokens.contains(Current.TokenText)) + if (BreakBeforeDecoratedTokens.contains(Current.TokenText)) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "mustBreak"); return true; + } } // If the return type spans multiple lines, wrap before the function name. @@ -576,6 +626,7 @@ !Style.isJavaScript()) || (Current.is(tok::kw_operator) && !Previous.is(tok::coloncolon))) && !Previous.is(tok::kw_template) && CurrentState.BreakBeforeParameter) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "mustBreak"); return true; } @@ -585,6 +636,7 @@ if (Style.ColumnLimit != 0 && Previous.is(BK_Block) && Previous.is(tok::l_brace) && !Current.isOneOf(tok::r_brace, tok::comment)) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "mustBreak"); return true; } @@ -592,15 +644,21 @@ ((Previous.is(tok::identifier) && Previous.TokenText == "endl") || (Previous.Tok.isLiteral() && (Previous.TokenText.endswith("\\n\"") || Previous.TokenText == "\'\\n\'")))) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "mustBreak"); return true; } - if (Previous.is(TT_BlockComment) && Previous.IsMultiline) + if (Previous.is(TT_BlockComment) && Previous.IsMultiline) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "mustBreak"); return true; + } - if (State.NoContinuation) + if (State.NoContinuation) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "mustBreak"); return true; + } + DEBUG_FORMAT_TRACE_TOKEN(Current, "!mustBreak"); return false; } @@ -694,10 +752,12 @@ // declaration unless there is multiple inheritance. if (Style.BreakInheritanceList == FormatStyle::BILS_BeforeComma && Current.is(TT_InheritanceColon)) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "NoLineBreak"); CurrentState.NoLineBreak = true; } if (Style.BreakInheritanceList == FormatStyle::BILS_AfterColon && Previous.is(TT_InheritanceColon)) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "NoLineBreak"); CurrentState.NoLineBreak = true; } @@ -735,10 +795,13 @@ // caaaaaaaaaaaaaaaaaaaaaaall(aaaaaaaaaaaaaa, aaaaaaaaa)))); Current.FakeLParens.size() > 0 && Current.FakeLParens.back() > prec::Unknown) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "NoLineBreak"); CurrentState.NoLineBreak = true; } - if (Previous.is(TT_TemplateString) && Previous.opensScope()) + if (Previous.is(TT_TemplateString) && Previous.opensScope()) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "NoLineBreak"); CurrentState.NoLineBreak = true; + } // Align following lines within parentheses / brackets if configured. // Note: This doesn't apply to macro expansion lines, which are MACRO( , , ) @@ -752,15 +815,19 @@ CurrentState.Indent = State.Column + Spaces; CurrentState.IsAligned = true; } - if (CurrentState.AvoidBinPacking && startsNextParameter(Current, Style)) + if (CurrentState.AvoidBinPacking && startsNextParameter(Current, Style)) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "NoLineBreak"); CurrentState.NoLineBreak = true; + } if (startsSegmentOfBuilderTypeCall(Current) && State.Column > getNewLineColumn(State)) { CurrentState.ContainsUnwrappedBuilder = true; } - if (Current.is(TT_LambdaArrow) && Style.Language == FormatStyle::LK_Java) + if (Current.is(TT_LambdaArrow) && Style.Language == FormatStyle::LK_Java) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "NoLineBreak"); CurrentState.NoLineBreak = true; + } if (Current.isMemberAccess() && Previous.is(tok::r_paren) && (Previous.MatchingParen && (Previous.TotalLength - Previous.MatchingParen->TotalLength > 10))) { @@ -770,6 +837,7 @@ // 2); // We don't want to do this for short parameters as they can just be // indexes. + DEBUG_FORMAT_TRACE_TOKEN(Current, "NoLineBreak"); CurrentState.NoLineBreak = true; } @@ -799,6 +867,7 @@ !(HasTwoOperands && Style.AlignOperands != FormatStyle::OAS_DontAlign)) || (!CurrentState.LastOperatorWrapped && BreakBeforeOperator)) { + DEBUG_FORMAT_TRACE_TOKEN(Current, "NoLineBreakInOperand"); CurrentState.NoLineBreakInOperand = true; } } @@ -1535,6 +1604,8 @@ NewParenState.UnindentOperator = false; NewParenState.NoLineBreak = NewParenState.NoLineBreak || CurrentState.NoLineBreakInOperand; + DEBUG_FORMAT_TRACE_TOKEN(Current, (NewParenState.NoLineBreak ? "" : "!") + << "NoLineBreak"); // Don't propagate AvoidBinPacking into subexpressions of arg/param lists. if (PrecedenceLevel > prec::Comma) diff --git a/clang/lib/Format/FormatDebug.h b/clang/lib/Format/FormatDebug.h new file mode 100644 --- /dev/null +++ b/clang/lib/Format/FormatDebug.h @@ -0,0 +1,41 @@ +//===--- FormatDebug.h - Format C++ code ------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file declares utilities used in clang-format in debug mode. +/// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_LIB_FORMAT_FORMATDEBUG_H +#define LLVM_CLANG_LIB_FORMAT_FORMATDEBUG_H + +#include "llvm/Support/Regex.h" + +namespace clang { +namespace format { +namespace internal { + +#ifndef NDEBUG + +extern const llvm::Regex &DebugTraceToken(); +extern const llvm::Regex &DebugForceMustBreak(); +extern const llvm::Regex &DebugForceMustNotBreak(); + +#define DEBUG_FORMAT_TRACE_TOKEN(Tok, Debug) \ + if (internal::DebugTraceToken().match((Tok).TokenText)) { \ + llvm::dbgs() << __FILE__ << ":" << __LINE__ << ": tracing " \ + << (Tok).TokenText << ": " << Debug << "\n"; \ + } else { \ + } + +#endif + +} // namespace internal +} // namespace format +} // namespace clang + +#endif \ No newline at end of file diff --git a/clang/lib/Format/FormatDebug.cpp b/clang/lib/Format/FormatDebug.cpp new file mode 100644 --- /dev/null +++ b/clang/lib/Format/FormatDebug.cpp @@ -0,0 +1,65 @@ +//===--- FormatDebug.cpp - Format C++ code ----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file implements utilities used in clang-format in debug mode. +/// +//===----------------------------------------------------------------------===// + +#include "FormatDebug.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Regex.h" + +namespace clang { +namespace format { +namespace internal { + +#ifndef NDEBUG + +namespace { + +llvm::cl::opt + DebugTraceTokenRe("debug-trace-token", + llvm::cl::desc("Regular expression to trace formatting " + "decisions of tokens whose text matches."), + llvm::cl::Hidden); + +llvm::cl::opt DebugForceMustBreakRe( + "debug-force-must-break", + llvm::cl::desc("Regular expression to force line breaks before tokens " + "whose text matches."), + llvm::cl::Hidden); + +llvm::cl::opt DebugForceMustNotBreakRe( + "debug-force-must-not-break", + llvm::cl::desc("Regular expression to force not breaking before tokens " + "whose text matches."), + llvm::cl::Hidden); + +} // namespace + +const llvm::Regex &DebugTraceToken() { + static llvm::Regex R(DebugTraceTokenRe); + return R; +} + +const llvm::Regex &DebugForceMustBreak() { + static llvm::Regex R(DebugForceMustBreakRe); + return R; +} + +const llvm::Regex &DebugForceMustNotBreak() { + static llvm::Regex R(DebugForceMustNotBreakRe); + return R; +} + +#endif + +} // namespace internal +} // namespace format +} // namespace clang \ No newline at end of file diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -13,6 +13,8 @@ //===----------------------------------------------------------------------===// #include "TokenAnnotator.h" +#include "ContinuationIndenter.h" +#include "FormatDebug.h" #include "FormatToken.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TokenKinds.h" @@ -3244,6 +3246,7 @@ const auto &Children = Prev->Children; if (!Children.empty() && Children.back()->Last->is(TT_LineComment)) { + DEBUG_FORMAT_TRACE_TOKEN(*Current, "MustBreakBefore"); Current->MustBreakBefore = true; } else { Current->MustBreakBefore = @@ -3252,6 +3255,8 @@ Current->is(TT_FunctionDeclarationName)) { Current->MustBreakBefore = mustBreakForReturnType(Line); } + DEBUG_FORMAT_TRACE_TOKEN(*Current, (Current->MustBreakBefore ? "" : "!") + << "MustBreakBefore"); } Current->CanBreakBefore = diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp --- a/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "UnwrappedLineFormatter.h" +#include "FormatDebug.h" #include "FormatToken.h" #include "NamespaceEndCommentsFixer.h" #include "WhitespaceManager.h" @@ -1252,17 +1253,43 @@ /// penalty of \p Penalty. Insert a line break if \p NewLine is \c true. void addNextStateToQueue(unsigned Penalty, StateNode *PreviousNode, bool NewLine, unsigned *Count, QueueType *Queue) { - if (NewLine && !Indenter->canBreak(PreviousNode->State)) + bool MustBreak = false; + bool MustNotBreak = false; + LLVM_DEBUG({ + if (internal::DebugForceMustBreak().match( + PreviousNode->State.NextToken->TokenText)) { + MustBreak = true; + } + if (internal::DebugForceMustNotBreak().match( + PreviousNode->State.NextToken->TokenText)) { + MustNotBreak = true; + } + }); + + if (NewLine && (!Indenter->canBreak(PreviousNode->State) || MustNotBreak) && + !MustBreak) { + DEBUG_FORMAT_TRACE_TOKEN(*PreviousNode->State.NextToken, + "Cannot break before"); return; - if (!NewLine && Indenter->mustBreak(PreviousNode->State)) + } + if (!NewLine && (Indenter->mustBreak(PreviousNode->State) || MustBreak) && + !MustNotBreak) { + DEBUG_FORMAT_TRACE_TOKEN(*PreviousNode->State.NextToken, + "Must break before"); return; + } StateNode *Node = new (Allocator.Allocate()) StateNode(PreviousNode->State, NewLine, PreviousNode); if (!formatChildren(Node->State, NewLine, /*DryRun=*/true, Penalty)) return; - Penalty += Indenter->addTokenToState(Node->State, NewLine, true); + unsigned AddPenalty = Indenter->addTokenToState(Node->State, NewLine, true); + DEBUG_FORMAT_TRACE_TOKEN(*PreviousNode->State.NextToken, + "Penalty for " << (!NewLine ? "not " : "") + << "breaking before token is " + << AddPenalty); + Penalty += AddPenalty; Queue->push(QueueItem(OrderedPenalty(Penalty, *Count), Node)); ++(*Count);