clang: lib/Format/WhitespaceManager.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

15#include "llvm/ADT/STLExtras.h"

16#include "llvm/ADT/SmallVector.h"

17#include

18

20namespace format {

21

32}

33

51}

52

54 unsigned Spaces,

55 unsigned StartOfTokenColumn,

56 bool IsAligned, bool InPPDirective) {

58 return;

61 Spaces, StartOfTokenColumn, Newlines, "", "",

62 IsAligned, InPPDirective && !Tok.IsFirst,

63 false));

64}

65

67 bool InPPDirective) {

69 return;

70 Changes.push_back(Change(Tok, false,

73 false, InPPDirective && !Tok.IsFirst,

74 false));

75}

76

77llvm::Error

79 return Replaces.add(Replacement);

80}

81

83 size_t LF = Text.count('\n');

84 size_t CR = Text.count('\r') * 2;

85 return LF == CR ? DefaultToCRLF : CR > LF;

86}

87

89 const FormatToken &Tok, unsigned Offset, unsigned ReplaceChars,

90 StringRef PreviousPostfix, StringRef CurrentPrefix, bool InPPDirective,

91 unsigned Newlines, int Spaces) {

93 return;

95 Changes.push_back(

96 Change(Tok, true,

98 std::max(0, Spaces), Newlines, PreviousPostfix, CurrentPrefix,

99 true, InPPDirective && !Tok.IsFirst,

100 true));

101}

102

104 if (Changes.empty())

105 return Replaces;

106

108 calculateLineBreakInformation();

109 alignConsecutiveMacros();

110 alignConsecutiveShortCaseStatements(true);

111 alignConsecutiveShortCaseStatements(false);

112 alignConsecutiveDeclarations();

113 alignConsecutiveBitFields();

114 alignConsecutiveAssignments();

116 alignConsecutiveTableGenBreakingDAGArgColons();

117 alignConsecutiveTableGenCondOperatorColons();

118 alignConsecutiveTableGenDefinitions();

119 }

120 alignChainedConditionals();

121 alignTrailingComments();

122 alignEscapedNewlines();

123 alignArrayInitializers();

124 generateChanges();

125

126 return Replaces;

127}

128

129void WhitespaceManager::calculateLineBreakInformation() {

130 Changes[0].PreviousEndOfTokenColumn = 0;

131 Change *LastOutsideTokenChange = &Changes[0];

132 for (unsigned I = 1, e = Changes.size(); I != e; ++I) {

133 auto &C = Changes[I];

134 auto &P = Changes[I - 1];

135 auto &PrevTokLength = P.TokenLength;

137 C.OriginalWhitespaceRange.getBegin();

139 P.OriginalWhitespaceRange.getEnd();

140 unsigned OriginalWhitespaceStartOffset =

141 SourceMgr.getFileOffset(OriginalWhitespaceStart);

142 unsigned PreviousOriginalWhitespaceEndOffset =

143 SourceMgr.getFileOffset(PreviousOriginalWhitespaceEnd);

144 assert(PreviousOriginalWhitespaceEndOffset <=

145 OriginalWhitespaceStartOffset);

146 const char *const PreviousOriginalWhitespaceEndData =

148 StringRef Text(PreviousOriginalWhitespaceEndData,

150 PreviousOriginalWhitespaceEndData);

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172 auto NewlinePos = Text.find_first_of('\n');

173 if (NewlinePos == StringRef::npos) {

174 PrevTokLength = OriginalWhitespaceStartOffset -

175 PreviousOriginalWhitespaceEndOffset +

176 C.PreviousLinePostfix.size() + P.CurrentLinePrefix.size();

177 if (P.IsInsideToken)

178 PrevTokLength = std::min(PrevTokLength, P.Tok->ColumnWidth);

179 } else {

180 PrevTokLength = NewlinePos + P.CurrentLinePrefix.size();

181 }

182

183

184

185 if (P.IsInsideToken && P.NewlinesBefore == 0)

186 LastOutsideTokenChange->TokenLength += PrevTokLength + P.Spaces;

187 else

188 LastOutsideTokenChange = &P;

189

190 C.PreviousEndOfTokenColumn = P.StartOfTokenColumn + PrevTokLength;

191

192 P.IsTrailingComment =

193 (C.NewlinesBefore > 0 || C.Tok->is(tok::eof) ||

194 (C.IsInsideToken && C.Tok->is(tok::comment))) &&

195 P.Tok->is(tok::comment) &&

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226 OriginalWhitespaceStart != PreviousOriginalWhitespaceEnd;

227 }

228

229

230 Changes.back().TokenLength = 0;

231 Changes.back().IsTrailingComment = Changes.back().Tok->is(tok::comment);

232

233 const WhitespaceManager::Change *LastBlockComment = nullptr;

234 for (auto &Change : Changes) {

235

236

237

238 if (Change.IsInsideToken && Change.NewlinesBefore == 0)

239 Change.IsTrailingComment = false;

240 Change.StartOfBlockComment = nullptr;

241 Change.IndentationOffset = 0;

242 if (Change.Tok->is(tok::comment)) {

243 if (Change.Tok->is(TT_LineComment) || !Change.IsInsideToken) {

244 LastBlockComment = &Change;

245 } else if ((Change.StartOfBlockComment = LastBlockComment)) {

246 Change.IndentationOffset =

247 Change.StartOfTokenColumn -

248 Change.StartOfBlockComment->StartOfTokenColumn;

249 }

250 } else {

251 LastBlockComment = nullptr;

252 }

253 }

254

255

256

257

258

259 SmallVector<bool, 16> ScopeStack;

260 int ConditionalsLevel = 0;

261 for (auto &Change : Changes) {

262 for (unsigned i = 0, e = Change.Tok->FakeLParens.size(); i != e; ++i) {

263 bool isNestedConditional =

265 !(i == 0 && Change.Tok->Previous &&

266 Change.Tok->Previous->is(TT_ConditionalExpr) &&

267 Change.Tok->Previous->is(tok::colon));

268 if (isNestedConditional)

269 ++ConditionalsLevel;

270 ScopeStack.push_back(isNestedConditional);

271 }

272

273 Change.ConditionalsLevel = ConditionalsLevel;

274

275 for (unsigned i = Change.Tok->FakeRParens; i > 0 && ScopeStack.size(); --i)

276 if (ScopeStack.pop_back_val())

277 --ConditionalsLevel;

278 }

279}

280

281

282

283

284

285template

286static void

288 unsigned Column, bool RightJustify, F &&Matches,

290 bool FoundMatchOnLine = false;

291 int Shift = 0;

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

314

