blob: 9a0fa7d31de02c55c85f05d9ede70955375ec087 [file] [log] [blame]
Daniel Jasperf7935112012-12-03 18:12:45 +00001//===--- Format.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 functions declared in Format.h. This will be
12/// split into separate files as we go.
13///
14/// This is EXPERIMENTAL code under heavy development. It is not in a state yet,
15/// where it can be used to format real code.
16///
17//===----------------------------------------------------------------------===//
18
19#include "clang/Format/Format.h"
Chandler Carruth3a022472012-12-04 09:13:33 +000020#include "UnwrappedLineParser.h"
Daniel Jasperf7935112012-12-03 18:12:45 +000021#include "clang/Basic/SourceManager.h"
22#include "clang/Lex/Lexer.h"
23
Daniel Jasper8b529712012-12-04 13:02:32 +000024#include <string>
25
Daniel Jasperf7935112012-12-03 18:12:45 +000026namespace clang {
27namespace format {
28
29// FIXME: Move somewhere sane.
30struct TokenAnnotation {
Daniel Jasperaa1c9202012-12-05 14:57:28 +000031 enum TokenType {
32 TT_Unknown,
33 TT_TemplateOpener,
34 TT_TemplateCloser,
35 TT_BinaryOperator,
36 TT_UnaryOperator,
Daniel Jasper8dd40472012-12-21 09:41:31 +000037 TT_TrailingUnaryOperator,
Daniel Jasperaa1c9202012-12-05 14:57:28 +000038 TT_OverloadedOperator,
39 TT_PointerOrReference,
40 TT_ConditionalExpr,
Daniel Jasper2af6bbe2012-12-18 21:05:13 +000041 TT_CtorInitializerColon,
Daniel Jasperaa1c9202012-12-05 14:57:28 +000042 TT_LineComment,
Fariborz Jahanian68a542a2012-12-20 19:54:13 +000043 TT_BlockComment,
44 TT_ObjCMethodSpecifier
Daniel Jasperaa1c9202012-12-05 14:57:28 +000045 };
Daniel Jasperf7935112012-12-03 18:12:45 +000046
47 TokenType Type;
48
Daniel Jasperf7935112012-12-03 18:12:45 +000049 bool SpaceRequiredBefore;
50 bool CanBreakBefore;
51 bool MustBreakBefore;
52};
53
54using llvm::MutableArrayRef;
55
56FormatStyle getLLVMStyle() {
57 FormatStyle LLVMStyle;
58 LLVMStyle.ColumnLimit = 80;
59 LLVMStyle.MaxEmptyLinesToKeep = 1;
60 LLVMStyle.PointerAndReferenceBindToType = false;
61 LLVMStyle.AccessModifierOffset = -2;
62 LLVMStyle.SplitTemplateClosingGreater = true;
Alexander Kornienko578fdd82012-12-06 18:03:27 +000063 LLVMStyle.IndentCaseLabels = false;
Daniel Jasperf7935112012-12-03 18:12:45 +000064 return LLVMStyle;
65}
66
67FormatStyle getGoogleStyle() {
68 FormatStyle GoogleStyle;
69 GoogleStyle.ColumnLimit = 80;
70 GoogleStyle.MaxEmptyLinesToKeep = 1;
71 GoogleStyle.PointerAndReferenceBindToType = true;
72 GoogleStyle.AccessModifierOffset = -1;
73 GoogleStyle.SplitTemplateClosingGreater = false;
Alexander Kornienko578fdd82012-12-06 18:03:27 +000074 GoogleStyle.IndentCaseLabels = true;
Daniel Jasperf7935112012-12-03 18:12:45 +000075 return GoogleStyle;
76}
77
78struct OptimizationParameters {
Daniel Jasperf7935112012-12-03 18:12:45 +000079 unsigned PenaltyIndentLevel;
80};
81
82class UnwrappedLineFormatter {
83public:
84 UnwrappedLineFormatter(const FormatStyle &Style, SourceManager &SourceMgr,
85 const UnwrappedLine &Line,
86 const std::vector<TokenAnnotation> &Annotations,
Alexander Kornienko870f9eb2012-12-04 17:27:50 +000087 tooling::Replacements &Replaces, bool StructuralError)
Daniel Jasper2af6bbe2012-12-18 21:05:13 +000088 : Style(Style), SourceMgr(SourceMgr), Line(Line),
89 Annotations(Annotations), Replaces(Replaces),
Alexander Kornienko870f9eb2012-12-04 17:27:50 +000090 StructuralError(StructuralError) {
Daniel Jasperf7935112012-12-03 18:12:45 +000091 Parameters.PenaltyIndentLevel = 5;
92 }
93
94 void format() {
Daniel Jaspere9de2602012-12-06 09:56:08 +000095 // Format first token and initialize indent.
Alexander Kornienko870f9eb2012-12-04 17:27:50 +000096 unsigned Indent = formatFirstToken();
Daniel Jaspere9de2602012-12-06 09:56:08 +000097
98 // Initialize state dependent on indent.
Daniel Jasperf7935112012-12-03 18:12:45 +000099 IndentState State;
Daniel Jaspere9de2602012-12-06 09:56:08 +0000100 State.Column = Indent;
Daniel Jaspere9de2602012-12-06 09:56:08 +0000101 State.ConsumedTokens = 0;
Alexander Kornienko870f9eb2012-12-04 17:27:50 +0000102 State.Indent.push_back(Indent + 4);
103 State.LastSpace.push_back(Indent);
Daniel Jaspere9de2602012-12-06 09:56:08 +0000104 State.FirstLessLess.push_back(0);
105
106 // The first token has already been indented and thus consumed.
107 moveStateToNextToken(State);
Daniel Jasperf7935112012-12-03 18:12:45 +0000108
Daniel Jasper2af6bbe2012-12-18 21:05:13 +0000109 // Check whether the UnwrappedLine can be put onto a single line. If so,
110 // this is bound to be the optimal solution (by definition) and we don't
111 // need to analyze the entire solution space.
112 unsigned Columns = State.Column;
113 bool FitsOnALine = true;
114 for (unsigned i = 1, n = Line.Tokens.size(); i != n; ++i) {
115 Columns += (Annotations[i].SpaceRequiredBefore ? 1 : 0) +
116 Line.Tokens[i].Tok.getLength();
117 // A special case for the colon of a constructor initializer as this only
118 // needs to be put on a new line if the line needs to be split.
119 if (Columns > Style.ColumnLimit ||
120 (Annotations[i].MustBreakBefore &&
121 Annotations[i].Type != TokenAnnotation::TT_CtorInitializerColon)) {
122 FitsOnALine = false;
123 break;
124 }
125 }
126
Daniel Jasperf7935112012-12-03 18:12:45 +0000127 // Start iterating at 1 as we have correctly formatted of Token #0 above.
128 for (unsigned i = 1, n = Line.Tokens.size(); i != n; ++i) {
Daniel Jasper2af6bbe2012-12-18 21:05:13 +0000129 if (FitsOnALine) {
130 addTokenToState(false, false, State);
131 } else {
132 unsigned NoBreak = calcPenalty(State, false, UINT_MAX);
133 unsigned Break = calcPenalty(State, true, NoBreak);
134 addTokenToState(Break < NoBreak, false, State);
135 }
Daniel Jasperf7935112012-12-03 18:12:45 +0000136 }
137 }
138
139private:
140 /// \brief The current state when indenting a unwrapped line.
141 ///
142 /// As the indenting tries different combinations this is copied by value.
143 struct IndentState {
144 /// \brief The number of used columns in the current line.
145 unsigned Column;
146
147 /// \brief The number of tokens already consumed.
148 unsigned ConsumedTokens;
149
150 /// \brief The position to which a specific parenthesis level needs to be
151 /// indented.
152 std::vector<unsigned> Indent;
153
Daniel Jaspere9de2602012-12-06 09:56:08 +0000154 /// \brief The position of the last space on each level.
155 ///
156 /// Used e.g. to break like:
157 /// functionCall(Parameter, otherCall(
158 /// OtherParameter));
Daniel Jasperf7935112012-12-03 18:12:45 +0000159 std::vector<unsigned> LastSpace;
160
Daniel Jaspere9de2602012-12-06 09:56:08 +0000161 /// \brief The position the first "<<" operator encountered on each level.
162 ///
163 /// Used to align "<<" operators. 0 if no such operator has been encountered
164 /// on a level.
165 std::vector<unsigned> FirstLessLess;
166
Daniel Jasperf7935112012-12-03 18:12:45 +0000167 /// \brief Comparison operator to be able to used \c IndentState in \c map.
168 bool operator<(const IndentState &Other) const {
169 if (Other.ConsumedTokens != ConsumedTokens)
170 return Other.ConsumedTokens > ConsumedTokens;
171 if (Other.Column != Column)
172 return Other.Column > Column;
173 if (Other.Indent.size() != Indent.size())
174 return Other.Indent.size() > Indent.size();
175 for (int i = 0, e = Indent.size(); i != e; ++i) {
176 if (Other.Indent[i] != Indent[i])
177 return Other.Indent[i] > Indent[i];
178 }
179 if (Other.LastSpace.size() != LastSpace.size())
180 return Other.LastSpace.size() > LastSpace.size();
181 for (int i = 0, e = LastSpace.size(); i != e; ++i) {
182 if (Other.LastSpace[i] != LastSpace[i])
183 return Other.LastSpace[i] > LastSpace[i];
184 }
Daniel Jaspere9de2602012-12-06 09:56:08 +0000185 if (Other.FirstLessLess.size() != FirstLessLess.size())
186 return Other.FirstLessLess.size() > FirstLessLess.size();
187 for (int i = 0, e = FirstLessLess.size(); i != e; ++i) {
188 if (Other.FirstLessLess[i] != FirstLessLess[i])
189 return Other.FirstLessLess[i] > FirstLessLess[i];
190 }
Daniel Jasperf7935112012-12-03 18:12:45 +0000191 return false;
192 }
193 };
194
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000195 /// \brief Appends the next token to \p State and updates information
196 /// necessary for indentation.
197 ///
198 /// Puts the token on the current line if \p Newline is \c true and adds a
199 /// line break and necessary indentation otherwise.
200 ///
201 /// If \p DryRun is \c false, also creates and stores the required
202 /// \c Replacement.
203 void addTokenToState(bool Newline, bool DryRun, IndentState &State) {
Daniel Jasperf7935112012-12-03 18:12:45 +0000204 unsigned Index = State.ConsumedTokens;
205 const FormatToken &Current = Line.Tokens[Index];
206 const FormatToken &Previous = Line.Tokens[Index - 1];
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000207 unsigned ParenLevel = State.Indent.size() - 1;
Daniel Jasperf7935112012-12-03 18:12:45 +0000208
209 if (Newline) {
210 if (Current.Tok.is(tok::string_literal) &&
211 Previous.Tok.is(tok::string_literal))
212 State.Column = State.Column - Previous.Tok.getLength();
Daniel Jaspere9de2602012-12-06 09:56:08 +0000213 else if (Current.Tok.is(tok::lessless) &&
214 State.FirstLessLess[ParenLevel] != 0)
215 State.Column = State.FirstLessLess[ParenLevel];
Daniel Jasper5485d0c2012-12-17 14:34:14 +0000216 else if (ParenLevel != 0 &&
217 (Previous.Tok.is(tok::equal) || Current.Tok.is(tok::arrow) ||
218 Current.Tok.is(tok::period)))
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000219 // Indent and extra 4 spaces after '=' as it continues an expression.
220 // Don't do that on the top level, as we already indent 4 there.
Daniel Jasperf7935112012-12-03 18:12:45 +0000221 State.Column = State.Indent[ParenLevel] + 4;
Daniel Jasper9b155472012-12-04 10:50:12 +0000222 else
Daniel Jasperf7935112012-12-03 18:12:45 +0000223 State.Column = State.Indent[ParenLevel];
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000224
Daniel Jasperf7935112012-12-03 18:12:45 +0000225 if (!DryRun)
226 replaceWhitespace(Current, 1, State.Column);
227
Daniel Jasper9b155472012-12-04 10:50:12 +0000228 State.LastSpace[ParenLevel] = State.Indent[ParenLevel];
Daniel Jasperf7935112012-12-03 18:12:45 +0000229 if (Current.Tok.is(tok::colon) &&
Fariborz Jahanian68a542a2012-12-20 19:54:13 +0000230 Annotations[Index].Type != TokenAnnotation::TT_ConditionalExpr &&
231 Annotations[0].Type != TokenAnnotation::TT_ObjCMethodSpecifier)
Daniel Jasperf7935112012-12-03 18:12:45 +0000232 State.Indent[ParenLevel] += 2;
Daniel Jasperf7935112012-12-03 18:12:45 +0000233 } else {
234 unsigned Spaces = Annotations[Index].SpaceRequiredBefore ? 1 : 0;
235 if (Annotations[Index].Type == TokenAnnotation::TT_LineComment)
236 Spaces = 2;
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000237
Daniel Jasperf7935112012-12-03 18:12:45 +0000238 if (!DryRun)
239 replaceWhitespace(Current, 0, Spaces);
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000240
241 if (Previous.Tok.is(tok::l_paren) ||
242 Annotations[Index - 1].Type == TokenAnnotation::TT_TemplateOpener)
Daniel Jasperf7935112012-12-03 18:12:45 +0000243 State.Indent[ParenLevel] = State.Column;
Daniel Jasper2af6bbe2012-12-18 21:05:13 +0000244
Daniel Jasperf7935112012-12-03 18:12:45 +0000245 // Top-level spaces are exempt as that mostly leads to better results.
Daniel Jaspere9de2602012-12-06 09:56:08 +0000246 State.Column += Spaces;
Daniel Jasper9b155472012-12-04 10:50:12 +0000247 if (Spaces > 0 && ParenLevel != 0)
Daniel Jaspere9de2602012-12-06 09:56:08 +0000248 State.LastSpace[ParenLevel] = State.Column;
Daniel Jasperf7935112012-12-03 18:12:45 +0000249 }
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000250 moveStateToNextToken(State);
251 }
Daniel Jasperf7935112012-12-03 18:12:45 +0000252
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000253 /// \brief Mark the next token as consumed in \p State and modify its stacks
254 /// accordingly.
255 void moveStateToNextToken(IndentState &State) {
256 unsigned Index = State.ConsumedTokens;
257 const FormatToken &Current = Line.Tokens[Index];
Daniel Jaspere9de2602012-12-06 09:56:08 +0000258 unsigned ParenLevel = State.Indent.size() - 1;
259
260 if (Current.Tok.is(tok::lessless) && State.FirstLessLess[ParenLevel] == 0)
261 State.FirstLessLess[ParenLevel] = State.Column;
262
263 State.Column += Current.Tok.getLength();
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000264
265 // If we encounter an opening (, [ or <, we add a level to our stacks to
266 // prepare for the following tokens.
267 if (Current.Tok.is(tok::l_paren) || Current.Tok.is(tok::l_square) ||
268 Annotations[Index].Type == TokenAnnotation::TT_TemplateOpener) {
269 State.Indent.push_back(4 + State.LastSpace.back());
270 State.LastSpace.push_back(State.LastSpace.back());
Daniel Jaspere9de2602012-12-06 09:56:08 +0000271 State.FirstLessLess.push_back(0);
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000272 }
273
274 // If we encounter a closing ), ] or >, we can remove a level from our
275 // stacks.
Daniel Jasper9b155472012-12-04 10:50:12 +0000276 if (Current.Tok.is(tok::r_paren) || Current.Tok.is(tok::r_square) ||
277 Annotations[Index].Type == TokenAnnotation::TT_TemplateCloser) {
Daniel Jasperf7935112012-12-03 18:12:45 +0000278 State.Indent.pop_back();
279 State.LastSpace.pop_back();
Daniel Jaspere9de2602012-12-06 09:56:08 +0000280 State.FirstLessLess.pop_back();
Daniel Jasperf7935112012-12-03 18:12:45 +0000281 }
282
283 ++State.ConsumedTokens;
284 }
285
Daniel Jasper5485d0c2012-12-17 14:34:14 +0000286 /// \brief Calculate the panelty for splitting after the token at \p Index.
287 unsigned splitPenalty(unsigned Index) {
288 assert(Index < Line.Tokens.size() &&
289 "Tried to calculate penalty for splitting after the last token");
290 const FormatToken &Left = Line.Tokens[Index];
291 const FormatToken &Right = Line.Tokens[Index + 1];
Daniel Jasper2af6bbe2012-12-18 21:05:13 +0000292 if (Left.Tok.is(tok::semi) || Left.Tok.is(tok::comma))
Daniel Jasperf7935112012-12-03 18:12:45 +0000293 return 0;
Daniel Jasper5485d0c2012-12-17 14:34:14 +0000294 if (Left.Tok.is(tok::equal) || Left.Tok.is(tok::l_paren) ||
295 Left.Tok.is(tok::pipepipe) || Left.Tok.is(tok::ampamp))
Daniel Jasperf7935112012-12-03 18:12:45 +0000296 return 2;
Daniel Jasper5485d0c2012-12-17 14:34:14 +0000297
298 if (Right.Tok.is(tok::arrow) || Right.Tok.is(tok::period))
299 return 200;
300
Daniel Jasperf7935112012-12-03 18:12:45 +0000301 return 3;
302 }
303
304 /// \brief Calculate the number of lines needed to format the remaining part
305 /// of the unwrapped line.
306 ///
307 /// Assumes the formatting so far has led to
308 /// the \c IndentState \p State. If \p NewLine is set, a new line will be
309 /// added after the previous token.
310 ///
311 /// \param StopAt is used for optimization. If we can determine that we'll
312 /// definitely need at least \p StopAt additional lines, we already know of a
313 /// better solution.
314 unsigned calcPenalty(IndentState State, bool NewLine, unsigned StopAt) {
315 // We are at the end of the unwrapped line, so we don't need any more lines.
316 if (State.ConsumedTokens >= Line.Tokens.size())
317 return 0;
318
319 if (!NewLine && Annotations[State.ConsumedTokens].MustBreakBefore)
320 return UINT_MAX;
321 if (NewLine && !Annotations[State.ConsumedTokens].CanBreakBefore)
322 return UINT_MAX;
323
Daniel Jasperaa1c9202012-12-05 14:57:28 +0000324 unsigned CurrentPenalty = 0;
325 if (NewLine) {
326 CurrentPenalty += Parameters.PenaltyIndentLevel * State.Indent.size() +
Daniel Jasper2af6bbe2012-12-18 21:05:13 +0000327 splitPenalty(State.ConsumedTokens - 1);
Daniel Jasperaa1c9202012-12-05 14:57:28 +0000328 }
329
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000330 addTokenToState(NewLine, true, State);
Daniel Jasperf7935112012-12-03 18:12:45 +0000331
332 // Exceeding column limit is bad.
333 if (State.Column > Style.ColumnLimit)
334 return UINT_MAX;
335
Daniel Jasperf7935112012-12-03 18:12:45 +0000336 if (StopAt <= CurrentPenalty)
337 return UINT_MAX;
338 StopAt -= CurrentPenalty;
339
Daniel Jasperf7935112012-12-03 18:12:45 +0000340 StateMap::iterator I = Memory.find(State);
Daniel Jasperaa1c9202012-12-05 14:57:28 +0000341 if (I != Memory.end()) {
342 // If this state has already been examined, we can safely return the
343 // previous result if we
344 // - have not hit the optimatization (and thus returned UINT_MAX) OR
345 // - are now computing for a smaller or equal StopAt.
346 unsigned SavedResult = I->second.first;
347 unsigned SavedStopAt = I->second.second;
Daniel Jasper5485d0c2012-12-17 14:34:14 +0000348 if (SavedResult != UINT_MAX)
349 return SavedResult + CurrentPenalty;
350 else if (StopAt <= SavedStopAt)
351 return UINT_MAX;
Daniel Jasperaa1c9202012-12-05 14:57:28 +0000352 }
Daniel Jasperf7935112012-12-03 18:12:45 +0000353
354 unsigned NoBreak = calcPenalty(State, false, StopAt);
355 unsigned WithBreak = calcPenalty(State, true, std::min(StopAt, NoBreak));
356 unsigned Result = std::min(NoBreak, WithBreak);
Daniel Jasper5485d0c2012-12-17 14:34:14 +0000357
358 // We have to store 'Result' without adding 'CurrentPenalty' as the latter
359 // can depend on 'NewLine'.
Daniel Jasperaa1c9202012-12-05 14:57:28 +0000360 Memory[State] = std::pair<unsigned, unsigned>(Result, StopAt);
Daniel Jasper5485d0c2012-12-17 14:34:14 +0000361
362 return Result == UINT_MAX ? UINT_MAX : Result + CurrentPenalty;
Daniel Jasperf7935112012-12-03 18:12:45 +0000363 }
364
365 /// \brief Replaces the whitespace in front of \p Tok. Only call once for
366 /// each \c FormatToken.
367 void replaceWhitespace(const FormatToken &Tok, unsigned NewLines,
368 unsigned Spaces) {
369 Replaces.insert(tooling::Replacement(
370 SourceMgr, Tok.WhiteSpaceStart, Tok.WhiteSpaceLength,
371 std::string(NewLines, '\n') + std::string(Spaces, ' ')));
372 }
373
374 /// \brief Add a new line and the required indent before the first Token
Alexander Kornienkobc09a7e2012-12-05 13:56:52 +0000375 /// of the \c UnwrappedLine if there was no structural parsing error.
376 /// Returns the indent level of the \c UnwrappedLine.
Alexander Kornienko870f9eb2012-12-04 17:27:50 +0000377 unsigned formatFirstToken() {
Daniel Jasperf7935112012-12-03 18:12:45 +0000378 const FormatToken &Token = Line.Tokens[0];
Alexander Kornienko870f9eb2012-12-04 17:27:50 +0000379 if (!Token.WhiteSpaceStart.isValid() || StructuralError)
380 return SourceMgr.getSpellingColumnNumber(Token.Tok.getLocation()) - 1;
381
382 unsigned Newlines =
383 std::min(Token.NewlinesBefore, Style.MaxEmptyLinesToKeep + 1);
384 unsigned Offset = SourceMgr.getFileOffset(Token.WhiteSpaceStart);
385 if (Newlines == 0 && Offset != 0)
386 Newlines = 1;
387 unsigned Indent = Line.Level * 2;
Alexander Kornienko2ca766f2012-12-10 16:34:48 +0000388 if ((Token.Tok.is(tok::kw_public) || Token.Tok.is(tok::kw_protected) ||
389 Token.Tok.is(tok::kw_private)) &&
390 static_cast<int>(Indent) + Style.AccessModifierOffset >= 0)
Alexander Kornienko870f9eb2012-12-04 17:27:50 +0000391 Indent += Style.AccessModifierOffset;
392 replaceWhitespace(Token, Newlines, Indent);
393 return Indent;
Daniel Jasperf7935112012-12-03 18:12:45 +0000394 }
395
396 FormatStyle Style;
397 SourceManager &SourceMgr;
398 const UnwrappedLine &Line;
399 const std::vector<TokenAnnotation> &Annotations;
400 tooling::Replacements &Replaces;
Alexander Kornienko870f9eb2012-12-04 17:27:50 +0000401 bool StructuralError;
Daniel Jasperf7935112012-12-03 18:12:45 +0000402
Daniel Jasperaa1c9202012-12-05 14:57:28 +0000403 // A map from an indent state to a pair (Result, Used-StopAt).
404 typedef std::map<IndentState, std::pair<unsigned, unsigned> > StateMap;
405 StateMap Memory;
406
Daniel Jasperf7935112012-12-03 18:12:45 +0000407 OptimizationParameters Parameters;
408};
409
410/// \brief Determines extra information about the tokens comprising an
411/// \c UnwrappedLine.
412class TokenAnnotator {
413public:
414 TokenAnnotator(const UnwrappedLine &Line, const FormatStyle &Style,
415 SourceManager &SourceMgr)
Daniel Jasper2af6bbe2012-12-18 21:05:13 +0000416 : Line(Line), Style(Style), SourceMgr(SourceMgr) {
Daniel Jasperf7935112012-12-03 18:12:45 +0000417 }
418
419 /// \brief A parser that gathers additional information about tokens.
420 ///
421 /// The \c TokenAnnotator tries to matches parenthesis and square brakets and
422 /// store a parenthesis levels. It also tries to resolve matching "<" and ">"
423 /// into template parameter lists.
424 class AnnotatingParser {
425 public:
Manuel Klimek6a5619d2012-12-03 20:55:42 +0000426 AnnotatingParser(const SmallVector<FormatToken, 16> &Tokens,
Daniel Jasperf7935112012-12-03 18:12:45 +0000427 std::vector<TokenAnnotation> &Annotations)
Daniel Jasper2af6bbe2012-12-18 21:05:13 +0000428 : Tokens(Tokens), Annotations(Annotations), Index(0) {
Daniel Jasperf7935112012-12-03 18:12:45 +0000429 }
430
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000431 bool parseAngle() {
Daniel Jasperf7935112012-12-03 18:12:45 +0000432 while (Index < Tokens.size()) {
433 if (Tokens[Index].Tok.is(tok::greater)) {
Daniel Jasper9b155472012-12-04 10:50:12 +0000434 Annotations[Index].Type = TokenAnnotation::TT_TemplateCloser;
Daniel Jasperf7935112012-12-03 18:12:45 +0000435 next();
436 return true;
437 }
438 if (Tokens[Index].Tok.is(tok::r_paren) ||
439 Tokens[Index].Tok.is(tok::r_square))
440 return false;
441 if (Tokens[Index].Tok.is(tok::pipepipe) ||
442 Tokens[Index].Tok.is(tok::ampamp) ||
443 Tokens[Index].Tok.is(tok::question) ||
444 Tokens[Index].Tok.is(tok::colon))
445 return false;
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000446 consumeToken();
Daniel Jasperf7935112012-12-03 18:12:45 +0000447 }
448 return false;
449 }
450
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000451 bool parseParens() {
Daniel Jasperf7935112012-12-03 18:12:45 +0000452 while (Index < Tokens.size()) {
453 if (Tokens[Index].Tok.is(tok::r_paren)) {
Daniel Jasperf7935112012-12-03 18:12:45 +0000454 next();
455 return true;
456 }
457 if (Tokens[Index].Tok.is(tok::r_square))
458 return false;
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000459 consumeToken();
Daniel Jasperf7935112012-12-03 18:12:45 +0000460 }
461 return false;
462 }
463
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000464 bool parseSquare() {
Daniel Jasperf7935112012-12-03 18:12:45 +0000465 while (Index < Tokens.size()) {
466 if (Tokens[Index].Tok.is(tok::r_square)) {
Daniel Jasperf7935112012-12-03 18:12:45 +0000467 next();
468 return true;
469 }
470 if (Tokens[Index].Tok.is(tok::r_paren))
471 return false;
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000472 consumeToken();
Daniel Jasperf7935112012-12-03 18:12:45 +0000473 }
474 return false;
475 }
476
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000477 bool parseConditional() {
Daniel Jasperf7935112012-12-03 18:12:45 +0000478 while (Index < Tokens.size()) {
479 if (Tokens[Index].Tok.is(tok::colon)) {
480 Annotations[Index].Type = TokenAnnotation::TT_ConditionalExpr;
481 next();
482 return true;
483 }
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000484 consumeToken();
Daniel Jasperf7935112012-12-03 18:12:45 +0000485 }
486 return false;
487 }
488
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000489 void consumeToken() {
Daniel Jasperf7935112012-12-03 18:12:45 +0000490 unsigned CurrentIndex = Index;
491 next();
492 switch (Tokens[CurrentIndex].Tok.getKind()) {
493 case tok::l_paren:
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000494 parseParens();
Daniel Jasper2af6bbe2012-12-18 21:05:13 +0000495 if (Index < Tokens.size() && Tokens[Index].Tok.is(tok::colon)) {
496 Annotations[Index].Type = TokenAnnotation::TT_CtorInitializerColon;
497 next();
498 }
Daniel Jasperf7935112012-12-03 18:12:45 +0000499 break;
500 case tok::l_square:
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000501 parseSquare();
Daniel Jasperf7935112012-12-03 18:12:45 +0000502 break;
503 case tok::less:
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000504 if (parseAngle())
Daniel Jasperf7935112012-12-03 18:12:45 +0000505 Annotations[CurrentIndex].Type = TokenAnnotation::TT_TemplateOpener;
506 else {
507 Annotations[CurrentIndex].Type = TokenAnnotation::TT_BinaryOperator;
508 Index = CurrentIndex + 1;
509 }
510 break;
511 case tok::greater:
512 Annotations[CurrentIndex].Type = TokenAnnotation::TT_BinaryOperator;
513 break;
514 case tok::kw_operator:
515 if (!Tokens[Index].Tok.is(tok::l_paren))
516 Annotations[Index].Type = TokenAnnotation::TT_OverloadedOperator;
517 next();
518 break;
519 case tok::question:
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000520 parseConditional();
Daniel Jasperf7935112012-12-03 18:12:45 +0000521 break;
522 default:
523 break;
524 }
525 }
526
527 void parseLine() {
528 while (Index < Tokens.size()) {
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000529 consumeToken();
Daniel Jasperf7935112012-12-03 18:12:45 +0000530 }
531 }
532
533 void next() {
534 ++Index;
535 }
536
537 private:
Daniel Jasperf7935112012-12-03 18:12:45 +0000538 const SmallVector<FormatToken, 16> &Tokens;
539 std::vector<TokenAnnotation> &Annotations;
540 unsigned Index;
541 };
542
543 void annotate() {
544 Annotations.clear();
545 for (int i = 0, e = Line.Tokens.size(); i != e; ++i) {
546 Annotations.push_back(TokenAnnotation());
547 }
548
Manuel Klimek6a5619d2012-12-03 20:55:42 +0000549 AnnotatingParser Parser(Line.Tokens, Annotations);
Daniel Jasperf7935112012-12-03 18:12:45 +0000550 Parser.parseLine();
551
552 determineTokenTypes();
Fariborz Jahanian68a542a2012-12-20 19:54:13 +0000553 bool IsObjCMethodDecl =
Daniel Jasper8dd40472012-12-21 09:41:31 +0000554 (Line.Tokens.size() > 0 &&
555 (Annotations[0].Type == TokenAnnotation::TT_ObjCMethodSpecifier));
Daniel Jasperf7935112012-12-03 18:12:45 +0000556 for (int i = 1, e = Line.Tokens.size(); i != e; ++i) {
557 TokenAnnotation &Annotation = Annotations[i];
558
559 Annotation.CanBreakBefore =
560 canBreakBetween(Line.Tokens[i - 1], Line.Tokens[i]);
561
Daniel Jasper2af6bbe2012-12-18 21:05:13 +0000562 if (Annotation.Type == TokenAnnotation::TT_CtorInitializerColon) {
563 Annotation.MustBreakBefore = true;
564 Annotation.SpaceRequiredBefore = true;
Daniel Jasper8dd40472012-12-21 09:41:31 +0000565 } else if (IsObjCMethodDecl && Line.Tokens[i].Tok.is(tok::identifier) &&
566 (i != e - 1) && Line.Tokens[i + 1].Tok.is(tok::colon) &&
567 Line.Tokens[i - 1].Tok.is(tok::identifier)) {
Fariborz Jahanian68a542a2012-12-20 19:54:13 +0000568 Annotation.CanBreakBefore = true;
569 Annotation.SpaceRequiredBefore = true;
Daniel Jasper8dd40472012-12-21 09:41:31 +0000570 } else if (IsObjCMethodDecl && Line.Tokens[i].Tok.is(tok::identifier) &&
571 Line.Tokens[i - 1].Tok.is(tok::l_paren) &&
572 Line.Tokens[i - 2].Tok.is(tok::colon)) {
Fariborz Jahanian68a542a2012-12-20 19:54:13 +0000573 // Don't break this identifier as ':' or identifier
574 // before it will break.
575 Annotation.CanBreakBefore = false;
576 } else if (Line.Tokens[i].Tok.is(tok::at) &&
Daniel Jasper8dd40472012-12-21 09:41:31 +0000577 Line.Tokens[i - 2].Tok.is(tok::at)) {
Fariborz Jahanian68a542a2012-12-20 19:54:13 +0000578 // Don't put two objc's '@' on the same line. This could happen,
579 // as in, @optinal @property ...
580 Annotation.MustBreakBefore = true;
Daniel Jasper2af6bbe2012-12-18 21:05:13 +0000581 } else if (Line.Tokens[i].Tok.is(tok::colon)) {
Daniel Jasper55b6b642012-12-05 16:24:48 +0000582 Annotation.SpaceRequiredBefore =
Fariborz Jahanian68a542a2012-12-20 19:54:13 +0000583 Line.Tokens[0].Tok.isNot(tok::kw_case) && !IsObjCMethodDecl &&
584 (i != e - 1);
585 // Don't break at ':' if identifier before it can beak.
Daniel Jasper8dd40472012-12-21 09:41:31 +0000586 if (IsObjCMethodDecl && Line.Tokens[i - 1].Tok.is(tok::identifier) &&
587 Annotations[i - 1].CanBreakBefore)
Fariborz Jahanian68a542a2012-12-20 19:54:13 +0000588 Annotation.CanBreakBefore = false;
Daniel Jasper8dd40472012-12-21 09:41:31 +0000589 } else if (
590 Annotations[i - 1].Type == TokenAnnotation::TT_ObjCMethodSpecifier) {
Fariborz Jahanian68a542a2012-12-20 19:54:13 +0000591 Annotation.SpaceRequiredBefore = true;
Daniel Jasper8dd40472012-12-21 09:41:31 +0000592 } else if (Annotations[i - 1].Type == TokenAnnotation::TT_UnaryOperator) {
Daniel Jasperf7935112012-12-03 18:12:45 +0000593 Annotation.SpaceRequiredBefore = false;
594 } else if (Annotation.Type == TokenAnnotation::TT_UnaryOperator) {
595 Annotation.SpaceRequiredBefore =
Daniel Jasper8b529712012-12-04 13:02:32 +0000596 Line.Tokens[i - 1].Tok.isNot(tok::l_paren) &&
597 Line.Tokens[i - 1].Tok.isNot(tok::l_square);
Daniel Jasperf7935112012-12-03 18:12:45 +0000598 } else if (Line.Tokens[i - 1].Tok.is(tok::greater) &&
599 Line.Tokens[i].Tok.is(tok::greater)) {
Daniel Jasper8b529712012-12-04 13:02:32 +0000600 if (Annotation.Type == TokenAnnotation::TT_TemplateCloser &&
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000601 Annotations[i - 1].Type == TokenAnnotation::TT_TemplateCloser)
Daniel Jasper9b155472012-12-04 10:50:12 +0000602 Annotation.SpaceRequiredBefore = Style.SplitTemplateClosingGreater;
Daniel Jasperf7935112012-12-03 18:12:45 +0000603 else
604 Annotation.SpaceRequiredBefore = false;
605 } else if (
606 Annotation.Type == TokenAnnotation::TT_BinaryOperator ||
607 Annotations[i - 1].Type == TokenAnnotation::TT_BinaryOperator) {
608 Annotation.SpaceRequiredBefore = true;
609 } else if (
Daniel Jasper9b155472012-12-04 10:50:12 +0000610 Annotations[i - 1].Type == TokenAnnotation::TT_TemplateCloser &&
Daniel Jasperf7935112012-12-03 18:12:45 +0000611 Line.Tokens[i].Tok.is(tok::l_paren)) {
612 Annotation.SpaceRequiredBefore = false;
Daniel Jasper8b529712012-12-04 13:02:32 +0000613 } else if (Line.Tokens[i].Tok.is(tok::less) &&
614 Line.Tokens[0].Tok.is(tok::hash)) {
615 Annotation.SpaceRequiredBefore = true;
Daniel Jasper8dd40472012-12-21 09:41:31 +0000616 } else if (IsObjCMethodDecl && Line.Tokens[i - 1].Tok.is(tok::r_paren) &&
617 Line.Tokens[i].Tok.is(tok::identifier)) {
Fariborz Jahanian68a542a2012-12-20 19:54:13 +0000618 // Don't space between ')' and <id>
619 Annotation.SpaceRequiredBefore = false;
Daniel Jasper8dd40472012-12-21 09:41:31 +0000620 } else if (IsObjCMethodDecl && Line.Tokens[i - 1].Tok.is(tok::colon) &&
621 Line.Tokens[i].Tok.is(tok::l_paren)) {
Fariborz Jahanian68a542a2012-12-20 19:54:13 +0000622 // Don't space between ':' and '('
623 Annotation.SpaceRequiredBefore = false;
Daniel Jasper8dd40472012-12-21 09:41:31 +0000624 } else if (Annotation.Type == TokenAnnotation::TT_TrailingUnaryOperator) {
625 Annotation.SpaceRequiredBefore = false;
626 } else {
Daniel Jasperf7935112012-12-03 18:12:45 +0000627 Annotation.SpaceRequiredBefore =
628 spaceRequiredBetween(Line.Tokens[i - 1].Tok, Line.Tokens[i].Tok);
629 }
630
631 if (Annotations[i - 1].Type == TokenAnnotation::TT_LineComment ||
632 (Line.Tokens[i].Tok.is(tok::string_literal) &&
633 Line.Tokens[i - 1].Tok.is(tok::string_literal))) {
634 Annotation.MustBreakBefore = true;
635 }
636
637 if (Annotation.MustBreakBefore)
638 Annotation.CanBreakBefore = true;
639 }
640 }
641
642 const std::vector<TokenAnnotation> &getAnnotations() {
643 return Annotations;
644 }
645
646private:
647 void determineTokenTypes() {
Daniel Jasperaa1c9202012-12-05 14:57:28 +0000648 bool AssignmentEncountered = false;
Daniel Jasperf7935112012-12-03 18:12:45 +0000649 for (int i = 0, e = Line.Tokens.size(); i != e; ++i) {
650 TokenAnnotation &Annotation = Annotations[i];
651 const FormatToken &Tok = Line.Tokens[i];
652
Daniel Jasperaa1c9202012-12-05 14:57:28 +0000653 if (Tok.Tok.is(tok::equal) || Tok.Tok.is(tok::plusequal) ||
654 Tok.Tok.is(tok::minusequal) || Tok.Tok.is(tok::starequal) ||
655 Tok.Tok.is(tok::slashequal))
656 AssignmentEncountered = true;
Daniel Jasper426702d2012-12-05 07:51:39 +0000657
Daniel Jasper8dd40472012-12-21 09:41:31 +0000658 if (Tok.Tok.is(tok::star) || Tok.Tok.is(tok::amp)) {
Daniel Jasperaa1c9202012-12-05 14:57:28 +0000659 Annotation.Type = determineStarAmpUsage(i, AssignmentEncountered);
Daniel Jasper8dd40472012-12-21 09:41:31 +0000660 } else if (Tok.Tok.is(tok::minus) || Tok.Tok.is(tok::plus)) {
661 Annotation.Type = determinePlusMinusUsage(i);
662 } else if (Tok.Tok.is(tok::minusminus) || Tok.Tok.is(tok::plusplus)) {
663 Annotation.Type = determineIncrementUsage(i);
664 } else if (Tok.Tok.is(tok::exclaim)) {
Daniel Jasperf7935112012-12-03 18:12:45 +0000665 Annotation.Type = TokenAnnotation::TT_UnaryOperator;
Daniel Jasper8dd40472012-12-21 09:41:31 +0000666 } else if (isBinaryOperator(Line.Tokens[i]))
Daniel Jasperf7935112012-12-03 18:12:45 +0000667 Annotation.Type = TokenAnnotation::TT_BinaryOperator;
668 else if (Tok.Tok.is(tok::comment)) {
669 StringRef Data(SourceMgr.getCharacterData(Tok.Tok.getLocation()),
670 Tok.Tok.getLength());
671 if (Data.startswith("//"))
672 Annotation.Type = TokenAnnotation::TT_LineComment;
673 else
674 Annotation.Type = TokenAnnotation::TT_BlockComment;
675 }
676 }
677 }
678
Daniel Jasperf7935112012-12-03 18:12:45 +0000679 bool isBinaryOperator(const FormatToken &Tok) {
680 switch (Tok.Tok.getKind()) {
681 case tok::equal:
682 case tok::equalequal:
Daniel Jasper426702d2012-12-05 07:51:39 +0000683 case tok::exclaimequal:
Daniel Jasperf7935112012-12-03 18:12:45 +0000684 case tok::star:
685 //case tok::amp:
686 case tok::plus:
687 case tok::slash:
688 case tok::minus:
689 case tok::ampamp:
690 case tok::pipe:
691 case tok::pipepipe:
692 case tok::percent:
693 return true;
694 default:
695 return false;
696 }
697 }
698
Daniel Jasper426702d2012-12-05 07:51:39 +0000699 TokenAnnotation::TokenType determineStarAmpUsage(unsigned Index,
Daniel Jasperaa1c9202012-12-05 14:57:28 +0000700 bool AssignmentEncountered) {
Daniel Jasperf7935112012-12-03 18:12:45 +0000701 if (Index == Annotations.size())
702 return TokenAnnotation::TT_Unknown;
703
704 if (Index == 0 || Line.Tokens[Index - 1].Tok.is(tok::l_paren) ||
705 Line.Tokens[Index - 1].Tok.is(tok::comma) ||
706 Annotations[Index - 1].Type == TokenAnnotation::TT_BinaryOperator)
707 return TokenAnnotation::TT_UnaryOperator;
708
709 if (Line.Tokens[Index - 1].Tok.isLiteral() ||
Daniel Jasper8dd40472012-12-21 09:41:31 +0000710 Line.Tokens[Index + 1].Tok.isLiteral() ||
711 Line.Tokens[Index + 1].Tok.is(tok::kw_sizeof))
Daniel Jasperf7935112012-12-03 18:12:45 +0000712 return TokenAnnotation::TT_BinaryOperator;
713
Daniel Jasper426702d2012-12-05 07:51:39 +0000714 // It is very unlikely that we are going to find a pointer or reference type
715 // definition on the RHS of an assignment.
Daniel Jasperaa1c9202012-12-05 14:57:28 +0000716 if (AssignmentEncountered)
Daniel Jasper426702d2012-12-05 07:51:39 +0000717 return TokenAnnotation::TT_BinaryOperator;
718
Daniel Jasperf7935112012-12-03 18:12:45 +0000719 return TokenAnnotation::TT_PointerOrReference;
720 }
721
Daniel Jasper8dd40472012-12-21 09:41:31 +0000722 TokenAnnotation::TokenType determinePlusMinusUsage(unsigned Index) {
723 // At the start of the line, +/- specific ObjectiveC method declarations.
724 if (Index == 0)
725 return TokenAnnotation::TT_ObjCMethodSpecifier;
726
727 // Use heuristics to recognize unary operators.
728 const Token &PreviousTok = Line.Tokens[Index - 1].Tok;
729 if (PreviousTok.is(tok::equal) || PreviousTok.is(tok::l_paren) ||
730 PreviousTok.is(tok::comma) || PreviousTok.is(tok::l_square) ||
731 PreviousTok.is(tok::question) || PreviousTok.is(tok::colon))
732 return TokenAnnotation::TT_UnaryOperator;
733
734 // There can't be to consecutive binary operators.
735 if (Annotations[Index - 1].Type == TokenAnnotation::TT_BinaryOperator)
736 return TokenAnnotation::TT_UnaryOperator;
737
738 // Fall back to marking the token as binary operator.
739 return TokenAnnotation::TT_BinaryOperator;
740 }
741
742 /// \brief Determine whether ++/-- are pre- or post-increments/-decrements.
743 TokenAnnotation::TokenType determineIncrementUsage(unsigned Index) {
744 if (Index != 0 && Line.Tokens[Index - 1].Tok.is(tok::identifier))
745 return TokenAnnotation::TT_TrailingUnaryOperator;
746
747 return TokenAnnotation::TT_UnaryOperator;
Daniel Jasperf7935112012-12-03 18:12:45 +0000748 }
749
750 bool spaceRequiredBetween(Token Left, Token Right) {
Daniel Jaspera4396862012-12-10 18:59:13 +0000751 if (Right.is(tok::r_paren) || Right.is(tok::semi) || Right.is(tok::comma))
752 return false;
Daniel Jasperf7935112012-12-03 18:12:45 +0000753 if (Left.is(tok::kw_template) && Right.is(tok::less))
754 return true;
755 if (Left.is(tok::arrow) || Right.is(tok::arrow))
756 return false;
757 if (Left.is(tok::exclaim) || Left.is(tok::tilde))
758 return false;
Fariborz Jahanian68a542a2012-12-20 19:54:13 +0000759 if (Left.is(tok::at) && Right.is(tok::identifier))
760 return false;
Daniel Jasperf7935112012-12-03 18:12:45 +0000761 if (Left.is(tok::less) || Right.is(tok::greater) || Right.is(tok::less))
762 return false;
Daniel Jasper27234032012-12-07 09:52:15 +0000763 if (Right.is(tok::amp) || Right.is(tok::star))
764 return Left.isLiteral() ||
765 (Left.isNot(tok::star) && Left.isNot(tok::amp) &&
766 !Style.PointerAndReferenceBindToType);
Daniel Jasperf7935112012-12-03 18:12:45 +0000767 if (Left.is(tok::amp) || Left.is(tok::star))
768 return Right.isLiteral() || Style.PointerAndReferenceBindToType;
769 if (Right.is(tok::star) && Left.is(tok::l_paren))
770 return false;
Daniel Jasperf7935112012-12-03 18:12:45 +0000771 if (Left.is(tok::l_square) || Right.is(tok::l_square) ||
772 Right.is(tok::r_square))
773 return false;
Daniel Jasper27234032012-12-07 09:52:15 +0000774 if (Left.is(tok::coloncolon) ||
775 (Right.is(tok::coloncolon) &&
776 (Left.is(tok::identifier) || Left.is(tok::greater))))
Daniel Jasperf7935112012-12-03 18:12:45 +0000777 return false;
778 if (Left.is(tok::period) || Right.is(tok::period))
779 return false;
780 if (Left.is(tok::colon) || Right.is(tok::colon))
781 return true;
Daniel Jasperf7935112012-12-03 18:12:45 +0000782 if (Left.is(tok::l_paren))
783 return false;
784 if (Left.is(tok::hash))
785 return false;
Daniel Jasperf7935112012-12-03 18:12:45 +0000786 if (Right.is(tok::l_paren)) {
Daniel Jasper8dd40472012-12-21 09:41:31 +0000787 return Left.is(tok::kw_if) || Left.is(tok::kw_for) ||
788 Left.is(tok::kw_while) || Left.is(tok::kw_switch) ||
789 (Left.isNot(tok::identifier) && Left.isNot(tok::kw_sizeof) &&
790 Left.isNot(tok::kw_typeof));
Daniel Jasperf7935112012-12-03 18:12:45 +0000791 }
792 return true;
793 }
794
795 bool canBreakBetween(const FormatToken &Left, const FormatToken &Right) {
Daniel Jaspere25509f2012-12-17 11:29:41 +0000796 if (Right.Tok.is(tok::r_paren) || Right.Tok.is(tok::l_brace) ||
797 Right.Tok.is(tok::comment) || Right.Tok.is(tok::greater))
Daniel Jasperf7935112012-12-03 18:12:45 +0000798 return false;
Daniel Jasper5485d0c2012-12-17 14:34:14 +0000799 if (isBinaryOperator(Left) || Right.Tok.is(tok::lessless) ||
800 Right.Tok.is(tok::arrow) || Right.Tok.is(tok::period))
Daniel Jaspere9de2602012-12-06 09:56:08 +0000801 return true;
Daniel Jaspere25509f2012-12-17 11:29:41 +0000802 return Right.Tok.is(tok::colon) || Left.Tok.is(tok::comma) || Left.Tok.is(
803 tok::semi) || Left.Tok.is(tok::equal) || Left.Tok.is(tok::ampamp) ||
804 Left.Tok.is(tok::pipepipe) || Left.Tok.is(tok::l_brace) ||
Daniel Jasperf7935112012-12-03 18:12:45 +0000805 (Left.Tok.is(tok::l_paren) && !Right.Tok.is(tok::r_paren));
806 }
807
808 const UnwrappedLine &Line;
809 FormatStyle Style;
810 SourceManager &SourceMgr;
811 std::vector<TokenAnnotation> Annotations;
812};
813
Alexander Kornienkoe3276842012-12-07 16:15:44 +0000814class LexerBasedFormatTokenSource : public FormatTokenSource {
815public:
816 LexerBasedFormatTokenSource(Lexer &Lex, SourceManager &SourceMgr)
Daniel Jasper2af6bbe2012-12-18 21:05:13 +0000817 : GreaterStashed(false), Lex(Lex), SourceMgr(SourceMgr),
Alexander Kornienkoe3276842012-12-07 16:15:44 +0000818 IdentTable(Lex.getLangOpts()) {
819 Lex.SetKeepWhitespaceMode(true);
820 }
821
822 virtual FormatToken getNextToken() {
823 if (GreaterStashed) {
824 FormatTok.NewlinesBefore = 0;
825 FormatTok.WhiteSpaceStart =
826 FormatTok.Tok.getLocation().getLocWithOffset(1);
827 FormatTok.WhiteSpaceLength = 0;
828 GreaterStashed = false;
829 return FormatTok;
830 }
831
832 FormatTok = FormatToken();
833 Lex.LexFromRawLexer(FormatTok.Tok);
834 FormatTok.WhiteSpaceStart = FormatTok.Tok.getLocation();
835
836 // Consume and record whitespace until we find a significant token.
837 while (FormatTok.Tok.is(tok::unknown)) {
838 FormatTok.NewlinesBefore += tokenText(FormatTok.Tok).count('\n');
839 FormatTok.WhiteSpaceLength += FormatTok.Tok.getLength();
840
841 if (FormatTok.Tok.is(tok::eof))
842 return FormatTok;
843 Lex.LexFromRawLexer(FormatTok.Tok);
844 }
845
846 if (FormatTok.Tok.is(tok::raw_identifier)) {
847 const IdentifierInfo &Info = IdentTable.get(tokenText(FormatTok.Tok));
848 FormatTok.Tok.setKind(Info.getTokenID());
849 }
850
851 if (FormatTok.Tok.is(tok::greatergreater)) {
852 FormatTok.Tok.setKind(tok::greater);
853 GreaterStashed = true;
854 }
855
856 return FormatTok;
857 }
858
859private:
860 FormatToken FormatTok;
861 bool GreaterStashed;
862 Lexer &Lex;
863 SourceManager &SourceMgr;
864 IdentifierTable IdentTable;
865
866 /// Returns the text of \c FormatTok.
867 StringRef tokenText(Token &Tok) {
868 return StringRef(SourceMgr.getCharacterData(Tok.getLocation()),
869 Tok.getLength());
870 }
871};
872
Daniel Jasperf7935112012-12-03 18:12:45 +0000873class Formatter : public UnwrappedLineConsumer {
874public:
875 Formatter(const FormatStyle &Style, Lexer &Lex, SourceManager &SourceMgr,
876 const std::vector<CharSourceRange> &Ranges)
Daniel Jasper2af6bbe2012-12-18 21:05:13 +0000877 : Style(Style), Lex(Lex), SourceMgr(SourceMgr), Ranges(Ranges),
Alexander Kornienko870f9eb2012-12-04 17:27:50 +0000878 StructuralError(false) {
Daniel Jasperf7935112012-12-03 18:12:45 +0000879 }
880
Daniel Jasper61bd3a12012-12-04 21:05:31 +0000881 virtual ~Formatter() {
882 }
883
Daniel Jasperf7935112012-12-03 18:12:45 +0000884 tooling::Replacements format() {
Alexander Kornienkoe3276842012-12-07 16:15:44 +0000885 LexerBasedFormatTokenSource Tokens(Lex, SourceMgr);
886 UnwrappedLineParser Parser(Style, Tokens, *this);
Alexander Kornienko870f9eb2012-12-04 17:27:50 +0000887 StructuralError = Parser.parse();
888 for (std::vector<UnwrappedLine>::iterator I = UnwrappedLines.begin(),
889 E = UnwrappedLines.end();
890 I != E; ++I)
Alexander Kornienkobc09a7e2012-12-05 13:56:52 +0000891 formatUnwrappedLine(*I);
Daniel Jasperf7935112012-12-03 18:12:45 +0000892 return Replaces;
893 }
894
895private:
Alexander Kornienkobc09a7e2012-12-05 13:56:52 +0000896 virtual void consumeUnwrappedLine(const UnwrappedLine &TheLine) {
Alexander Kornienko870f9eb2012-12-04 17:27:50 +0000897 UnwrappedLines.push_back(TheLine);
898 }
899
Alexander Kornienkobc09a7e2012-12-05 13:56:52 +0000900 void formatUnwrappedLine(const UnwrappedLine &TheLine) {
Daniel Jasperf7935112012-12-03 18:12:45 +0000901 if (TheLine.Tokens.size() == 0)
902 return;
903
904 CharSourceRange LineRange =
905 CharSourceRange::getTokenRange(TheLine.Tokens.front().Tok.getLocation(),
906 TheLine.Tokens.back().Tok.getLocation());
907
908 for (unsigned i = 0, e = Ranges.size(); i != e; ++i) {
909 if (SourceMgr.isBeforeInTranslationUnit(LineRange.getEnd(),
910 Ranges[i].getBegin()) ||
911 SourceMgr.isBeforeInTranslationUnit(Ranges[i].getEnd(),
912 LineRange.getBegin()))
913 continue;
914
915 TokenAnnotator Annotator(TheLine, Style, SourceMgr);
916 Annotator.annotate();
917 UnwrappedLineFormatter Formatter(Style, SourceMgr, TheLine,
Alexander Kornienko870f9eb2012-12-04 17:27:50 +0000918 Annotator.getAnnotations(), Replaces,
919 StructuralError);
Daniel Jasperf7935112012-12-03 18:12:45 +0000920 Formatter.format();
921 return;
922 }
923 }
924
925 FormatStyle Style;
926 Lexer &Lex;
927 SourceManager &SourceMgr;
928 tooling::Replacements Replaces;
929 std::vector<CharSourceRange> Ranges;
Alexander Kornienko870f9eb2012-12-04 17:27:50 +0000930 std::vector<UnwrappedLine> UnwrappedLines;
931 bool StructuralError;
Daniel Jasperf7935112012-12-03 18:12:45 +0000932};
933
934tooling::Replacements reformat(const FormatStyle &Style, Lexer &Lex,
935 SourceManager &SourceMgr,
936 std::vector<CharSourceRange> Ranges) {
937 Formatter formatter(Style, Lex, SourceMgr, Ranges);
938 return formatter.format();
939}
940
941} // namespace format
942} // namespace clang