blob: 38f66dfbe0313bbbeb77bb8acab719e6abb3f22d [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 Jasper9b155472012-12-04 10:50:12 +000031 enum TokenType { TT_Unknown, TT_TemplateOpener, TT_TemplateCloser,
32 TT_BinaryOperator, TT_UnaryOperator, TT_OverloadedOperator,
33 TT_PointerOrReference, TT_ConditionalExpr, TT_LineComment,
34 TT_BlockComment };
Daniel Jasperf7935112012-12-03 18:12:45 +000035
36 TokenType Type;
37
Daniel Jasperf7935112012-12-03 18:12:45 +000038 bool SpaceRequiredBefore;
39 bool CanBreakBefore;
40 bool MustBreakBefore;
41};
42
43using llvm::MutableArrayRef;
44
45FormatStyle getLLVMStyle() {
46 FormatStyle LLVMStyle;
47 LLVMStyle.ColumnLimit = 80;
48 LLVMStyle.MaxEmptyLinesToKeep = 1;
49 LLVMStyle.PointerAndReferenceBindToType = false;
50 LLVMStyle.AccessModifierOffset = -2;
51 LLVMStyle.SplitTemplateClosingGreater = true;
52 return LLVMStyle;
53}
54
55FormatStyle getGoogleStyle() {
56 FormatStyle GoogleStyle;
57 GoogleStyle.ColumnLimit = 80;
58 GoogleStyle.MaxEmptyLinesToKeep = 1;
59 GoogleStyle.PointerAndReferenceBindToType = true;
60 GoogleStyle.AccessModifierOffset = -1;
61 GoogleStyle.SplitTemplateClosingGreater = false;
62 return GoogleStyle;
63}
64
65struct OptimizationParameters {
66 unsigned PenaltyExtraLine;
67 unsigned PenaltyIndentLevel;
68};
69
70class UnwrappedLineFormatter {
71public:
72 UnwrappedLineFormatter(const FormatStyle &Style, SourceManager &SourceMgr,
73 const UnwrappedLine &Line,
74 const std::vector<TokenAnnotation> &Annotations,
75 tooling::Replacements &Replaces)
76 : Style(Style),
77 SourceMgr(SourceMgr),
78 Line(Line),
79 Annotations(Annotations),
80 Replaces(Replaces) {
81 Parameters.PenaltyExtraLine = 100;
82 Parameters.PenaltyIndentLevel = 5;
83 }
84
85 void format() {
86 formatFirstToken();
87 count = 0;
88 IndentState State;
89 State.Column = Line.Level * 2 + Line.Tokens[0].Tok.getLength();
90 State.CtorInitializerOnNewLine = false;
91 State.InCtorInitializer = false;
92 State.ConsumedTokens = 1;
93
94 //State.UsedIndent.push_back(Line.Level * 2);
95 State.Indent.push_back(Line.Level * 2 + 4);
96 State.LastSpace.push_back(Line.Level * 2);
97
98 // Start iterating at 1 as we have correctly formatted of Token #0 above.
99 for (unsigned i = 1, n = Line.Tokens.size(); i != n; ++i) {
100 unsigned NoBreak = calcPenalty(State, false, UINT_MAX);
101 unsigned Break = calcPenalty(State, true, NoBreak);
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000102 addTokenToState(Break < NoBreak, false, State);
Daniel Jasperf7935112012-12-03 18:12:45 +0000103 }
104 }
105
106private:
107 /// \brief The current state when indenting a unwrapped line.
108 ///
109 /// As the indenting tries different combinations this is copied by value.
110 struct IndentState {
111 /// \brief The number of used columns in the current line.
112 unsigned Column;
113
114 /// \brief The number of tokens already consumed.
115 unsigned ConsumedTokens;
116
117 /// \brief The position to which a specific parenthesis level needs to be
118 /// indented.
119 std::vector<unsigned> Indent;
120
121 std::vector<unsigned> LastSpace;
122
123 bool CtorInitializerOnNewLine;
124 bool InCtorInitializer;
125
126 /// \brief Comparison operator to be able to used \c IndentState in \c map.
127 bool operator<(const IndentState &Other) const {
128 if (Other.ConsumedTokens != ConsumedTokens)
129 return Other.ConsumedTokens > ConsumedTokens;
130 if (Other.Column != Column)
131 return Other.Column > Column;
132 if (Other.Indent.size() != Indent.size())
133 return Other.Indent.size() > Indent.size();
134 for (int i = 0, e = Indent.size(); i != e; ++i) {
135 if (Other.Indent[i] != Indent[i])
136 return Other.Indent[i] > Indent[i];
137 }
138 if (Other.LastSpace.size() != LastSpace.size())
139 return Other.LastSpace.size() > LastSpace.size();
140 for (int i = 0, e = LastSpace.size(); i != e; ++i) {
141 if (Other.LastSpace[i] != LastSpace[i])
142 return Other.LastSpace[i] > LastSpace[i];
143 }
144 return false;
145 }
146 };
147
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000148 /// \brief Appends the next token to \p State and updates information
149 /// necessary for indentation.
150 ///
151 /// Puts the token on the current line if \p Newline is \c true and adds a
152 /// line break and necessary indentation otherwise.
153 ///
154 /// If \p DryRun is \c false, also creates and stores the required
155 /// \c Replacement.
156 void addTokenToState(bool Newline, bool DryRun, IndentState &State) {
Daniel Jasperf7935112012-12-03 18:12:45 +0000157 unsigned Index = State.ConsumedTokens;
158 const FormatToken &Current = Line.Tokens[Index];
159 const FormatToken &Previous = Line.Tokens[Index - 1];
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000160 unsigned ParenLevel = State.Indent.size() - 1;
Daniel Jasperf7935112012-12-03 18:12:45 +0000161
162 if (Newline) {
163 if (Current.Tok.is(tok::string_literal) &&
164 Previous.Tok.is(tok::string_literal))
165 State.Column = State.Column - Previous.Tok.getLength();
166 else if (Previous.Tok.is(tok::equal) && ParenLevel != 0)
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000167 // Indent and extra 4 spaces after '=' as it continues an expression.
168 // Don't do that on the top level, as we already indent 4 there.
Daniel Jasperf7935112012-12-03 18:12:45 +0000169 State.Column = State.Indent[ParenLevel] + 4;
Daniel Jasper9b155472012-12-04 10:50:12 +0000170 else
Daniel Jasperf7935112012-12-03 18:12:45 +0000171 State.Column = State.Indent[ParenLevel];
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000172
Daniel Jasperf7935112012-12-03 18:12:45 +0000173 if (!DryRun)
174 replaceWhitespace(Current, 1, State.Column);
175
176 State.Column += Current.Tok.getLength();
Daniel Jasper9b155472012-12-04 10:50:12 +0000177 State.LastSpace[ParenLevel] = State.Indent[ParenLevel];
Daniel Jasperf7935112012-12-03 18:12:45 +0000178 if (Current.Tok.is(tok::colon) &&
179 Annotations[Index].Type != TokenAnnotation::TT_ConditionalExpr) {
180 State.Indent[ParenLevel] += 2;
181 State.CtorInitializerOnNewLine = true;
182 State.InCtorInitializer = true;
183 }
184 } else {
185 unsigned Spaces = Annotations[Index].SpaceRequiredBefore ? 1 : 0;
186 if (Annotations[Index].Type == TokenAnnotation::TT_LineComment)
187 Spaces = 2;
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000188
Daniel Jasperf7935112012-12-03 18:12:45 +0000189 if (!DryRun)
190 replaceWhitespace(Current, 0, Spaces);
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000191
192 if (Previous.Tok.is(tok::l_paren) ||
193 Annotations[Index - 1].Type == TokenAnnotation::TT_TemplateOpener)
Daniel Jasperf7935112012-12-03 18:12:45 +0000194 State.Indent[ParenLevel] = State.Column;
195 if (Current.Tok.is(tok::colon)) {
196 State.Indent[ParenLevel] = State.Column + 3;
197 State.InCtorInitializer = true;
198 }
199 // Top-level spaces are exempt as that mostly leads to better results.
Daniel Jasper9b155472012-12-04 10:50:12 +0000200 if (Spaces > 0 && ParenLevel != 0)
Daniel Jasperf7935112012-12-03 18:12:45 +0000201 State.LastSpace[ParenLevel] = State.Column + Spaces;
202 State.Column += Current.Tok.getLength() + Spaces;
203 }
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000204 moveStateToNextToken(State);
205 }
Daniel Jasperf7935112012-12-03 18:12:45 +0000206
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000207 /// \brief Mark the next token as consumed in \p State and modify its stacks
208 /// accordingly.
209 void moveStateToNextToken(IndentState &State) {
210 unsigned Index = State.ConsumedTokens;
211 const FormatToken &Current = Line.Tokens[Index];
212
213 // If we encounter an opening (, [ or <, we add a level to our stacks to
214 // prepare for the following tokens.
215 if (Current.Tok.is(tok::l_paren) || Current.Tok.is(tok::l_square) ||
216 Annotations[Index].Type == TokenAnnotation::TT_TemplateOpener) {
217 State.Indent.push_back(4 + State.LastSpace.back());
218 State.LastSpace.push_back(State.LastSpace.back());
219 }
220
221 // If we encounter a closing ), ] or >, we can remove a level from our
222 // stacks.
Daniel Jasper9b155472012-12-04 10:50:12 +0000223 if (Current.Tok.is(tok::r_paren) || Current.Tok.is(tok::r_square) ||
224 Annotations[Index].Type == TokenAnnotation::TT_TemplateCloser) {
Daniel Jasperf7935112012-12-03 18:12:45 +0000225 State.Indent.pop_back();
226 State.LastSpace.pop_back();
227 }
228
229 ++State.ConsumedTokens;
230 }
231
232 typedef std::map<IndentState, unsigned> StateMap;
233 StateMap Memory;
234
235 unsigned splitPenalty(const FormatToken &Token) {
236 if (Token.Tok.is(tok::semi))
237 return 0;
238 if (Token.Tok.is(tok::comma))
239 return 1;
240 if (Token.Tok.is(tok::equal) || Token.Tok.is(tok::l_paren) ||
241 Token.Tok.is(tok::pipepipe) || Token.Tok.is(tok::ampamp))
242 return 2;
243 return 3;
244 }
245
246 /// \brief Calculate the number of lines needed to format the remaining part
247 /// of the unwrapped line.
248 ///
249 /// Assumes the formatting so far has led to
250 /// the \c IndentState \p State. If \p NewLine is set, a new line will be
251 /// added after the previous token.
252 ///
253 /// \param StopAt is used for optimization. If we can determine that we'll
254 /// definitely need at least \p StopAt additional lines, we already know of a
255 /// better solution.
256 unsigned calcPenalty(IndentState State, bool NewLine, unsigned StopAt) {
257 // We are at the end of the unwrapped line, so we don't need any more lines.
258 if (State.ConsumedTokens >= Line.Tokens.size())
259 return 0;
260
261 if (!NewLine && Annotations[State.ConsumedTokens].MustBreakBefore)
262 return UINT_MAX;
263 if (NewLine && !Annotations[State.ConsumedTokens].CanBreakBefore)
264 return UINT_MAX;
265
266 if (State.ConsumedTokens > 0 && !NewLine &&
267 State.CtorInitializerOnNewLine &&
268 Line.Tokens[State.ConsumedTokens - 1].Tok.is(tok::comma))
269 return UINT_MAX;
270
271 if (NewLine && State.InCtorInitializer && !State.CtorInitializerOnNewLine)
272 return UINT_MAX;
273
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000274 addTokenToState(NewLine, true, State);
Daniel Jasperf7935112012-12-03 18:12:45 +0000275
276 // Exceeding column limit is bad.
277 if (State.Column > Style.ColumnLimit)
278 return UINT_MAX;
279
280 unsigned CurrentPenalty = 0;
281 if (NewLine) {
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000282 CurrentPenalty += Parameters.PenaltyIndentLevel * State.Indent.size() +
Daniel Jasperf7935112012-12-03 18:12:45 +0000283 Parameters.PenaltyExtraLine +
284 splitPenalty(Line.Tokens[State.ConsumedTokens - 2]);
285 }
286
287 if (StopAt <= CurrentPenalty)
288 return UINT_MAX;
289 StopAt -= CurrentPenalty;
290
291 // Has this state already been examined?
292 StateMap::iterator I = Memory.find(State);
293 if (I != Memory.end())
294 return I->second;
295 ++count;
296
297 unsigned NoBreak = calcPenalty(State, false, StopAt);
298 unsigned WithBreak = calcPenalty(State, true, std::min(StopAt, NoBreak));
299 unsigned Result = std::min(NoBreak, WithBreak);
300 if (Result != UINT_MAX)
301 Result += CurrentPenalty;
302 Memory[State] = Result;
303 assert(Memory.find(State) != Memory.end());
304 return Result;
305 }
306
307 /// \brief Replaces the whitespace in front of \p Tok. Only call once for
308 /// each \c FormatToken.
309 void replaceWhitespace(const FormatToken &Tok, unsigned NewLines,
310 unsigned Spaces) {
311 Replaces.insert(tooling::Replacement(
312 SourceMgr, Tok.WhiteSpaceStart, Tok.WhiteSpaceLength,
313 std::string(NewLines, '\n') + std::string(Spaces, ' ')));
314 }
315
316 /// \brief Add a new line and the required indent before the first Token
317 /// of the \c UnwrappedLine.
318 void formatFirstToken() {
319 const FormatToken &Token = Line.Tokens[0];
320 if (Token.WhiteSpaceStart.isValid()) {
321 unsigned Newlines =
322 std::min(Token.NewlinesBefore, Style.MaxEmptyLinesToKeep + 1);
323 unsigned Offset = SourceMgr.getFileOffset(Token.WhiteSpaceStart);
324 if (Newlines == 0 && Offset != 0)
325 Newlines = 1;
326 unsigned Indent = Line.Level * 2;
327 if (Token.Tok.is(tok::kw_public) || Token.Tok.is(tok::kw_protected) ||
328 Token.Tok.is(tok::kw_private))
329 Indent += Style.AccessModifierOffset;
330 replaceWhitespace(Token, Newlines, Indent);
331 }
332 }
333
334 FormatStyle Style;
335 SourceManager &SourceMgr;
336 const UnwrappedLine &Line;
337 const std::vector<TokenAnnotation> &Annotations;
338 tooling::Replacements &Replaces;
339 unsigned int count;
340
341 OptimizationParameters Parameters;
342};
343
344/// \brief Determines extra information about the tokens comprising an
345/// \c UnwrappedLine.
346class TokenAnnotator {
347public:
348 TokenAnnotator(const UnwrappedLine &Line, const FormatStyle &Style,
349 SourceManager &SourceMgr)
350 : Line(Line),
351 Style(Style),
352 SourceMgr(SourceMgr) {
353 }
354
355 /// \brief A parser that gathers additional information about tokens.
356 ///
357 /// The \c TokenAnnotator tries to matches parenthesis and square brakets and
358 /// store a parenthesis levels. It also tries to resolve matching "<" and ">"
359 /// into template parameter lists.
360 class AnnotatingParser {
361 public:
Manuel Klimek6a5619d2012-12-03 20:55:42 +0000362 AnnotatingParser(const SmallVector<FormatToken, 16> &Tokens,
Daniel Jasperf7935112012-12-03 18:12:45 +0000363 std::vector<TokenAnnotation> &Annotations)
Manuel Klimek6a5619d2012-12-03 20:55:42 +0000364 : Tokens(Tokens),
Daniel Jasperf7935112012-12-03 18:12:45 +0000365 Annotations(Annotations),
366 Index(0) {
367 }
368
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000369 bool parseAngle() {
Daniel Jasperf7935112012-12-03 18:12:45 +0000370 while (Index < Tokens.size()) {
371 if (Tokens[Index].Tok.is(tok::greater)) {
Daniel Jasper9b155472012-12-04 10:50:12 +0000372 Annotations[Index].Type = TokenAnnotation::TT_TemplateCloser;
Daniel Jasperf7935112012-12-03 18:12:45 +0000373 next();
374 return true;
375 }
376 if (Tokens[Index].Tok.is(tok::r_paren) ||
377 Tokens[Index].Tok.is(tok::r_square))
378 return false;
379 if (Tokens[Index].Tok.is(tok::pipepipe) ||
380 Tokens[Index].Tok.is(tok::ampamp) ||
381 Tokens[Index].Tok.is(tok::question) ||
382 Tokens[Index].Tok.is(tok::colon))
383 return false;
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000384 consumeToken();
Daniel Jasperf7935112012-12-03 18:12:45 +0000385 }
386 return false;
387 }
388
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000389 bool parseParens() {
Daniel Jasperf7935112012-12-03 18:12:45 +0000390 while (Index < Tokens.size()) {
391 if (Tokens[Index].Tok.is(tok::r_paren)) {
Daniel Jasperf7935112012-12-03 18:12:45 +0000392 next();
393 return true;
394 }
395 if (Tokens[Index].Tok.is(tok::r_square))
396 return false;
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000397 consumeToken();
Daniel Jasperf7935112012-12-03 18:12:45 +0000398 }
399 return false;
400 }
401
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000402 bool parseSquare() {
Daniel Jasperf7935112012-12-03 18:12:45 +0000403 while (Index < Tokens.size()) {
404 if (Tokens[Index].Tok.is(tok::r_square)) {
Daniel Jasperf7935112012-12-03 18:12:45 +0000405 next();
406 return true;
407 }
408 if (Tokens[Index].Tok.is(tok::r_paren))
409 return false;
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000410 consumeToken();
Daniel Jasperf7935112012-12-03 18:12:45 +0000411 }
412 return false;
413 }
414
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000415 bool parseConditional() {
Daniel Jasperf7935112012-12-03 18:12:45 +0000416 while (Index < Tokens.size()) {
417 if (Tokens[Index].Tok.is(tok::colon)) {
418 Annotations[Index].Type = TokenAnnotation::TT_ConditionalExpr;
419 next();
420 return true;
421 }
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000422 consumeToken();
Daniel Jasperf7935112012-12-03 18:12:45 +0000423 }
424 return false;
425 }
426
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000427 void consumeToken() {
Daniel Jasperf7935112012-12-03 18:12:45 +0000428 unsigned CurrentIndex = Index;
429 next();
430 switch (Tokens[CurrentIndex].Tok.getKind()) {
431 case tok::l_paren:
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000432 parseParens();
Daniel Jasperf7935112012-12-03 18:12:45 +0000433 break;
434 case tok::l_square:
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000435 parseSquare();
Daniel Jasperf7935112012-12-03 18:12:45 +0000436 break;
437 case tok::less:
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000438 if (parseAngle())
Daniel Jasperf7935112012-12-03 18:12:45 +0000439 Annotations[CurrentIndex].Type = TokenAnnotation::TT_TemplateOpener;
440 else {
441 Annotations[CurrentIndex].Type = TokenAnnotation::TT_BinaryOperator;
442 Index = CurrentIndex + 1;
443 }
444 break;
445 case tok::greater:
446 Annotations[CurrentIndex].Type = TokenAnnotation::TT_BinaryOperator;
447 break;
448 case tok::kw_operator:
449 if (!Tokens[Index].Tok.is(tok::l_paren))
450 Annotations[Index].Type = TokenAnnotation::TT_OverloadedOperator;
451 next();
452 break;
453 case tok::question:
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000454 parseConditional();
Daniel Jasperf7935112012-12-03 18:12:45 +0000455 break;
456 default:
457 break;
458 }
459 }
460
461 void parseLine() {
462 while (Index < Tokens.size()) {
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000463 consumeToken();
Daniel Jasperf7935112012-12-03 18:12:45 +0000464 }
465 }
466
467 void next() {
468 ++Index;
469 }
470
471 private:
Daniel Jasperf7935112012-12-03 18:12:45 +0000472 const SmallVector<FormatToken, 16> &Tokens;
473 std::vector<TokenAnnotation> &Annotations;
474 unsigned Index;
475 };
476
477 void annotate() {
478 Annotations.clear();
479 for (int i = 0, e = Line.Tokens.size(); i != e; ++i) {
480 Annotations.push_back(TokenAnnotation());
481 }
482
Manuel Klimek6a5619d2012-12-03 20:55:42 +0000483 AnnotatingParser Parser(Line.Tokens, Annotations);
Daniel Jasperf7935112012-12-03 18:12:45 +0000484 Parser.parseLine();
485
486 determineTokenTypes();
487
488 for (int i = 1, e = Line.Tokens.size(); i != e; ++i) {
489 TokenAnnotation &Annotation = Annotations[i];
490
491 Annotation.CanBreakBefore =
492 canBreakBetween(Line.Tokens[i - 1], Line.Tokens[i]);
493
494 if (Line.Tokens[i].Tok.is(tok::colon)) {
495 if (Line.Tokens[0].Tok.is(tok::kw_case) || i == e - 1) {
496 Annotation.SpaceRequiredBefore = false;
497 } else {
498 Annotation.SpaceRequiredBefore = TokenAnnotation::TT_ConditionalExpr;
499 }
500 } else if (Annotations[i - 1].Type == TokenAnnotation::TT_UnaryOperator) {
501 Annotation.SpaceRequiredBefore = false;
502 } else if (Annotation.Type == TokenAnnotation::TT_UnaryOperator) {
503 Annotation.SpaceRequiredBefore =
Daniel Jasper8b529712012-12-04 13:02:32 +0000504 Line.Tokens[i - 1].Tok.isNot(tok::l_paren) &&
505 Line.Tokens[i - 1].Tok.isNot(tok::l_square);
Daniel Jasperf7935112012-12-03 18:12:45 +0000506 } else if (Line.Tokens[i - 1].Tok.is(tok::greater) &&
507 Line.Tokens[i].Tok.is(tok::greater)) {
Daniel Jasper8b529712012-12-04 13:02:32 +0000508 if (Annotation.Type == TokenAnnotation::TT_TemplateCloser &&
Daniel Jasper6021c4a2012-12-04 14:54:30 +0000509 Annotations[i - 1].Type == TokenAnnotation::TT_TemplateCloser)
Daniel Jasper9b155472012-12-04 10:50:12 +0000510 Annotation.SpaceRequiredBefore = Style.SplitTemplateClosingGreater;
Daniel Jasperf7935112012-12-03 18:12:45 +0000511 else
512 Annotation.SpaceRequiredBefore = false;
513 } else if (
514 Annotation.Type == TokenAnnotation::TT_BinaryOperator ||
515 Annotations[i - 1].Type == TokenAnnotation::TT_BinaryOperator) {
516 Annotation.SpaceRequiredBefore = true;
517 } else if (
Daniel Jasper9b155472012-12-04 10:50:12 +0000518 Annotations[i - 1].Type == TokenAnnotation::TT_TemplateCloser &&
Daniel Jasperf7935112012-12-03 18:12:45 +0000519 Line.Tokens[i].Tok.is(tok::l_paren)) {
520 Annotation.SpaceRequiredBefore = false;
Daniel Jasper8b529712012-12-04 13:02:32 +0000521 } else if (Line.Tokens[i].Tok.is(tok::less) &&
522 Line.Tokens[0].Tok.is(tok::hash)) {
523 Annotation.SpaceRequiredBefore = true;
Daniel Jasperf7935112012-12-03 18:12:45 +0000524 } else {
525 Annotation.SpaceRequiredBefore =
526 spaceRequiredBetween(Line.Tokens[i - 1].Tok, Line.Tokens[i].Tok);
527 }
528
529 if (Annotations[i - 1].Type == TokenAnnotation::TT_LineComment ||
530 (Line.Tokens[i].Tok.is(tok::string_literal) &&
531 Line.Tokens[i - 1].Tok.is(tok::string_literal))) {
532 Annotation.MustBreakBefore = true;
533 }
534
535 if (Annotation.MustBreakBefore)
536 Annotation.CanBreakBefore = true;
537 }
538 }
539
540 const std::vector<TokenAnnotation> &getAnnotations() {
541 return Annotations;
542 }
543
544private:
545 void determineTokenTypes() {
546 for (int i = 0, e = Line.Tokens.size(); i != e; ++i) {
547 TokenAnnotation &Annotation = Annotations[i];
548 const FormatToken &Tok = Line.Tokens[i];
549
550 if (Tok.Tok.is(tok::star) || Tok.Tok.is(tok::amp))
551 Annotation.Type = determineStarAmpUsage(i);
Daniel Jasper8b529712012-12-04 13:02:32 +0000552 else if (isUnaryOperator(i))
Daniel Jasperf7935112012-12-03 18:12:45 +0000553 Annotation.Type = TokenAnnotation::TT_UnaryOperator;
554 else if (isBinaryOperator(Line.Tokens[i]))
555 Annotation.Type = TokenAnnotation::TT_BinaryOperator;
556 else if (Tok.Tok.is(tok::comment)) {
557 StringRef Data(SourceMgr.getCharacterData(Tok.Tok.getLocation()),
558 Tok.Tok.getLength());
559 if (Data.startswith("//"))
560 Annotation.Type = TokenAnnotation::TT_LineComment;
561 else
562 Annotation.Type = TokenAnnotation::TT_BlockComment;
563 }
564 }
565 }
566
Daniel Jasper8b529712012-12-04 13:02:32 +0000567 bool isUnaryOperator(unsigned Index) {
568 const Token &Tok = Line.Tokens[Index].Tok;
569 if (Tok.isNot(tok::minus) && Tok.isNot(tok::plus))
570 return false;
571 const Token &PreviousTok = Line.Tokens[Index - 1].Tok;
572 if (PreviousTok.is(tok::equal) || PreviousTok.is(tok::l_paren) ||
573 PreviousTok.is(tok::comma) || PreviousTok.is(tok::l_square))
574 return true;
575 return Annotations[Index - 1].Type == TokenAnnotation::TT_BinaryOperator;
576 }
577
Daniel Jasperf7935112012-12-03 18:12:45 +0000578 bool isBinaryOperator(const FormatToken &Tok) {
579 switch (Tok.Tok.getKind()) {
580 case tok::equal:
581 case tok::equalequal:
582 case tok::star:
583 //case tok::amp:
584 case tok::plus:
585 case tok::slash:
586 case tok::minus:
587 case tok::ampamp:
588 case tok::pipe:
589 case tok::pipepipe:
590 case tok::percent:
591 return true;
592 default:
593 return false;
594 }
595 }
596
597 TokenAnnotation::TokenType determineStarAmpUsage(unsigned Index) {
598 if (Index == Annotations.size())
599 return TokenAnnotation::TT_Unknown;
600
601 if (Index == 0 || Line.Tokens[Index - 1].Tok.is(tok::l_paren) ||
602 Line.Tokens[Index - 1].Tok.is(tok::comma) ||
603 Annotations[Index - 1].Type == TokenAnnotation::TT_BinaryOperator)
604 return TokenAnnotation::TT_UnaryOperator;
605
606 if (Line.Tokens[Index - 1].Tok.isLiteral() ||
607 Line.Tokens[Index + 1].Tok.isLiteral())
608 return TokenAnnotation::TT_BinaryOperator;
609
610 return TokenAnnotation::TT_PointerOrReference;
611 }
612
613 bool isIfForOrWhile(Token Tok) {
614 return Tok.is(tok::kw_if) || Tok.is(tok::kw_for) || Tok.is(tok::kw_while);
615 }
616
617 bool spaceRequiredBetween(Token Left, Token Right) {
618 if (Left.is(tok::kw_template) && Right.is(tok::less))
619 return true;
620 if (Left.is(tok::arrow) || Right.is(tok::arrow))
621 return false;
622 if (Left.is(tok::exclaim) || Left.is(tok::tilde))
623 return false;
624 if (Left.is(tok::less) || Right.is(tok::greater) || Right.is(tok::less))
625 return false;
626 if (Left.is(tok::amp) || Left.is(tok::star))
627 return Right.isLiteral() || Style.PointerAndReferenceBindToType;
628 if (Right.is(tok::star) && Left.is(tok::l_paren))
629 return false;
630 if (Right.is(tok::amp) || Right.is(tok::star))
631 return Left.isLiteral() || !Style.PointerAndReferenceBindToType;
632 if (Left.is(tok::l_square) || Right.is(tok::l_square) ||
633 Right.is(tok::r_square))
634 return false;
635 if (Left.is(tok::coloncolon) || Right.is(tok::coloncolon))
636 return false;
637 if (Left.is(tok::period) || Right.is(tok::period))
638 return false;
639 if (Left.is(tok::colon) || Right.is(tok::colon))
640 return true;
641 if ((Left.is(tok::plusplus) && Right.isAnyIdentifier()) ||
642 (Left.isAnyIdentifier() && Right.is(tok::plusplus)) ||
643 (Left.is(tok::minusminus) && Right.isAnyIdentifier()) ||
644 (Left.isAnyIdentifier() && Right.is(tok::minusminus)))
645 return false;
646 if (Left.is(tok::l_paren))
647 return false;
648 if (Left.is(tok::hash))
649 return false;
650 if (Right.is(tok::r_paren) || Right.is(tok::semi) || Right.is(tok::comma))
651 return false;
652 if (Right.is(tok::l_paren)) {
653 return !Left.isAnyIdentifier() || isIfForOrWhile(Left);
654 }
655 return true;
656 }
657
658 bool canBreakBetween(const FormatToken &Left, const FormatToken &Right) {
659 if (Right.Tok.is(tok::r_paren))
660 return false;
661 if (isBinaryOperator(Left))
662 return true;
663 return Right.Tok.is(tok::colon) || Left.Tok.is(tok::comma) || Left.Tok.is(
664 tok::semi) || Left.Tok.is(tok::equal) || Left.Tok.is(tok::ampamp) ||
665 (Left.Tok.is(tok::l_paren) && !Right.Tok.is(tok::r_paren));
666 }
667
668 const UnwrappedLine &Line;
669 FormatStyle Style;
670 SourceManager &SourceMgr;
671 std::vector<TokenAnnotation> Annotations;
672};
673
674class Formatter : public UnwrappedLineConsumer {
675public:
676 Formatter(const FormatStyle &Style, Lexer &Lex, SourceManager &SourceMgr,
677 const std::vector<CharSourceRange> &Ranges)
678 : Style(Style),
679 Lex(Lex),
680 SourceMgr(SourceMgr),
681 Ranges(Ranges) {
682 }
683
684 tooling::Replacements format() {
685 UnwrappedLineParser Parser(Lex, SourceMgr, *this);
686 Parser.parse();
687 return Replaces;
688 }
689
690private:
691 virtual void formatUnwrappedLine(const UnwrappedLine &TheLine) {
692 if (TheLine.Tokens.size() == 0)
693 return;
694
695 CharSourceRange LineRange =
696 CharSourceRange::getTokenRange(TheLine.Tokens.front().Tok.getLocation(),
697 TheLine.Tokens.back().Tok.getLocation());
698
699 for (unsigned i = 0, e = Ranges.size(); i != e; ++i) {
700 if (SourceMgr.isBeforeInTranslationUnit(LineRange.getEnd(),
701 Ranges[i].getBegin()) ||
702 SourceMgr.isBeforeInTranslationUnit(Ranges[i].getEnd(),
703 LineRange.getBegin()))
704 continue;
705
706 TokenAnnotator Annotator(TheLine, Style, SourceMgr);
707 Annotator.annotate();
708 UnwrappedLineFormatter Formatter(Style, SourceMgr, TheLine,
709 Annotator.getAnnotations(), Replaces);
710 Formatter.format();
711 return;
712 }
713 }
714
715 FormatStyle Style;
716 Lexer &Lex;
717 SourceManager &SourceMgr;
718 tooling::Replacements Replaces;
719 std::vector<CharSourceRange> Ranges;
720};
721
722tooling::Replacements reformat(const FormatStyle &Style, Lexer &Lex,
723 SourceManager &SourceMgr,
724 std::vector<CharSourceRange> Ranges) {
725 Formatter formatter(Style, Lex, SourceMgr, Ranges);
726 return formatter.format();
727}
728
729} // namespace format
730} // namespace clang