315 for (unsigned i = Start; i != End; ++i) {

316 auto &CurrentChange = Changes[i];

317 if (ScopeStack.size() != 0 &&

318 CurrentChange.indentAndNestingLevel() <

319 Changes[ScopeStack.back()].indentAndNestingLevel()) {

320 ScopeStack.pop_back();

321 }

322

323

324

325 unsigned PreviousNonComment = i - 1;

326 while (PreviousNonComment > Start &&

327 Changes[PreviousNonComment].Tok->is(tok::comment)) {

328 --PreviousNonComment;

329 }

330 if (i != Start && CurrentChange.indentAndNestingLevel() >

331 Changes[PreviousNonComment].indentAndNestingLevel()) {

332 ScopeStack.push_back(i);

333 }

334

335 bool InsideNestedScope = ScopeStack.size() != 0;

336 bool ContinuedStringLiteral = i > Start &&

337 CurrentChange.Tok->is(tok::string_literal) &&

338 Changes[i - 1].Tok->is(tok::string_literal);

339 bool SkipMatchCheck = InsideNestedScope || ContinuedStringLiteral;

340

341 if (CurrentChange.NewlinesBefore > 0 && !SkipMatchCheck) {

342 Shift = 0;

343 FoundMatchOnLine = false;

344 }

345

346

347

348

349 if (!FoundMatchOnLine && !SkipMatchCheck && Matches(CurrentChange)) {

350 FoundMatchOnLine = true;

351 Shift = Column - (RightJustify ? CurrentChange.TokenLength : 0) -

352 CurrentChange.StartOfTokenColumn;

353 CurrentChange.Spaces += Shift;

354

355

356 if (CurrentChange.NewlinesBefore == 0) {

357 CurrentChange.Spaces =

358 std::max(CurrentChange.Spaces,

359 static_cast<int>(CurrentChange.Tok->SpacesRequiredBefore));

360 }

361 }

362

363 if (Shift == 0)

364 continue;

365

366

367

368 if (InsideNestedScope && CurrentChange.NewlinesBefore > 0) {

369 unsigned ScopeStart = ScopeStack.back();

370 auto ShouldShiftBeAdded = [&] {

371

372 if (Changes[ScopeStart - 1].Tok->is(TT_FunctionDeclarationName))

373 return true;

374

375

376 if (Changes[ScopeStart - 1].Tok->is(TT_LambdaLBrace))

377 return false;

378

379

380 if (ScopeStart > Start + 1 &&

381 Changes[ScopeStart - 2].Tok->is(TT_FunctionDeclarationName)) {

382 return true;

383 }

384

385

386 if (ScopeStart > Start + 1 &&

387 Changes[ScopeStart - 2].Tok->isOneOf(tok::identifier,

388 TT_TemplateCloser) &&

389 Changes[ScopeStart - 1].Tok->is(tok::l_paren) &&

390 Changes[ScopeStart].Tok->isNot(TT_LambdaLSquare)) {

391 if (CurrentChange.Tok->MatchingParen &&

392 CurrentChange.Tok->MatchingParen->is(TT_LambdaLBrace)) {

393 return false;

394 }

395 if (Changes[ScopeStart].NewlinesBefore > 0)

396 return false;

397 if (CurrentChange.Tok->is(tok::l_brace) &&

399 return true;

400 }

401 return Style.BinPackArguments;

402 }

403

404

405 if (CurrentChange.Tok->is(TT_ConditionalExpr))

406 return true;

407

408

409 if (CurrentChange.Tok->is(TT_DesignatedInitializerPeriod))

410 return true;

411

412

413 if (CurrentChange.Tok->Previous &&

414 CurrentChange.Tok->Previous->is(TT_ConditionalExpr)) {

415 return true;

416 }

417

418

419 if (ScopeStart > Start + 1 &&

420 Changes[ScopeStart - 2].Tok->is(tok::identifier) &&

421 Changes[ScopeStart - 1].Tok->is(tok::l_brace) &&

422 CurrentChange.Tok->is(tok::l_brace) &&

424 return true;

425 }

426

427

428 if (ScopeStart > Start + 1 &&

429 Changes[ScopeStart - 2].Tok->isNot(tok::identifier) &&

430 Changes[ScopeStart - 1].Tok->is(tok::l_brace) &&

431 CurrentChange.Tok->isNot(tok::r_brace)) {

432 for (unsigned OuterScopeStart : llvm::reverse(ScopeStack)) {

433

434 if (OuterScopeStart > Start &&

435 Changes[OuterScopeStart - 1].Tok->is(TT_LambdaLBrace)) {

436 return false;

437 }

438 }

439 if (Changes[ScopeStart].NewlinesBefore > 0)

440 return false;

441 return true;

442 }

443

444

445 if (Changes[ScopeStart - 1].Tok->is(TT_TemplateOpener))

446 return true;

447

448 return false;

449 };

450

451 if (ShouldShiftBeAdded())

452 CurrentChange.Spaces += Shift;

453 }

454

455 if (ContinuedStringLiteral)

456 CurrentChange.Spaces += Shift;

457

458

459 assert(Shift > 0 || Changes[i].NewlinesBefore > 0 ||

460 CurrentChange.Spaces >=

461 static_cast<int>(Changes[i].Tok->SpacesRequiredBefore) ||

462 CurrentChange.Tok->is(tok::eof));

463

464 CurrentChange.StartOfTokenColumn += Shift;

465 if (i + 1 != Changes.size())

466 Changes[i + 1].PreviousEndOfTokenColumn += Shift;

467

468

469

472 CurrentChange.Spaces != 0 &&

473 !CurrentChange.Tok->isOneOf(tok::equal, tok::r_paren,

474 TT_TemplateCloser)) {

475 const bool ReferenceNotRightAligned =

479 Previous >= 0 && Changes[Previous].Tok->is(TT_PointerOrReference);

481 assert(Changes[Previous].Tok->isPointerOrReference());

482 if (Changes[Previous].Tok->isNot(tok::star)) {

483 if (ReferenceNotRightAligned)

484 continue;

486 continue;

487 }

488 Changes[Previous + 1].Spaces -= Shift;

489 Changes[Previous].Spaces += Shift;

490 Changes[Previous].StartOfTokenColumn += Shift;

491 }

492 }

493 }

494}

495

496

497

498

499

500

501

502

503

504

505

506

507

508

509

510

511

512

513

514

515

516

517

518

519

520

521

522

523

524

525

526

527template

530 unsigned StartAt,

532 bool RightJustify = false) {

533

534

535

536

537

538

539

540

541 unsigned WidthLeft = 0;

542

543

544 unsigned WidthAnchor = 0;

545

546

547 unsigned WidthRight = 0;

548

549

550 unsigned StartOfSequence = 0;

551 unsigned EndOfSequence = 0;

552

553

554

555 auto IndentAndNestingLevel = StartAt < Changes.size()

556 ? Changes[StartAt].indentAndNestingLevel()

557 : std::tuple<unsigned, unsigned, unsigned>();

558

559

560

561

562 unsigned CommasBeforeLastMatch = 0;

563 unsigned CommasBeforeMatch = 0;

564

565

566 bool FoundMatchOnLine = false;

567

568

569 bool LineIsComment = true;

570

571

572

573

574

575

576

577

578 auto AlignCurrentSequence = [&] {

579 if (StartOfSequence > 0 && StartOfSequence < EndOfSequence) {

581 WidthLeft + WidthAnchor, RightJustify, Matches,

582 Changes);

583 }

584 WidthLeft = 0;

585 WidthAnchor = 0;

586 WidthRight = 0;

587 StartOfSequence = 0;

588 EndOfSequence = 0;

589 };

590

591 unsigned i = StartAt;

