12 #include "llvm/Support/Debug.h"
14 #define DEBUG_TYPE "format-formatter"
21 bool startsExternCBlock(
const AnnotatedLine &
Line) {
22 const FormatToken *
Next = Line.First->getNextNonComment();
23 const FormatToken *NextNext = Next ? Next->getNextNonComment() :
nullptr;
24 return Line.startsWith(tok::kw_extern) && Next && Next->isStringLiteral() &&
25 NextNext && NextNext->is(tok::l_brace);
37 class LevelIndentTracker {
39 LevelIndentTracker(
const FormatStyle &
Style,
40 const AdditionalKeywords &
Keywords,
unsigned StartLevel,
43 for (
unsigned i = 0; i != StartLevel; ++i)
44 IndentForLevel.push_back(Style.IndentWidth * i + AdditionalIndent);
48 unsigned getIndent()
const {
return Indent; }
52 void nextLine(
const AnnotatedLine &Line) {
53 Offset = getIndentOffset(*Line.First);
58 if (Line.InPPDirective) {
73 void adjustToUnmodifiedLine(
const AnnotatedLine &Line) {
74 unsigned LevelIndent = Line.First->OriginalColumn;
75 if (static_cast<int>(LevelIndent) -
Offset >= 0)
77 if ((!Line.First->is(tok::comment) ||
IndentForLevel[Line.Level] == -1) &&
87 int getIndentOffset(
const FormatToken &RootToken) {
91 if (RootToken.isAccessSpecifier(
false) ||
92 RootToken.isObjCAccessSpecifier() ||
93 (RootToken.isOneOf(Keywords.kw_signals, Keywords.kw_qsignals) &&
94 RootToken.Next && RootToken.Next->is(tok::colon)))
95 return Style.AccessModifierOffset;
105 if (IndentForLevel[Level] != -1)
106 return IndentForLevel[
Level];
109 return getIndent(IndentForLevel, Level - 1) + Style.IndentWidth;
131 LineJoiner(
const FormatStyle &
Style,
const AdditionalKeywords &
Keywords,
132 const SmallVectorImpl<AnnotatedLine *> &Lines)
134 Next(Lines.begin()) {}
137 const AnnotatedLine *getNextMergedLine(
bool DryRun,
138 LevelIndentTracker &IndentTracker) {
142 IndentTracker.nextLine(*Current);
143 unsigned MergedLines =
144 tryFitMultipleLinesInOne(IndentTracker.getIndent(),
Next,
End);
145 if (MergedLines > 0 && Style.ColumnLimit == 0)
148 for (
unsigned i = 0; i < MergedLines; ++i)
149 if (
Next[i + 1]->First->NewlinesBefore > 0)
152 for (
unsigned i = 0; i < MergedLines; ++i)
161 tryFitMultipleLinesInOne(
unsigned Indent,
162 SmallVectorImpl<AnnotatedLine *>::const_iterator
I,
163 SmallVectorImpl<AnnotatedLine *>::const_iterator
E) {
168 const AnnotatedLine *TheLine = *
I;
169 if (TheLine->Last->is(TT_LineComment))
171 if (I[1]->Type ==
LT_Invalid || I[1]->First->MustBreakBefore)
173 if (TheLine->InPPDirective &&
174 (!I[1]->InPPDirective || I[1]->First->HasUnescapedNewline))
177 if (Style.ColumnLimit > 0 && Indent > Style.ColumnLimit)
184 Limit = TheLine->Last->TotalLength > Limit
186 : Limit - TheLine->Last->TotalLength;
190 bool MergeShortFunctions =
193 I[1]->First->is(tok::r_brace)) ||
195 TheLine->Level != 0);
197 if (TheLine->Last->is(TT_FunctionLBrace) &&
198 TheLine->First != TheLine->Last) {
199 return MergeShortFunctions ? tryMergeSimpleBlock(I, E, Limit) : 0;
201 if (TheLine->Last->is(tok::l_brace)) {
202 return !Style.BraceWrapping.AfterFunction
203 ? tryMergeSimpleBlock(I, E, Limit)
206 if (I[1]->First->is(TT_FunctionLBrace) &&
207 Style.BraceWrapping.AfterFunction) {
208 if (I[1]->
Last->is(TT_LineComment))
212 if (Limit <= 2 || (Style.ColumnLimit == 0 && containsMustBreak(TheLine)))
216 unsigned MergedLines = 0;
217 if (MergeShortFunctions) {
218 MergedLines = tryMergeSimpleBlock(I + 1, E, Limit);
226 if (TheLine->First->is(tok::kw_if)) {
227 return Style.AllowShortIfStatementsOnASingleLine
228 ? tryMergeSimpleControlStatement(I, E, Limit)
231 if (TheLine->First->isOneOf(tok::kw_for, tok::kw_while)) {
232 return Style.AllowShortLoopsOnASingleLine
233 ? tryMergeSimpleControlStatement(I, E, Limit)
236 if (TheLine->First->isOneOf(tok::kw_case, tok::kw_default)) {
237 return Style.AllowShortCaseLabelsOnASingleLine
238 ? tryMergeShortCaseLabels(I, E, Limit)
241 if (TheLine->InPPDirective &&
242 (TheLine->First->HasUnescapedNewline || TheLine->First->IsFirst)) {
243 return tryMergeSimplePPDirective(I, E, Limit);
249 tryMergeSimplePPDirective(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
250 SmallVectorImpl<AnnotatedLine *>::const_iterator E,
254 if (I + 2 != E && I[2]->InPPDirective && !I[2]->First->HasUnescapedNewline)
256 if (1 + I[1]->
Last->TotalLength > Limit)
261 unsigned tryMergeSimpleControlStatement(
262 SmallVectorImpl<AnnotatedLine *>::const_iterator I,
263 SmallVectorImpl<AnnotatedLine *>::const_iterator E,
unsigned Limit) {
266 if (Style.BraceWrapping.AfterControlStatement &&
267 (I[1]->First->is(tok::l_brace) && !Style.AllowShortBlocksOnASingleLine))
269 if (I[1]->InPPDirective != (*I)->InPPDirective ||
270 (I[1]->InPPDirective && I[1]->First->HasUnescapedNewline))
272 Limit = limitConsideringMacros(I + 1, E, Limit);
273 AnnotatedLine &Line = **
I;
274 if (Line.Last->isNot(tok::r_paren))
276 if (1 + I[1]->
Last->TotalLength > Limit)
278 if (I[1]->First->isOneOf(tok::semi, tok::kw_if, tok::kw_for, tok::kw_while,
282 if (I + 2 != E && Line.startsWith(tok::kw_if) &&
283 I[2]->First->is(tok::kw_else))
289 tryMergeShortCaseLabels(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
290 SmallVectorImpl<AnnotatedLine *>::const_iterator E,
292 if (Limit == 0 || I + 1 == E ||
293 I[1]->First->isOneOf(tok::kw_case, tok::kw_default))
295 unsigned NumStmts = 0;
297 bool InPPDirective = I[0]->InPPDirective;
298 for (; NumStmts < 3; ++NumStmts) {
299 if (I + 1 + NumStmts == E)
301 const AnnotatedLine *Line = I[1 + NumStmts];
302 if (Line->InPPDirective != InPPDirective)
304 if (Line->First->isOneOf(tok::kw_case, tok::kw_default, tok::r_brace))
306 if (Line->First->isOneOf(tok::kw_if, tok::kw_for, tok::kw_switch,
307 tok::kw_while, tok::comment) ||
308 Line->Last->is(tok::comment))
310 Length += I[1 + NumStmts]->Last->TotalLength + 1;
312 if (NumStmts == 0 || NumStmts == 3 || Length > Limit)
318 tryMergeSimpleBlock(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
319 SmallVectorImpl<AnnotatedLine *>::const_iterator E,
321 AnnotatedLine &Line = **
I;
327 Line.First->isOneOf(tok::at, tok::minus, tok::plus))
332 if (Line.First->isOneOf(tok::kw_else, tok::kw_case) ||
333 (Line.First->Next && Line.First->Next->is(tok::kw_else)))
335 if (Line.First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_do, tok::kw_try,
336 tok::kw___try, tok::kw_catch, tok::kw___finally,
337 tok::kw_for, tok::r_brace, Keywords.kw___except)) {
338 if (!Style.AllowShortBlocksOnASingleLine)
340 if (!Style.AllowShortIfStatementsOnASingleLine &&
341 Line.startsWith(tok::kw_if))
343 if (!Style.AllowShortLoopsOnASingleLine &&
344 Line.First->isOneOf(tok::kw_while, tok::kw_do, tok::kw_for))
351 if (Line.First->isOneOf(tok::kw_try, tok::kw___try, tok::kw_catch,
352 Keywords.kw___except, tok::kw___finally))
356 FormatToken *Tok = I[1]->First;
357 if (Tok->is(tok::r_brace) && !Tok->MustBreakBefore &&
358 (Tok->getNextNonComment() ==
nullptr ||
359 Tok->getNextNonComment()->is(tok::semi))) {
361 Tok->SpacesRequiredBefore = 0;
362 Tok->CanBreakBefore =
true;
364 }
else if (Limit != 0 && !Line.startsWith(tok::kw_namespace) &&
365 !startsExternCBlock(Line)) {
367 if (Line.First->isOneOf(tok::kw_class, tok::kw_union, tok::kw_struct,
368 Keywords.kw_interface))
374 Limit = limitConsideringMacros(I + 2, E, Limit);
376 if (!nextTwoLinesFitInto(I, Limit))
381 if (I[1]->
Last->is(TT_LineComment))
384 if (Tok->is(tok::l_brace) && Tok->BlockKind !=
BK_BracedInit)
391 if (Tok->isNot(tok::r_brace))
395 if (Tok->Next && Tok->Next->is(tok::kw_else))
406 limitConsideringMacros(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
407 SmallVectorImpl<AnnotatedLine *>::const_iterator E,
409 if (I[0]->InPPDirective && I + 1 != E &&
410 !I[1]->First->HasUnescapedNewline && !I[1]->First->is(
tok::eof)) {
411 return Limit < 2 ? 0 : Limit - 2;
416 bool nextTwoLinesFitInto(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
418 if (I[1]->First->MustBreakBefore || I[2]->First->MustBreakBefore)
420 return 1 + I[1]->Last->TotalLength + 1 + I[2]->Last->TotalLength <= Limit;
423 bool containsMustBreak(
const AnnotatedLine *Line) {
424 for (
const FormatToken *Tok = Line->First; Tok; Tok = Tok->Next) {
425 if (Tok->MustBreakBefore)
431 void join(AnnotatedLine &A,
const AnnotatedLine &B) {
432 assert(!A.Last->Next);
433 assert(!B.First->Previous);
436 A.Last->Next = B.First;
437 B.First->Previous = A.Last;
438 B.First->CanBreakBefore =
true;
439 unsigned LengthA = A.Last->TotalLength + B.First->SpacesRequiredBefore;
440 for (FormatToken *Tok = B.First; Tok; Tok = Tok->Next) {
441 Tok->TotalLength += LengthA;
446 const FormatStyle &
Style;
448 const SmallVectorImpl<AnnotatedLine *>::const_iterator
End;
450 SmallVectorImpl<AnnotatedLine *>::const_iterator
Next;
453 static void markFinalized(FormatToken *Tok) {
454 for (; Tok; Tok = Tok->Next) {
455 Tok->Finalized =
true;
456 for (AnnotatedLine *Child : Tok->Children)
457 markFinalized(Child->First);
462 static void printLineState(
const LineState &
State) {
463 llvm::dbgs() <<
"State: ";
464 for (
const ParenState &
P : State.Stack) {
465 llvm::dbgs() << P.Indent <<
"|" << P.LastSpace <<
"|" << P.NestedBlockIndent
468 llvm::dbgs() << State.NextToken->TokenText <<
"\n";
473 class LineFormatter {
476 const FormatStyle &Style,
478 : Indenter(Indenter), Whitespaces(Whitespaces), Style(Style),
479 BlockFormatter(BlockFormatter) {}
480 virtual ~LineFormatter() {}
485 virtual unsigned formatLine(
const AnnotatedLine &Line,
unsigned FirstIndent,
509 bool formatChildren(LineState &State,
bool NewLine,
bool DryRun,
511 const FormatToken *LBrace = State.NextToken->getPreviousNonComment();
512 FormatToken &
Previous = *State.NextToken->Previous;
513 if (!LBrace || LBrace->isNot(tok::l_brace) ||
514 LBrace->BlockKind !=
BK_Block || Previous.Children.size() == 0)
521 Previous.Children[0]->Level * Style.IndentWidth;
524 BlockFormatter->format(Previous.Children, DryRun, AdditionalIndent,
529 if (Previous.Children[0]->First->MustBreakBefore)
533 if (Previous.Children.size() > 1)
537 if (Previous.is(tok::comment))
541 if (Previous.Children[0]->Last->isTrailingComment())
546 if (Style.ColumnLimit > 0 &&
547 Previous.Children[0]->Last->TotalLength + State.Column + 2 >
553 *Previous.Children[0]->First,
555 State.Column, State.Line->InPPDirective);
557 Penalty += formatLine(*Previous.Children[0], State.Column + 1, DryRun);
559 State.Column += 1 + Previous.Children[0]->Last->TotalLength;
567 const FormatStyle &
Style;
572 class NoColumnLimitLineFormatter :
public LineFormatter {
574 NoColumnLimitLineFormatter(ContinuationIndenter *
Indenter,
576 const FormatStyle &Style,
578 : LineFormatter(Indenter, Whitespaces, Style, BlockFormatter) {}
582 unsigned formatLine(
const AnnotatedLine &Line,
unsigned FirstIndent,
583 bool DryRun)
override {
586 Indenter->getInitialState(FirstIndent, &Line,
false);
587 while (State.NextToken) {
589 Indenter->mustBreak(State) ||
590 (Indenter->canBreak(State) && State.NextToken->NewlinesBefore > 0);
591 unsigned Penalty = 0;
592 formatChildren(State, Newline,
false, Penalty);
593 Indenter->addTokenToState(State, Newline,
false);
600 class NoLineBreakFormatter :
public LineFormatter {
602 NoLineBreakFormatter(ContinuationIndenter *Indenter,
603 WhitespaceManager *Whitespaces,
const FormatStyle &Style,
604 UnwrappedLineFormatter *BlockFormatter)
605 : LineFormatter(Indenter, Whitespaces, Style, BlockFormatter) {}
608 unsigned formatLine(
const AnnotatedLine &Line,
unsigned FirstIndent,
609 bool DryRun)
override {
610 unsigned Penalty = 0;
611 LineState State = Indenter->getInitialState(FirstIndent, &Line, DryRun);
612 while (State.NextToken) {
613 formatChildren(State,
false, DryRun, Penalty);
614 Indenter->addTokenToState(State,
false, DryRun);
621 class OptimizingLineFormatter :
public LineFormatter {
623 OptimizingLineFormatter(ContinuationIndenter *Indenter,
624 WhitespaceManager *Whitespaces,
625 const FormatStyle &Style,
626 UnwrappedLineFormatter *BlockFormatter)
627 : LineFormatter(Indenter, Whitespaces, Style, BlockFormatter) {}
631 unsigned formatLine(
const AnnotatedLine &Line,
unsigned FirstIndent,
632 bool DryRun)
override {
633 LineState State = Indenter->getInitialState(FirstIndent, &Line, DryRun);
638 State.Stack.back().BreakBeforeParameter =
true;
641 return analyzeSolutionSpace(State, DryRun);
645 struct CompareLineStatePointers {
646 bool operator()(LineState *obj1, LineState *obj2)
const {
647 return *obj1 < *obj2;
656 typedef std::pair<unsigned, unsigned> OrderedPenalty;
661 StateNode(
const LineState &State,
bool NewLine, StateNode *Previous)
662 : State(State), NewLine(NewLine), Previous(Previous) {}
670 typedef std::pair<OrderedPenalty, StateNode *> QueueItem;
673 typedef std::priority_queue<QueueItem, std::vector<QueueItem>,
674 std::greater<QueueItem>> QueueType;
684 unsigned analyzeSolutionSpace(LineState &InitialState,
bool DryRun) {
685 std::set<LineState *, CompareLineStatePointers> Seen;
694 new (
Allocator.Allocate()) StateNode(InitialState,
false,
nullptr);
695 Queue.push(QueueItem(OrderedPenalty(0, Count), Node));
698 unsigned Penalty = 0;
701 while (!Queue.empty()) {
702 Penalty = Queue.top().first.first;
703 StateNode *Node = Queue.top().second;
704 if (!Node->State.NextToken) {
705 DEBUG(llvm::dbgs() <<
"\n---\nPenalty for line: " << Penalty <<
"\n");
713 Node->State.IgnoreStackForComparison =
true;
715 if (!Seen.insert(&Node->State).second)
721 addNextStateToQueue(Penalty, Node,
false, &Count, &Queue);
723 addNextStateToQueue(Penalty, Node,
true, &Count, &Queue);
729 DEBUG(llvm::dbgs() <<
"Could not find a solution.\n");
735 reconstructPath(InitialState, Queue.top().second);
737 DEBUG(llvm::dbgs() <<
"Total number of analyzed states: " << Count <<
"\n");
738 DEBUG(llvm::dbgs() <<
"---\n");
747 void addNextStateToQueue(
unsigned Penalty, StateNode *PreviousNode,
748 bool NewLine,
unsigned *Count, QueueType *Queue) {
749 if (NewLine && !Indenter->canBreak(PreviousNode->State))
751 if (!NewLine && Indenter->mustBreak(PreviousNode->State))
754 StateNode *Node =
new (
Allocator.Allocate())
755 StateNode(PreviousNode->State, NewLine, PreviousNode);
756 if (!formatChildren(Node->State, NewLine,
true, Penalty))
759 Penalty += Indenter->addTokenToState(Node->State, NewLine,
true);
761 Queue->push(QueueItem(OrderedPenalty(Penalty, *Count), Node));
767 void reconstructPath(LineState &State, StateNode *Best) {
768 std::deque<StateNode *> Path;
770 while (Best->Previous) {
771 Path.push_front(Best);
772 Best = Best->Previous;
776 unsigned Penalty = 0;
777 formatChildren(State, (*I)->NewLine,
false, Penalty);
778 Penalty += Indenter->addTokenToState(State, (*I)->NewLine,
false);
781 printLineState((*I)->Previous->State);
783 llvm::dbgs() <<
"Penalty for placing "
784 << (*I)->Previous->State.NextToken->Tok.getName() <<
": "
798 bool DryRun,
int AdditionalIndent,
799 bool FixBadIndentation) {
800 LineJoiner Joiner(Style, Keywords, Lines);
803 std::pair<const SmallVectorImpl<AnnotatedLine *> *,
unsigned> CacheKey(
804 &Lines, AdditionalIndent);
805 auto CacheIt = PenaltyCache.find(CacheKey);
806 if (DryRun && CacheIt != PenaltyCache.end())
807 return CacheIt->second;
809 assert(!Lines.empty());
810 unsigned Penalty = 0;
811 LevelIndentTracker IndentTracker(Style, Keywords, Lines[0]->
Level,
820 Joiner.getNextMergedLine(DryRun, IndentTracker);
821 Line; Line = NextLine) {
823 unsigned Indent = IndentTracker.getIndent();
829 bool ContinueFormatting =
830 TheLine.
Level > RangeMinLevel ||
833 bool FixIndentation = (FixBadIndentation || ContinueFormatting) &&
835 bool ShouldFormat = TheLine.
Affected || FixIndentation;
839 *IncompleteFormat =
true;
843 formatFirstToken(*TheLine.
First, PreviousLine, TheLine.
Level, Indent,
846 NextLine = Joiner.getNextMergedLine(DryRun, IndentTracker);
847 unsigned ColumnLimit = getColumnLimit(TheLine.
InPPDirective, NextLine);
848 bool FitsIntoOneLine =
852 !Style.JavaScriptWrapImports));
854 if (Style.ColumnLimit == 0)
855 NoColumnLimitLineFormatter(Indenter, Whitespaces, Style,
this)
856 .formatLine(TheLine, Indent, DryRun);
857 else if (FitsIntoOneLine)
858 Penalty += NoLineBreakFormatter(Indenter, Whitespaces, Style,
this)
859 .formatLine(TheLine, Indent, DryRun);
861 Penalty += OptimizingLineFormatter(Indenter, Whitespaces, Style,
this)
862 .formatLine(TheLine, Indent, DryRun);
869 if (!Tok->Children.empty())
870 format(Tok->Children, DryRun);
877 IndentTracker.adjustToUnmodifiedLine(TheLine);
879 bool ReformatLeadingWhitespace =
880 StartsNewLine && ((PreviousLine && PreviousLine->
Affected) ||
883 if (ReformatLeadingWhitespace)
884 formatFirstToken(*TheLine.
First, PreviousLine, TheLine.
Level,
888 Whitespaces->addUntouchableToken(*TheLine.
First,
893 Whitespaces->addUntouchableToken(*Tok, TheLine.
InPPDirective);
895 NextLine = Joiner.getNextMergedLine(DryRun, IndentTracker);
899 markFinalized(TheLine.
First);
900 PreviousLine = &TheLine;
902 PenaltyCache[CacheKey] = Penalty;
906 void UnwrappedLineFormatter::formatFirstToken(
FormatToken &RootToken,
908 unsigned IndentLevel,
910 bool InPPDirective) {
913 Whitespaces->replaceWhitespace(RootToken, Newlines, 0,
920 if (RootToken.
is(tok::r_brace) &&
924 if (Newlines == 0 && !RootToken.
IsFirst)
930 if (!Style.KeepEmptyLinesAtTheStartOfBlocks && PreviousLine &&
931 PreviousLine->
Last->
is(tok::l_brace) &&
932 PreviousLine->
First->
isNot(tok::kw_namespace) &&
933 !startsExternCBlock(*PreviousLine))
937 if (PreviousLine && PreviousLine->
Last->
isOneOf(tok::semi, tok::r_brace) &&
946 Whitespaces->replaceWhitespace(RootToken, Newlines, IndentLevel, Indent,
947 Indent, InPPDirective &&
952 UnwrappedLineFormatter::getColumnLimit(
bool InPPDirective,
953 const AnnotatedLine *NextLine)
const {
956 bool ContinuesPPDirective =
961 (NextLine->InPPDirective &&
964 !NextLine->First->HasUnescapedNewline));
965 return Style.ColumnLimit - (ContinuesPPDirective ? 2 : 0);
detail::InMemoryDirectory::const_iterator I
WhitespaceManager class manages whitespace around tokens and their replacements.
char __ovld __cnfn min(char x, char y)
Returns y if y < x, otherwise it returns x.
const TemplateArgument * iterator
ast_type_traits::DynTypedNode Node
if(T->getSizeExpr()) TRY_TO(TraverseStmt(T-> getSizeExpr()))
detail::InMemoryDirectory::const_iterator E