]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/llvm/tools/clang/lib/Format/WhitespaceManager.cpp
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / llvm / tools / clang / lib / Format / WhitespaceManager.cpp
1 //===--- WhitespaceManager.cpp - Format C++ code --------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 ///
10 /// \file
11 /// \brief This file implements WhitespaceManager class.
12 ///
13 //===----------------------------------------------------------------------===//
14
15 #include "WhitespaceManager.h"
16 #include "llvm/ADT/STLExtras.h"
17
18 namespace clang {
19 namespace format {
20
21 void WhitespaceManager::replaceWhitespace(const AnnotatedToken &Tok,
22                                           unsigned NewLines, unsigned Spaces,
23                                           unsigned WhitespaceStartColumn) {
24   if (NewLines > 0)
25     alignEscapedNewlines();
26
27   // 2+ newlines mean an empty line separating logic scopes.
28   if (NewLines >= 2)
29     alignComments();
30
31   // Align line comments if they are trailing or if they continue other
32   // trailing comments.
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, ""));
40
41     bool LineExceedsColumnLimit =
42         Spaces + WhitespaceStartColumn + Tok.FormatTok.TokenLength >
43         Style.ColumnLimit;
44     // Align comment with other comments.
45     if ((Tok.Parent != NULL || !Comments.empty()) &&
46         !LineExceedsColumnLimit) {
47       unsigned MinColumn =
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));
53       return;
54     }
55   }
56
57   // If this line does not have a trailing comment, align the stored comments.
58   if (Tok.Children.empty() && !Tok.isTrailingComment())
59     alignComments();
60
61   storeReplacement(Tok.FormatTok.WhiteSpaceStart,
62                    Tok.FormatTok.WhiteSpaceLength,
63                    getNewLineText(NewLines, Spaces));
64 }
65
66 void WhitespaceManager::replacePPWhitespace(const AnnotatedToken &Tok,
67                                             unsigned NewLines, unsigned Spaces,
68                                             unsigned WhitespaceStartColumn) {
69   if (NewLines == 0) {
70     replaceWhitespace(Tok, NewLines, Spaces, WhitespaceStartColumn);
71   } else {
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));
78   }
79 }
80
81 void WhitespaceManager::breakToken(const FormatToken &Tok, unsigned Offset,
82                                    unsigned ReplaceChars, StringRef Prefix,
83                                    StringRef Postfix, bool InPPDirective,
84                                    unsigned Spaces,
85                                    unsigned WhitespaceStartColumn) {
86   SourceLocation Location =
87       Tok.getStartOfNonWhitespace().getLocWithOffset(Offset);
88   if (InPPDirective) {
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);
97   } else {
98     std::string ReplacementText =
99         (Prefix + getNewLineText(1, Spaces) + Postfix).str();
100     Replaces.insert(tooling::Replacement(SourceMgr, Location, ReplaceChars,
101                                          ReplacementText));
102   }
103 }
104
105 const tooling::Replacements &WhitespaceManager::generateReplacements() {
106   alignComments();
107   alignEscapedNewlines();
108   return Replaces;
109 }
110
111 void WhitespaceManager::addReplacement(const SourceLocation &SourceLoc,
112                                        unsigned ReplaceChars, StringRef Text) {
113   Replaces.insert(
114       tooling::Replacement(SourceMgr, SourceLoc, ReplaceChars, Text));
115 }
116
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);
121 }
122
123 std::string WhitespaceManager::getNewLineText(unsigned NewLines,
124                                               unsigned Spaces) {
125   return std::string(NewLines, '\n') + std::string(Spaces, ' ');
126 }
127
128 std::string WhitespaceManager::getNewLineText(unsigned NewLines,
129                                               unsigned Spaces,
130                                               unsigned WhitespaceStartColumn,
131                                               unsigned EscapedNewlineColumn) {
132   std::string NewLineText;
133   if (NewLines > 0) {
134     unsigned Offset =
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";
139       Offset = 0;
140     }
141   }
142   return NewLineText + std::string(Spaces, ' ');
143 }
144
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;
154       Start = I;
155     } else {
156       MinColumn = std::max(MinColumn, I->MinColumn);
157       MaxColumn = std::min(MaxColumn, I->MaxColumn);
158     }
159   }
160   alignComments(Start, Comments.end(), MinColumn);
161   Comments.clear();
162 }
163
164 void WhitespaceManager::alignComments(token_iterator I, token_iterator E,
165                                       unsigned Column) {
166   while (I != E) {
167     if (!I->Untouchable) {
168       unsigned Spaces = I->Spaces + Column - I->MinColumn;
169       storeReplacement(I->ReplacementLoc, I->ReplacementLength,
170                        getNewLineText(I->NewLines, Spaces));
171     }
172     ++I;
173   }
174 }
175
176 void WhitespaceManager::alignEscapedNewlines() {
177   unsigned MinColumn;
178   if (Style.AlignEscapedNewlinesLeft) {
179     MinColumn = 0;
180     for (token_iterator I = EscapedNewlines.begin(), E = EscapedNewlines.end();
181          I != E; ++I) {
182       if (I->MinColumn > MinColumn)
183         MinColumn = I->MinColumn;
184     }
185   } else {
186     MinColumn = Style.ColumnLimit;
187   }
188
189   for (token_iterator I = EscapedNewlines.begin(), E = EscapedNewlines.end();
190        I != E; ++I) {
191     // I->MinColumn - 2 is the end of the previous token (i.e. the
192     // WhitespaceStartColumn).
193     storeReplacement(
194         I->ReplacementLoc, I->ReplacementLength,
195         I->Prefix + getNewLineText(I->NewLines, I->Spaces, I->MinColumn - 2,
196                                    MinColumn) + I->Postfix);
197
198   }
199   EscapedNewlines.clear();
200 }
201
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)
206     return;
207   Replaces.insert(tooling::Replacement(SourceMgr, Loc, Length, Text));
208 }
209
210 } // namespace format
211 } // namespace clang