592 for (unsigned e = Changes.size(); i != e; ++i) {

593 auto &CurrentChange = Changes[i];

594 if (CurrentChange.indentAndNestingLevel() < IndentAndNestingLevel)

595 break;

596

597 if (CurrentChange.NewlinesBefore != 0) {

598 CommasBeforeMatch = 0;

599 EndOfSequence = i;

600

601

602 bool EmptyLineBreak =

603 (CurrentChange.NewlinesBefore > 1) && !ACS.AcrossEmptyLines;

604

605

606

607 bool NoMatchBreak =

608 !FoundMatchOnLine && !(LineIsComment && ACS.AcrossComments);

609

610 if (EmptyLineBreak || NoMatchBreak)

611 AlignCurrentSequence();

612

613

614

615 if (i == 0 || CurrentChange.Tok->isNot(tok::string_literal) ||

616 Changes[i - 1].Tok->isNot(tok::string_literal)) {

617 FoundMatchOnLine = false;

618 }

619 LineIsComment = true;

620 }

621

622 if (CurrentChange.Tok->isNot(tok::comment))

623 LineIsComment = false;

624

625 if (CurrentChange.Tok->is(tok::comma)) {

626 ++CommasBeforeMatch;

627 } else if (CurrentChange.indentAndNestingLevel() > IndentAndNestingLevel) {

628

629 unsigned StoppedAt =

630 AlignTokens(Style, Matches, Changes, i, ACS, RightJustify);

631 i = StoppedAt - 1;

632 continue;

633 }

634

635 if (!Matches(CurrentChange))

636 continue;

637

638

639

640 if (FoundMatchOnLine || CommasBeforeMatch != CommasBeforeLastMatch)

641 AlignCurrentSequence();

642

643 CommasBeforeLastMatch = CommasBeforeMatch;

644 FoundMatchOnLine = true;

645

646 if (StartOfSequence == 0)

647 StartOfSequence = i;

648

649 unsigned ChangeWidthLeft = CurrentChange.StartOfTokenColumn;

650 unsigned ChangeWidthAnchor = 0;

651 unsigned ChangeWidthRight = 0;

652 if (RightJustify)

653 if (ACS.PadOperators)

654 ChangeWidthAnchor = CurrentChange.TokenLength;

655 else

656 ChangeWidthLeft += CurrentChange.TokenLength;

657 else

658 ChangeWidthRight = CurrentChange.TokenLength;

659 for (unsigned j = i + 1; j != e && Changes[j].NewlinesBefore == 0; ++j) {

660 ChangeWidthRight += Changes[j].Spaces;

661

662

663

664

665

666 if (!Changes[j].IsInsideToken)

667 ChangeWidthRight += Changes[j].TokenLength;

668 }

669

670

671 unsigned NewLeft = std::max(ChangeWidthLeft, WidthLeft);

672 unsigned NewAnchor = std::max(ChangeWidthAnchor, WidthAnchor);

673 unsigned NewRight = std::max(ChangeWidthRight, WidthRight);

674

675 if (Style.ColumnLimit != 0 &&

676 Style.ColumnLimit < NewLeft + NewAnchor + NewRight) {

677 AlignCurrentSequence();

678 StartOfSequence = i;

679 WidthLeft = ChangeWidthLeft;

680 WidthAnchor = ChangeWidthAnchor;

681 WidthRight = ChangeWidthRight;

682 } else {

683 WidthLeft = NewLeft;

684 WidthAnchor = NewAnchor;

685 WidthRight = NewRight;

686 }

687 }

688

689 EndOfSequence = i;

690 AlignCurrentSequence();

691 return i;

692}

693

694

695

696

697

698

699

700

702 unsigned &StartOfSequence, unsigned &EndOfSequence, unsigned &MinColumn,

705 if (StartOfSequence > 0 && StartOfSequence < EndOfSequence) {

706 bool FoundMatchOnLine = false;

707 int Shift = 0;

708

709 for (unsigned I = StartOfSequence; I != EndOfSequence; ++I) {

710 if (Changes[I].NewlinesBefore > 0) {

711 Shift = 0;

712 FoundMatchOnLine = false;

713 }

714

715

716

717

718 if (!FoundMatchOnLine && Matches(Changes[I])) {

719 FoundMatchOnLine = true;

720 Shift = MinColumn - Changes[I].StartOfTokenColumn;

721 Changes[I].Spaces += Shift;

722 }

723

724 assert(Shift >= 0);

725 Changes[I].StartOfTokenColumn += Shift;

726 if (I + 1 != Changes.size())

727 Changes[I + 1].PreviousEndOfTokenColumn += Shift;

728 }

729 }

730

731 MinColumn = 0;

732 StartOfSequence = 0;

733 EndOfSequence = 0;

734}

735

736void WhitespaceManager::alignConsecutiveMacros() {

737 if (!Style.AlignConsecutiveMacros.Enabled)

738 return;

739

740 auto AlignMacrosMatches = [](const Change &C) {

741 const FormatToken *Current = C.Tok;

742 unsigned SpacesRequiredBefore = 1;

743

744 if (Current->SpacesRequiredBefore == 0 || !Current->Previous)

745 return false;

746

747 Current = Current->Previous;

748

749

750

751 if (Current->is(tok::r_paren) && Current->MatchingParen) {

752 Current = Current->MatchingParen->Previous;

753 SpacesRequiredBefore = 0;

754 }

755

756 if (!Current || Current->isNot(tok::identifier))

757 return false;

758

759 if (!Current->Previous || Current->Previous->isNot(tok::pp_define))

760 return false;

761

762

763

764

765

766 return Current->Next->SpacesRequiredBefore == SpacesRequiredBefore;

767 };

768

769 unsigned MinColumn = 0;

770

771

772 unsigned StartOfSequence = 0;

773 unsigned EndOfSequence = 0;

774

775

776 bool FoundMatchOnLine = false;

777

778

779 bool LineIsComment = true;

780

781 unsigned I = 0;

782 for (unsigned E = Changes.size(); I != E; ++I) {

783 if (Changes[I].NewlinesBefore != 0) {

784 EndOfSequence = I;

785

786

787 bool EmptyLineBreak = (Changes[I].NewlinesBefore > 1) &&

788 !Style.AlignConsecutiveMacros.AcrossEmptyLines;

789

790

791

792 bool NoMatchBreak =

793 !FoundMatchOnLine &&

794 !(LineIsComment && Style.AlignConsecutiveMacros.AcrossComments);

795

796 if (EmptyLineBreak || NoMatchBreak) {

798 AlignMacrosMatches, Changes);

799 }

800

801

802 FoundMatchOnLine = false;

803 LineIsComment = true;

804 }

805

806 if (Changes[I].Tok->isNot(tok::comment))

807 LineIsComment = false;

808

809 if (!AlignMacrosMatches(Changes[I]))

810 continue;

811

812 FoundMatchOnLine = true;

813

814 if (StartOfSequence == 0)

815 StartOfSequence = I;

816

817 unsigned ChangeMinColumn = Changes[I].StartOfTokenColumn;

818 MinColumn = std::max(MinColumn, ChangeMinColumn);

819 }

820

821 EndOfSequence = I;

823 AlignMacrosMatches, Changes);

824}

825

826void WhitespaceManager::alignConsecutiveAssignments() {

827 if (!Style.AlignConsecutiveAssignments.Enabled)

828 return;

829

831 Style,

832 [&](const Change &C) {

833

834 if (C.NewlinesBefore > 0)

835 return false;

836

837

838 if (&C != &Changes.back() && (&C + 1)->NewlinesBefore > 0)

839 return false;

840

841

842 FormatToken *Previous = C.Tok->getPreviousNonComment();

844 return false;

845

846 return Style.AlignConsecutiveAssignments.AlignCompound

848 : (C.Tok->is(tok::equal) ||

849

850

851

852 (Style.isVerilog() && C.Tok->is(tok::lessequal) &&

854 },

855 Changes, 0, Style.AlignConsecutiveAssignments,

856 true);

857}

858

859void WhitespaceManager::alignConsecutiveBitFields() {

860 alignConsecutiveColons(Style.AlignConsecutiveBitFields, TT_BitFieldColon);

861}

862

863void WhitespaceManager::alignConsecutiveColons(

864 const FormatStyle::AlignConsecutiveStyle &AlignStyle, TokenType Type) {

865 if (!AlignStyle.Enabled)

866 return;

867

869 Style,

870 [&](Change const &C) {

871

872 if (C.NewlinesBefore > 0)

873 return false;

874

875

876 if (&C != &Changes.back() && (&C + 1)->NewlinesBefore > 0)

877 return false;

878

879 return C.Tok->is(Type);

880 },

881 Changes, 0, AlignStyle);

882}

883

