1 //===--- WhitespaceManager.cpp - Format C++ code --------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
11 /// \brief This file implements WhitespaceManager class.
13 //===----------------------------------------------------------------------===//
15 #include "WhitespaceManager.h"
16 #include "llvm/ADT/STLExtras.h"
21 void WhitespaceManager::replaceWhitespace(const AnnotatedToken &Tok,
22 unsigned NewLines, unsigned Spaces,
23 unsigned WhitespaceStartColumn) {
25 alignEscapedNewlines();
27 // 2+ newlines mean an empty line separating logic scopes.
31 // Align line comments if they are trailing or if they continue other
33 if (Tok.isTrailingComment()) {
34 SourceLocation TokenEndLoc = Tok.FormatTok.getStartOfNonWhitespace()
35 .getLocWithOffset(Tok.FormatTok.TokenLength);
36 // Remove the comment's trailing whitespace.
37 if (Tok.FormatTok.TrailingWhiteSpaceLength != 0)
38 Replaces.insert(tooling::Replacement(
39 SourceMgr, TokenEndLoc, Tok.FormatTok.TrailingWhiteSpaceLength, ""));
41 bool LineExceedsColumnLimit =
42 Spaces + WhitespaceStartColumn + Tok.FormatTok.TokenLength >
44 // Align comment with other comments.
45 if ((Tok.Parent != NULL || !Comments.empty()) &&
46 !LineExceedsColumnLimit) {
48 NewLines > 0 ? Spaces : WhitespaceStartColumn + Spaces;
49 unsigned MaxColumn = Style.ColumnLimit - Tok.FormatTok.TokenLength;
50 Comments.push_back(StoredToken(
51 Tok.FormatTok.WhiteSpaceStart, Tok.FormatTok.WhiteSpaceLength,
52 MinColumn, MaxColumn, NewLines, Spaces));
57 // If this line does not have a trailing comment, align the stored comments.
58 if (Tok.Children.empty() && !Tok.isTrailingComment())
61 storeReplacement(Tok.FormatTok.WhiteSpaceStart,
62 Tok.FormatTok.WhiteSpaceLength,
63 getNewLineText(NewLines, Spaces));
66 void WhitespaceManager::replacePPWhitespace(const AnnotatedToken &Tok,
67 unsigned NewLines, unsigned Spaces,
68 unsigned WhitespaceStartColumn) {
70 replaceWhitespace(Tok, NewLines, Spaces, WhitespaceStartColumn);
72 // The earliest position for "\" is 2 after the last token.
73 unsigned MinColumn = WhitespaceStartColumn + 2;
74 unsigned MaxColumn = Style.ColumnLimit;
75 EscapedNewlines.push_back(StoredToken(
76 Tok.FormatTok.WhiteSpaceStart, Tok.FormatTok.WhiteSpaceLength,
77 MinColumn, MaxColumn, NewLines, Spaces));
81 void WhitespaceManager::breakToken(const FormatToken &Tok, unsigned Offset,
82 unsigned ReplaceChars, StringRef Prefix,
83 StringRef Postfix, bool InPPDirective,
85 unsigned WhitespaceStartColumn) {
86 SourceLocation Location =
87 Tok.getStartOfNonWhitespace().getLocWithOffset(Offset);
89 // The earliest position for "\" is 2 after the last token.
90 unsigned MinColumn = WhitespaceStartColumn + 2;
91 unsigned MaxColumn = Style.ColumnLimit;
92 StoredToken StoredTok = StoredToken(Location, ReplaceChars, MinColumn,
93 MaxColumn, /*NewLines=*/ 1, Spaces);
94 StoredTok.Prefix = Prefix;
95 StoredTok.Postfix = Postfix;
96 EscapedNewlines.push_back(StoredTok);
98 std::string ReplacementText =
99 (Prefix + getNewLineText(1, Spaces) + Postfix).str();
100 Replaces.insert(tooling::Replacement(SourceMgr, Location, ReplaceChars,
105 const tooling::Replacements &WhitespaceManager::generateReplacements() {
107 alignEscapedNewlines();
111 void WhitespaceManager::addReplacement(const SourceLocation &SourceLoc,
112 unsigned ReplaceChars, StringRef Text) {
114 tooling::Replacement(SourceMgr, SourceLoc, ReplaceChars, Text));
117 void WhitespaceManager::addUntouchableComment(unsigned Column) {
118 StoredToken Tok = StoredToken(SourceLocation(), 0, Column, Column, 0, 0);
119 Tok.Untouchable = true;
120 Comments.push_back(Tok);
123 std::string WhitespaceManager::getNewLineText(unsigned NewLines,
125 return std::string(NewLines, '\n') + std::string(Spaces, ' ');
128 std::string WhitespaceManager::getNewLineText(unsigned NewLines,
130 unsigned WhitespaceStartColumn,
131 unsigned EscapedNewlineColumn) {
132 std::string NewLineText;
135 std::min<int>(EscapedNewlineColumn - 1, WhitespaceStartColumn);
136 for (unsigned i = 0; i < NewLines; ++i) {
137 NewLineText += std::string(EscapedNewlineColumn - Offset - 1, ' ');
138 NewLineText += "\\\n";
142 return NewLineText + std::string(Spaces, ' ');
145 void WhitespaceManager::alignComments() {
146 unsigned MinColumn = 0;
147 unsigned MaxColumn = UINT_MAX;
148 token_iterator Start = Comments.begin();
149 for (token_iterator I = Start, E = Comments.end(); I != E; ++I) {
150 if (I->MinColumn > MaxColumn || I->MaxColumn < MinColumn) {
151 alignComments(Start, I, MinColumn);
152 MinColumn = I->MinColumn;
153 MaxColumn = I->MaxColumn;
156 MinColumn = std::max(MinColumn, I->MinColumn);
157 MaxColumn = std::min(MaxColumn, I->MaxColumn);
160 alignComments(Start, Comments.end(), MinColumn);
164 void WhitespaceManager::alignComments(token_iterator I, token_iterator E,
167 if (!I->Untouchable) {
168 unsigned Spaces = I->Spaces + Column - I->MinColumn;
169 storeReplacement(I->ReplacementLoc, I->ReplacementLength,
170 getNewLineText(I->NewLines, Spaces));
176 void WhitespaceManager::alignEscapedNewlines() {
178 if (Style.AlignEscapedNewlinesLeft) {
180 for (token_iterator I = EscapedNewlines.begin(), E = EscapedNewlines.end();
182 if (I->MinColumn > MinColumn)
183 MinColumn = I->MinColumn;
186 MinColumn = Style.ColumnLimit;
189 for (token_iterator I = EscapedNewlines.begin(), E = EscapedNewlines.end();
191 // I->MinColumn - 2 is the end of the previous token (i.e. the
192 // WhitespaceStartColumn).
194 I->ReplacementLoc, I->ReplacementLength,
195 I->Prefix + getNewLineText(I->NewLines, I->Spaces, I->MinColumn - 2,
196 MinColumn) + I->Postfix);
199 EscapedNewlines.clear();
202 void WhitespaceManager::storeReplacement(SourceLocation Loc, unsigned Length,
203 const std::string Text) {
204 // Don't create a replacement, if it does not change anything.
205 if (StringRef(SourceMgr.getCharacterData(Loc), Length) == Text)
207 Replaces.insert(tooling::Replacement(SourceMgr, Loc, Length, Text));
210 } // namespace format