884void WhitespaceManager::alignConsecutiveShortCaseStatements(bool IsExpr) {

885 if (!Style.AlignConsecutiveShortCaseStatements.Enabled ||

886 !(IsExpr ? Style.AllowShortCaseExpressionOnASingleLine

887 : Style.AllowShortCaseLabelsOnASingleLine)) {

888 return;

889 }

890

891 const auto Type = IsExpr ? TT_CaseLabelArrow : TT_CaseLabelColon;

892 const auto &Option = Style.AlignConsecutiveShortCaseStatements;

893 const bool AlignArrowOrColon =

894 IsExpr ? Option.AlignCaseArrows : Option.AlignCaseColons;

895

896 auto Matches = [&](const Change &C) {

897 if (AlignArrowOrColon)

898 return C.Tok->is(Type);

899

900

901

902

903

904 return C.IsInsideToken && C.Tok->Previous && C.Tok->Previous->is(Type);

905 };

906

907 unsigned MinColumn = 0;

908

909

910

911

912 unsigned MinEmptyCaseColumn = 0;

913

914

915 unsigned StartOfSequence = 0;

916 unsigned EndOfSequence = 0;

917

918

919 bool FoundMatchOnLine = false;

920

921 bool LineIsComment = true;

922 bool LineIsEmptyCase = false;

923

924 unsigned I = 0;

925 for (unsigned E = Changes.size(); I != E; ++I) {

926 if (Changes[I].NewlinesBefore != 0) {

927

928 bool EmptyLineBreak =

929 (Changes[I].NewlinesBefore > 1) &&

930 !Style.AlignConsecutiveShortCaseStatements.AcrossEmptyLines;

931

932

933

934 bool NoMatchBreak =

935 !FoundMatchOnLine &&

936 !(LineIsComment &&

937 Style.AlignConsecutiveShortCaseStatements.AcrossComments) &&

938 !LineIsEmptyCase;

939

940 if (EmptyLineBreak || NoMatchBreak) {

942 Matches, Changes);

943 MinEmptyCaseColumn = 0;

944 }

945

946

947 FoundMatchOnLine = false;

948 LineIsComment = true;

949 LineIsEmptyCase = false;

950 }

951

952 if (Changes[I].Tok->isNot(tok::comment))

953 LineIsComment = false;

954

955 if (Changes[I].Tok->is(Type)) {

956 LineIsEmptyCase =

957 !Changes[I].Tok->Next || Changes[I].Tok->Next->isTrailingComment();

958

959 if (LineIsEmptyCase) {

960 if (Style.AlignConsecutiveShortCaseStatements.AlignCaseColons) {

961 MinEmptyCaseColumn =

962 std::max(MinEmptyCaseColumn, Changes[I].StartOfTokenColumn);

963 } else {

964 MinEmptyCaseColumn =

965 std::max(MinEmptyCaseColumn, Changes[I].StartOfTokenColumn + 2);

966 }

967 }

968 }

969

970 if (!Matches(Changes[I]))

971 continue;

972

973 if (LineIsEmptyCase)

974 continue;

975

976 FoundMatchOnLine = true;

977

978 if (StartOfSequence == 0)

979 StartOfSequence = I;

980

981 EndOfSequence = I + 1;

982

983 MinColumn = std::max(MinColumn, Changes[I].StartOfTokenColumn);

984

985

986 MinColumn = std::max(MinColumn, MinEmptyCaseColumn);

987 }

988

990 Changes);

991}

992

993void WhitespaceManager::alignConsecutiveTableGenBreakingDAGArgColons() {

994 alignConsecutiveColons(Style.AlignConsecutiveTableGenBreakingDAGArgColons,

995 TT_TableGenDAGArgListColonToAlign);

996}

997

998void WhitespaceManager::alignConsecutiveTableGenCondOperatorColons() {

999 alignConsecutiveColons(Style.AlignConsecutiveTableGenCondOperatorColons,

1000 TT_TableGenCondOperatorColon);

1001}

1002

1003void WhitespaceManager::alignConsecutiveTableGenDefinitions() {

1004 alignConsecutiveColons(Style.AlignConsecutiveTableGenDefinitionColons,

1005 TT_InheritanceColon);

1006}

1007

1008void WhitespaceManager::alignConsecutiveDeclarations() {

1009 if (!Style.AlignConsecutiveDeclarations.Enabled)

1010 return;

1011

1013 Style,

1014 [&](Change const &C) {

1015 if (Style.AlignConsecutiveDeclarations.AlignFunctionPointers) {

1016 for (const auto *Prev = C.Tok->Previous; Prev; Prev = Prev->Previous)

1017 if (Prev->is(tok::equal))

1018 return false;

1019 if (C.Tok->is(TT_FunctionTypeLParen))

1020 return true;

1021 }

1022 if (C.Tok->is(TT_FunctionDeclarationName))

1023 return Style.AlignConsecutiveDeclarations.AlignFunctionDeclarations;

1024 if (C.Tok->isNot(TT_StartOfName))

1025 return false;

1026 if (C.Tok->Previous &&

1027 C.Tok->Previous->is(TT_StatementAttributeLikeMacro))

1028 return false;

1029

1030 for (FormatToken *Next = C.Tok->Next; Next; Next = Next->Next) {

1031 if (Next->is(tok::comment))

1032 continue;

1033 if (Next->is(TT_PointerOrReference))

1034 return false;

1035 if (!Next->Tok.getIdentifierInfo())

1036 break;

1037 if (Next->isOneOf(TT_StartOfName, TT_FunctionDeclarationName,

1038 tok::kw_operator)) {

1039 return false;

1040 }

1041 }

1042 return true;

1043 },

1044 Changes, 0, Style.AlignConsecutiveDeclarations);

1045}

1046

1047void WhitespaceManager::alignChainedConditionals() {

1048 if (Style.BreakBeforeTernaryOperators) {

1050 Style,

1051 [](Change const &C) {

1052

1053 return C.Tok->is(TT_ConditionalExpr) &&

1054 ((C.Tok->is(tok::question) && C.NewlinesBefore) ||

1055 (C.Tok->is(tok::colon) && C.Tok->Next &&

1056 (C.Tok->Next->FakeLParens.size() == 0 ||

1058 },

1059 Changes, 0);

1060 } else {

1061 static auto AlignWrappedOperand = [](Change const &C) {

1062 FormatToken *Previous = C.Tok->getPreviousNonComment();

1063 return C.NewlinesBefore && Previous && Previous->is(TT_ConditionalExpr) &&

1064 (Previous->is(tok::colon) &&

1065 (C.Tok->FakeLParens.size() == 0 ||

1067 };

1068

1069

1070

1071 for (Change &C : Changes)

1072 if (AlignWrappedOperand(C))

1073 C.StartOfTokenColumn -= 2;

1075 Style,

1076 [this](Change const &C) {

1077

1078

1079

1080 return (C.Tok->is(TT_ConditionalExpr) && C.Tok->is(tok::question) &&

1081 &C != &Changes.back() && (&C + 1)->NewlinesBefore == 0 &&

1082 !(&C + 1)->IsTrailingComment) ||

1083 AlignWrappedOperand(C);

1084 },

1085 Changes, 0);

1086 }

1087}

1088

1089void WhitespaceManager::alignTrailingComments() {

1091 return;

1092

1093 const int Size = Changes.size();

1094 int MinColumn = 0;

1095 int StartOfSequence = 0;

1096 bool BreakBeforeNext = false;

1097 int NewLineThreshold = 1;

1099 NewLineThreshold = Style.AlignTrailingComments.OverEmptyLines + 1;

1100

1101 for (int I = 0, MaxColumn = INT_MAX, Newlines = 0; I < Size; ++I) {

1102 auto &C = Changes[I];

1103 if (C.StartOfBlockComment)

1104 continue;

1105 Newlines += C.NewlinesBefore;

1106 if (C.IsTrailingComment)

1107 continue;

1108

1110 const int OriginalSpaces =

1111 C.OriginalWhitespaceRange.getEnd().getRawEncoding() -

1112 C.OriginalWhitespaceRange.getBegin().getRawEncoding() -

1113 C.Tok->LastNewlineOffset;

1114 assert(OriginalSpaces >= 0);

1115 const auto RestoredLineLength =

1116 C.StartOfTokenColumn + C.TokenLength + OriginalSpaces;

1117

1118

1119 if (RestoredLineLength >= Style.ColumnLimit && Style.ColumnLimit > 0)

1120 break;

1121 C.Spaces = C.NewlinesBefore > 0 ? C.Tok->OriginalColumn : OriginalSpaces;

1122 continue;

1123 }

1124

1125 const int ChangeMinColumn = C.StartOfTokenColumn;

1126 int ChangeMaxColumn;

1127

1128

1129

1130 if (C.CreateReplacement)

1131 ChangeMaxColumn = ChangeMinColumn;

1132 else if (Style.ColumnLimit == 0)

1133 ChangeMaxColumn = INT_MAX;

1134 else if (Style.ColumnLimit >= C.TokenLength)

1135 ChangeMaxColumn = Style.ColumnLimit - C.TokenLength;

1136 else

1137 ChangeMaxColumn = ChangeMinColumn;

1138

1139 if (I + 1 < Size && Changes[I + 1].ContinuesPPDirective &&

1140 ChangeMaxColumn >= 2) {

1141 ChangeMaxColumn -= 2;

1142 }

1143

1144 bool WasAlignedWithStartOfNextLine = false;

1145 if (C.NewlinesBefore >= 1) {

1146 const auto CommentColumn =

1148 for (int J = I + 1; J < Size; ++J) {

1149 if (Changes[J].Tok->is(tok::comment))

1150 continue;

1151

1153 Changes[J].OriginalWhitespaceRange.getEnd());

1154

1155

1156 WasAlignedWithStartOfNextLine =

1157 CommentColumn == NextColumn ||

1158 CommentColumn == NextColumn + Style.IndentWidth;

1159 break;

1160 }

1161 }

1162

1163

1164

1165 auto DontAlignThisComment = [](const auto *Tok) {

1166 if (Tok->is(tok::semi)) {

1167 Tok = Tok->getPreviousNonComment();

1168 if (!Tok)

1169 return false;

1170 }

1171 if (Tok->is(tok::r_paren)) {

1172

1173 Tok = Tok->MatchingParen;

1174 if (!Tok)

1175 return false;

1176 Tok = Tok->getPreviousNonComment();

1177 if (!Tok)

1178 return false;

1179 if (Tok->is(TT_DoWhile)) {

1180 const auto *Prev = Tok->getPreviousNonComment();

1181 if (!Prev) {

1182

1183 return true;

1184 }

1185 Tok = Prev;

1186 }

1187 }

1188

1189 if (Tok->isNot(tok::r_brace))

1190 return false;

1191

1192 while (Tok->Previous && Tok->Previous->is(tok::r_brace))

1193 Tok = Tok->Previous;

1194 return Tok->NewlinesBefore > 0;

1195 };

1196

1197 if (I > 0 && C.NewlinesBefore == 0 &&

1198 DontAlignThisComment(Changes[I - 1].Tok)) {

1199 alignTrailingComments(StartOfSequence, I, MinColumn);

1200

1201

1202 MinColumn = 0;

1204 StartOfSequence = I + 1;

1205 } else if (BreakBeforeNext || Newlines > NewLineThreshold ||

1206 (ChangeMinColumn > MaxColumn || ChangeMaxColumn < MinColumn) ||

1207

1208

1209 (C.NewlinesBefore == 1 && I > 0 &&

1210 !Changes[I - 1].IsTrailingComment) ||

1211 WasAlignedWithStartOfNextLine) {

1212 alignTrailingComments(StartOfSequence, I, MinColumn);

1213 MinColumn = ChangeMinColumn;

1214 MaxColumn = ChangeMaxColumn;

1215 StartOfSequence = I;

1216 } else {

1217 MinColumn = std::max(MinColumn, ChangeMinColumn);

1218 MaxColumn = std::min(MaxColumn, ChangeMaxColumn);

1219 }

1220 BreakBeforeNext = (I == 0) || (C.NewlinesBefore > 1) ||

1221

1222

1223 (C.NewlinesBefore == 1 && StartOfSequence == I);

1224 Newlines = 0;

1225 }

1226 alignTrailingComments(StartOfSequence, Size, MinColumn);

1227}

1228

1229void WhitespaceManager::alignTrailingComments(unsigned Start, unsigned End,

1231 for (unsigned i = Start; i != End; ++i) {

1233 if (Changes[i].IsTrailingComment)

1234 Shift = Column - Changes[i].StartOfTokenColumn;

1235 if (Changes[i].StartOfBlockComment) {

1236 Shift = Changes[i].IndentationOffset +

1237 Changes[i].StartOfBlockComment->StartOfTokenColumn -

1238 Changes[i].StartOfTokenColumn;

1239 }

1240 if (Shift <= 0)

1241 continue;

1242 Changes[i].Spaces += Shift;

1243 if (i + 1 != Changes.size())

1244 Changes[i + 1].PreviousEndOfTokenColumn += Shift;

1245 Changes[i].StartOfTokenColumn += Shift;

1246 }

1247}

1248

1249void WhitespaceManager::alignEscapedNewlines() {

1250 const auto Align = Style.AlignEscapedNewlines;

1252 return;

1253

1256 const auto MaxColumn = Style.ColumnLimit;

1257 unsigned MaxEndOfLine = AlignLeft ? 0 : MaxColumn;

1258 unsigned StartOfMacro = 0;

1259 for (unsigned i = 1, e = Changes.size(); i < e; ++i) {

1260 Change &C = Changes[i];

1261 if (C.NewlinesBefore == 0 && (!WithLastLine || C.Tok->isNot(tok::eof)))

1262 continue;

1263 const bool InPPDirective = C.ContinuesPPDirective;

1264 const auto BackslashColumn = C.PreviousEndOfTokenColumn + 2;

1265 if (InPPDirective ||

1266 (WithLastLine && (MaxColumn == 0 || BackslashColumn <= MaxColumn))) {

1267 MaxEndOfLine = std::max(BackslashColumn, MaxEndOfLine);

1268 }

1269 if (!InPPDirective) {

1270 alignEscapedNewlines(StartOfMacro + 1, i, MaxEndOfLine);

1271 MaxEndOfLine = AlignLeft ? 0 : MaxColumn;

1272 StartOfMacro = i;

1273 }

1274 }

1275 alignEscapedNewlines(StartOfMacro + 1, Changes.size(), MaxEndOfLine);

1276}

1277

1278void WhitespaceManager::alignEscapedNewlines(unsigned Start, unsigned End,

1280 for (unsigned i = Start; i < End; ++i) {

1281 Change &C = Changes[i];

1282 if (C.NewlinesBefore > 0) {

1283 assert(C.ContinuesPPDirective);

1284 if (C.PreviousEndOfTokenColumn + 1 > Column)

1285 C.EscapedNewlineColumn = 0;

1286 else

1287 C.EscapedNewlineColumn = Column;

1288 }

1289 }

1290}

1291

1292void WhitespaceManager::alignArrayInitializers() {

1294 return;

1295

1296 for (unsigned ChangeIndex = 1U, ChangeEnd = Changes.size();

1297 ChangeIndex < ChangeEnd; ++ChangeIndex) {

1298 auto &C = Changes[ChangeIndex];

1299 if (C.Tok->IsArrayInitializer) {

1300 bool FoundComplete = false;

1301 for (unsigned InsideIndex = ChangeIndex + 1; InsideIndex < ChangeEnd;

1302 ++InsideIndex) {

1303 if (Changes[InsideIndex].Tok == C.Tok->MatchingParen) {

1304 alignArrayInitializers(ChangeIndex, InsideIndex + 1);

1305 ChangeIndex = InsideIndex + 1;

1306 FoundComplete = true;

1307 break;

1308 }

1309 }

1310 if (!FoundComplete)

1311 ChangeIndex = ChangeEnd;

1312 }

1313 }

1314}

1315

1316void WhitespaceManager::alignArrayInitializers(unsigned Start, unsigned End) {

1317

1319 alignArrayInitializersRightJustified(getCells(Start, End));

1321 alignArrayInitializersLeftJustified(getCells(Start, End));

1322}

1323

1324void WhitespaceManager::alignArrayInitializersRightJustified(

1325 CellDescriptions &&CellDescs) {

1326 if (!CellDescs.isRectangular())

1327 return;

1328

1329 const int BracePadding = Style.Cpp11BracedListStyle ? 0 : 1;

1330 auto &Cells = CellDescs.Cells;

1331

1332 auto *CellIter = Cells.begin();

1333 for (auto i = 0U; i < CellDescs.CellCounts[0]; ++i, ++CellIter) {

1334 unsigned NetWidth = 0U;

1335 if (isSplitCell(*CellIter))

1336 NetWidth = getNetWidth(Cells.begin(), CellIter, CellDescs.InitialSpaces);

1337 auto CellWidth = getMaximumCellWidth(CellIter, NetWidth);

1338

1339 if (Changes[CellIter->Index].Tok->is(tok::r_brace)) {

1340

1341

1342

1343 const auto *Next = CellIter;

1344 do {

1345 const FormatToken *Previous = Changes[Next->Index].Tok->Previous;

1347 Changes[Next->Index].Spaces = BracePadding;

1348 Changes[Next->Index].NewlinesBefore = 0;

1349 }

1350 Next = Next->NextColumnElement;

1351 } while (Next);

1352

1353

1354 if (CellIter != Cells.begin()) {

1355 auto ThisNetWidth =

1356 getNetWidth(Cells.begin(), CellIter, CellDescs.InitialSpaces);

1357 auto MaxNetWidth = getMaximumNetWidth(

1358 Cells.begin(), CellIter, CellDescs.InitialSpaces,

1359 CellDescs.CellCounts[0], CellDescs.CellCounts.size());

1360 if (ThisNetWidth < MaxNetWidth)

1361 Changes[CellIter->Index].Spaces = (MaxNetWidth - ThisNetWidth);

1362 auto RowCount = 1U;

1363 auto Offset = std::distance(Cells.begin(), CellIter);

1364 for (const auto *Next = CellIter->NextColumnElement; Next;

1365 Next = Next->NextColumnElement) {

1366 if (RowCount >= CellDescs.CellCounts.size())

1367 break;

1368 auto *Start = (Cells.begin() + RowCount * CellDescs.CellCounts[0]);

1369 auto *End = Start + Offset;

1370 ThisNetWidth = getNetWidth(Start, End, CellDescs.InitialSpaces);

1371 if (ThisNetWidth < MaxNetWidth)

1372 Changes[Next->Index].Spaces = (MaxNetWidth - ThisNetWidth);

1373 ++RowCount;

1374 }

1375 }

1376 } else {

1377 auto ThisWidth =

1378 calculateCellWidth(CellIter->Index, CellIter->EndIndex, true) +

1379 NetWidth;

1380 if (Changes[CellIter->Index].NewlinesBefore == 0) {

1381 Changes[CellIter->Index].Spaces = (CellWidth - (ThisWidth + NetWidth));

1382 Changes[CellIter->Index].Spaces += (i > 0) ? 1 : BracePadding;

1383 }

1384 alignToStartOfCell(CellIter->Index, CellIter->EndIndex);

1385 for (const auto *Next = CellIter->NextColumnElement; Next;

1386 Next = Next->NextColumnElement) {

1387 ThisWidth =

1388 calculateCellWidth(Next->Index, Next->EndIndex, true) + NetWidth;

1389 if (Changes[Next->Index].NewlinesBefore == 0) {

1390 Changes[Next->Index].Spaces = (CellWidth - ThisWidth);

1391 Changes[Next->Index].Spaces += (i > 0) ? 1 : BracePadding;

1392 }

1393 alignToStartOfCell(Next->Index, Next->EndIndex);

1394 }

1395 }

1396 }

1397}

1398

1399void WhitespaceManager::alignArrayInitializersLeftJustified(

1400 CellDescriptions &&CellDescs) {

1401

1402 if (!CellDescs.isRectangular())

1403 return;

1404

1405 const int BracePadding = Style.Cpp11BracedListStyle ? 0 : 1;

1406 auto &Cells = CellDescs.Cells;

1407

1408 auto *CellIter = Cells.begin();

1409

1410 for (const auto *Next = CellIter; Next; Next = Next->NextColumnElement) {

1411 auto &Change = Changes[Next->Index];

1412 Change.Spaces =

1413 Change.NewlinesBefore == 0 ? BracePadding : CellDescs.InitialSpaces;

1414 }

1415 ++CellIter;

1416 for (auto i = 1U; i < CellDescs.CellCounts[0]; i++, ++CellIter) {

1417 auto MaxNetWidth = getMaximumNetWidth(

1418 Cells.begin(), CellIter, CellDescs.InitialSpaces,

1419 CellDescs.CellCounts[0], CellDescs.CellCounts.size());

1420 auto ThisNetWidth =

1421 getNetWidth(Cells.begin(), CellIter, CellDescs.InitialSpaces);

1422 if (Changes[CellIter->Index].NewlinesBefore == 0) {

1423 Changes[CellIter->Index].Spaces =

1424 MaxNetWidth - ThisNetWidth +

1425 (Changes[CellIter->Index].Tok->isNot(tok::r_brace) ? 1

1426 : BracePadding);

1427 }

1428 auto RowCount = 1U;

1429 auto Offset = std::distance(Cells.begin(), CellIter);

1430 for (const auto *Next = CellIter->NextColumnElement; Next;

1431 Next = Next->NextColumnElement) {

1432 if (RowCount >= CellDescs.CellCounts.size())

1433 break;

1434 auto *Start = (Cells.begin() + RowCount * CellDescs.CellCounts[0]);

1435 auto *End = Start + Offset;

1436 auto ThisNetWidth = getNetWidth(Start, End, CellDescs.InitialSpaces);

1437 if (Changes[Next->Index].NewlinesBefore == 0) {

1438 Changes[Next->Index].Spaces =

1439 MaxNetWidth - ThisNetWidth +

1440 (Changes[Next->Index].Tok->isNot(tok::r_brace) ? 1 : BracePadding);

1441 }

1442 ++RowCount;

1443 }

1444 }

1445}

1446

1447bool WhitespaceManager::isSplitCell(const CellDescription &Cell) {

1448 if (Cell.HasSplit)

1449 return true;

1450 for (const auto *Next = Cell.NextColumnElement; Next;

1451 Next = Next->NextColumnElement) {

1452 if (Next->HasSplit)

1453 return true;

1454 }

1455 return false;

1456}

1457

1458WhitespaceManager::CellDescriptions WhitespaceManager::getCells(unsigned Start,

1459 unsigned End) {

1460

1461 unsigned Depth = 0;

1462 unsigned Cell = 0;

1463 SmallVector CellCounts;

1464 unsigned InitialSpaces = 0;

1465 unsigned InitialTokenLength = 0;

1466 unsigned EndSpaces = 0;

1467 SmallVector Cells;

1468 const FormatToken *MatchingParen = nullptr;

1469 for (unsigned i = Start; i < End; ++i) {

1470 auto &C = Changes[i];

1471 if (C.Tok->is(tok::l_brace))

1472 ++Depth;

1473 else if (C.Tok->is(tok::r_brace))

1474 --Depth;

1475 if (Depth == 2) {

1476 if (C.Tok->is(tok::l_brace)) {

1477 Cell = 0;

1478 MatchingParen = C.Tok->MatchingParen;

1479 if (InitialSpaces == 0) {

1480 InitialSpaces = C.Spaces + C.TokenLength;

1481 InitialTokenLength = C.TokenLength;

1482 auto j = i - 1;

1483 for (; Changes[j].NewlinesBefore == 0 && j > Start; --j) {

1484 InitialSpaces += Changes[j].Spaces + Changes[j].TokenLength;

1485 InitialTokenLength += Changes[j].TokenLength;

1486 }

1487 if (C.NewlinesBefore == 0) {

1488 InitialSpaces += Changes[j].Spaces + Changes[j].TokenLength;

1489 InitialTokenLength += Changes[j].TokenLength;

1490 }

1491 }

1492 } else if (C.Tok->is(tok::comma)) {

1493 if (!Cells.empty())

1494 Cells.back().EndIndex = i;

1495 if (const auto *Next = C.Tok->getNextNonComment();

1496 Next && Next->isNot(tok::r_brace)) {

1497 ++Cell;

1498 }

1499 }

1500 } else if (Depth == 1) {

1501 if (C.Tok == MatchingParen) {

1502 if (!Cells.empty())

1503 Cells.back().EndIndex = i;

1504 Cells.push_back(CellDescription{i, ++Cell, i + 1, false, nullptr});

1505 CellCounts.push_back(C.Tok->Previous->isNot(tok::comma) ? Cell + 1

1506 : Cell);

1507

1508 const auto *NextNonComment = C.Tok->getNextNonComment();

1509 while (NextNonComment && NextNonComment->is(tok::comma))

1510 NextNonComment = NextNonComment->getNextNonComment();

1511 auto j = i;

1512 while (j < End && Changes[j].Tok != NextNonComment)

1513 ++j;

1514 if (j < End && Changes[j].NewlinesBefore == 0 &&

1515 Changes[j].Tok->isNot(tok::r_brace)) {

1516 Changes[j].NewlinesBefore = 1;

1517

1518 Changes[j].Spaces = InitialSpaces - InitialTokenLength;

1519 }

1520 } else if (C.Tok->is(tok::comment) && C.Tok->NewlinesBefore == 0) {

1521

1522 C.Spaces = Changes[i - 1].Tok->is(tok::comma) ? 1 : 2;

1523 } else if (C.Tok->is(tok::l_brace)) {

1524

1525

1526 auto j = i - 1;

1527 for (; j > 0 && !Changes[j].Tok->ArrayInitializerLineStart; --j)

1528 ;

1529 EndSpaces = Changes[j].Spaces;

1530 }

1531 } else if (Depth == 0 && C.Tok->is(tok::r_brace)) {

1532 C.NewlinesBefore = 1;

1533 C.Spaces = EndSpaces;

1534 }

1535 if (C.Tok->StartsColumn) {

1536

1537

1538 bool HasSplit = false;

1539 if (Changes[i].NewlinesBefore > 0) {

1540

1541

1542

1543

1544

1545

1546

1547

1548

1549

1550

1551

1552

1553

1554 auto j = i - 1;

1555 if ((j - 1) > Start && Changes[j].Tok->is(tok::comma) &&

1556 Changes[j - 1].NewlinesBefore > 0) {

1557 --j;

1558 auto LineLimit = Changes[j].Spaces + Changes[j].TokenLength;

1559 if (LineLimit < Style.ColumnLimit) {

1560 Changes[i].NewlinesBefore = 0;

1561 Changes[i].Spaces = 1;

1562 }

1563 }

1564 }

1565 while (Changes[i].NewlinesBefore > 0 && Changes[i].Tok == C.Tok) {

1566 Changes[i].Spaces = InitialSpaces;

1567 ++i;

1568 HasSplit = true;

1569 }

1570 if (Changes[i].Tok != C.Tok)

1571 --i;

1572 Cells.push_back(CellDescription{i, Cell, i, HasSplit, nullptr});

1573 }

1574 }

1575

1576 return linkCells({Cells, CellCounts, InitialSpaces});

1577}

1578

1579unsigned WhitespaceManager::calculateCellWidth(unsigned Start, unsigned End,

1580 bool WithSpaces) const {

1581 unsigned CellWidth = 0;

1582 for (auto i = Start; i < End; i++) {

1583 if (Changes[i].NewlinesBefore > 0)

1584 CellWidth = 0;

1585 CellWidth += Changes[i].TokenLength;

1586 CellWidth += (WithSpaces ? Changes[i].Spaces : 0);

1587 }

1588 return CellWidth;

1589}

1590

1591void WhitespaceManager::alignToStartOfCell(unsigned Start, unsigned End) {

1592 if ((End - Start) <= 1)

1593 return;

1594

1595

1596 for (auto i = Start + 1; i < End; i++)

1597 if (Changes[i].NewlinesBefore > 0)

1598 Changes[i].Spaces = Changes[Start].Spaces;

1599}

1600

1601WhitespaceManager::CellDescriptions

1602WhitespaceManager::linkCells(CellDescriptions &&CellDesc) {

1603 auto &Cells = CellDesc.Cells;

1604 for (auto *CellIter = Cells.begin(); CellIter != Cells.end(); ++CellIter) {

1605 if (!CellIter->NextColumnElement && (CellIter + 1) != Cells.end()) {

1606 for (auto *NextIter = CellIter + 1; NextIter != Cells.end(); ++NextIter) {

1607 if (NextIter->Cell == CellIter->Cell) {

1608 CellIter->NextColumnElement = &(*NextIter);

1609 break;

1610 }

1611 }

1612 }

1613 }

1614 return std::move(CellDesc);

1615}

1616

1617void WhitespaceManager::generateChanges() {

1618 for (unsigned i = 0, e = Changes.size(); i != e; ++i) {

1619 const Change &C = Changes[i];

1620 if (i > 0) {

1621 auto Last = Changes[i - 1].OriginalWhitespaceRange;

1622 auto New = Changes[i].OriginalWhitespaceRange;

1623

1624

1625

1626

1627

1628

1629

1630

1631

1632

1633

1634

1635

1636

1637

1638

1639

1640

1641

1642

1643

1644

1645

1646

1647

1648

1649

1650

1651

1652

1653

1654

1655

1656

1657

1658

1659

1660

1661

1662

1663

1664 if (Last.getBegin() == New.getBegin() &&

1665 (Last.getEnd() != Last.getBegin() ||

1666 New.getEnd() == New.getBegin())) {

1667 continue;

1668 }

1669 }

1670 if (C.CreateReplacement) {

1671 std::string ReplacementText = C.PreviousLinePostfix;

1672 if (C.ContinuesPPDirective) {

1673 appendEscapedNewlineText(ReplacementText, C.NewlinesBefore,

1674 C.PreviousEndOfTokenColumn,

1675 C.EscapedNewlineColumn);

1676 } else {

1677 appendNewlineText(ReplacementText, C);

1678 }

1679

1680

1681 appendIndentText(

1682 ReplacementText, C.Tok->IndentLevel, std::max(0, C.Spaces),

1683 std::max((int)C.StartOfTokenColumn, C.Spaces) - std::max(0, C.Spaces),

1684 C.IsAligned);

1685 ReplacementText.append(C.CurrentLinePrefix);

1686 storeReplacement(C.OriginalWhitespaceRange, ReplacementText);

1687 }

1688 }

1689}

1690

1691void WhitespaceManager::storeReplacement(SourceRange Range, StringRef Text) {

1692 unsigned WhitespaceLength = SourceMgr.getFileOffset(Range.getEnd()) -

1694

1696 WhitespaceLength) == Text) {

1697 return;

1698 }

1699 auto Err = Replaces.add(tooling::Replacement(

1701

1702

1703 if (Err) {

1704 llvm::errs() << llvm::toString(std::move(Err)) << "\n";

1705 assert(false);

1706 }

1707}

1708

1709void WhitespaceManager::appendNewlineText(std::string &Text, const Change &C) {

1710 if (C.NewlinesBefore <= 0)

1711 return;

1712

1713 StringRef Newline = UseCRLF ? "\r\n" : "\n";

1714 Text.append(Newline);

1715

1716 if (C.Tok->HasFormFeedBefore)

1717 Text.append("\f");

1718

1719 for (unsigned I = 1; I < C.NewlinesBefore; ++I)

1720 Text.append(Newline);

1721}

1722

1723void WhitespaceManager::appendEscapedNewlineText(

1724 std::string &Text, unsigned Newlines, unsigned PreviousEndOfTokenColumn,

1725 unsigned EscapedNewlineColumn) {

1726 if (Newlines > 0) {

1727 unsigned Spaces =

1728 std::max(1, EscapedNewlineColumn - PreviousEndOfTokenColumn - 1);

1729 for (unsigned i = 0; i < Newlines; ++i) {

1730 Text.append(Spaces, ' ');

1731 Text.append(UseCRLF ? "\\\r\n" : "\\\n");

1732 Spaces = std::max(0, EscapedNewlineColumn - 1);

1733 }

1734 }

1735}

1736

1737void WhitespaceManager::appendIndentText(std::string &Text,

1738 unsigned IndentLevel, unsigned Spaces,

1739 unsigned WhitespaceStartColumn,

1740 bool IsAligned) {

1741 switch (Style.UseTab) {

1743 Text.append(Spaces, ' ');

1744 break;

1746 if (Style.TabWidth) {

1747 unsigned FirstTabWidth =

1748 Style.TabWidth - WhitespaceStartColumn % Style.TabWidth;

1749

1750

1751 if (Spaces < FirstTabWidth || Spaces == 1) {

1752 Text.append(Spaces, ' ');

1753 break;

1754 }

1755

1756 Spaces -= FirstTabWidth;

1757 Text.append("\t");

1758

1759 Text.append(Spaces / Style.TabWidth, '\t');

1760 Text.append(Spaces % Style.TabWidth, ' ');

1761 } else if (Spaces == 1) {

1762 Text.append(Spaces, ' ');

1763 }

1764 break;

1765 }

1767 if (WhitespaceStartColumn == 0) {

1768 unsigned Indentation = IndentLevel * Style.IndentWidth;

1769 Spaces = appendTabIndent(Text, Spaces, Indentation);

1770 }

1771 Text.append(Spaces, ' ');

1772 break;

1774 if (WhitespaceStartColumn == 0)

1775 Spaces = appendTabIndent(Text, Spaces, Spaces);

1776 Text.append(Spaces, ' ');

1777 break;

1779 if (WhitespaceStartColumn == 0) {

1780 unsigned Indentation =

1781 IsAligned ? IndentLevel * Style.IndentWidth : Spaces;

1782 Spaces = appendTabIndent(Text, Spaces, Indentation);

1783 }

1784 Text.append(Spaces, ' ');

1785 break;

1786 }

1787}

1788

1789unsigned WhitespaceManager::appendTabIndent(std::string &Text, unsigned Spaces,

1790 unsigned Indentation) {

1791

1792

1793 if (Indentation > Spaces)

1794 Indentation = Spaces;

1795 if (Style.TabWidth) {

1796 unsigned Tabs = Indentation / Style.TabWidth;

1797 Text.append(Tabs, '\t');

1798 Spaces -= Tabs * Style.TabWidth;

1799 }

1800 return Spaces;

1801}

1802

1803}

1804}

WhitespaceManager class manages whitespace around tokens and their replacements.

static CharSourceRange getCharRange(SourceRange R)

Encodes a location in the source.

SourceLocation getLocWithOffset(IntTy Offset) const

Return a source location with the specified offset from this SourceLocation.

unsigned getFileOffset(SourceLocation SpellingLoc) const

Returns the offset from the start of the file that the specified SourceLocation represents.

const char * getCharacterData(SourceLocation SL, bool *Invalid=nullptr) const

Return a pointer to the start of the specified location in the appropriate spelling MemoryBuffer.

unsigned getSpellingColumnNumber(SourceLocation Loc, bool *Invalid=nullptr) const

bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const

Determines the order of 2 source locations in the translation unit.

A trivial tuple used to represent a source range.

SourceLocation getEnd() const

SourceLocation getBegin() const

Functor to sort changes in original source order.

bool operator()(const Change &C1, const Change &C2) const

void replaceWhitespaceInToken(const FormatToken &Tok, unsigned Offset, unsigned ReplaceChars, StringRef PreviousPostfix, StringRef CurrentPrefix, bool InPPDirective, unsigned Newlines, int Spaces)

Inserts or replaces whitespace in the middle of a token.

void addUntouchableToken(const FormatToken &Tok, bool InPPDirective)

Adds information about an unchangeable token's whitespace.

static bool inputUsesCRLF(StringRef Text, bool DefaultToCRLF)

Infers whether the input is using CRLF.

llvm::Error addReplacement(const tooling::Replacement &Replacement)

const tooling::Replacements & generateReplacements()

Returns all the Replacements created during formatting.

void replaceWhitespace(FormatToken &Tok, unsigned Newlines, unsigned Spaces, unsigned StartOfTokenColumn, bool IsAligned=false, bool InPPDirective=false)

Replaces the whitespace in front of Tok.

@ MR_ExpandedArg

The token was expanded from a macro argument when formatting the expanded token sequence.

static void AlignMatchingTokenSequence(unsigned &StartOfSequence, unsigned &EndOfSequence, unsigned &MinColumn, std::function< bool(const WhitespaceManager::Change &C)> Matches, SmallVector< WhitespaceManager::Change, 16 > &Changes)

static unsigned AlignTokens(const FormatStyle &Style, F &&Matches, SmallVector< WhitespaceManager::Change, 16 > &Changes, unsigned StartAt, const FormatStyle::AlignConsecutiveStyle &ACS={}, bool RightJustify=false)

static void AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End, unsigned Column, bool RightJustify, F &&Matches, SmallVector< WhitespaceManager::Change, 16 > &Changes)

TokenType

Determines the semantic type of a syntactic token, e.g.

The JSON file list parser is used to communicate input to InstallAPI.

if(T->getSizeExpr()) TRY_TO(TraverseStmt(const_cast< Expr * >(T -> getSizeExpr())))

for(const auto &A :T->param_types())

The FormatStyle is used to configure the formatting to follow specific guidelines.

@ UT_AlignWithSpaces

Use tabs for line continuation and indentation, and spaces for alignment.

@ UT_ForContinuationAndIndentation

Fill all leading whitespace with tabs, and use spaces for alignment that appears within a line (e....

@ UT_ForIndentation

Use tabs only for indentation.

@ UT_Always

Use tabs whenever we need to fill whitespace that spans at least from one tab stop to the next one.

@ TCAS_Never

Don't align trailing comments but other formatter applies.

@ TCAS_Leave

Leave trailing comments as they are.

@ TCAS_Always

Align trailing comments.

@ AIAS_Left

Align array column and left justify the columns e.g.:

@ AIAS_Right

Align array column and right justify the columns e.g.:

@ AIAS_None

Don't align array initializer columns.

@ ENAS_DontAlign

Don't align escaped newlines.

@ ENAS_Left

Align escaped newlines as far left as possible.

@ ENAS_LeftWithLastLine

Align escaped newlines as far left as possible, using the last line of the preprocessor directive as ...

@ PAS_Right

Align pointer to the right.

@ RAS_Right

Align reference to the right.

@ RAS_Pointer

Align reference like PointerAlignment.

A wrapper around a Token storing information about the whitespace characters preceding it.

unsigned OriginalColumn

The original 0-based column of this token, including expanded tabs.

SourceLocation getStartOfNonWhitespace() const

Returns actual token start location without leading escaped newlines and whitespace.

void setDecision(FormatDecision D)

unsigned Finalized

If true, this token has been fully formatted (indented and potentially re-formatted inside),...

std::optional< MacroExpansion > MacroCtx

unsigned NewlinesBefore

The number of newlines immediately before the Token.

unsigned IsFirst

Indicates that this is the first token of the file.

SourceRange WhitespaceRange

The range of the whitespace immediately preceding the Token.

Represents a change before a token, a break inside a token, or the layout of an unchanged token (or w...

Change(const FormatToken &Tok, bool CreateReplacement, SourceRange OriginalWhitespaceRange, int Spaces, unsigned StartOfTokenColumn, unsigned NewlinesBefore, StringRef PreviousLinePostfix, StringRef CurrentLinePrefix, bool IsAligned, bool ContinuesPPDirective, bool IsInsideToken)

Creates a Change.

const Change * StartOfBlockComment

SourceRange OriginalWhitespaceRange

std::string PreviousLinePostfix

std::string CurrentLinePrefix

unsigned StartOfTokenColumn

unsigned PreviousEndOfTokenColumn

unsigned EscapedNewlineColumn

bool ContinuesPPDirective