blob: 6ca70c7fadb9dfa781e2f318bb5f83897e88c66f [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 Jasperf7935112012-12-03 18:12:45 +000024namespace clang {
25namespace format {
26
27// FIXME: Move somewhere sane.
28struct TokenAnnotation {
29 enum TokenType { TT_Unknown, TT_TemplateOpener, TT_BinaryOperator,
30 TT_UnaryOperator, TT_OverloadedOperator, TT_PointerOrReference,
31 TT_ConditionalExpr, TT_LineComment, TT_BlockComment };
32
33 TokenType Type;
34
35 /// \brief The current parenthesis level, i.e. the number of opening minus
36 /// the number of closing parenthesis left of the current position.
37 unsigned ParenLevel;
38
39 bool SpaceRequiredBefore;
40 bool CanBreakBefore;
41 bool MustBreakBefore;
42};
43
44using llvm::MutableArrayRef;
45
46FormatStyle getLLVMStyle() {
47 FormatStyle LLVMStyle;
48 LLVMStyle.ColumnLimit = 80;
49 LLVMStyle.MaxEmptyLinesToKeep = 1;
50 LLVMStyle.PointerAndReferenceBindToType = false;
51 LLVMStyle.AccessModifierOffset = -2;
52 LLVMStyle.SplitTemplateClosingGreater = true;
53 return LLVMStyle;
54}
55
56FormatStyle getGoogleStyle() {
57 FormatStyle GoogleStyle;
58 GoogleStyle.ColumnLimit = 80;
59 GoogleStyle.MaxEmptyLinesToKeep = 1;
60 GoogleStyle.PointerAndReferenceBindToType = true;
61 GoogleStyle.AccessModifierOffset = -1;
62 GoogleStyle.SplitTemplateClosingGreater = false;
63 return GoogleStyle;
64}
65
66struct OptimizationParameters {
67 unsigned PenaltyExtraLine;
68 unsigned PenaltyIndentLevel;
69};
70
71class UnwrappedLineFormatter {
72public:
73 UnwrappedLineFormatter(const FormatStyle &Style, SourceManager &SourceMgr,
74 const UnwrappedLine &Line,
75 const std::vector<TokenAnnotation> &Annotations,
76 tooling::Replacements &Replaces)
77 : Style(Style),
78 SourceMgr(SourceMgr),
79 Line(Line),
80 Annotations(Annotations),
81 Replaces(Replaces) {
82 Parameters.PenaltyExtraLine = 100;
83 Parameters.PenaltyIndentLevel = 5;
84 }
85
86 void format() {
87 formatFirstToken();
88 count = 0;
89 IndentState State;
90 State.Column = Line.Level * 2 + Line.Tokens[0].Tok.getLength();
91 State.CtorInitializerOnNewLine = false;
92 State.InCtorInitializer = false;
93 State.ConsumedTokens = 1;
94
95 //State.UsedIndent.push_back(Line.Level * 2);
96 State.Indent.push_back(Line.Level * 2 + 4);
97 State.LastSpace.push_back(Line.Level * 2);
98
99 // Start iterating at 1 as we have correctly formatted of Token #0 above.
100 for (unsigned i = 1, n = Line.Tokens.size(); i != n; ++i) {
101 unsigned NoBreak = calcPenalty(State, false, UINT_MAX);
102 unsigned Break = calcPenalty(State, true, NoBreak);
103 addToken(Break < NoBreak, false, State);
104 }
105 }
106
107private:
108 /// \brief The current state when indenting a unwrapped line.
109 ///
110 /// As the indenting tries different combinations this is copied by value.
111 struct IndentState {
112 /// \brief The number of used columns in the current line.
113 unsigned Column;
114
115 /// \brief The number of tokens already consumed.
116 unsigned ConsumedTokens;
117
118 /// \brief The position to which a specific parenthesis level needs to be
119 /// indented.
120 std::vector<unsigned> Indent;
121
122 std::vector<unsigned> LastSpace;
123
124 bool CtorInitializerOnNewLine;
125 bool InCtorInitializer;
126
127 /// \brief Comparison operator to be able to used \c IndentState in \c map.
128 bool operator<(const IndentState &Other) const {
129 if (Other.ConsumedTokens != ConsumedTokens)
130 return Other.ConsumedTokens > ConsumedTokens;
131 if (Other.Column != Column)
132 return Other.Column > Column;
133 if (Other.Indent.size() != Indent.size())
134 return Other.Indent.size() > Indent.size();
135 for (int i = 0, e = Indent.size(); i != e; ++i) {
136 if (Other.Indent[i] != Indent[i])
137 return Other.Indent[i] > Indent[i];
138 }
139 if (Other.LastSpace.size() != LastSpace.size())
140 return Other.LastSpace.size() > LastSpace.size();
141 for (int i = 0, e = LastSpace.size(); i != e; ++i) {
142 if (Other.LastSpace[i] != LastSpace[i])
143 return Other.LastSpace[i] > LastSpace[i];
144 }
145 return false;
146 }
147 };
148
149 /// Append the next token to \p State.
150 void addToken(bool Newline, bool DryRun, IndentState &State) {
151 unsigned Index = State.ConsumedTokens;
152 const FormatToken &Current = Line.Tokens[Index];
153 const FormatToken &Previous = Line.Tokens[Index - 1];
154 unsigned ParenLevel = Annotations[Index].ParenLevel;
155
156 if (Current.Tok.is(tok::l_paren) || Current.Tok.is(tok::l_square) ||
157 Annotations[Index].Type == TokenAnnotation::TT_TemplateOpener) {
158 State.Indent.push_back(4 + State.LastSpace.back());
159 State.LastSpace.push_back(State.LastSpace.back());
160 }
161
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)
167 State.Column = State.Indent[ParenLevel] + 4;
Manuel Klimek6a5619d2012-12-03 20:55:42 +0000168 else if (ParenLevel < State.Indent.size())
Daniel Jasperf7935112012-12-03 18:12:45 +0000169 State.Column = State.Indent[ParenLevel];
170 if (!DryRun)
171 replaceWhitespace(Current, 1, State.Column);
172
173 State.Column += Current.Tok.getLength();
Manuel Klimek6a5619d2012-12-03 20:55:42 +0000174 if (ParenLevel < State.LastSpace.size())
175 State.LastSpace[ParenLevel] = State.Indent[ParenLevel];
Daniel Jasperf7935112012-12-03 18:12:45 +0000176 if (Current.Tok.is(tok::colon) &&
177 Annotations[Index].Type != TokenAnnotation::TT_ConditionalExpr) {
178 State.Indent[ParenLevel] += 2;
179 State.CtorInitializerOnNewLine = true;
180 State.InCtorInitializer = true;
181 }
182 } else {
183 unsigned Spaces = Annotations[Index].SpaceRequiredBefore ? 1 : 0;
184 if (Annotations[Index].Type == TokenAnnotation::TT_LineComment)
185 Spaces = 2;
186 if (!DryRun)
187 replaceWhitespace(Current, 0, Spaces);
188 if (Previous.Tok.is(tok::l_paren))
189 State.Indent[ParenLevel] = State.Column;
190 if (Previous.Tok.is(tok::less) &&
Manuel Klimek6a5619d2012-12-03 20:55:42 +0000191 Annotations[Index - 1].Type == TokenAnnotation::TT_TemplateOpener &&
192 ParenLevel < State.Indent.size())
Daniel Jasperf7935112012-12-03 18:12:45 +0000193 State.Indent[ParenLevel] = State.Column;
194 if (Current.Tok.is(tok::colon)) {
195 State.Indent[ParenLevel] = State.Column + 3;
196 State.InCtorInitializer = true;
197 }
198 // Top-level spaces are exempt as that mostly leads to better results.
Manuel Klimek6a5619d2012-12-03 20:55:42 +0000199 if (Spaces > 0 && ParenLevel != 0 &&
200 ParenLevel < State.LastSpace.size())
Daniel Jasperf7935112012-12-03 18:12:45 +0000201 State.LastSpace[ParenLevel] = State.Column + Spaces;
202 State.Column += Current.Tok.getLength() + Spaces;
203 }
204
Manuel Klimek6a5619d2012-12-03 20:55:42 +0000205 if (!DryRun &&
206 (Current.Tok.is(tok::r_paren) || Current.Tok.is(tok::r_square) ||
207 Annotations[Index].Type == TokenAnnotation::TT_TemplateOpener)) {
Daniel Jasperf7935112012-12-03 18:12:45 +0000208 State.Indent.pop_back();
209 State.LastSpace.pop_back();
210 }
211
212 ++State.ConsumedTokens;
213 }
214
215 typedef std::map<IndentState, unsigned> StateMap;
216 StateMap Memory;
217
218 unsigned splitPenalty(const FormatToken &Token) {
219 if (Token.Tok.is(tok::semi))
220 return 0;
221 if (Token.Tok.is(tok::comma))
222 return 1;
223 if (Token.Tok.is(tok::equal) || Token.Tok.is(tok::l_paren) ||
224 Token.Tok.is(tok::pipepipe) || Token.Tok.is(tok::ampamp))
225 return 2;
226 return 3;
227 }
228
229 /// \brief Calculate the number of lines needed to format the remaining part
230 /// of the unwrapped line.
231 ///
232 /// Assumes the formatting so far has led to
233 /// the \c IndentState \p State. If \p NewLine is set, a new line will be
234 /// added after the previous token.
235 ///
236 /// \param StopAt is used for optimization. If we can determine that we'll
237 /// definitely need at least \p StopAt additional lines, we already know of a
238 /// better solution.
239 unsigned calcPenalty(IndentState State, bool NewLine, unsigned StopAt) {
240 // We are at the end of the unwrapped line, so we don't need any more lines.
241 if (State.ConsumedTokens >= Line.Tokens.size())
242 return 0;
243
244 if (!NewLine && Annotations[State.ConsumedTokens].MustBreakBefore)
245 return UINT_MAX;
246 if (NewLine && !Annotations[State.ConsumedTokens].CanBreakBefore)
247 return UINT_MAX;
248
249 if (State.ConsumedTokens > 0 && !NewLine &&
250 State.CtorInitializerOnNewLine &&
251 Line.Tokens[State.ConsumedTokens - 1].Tok.is(tok::comma))
252 return UINT_MAX;
253
254 if (NewLine && State.InCtorInitializer && !State.CtorInitializerOnNewLine)
255 return UINT_MAX;
256
257 addToken(NewLine, true, State);
258
259 // Exceeding column limit is bad.
260 if (State.Column > Style.ColumnLimit)
261 return UINT_MAX;
262
263 unsigned CurrentPenalty = 0;
264 if (NewLine) {
265 CurrentPenalty += Parameters.PenaltyIndentLevel *
266 Annotations[State.ConsumedTokens - 1].ParenLevel +
267 Parameters.PenaltyExtraLine +
268 splitPenalty(Line.Tokens[State.ConsumedTokens - 2]);
269 }
270
271 if (StopAt <= CurrentPenalty)
272 return UINT_MAX;
273 StopAt -= CurrentPenalty;
274
275 // Has this state already been examined?
276 StateMap::iterator I = Memory.find(State);
277 if (I != Memory.end())
278 return I->second;
279 ++count;
280
281 unsigned NoBreak = calcPenalty(State, false, StopAt);
282 unsigned WithBreak = calcPenalty(State, true, std::min(StopAt, NoBreak));
283 unsigned Result = std::min(NoBreak, WithBreak);
284 if (Result != UINT_MAX)
285 Result += CurrentPenalty;
286 Memory[State] = Result;
287 assert(Memory.find(State) != Memory.end());
288 return Result;
289 }
290
291 /// \brief Replaces the whitespace in front of \p Tok. Only call once for
292 /// each \c FormatToken.
293 void replaceWhitespace(const FormatToken &Tok, unsigned NewLines,
294 unsigned Spaces) {
295 Replaces.insert(tooling::Replacement(
296 SourceMgr, Tok.WhiteSpaceStart, Tok.WhiteSpaceLength,
297 std::string(NewLines, '\n') + std::string(Spaces, ' ')));
298 }
299
300 /// \brief Add a new line and the required indent before the first Token
301 /// of the \c UnwrappedLine.
302 void formatFirstToken() {
303 const FormatToken &Token = Line.Tokens[0];
304 if (Token.WhiteSpaceStart.isValid()) {
305 unsigned Newlines =
306 std::min(Token.NewlinesBefore, Style.MaxEmptyLinesToKeep + 1);
307 unsigned Offset = SourceMgr.getFileOffset(Token.WhiteSpaceStart);
308 if (Newlines == 0 && Offset != 0)
309 Newlines = 1;
310 unsigned Indent = Line.Level * 2;
311 if (Token.Tok.is(tok::kw_public) || Token.Tok.is(tok::kw_protected) ||
312 Token.Tok.is(tok::kw_private))
313 Indent += Style.AccessModifierOffset;
314 replaceWhitespace(Token, Newlines, Indent);
315 }
316 }
317
318 FormatStyle Style;
319 SourceManager &SourceMgr;
320 const UnwrappedLine &Line;
321 const std::vector<TokenAnnotation> &Annotations;
322 tooling::Replacements &Replaces;
323 unsigned int count;
324
325 OptimizationParameters Parameters;
326};
327
328/// \brief Determines extra information about the tokens comprising an
329/// \c UnwrappedLine.
330class TokenAnnotator {
331public:
332 TokenAnnotator(const UnwrappedLine &Line, const FormatStyle &Style,
333 SourceManager &SourceMgr)
334 : Line(Line),
335 Style(Style),
336 SourceMgr(SourceMgr) {
337 }
338
339 /// \brief A parser that gathers additional information about tokens.
340 ///
341 /// The \c TokenAnnotator tries to matches parenthesis and square brakets and
342 /// store a parenthesis levels. It also tries to resolve matching "<" and ">"
343 /// into template parameter lists.
344 class AnnotatingParser {
345 public:
Manuel Klimek6a5619d2012-12-03 20:55:42 +0000346 AnnotatingParser(const SmallVector<FormatToken, 16> &Tokens,
Daniel Jasperf7935112012-12-03 18:12:45 +0000347 std::vector<TokenAnnotation> &Annotations)
Manuel Klimek6a5619d2012-12-03 20:55:42 +0000348 : Tokens(Tokens),
Daniel Jasperf7935112012-12-03 18:12:45 +0000349 Annotations(Annotations),
350 Index(0) {
351 }
352
353 bool parseAngle(unsigned Level) {
354 while (Index < Tokens.size()) {
355 if (Tokens[Index].Tok.is(tok::greater)) {
356 Annotations[Index].Type = TokenAnnotation::TT_TemplateOpener;
357 Annotations[Index].ParenLevel = Level;
358 next();
359 return true;
360 }
361 if (Tokens[Index].Tok.is(tok::r_paren) ||
362 Tokens[Index].Tok.is(tok::r_square))
363 return false;
364 if (Tokens[Index].Tok.is(tok::pipepipe) ||
365 Tokens[Index].Tok.is(tok::ampamp) ||
366 Tokens[Index].Tok.is(tok::question) ||
367 Tokens[Index].Tok.is(tok::colon))
368 return false;
369 consumeToken(Level);
370 }
371 return false;
372 }
373
374 bool parseParens(unsigned Level) {
375 while (Index < Tokens.size()) {
376 if (Tokens[Index].Tok.is(tok::r_paren)) {
377 Annotations[Index].ParenLevel = Level;
378 next();
379 return true;
380 }
381 if (Tokens[Index].Tok.is(tok::r_square))
382 return false;
383 consumeToken(Level);
384 }
385 return false;
386 }
387
388 bool parseSquare(unsigned Level) {
389 while (Index < Tokens.size()) {
390 if (Tokens[Index].Tok.is(tok::r_square)) {
391 Annotations[Index].ParenLevel = Level;
392 next();
393 return true;
394 }
395 if (Tokens[Index].Tok.is(tok::r_paren))
396 return false;
397 consumeToken(Level);
398 }
399 return false;
400 }
401
402 bool parseConditional(unsigned Level) {
403 while (Index < Tokens.size()) {
404 if (Tokens[Index].Tok.is(tok::colon)) {
405 Annotations[Index].Type = TokenAnnotation::TT_ConditionalExpr;
406 next();
407 return true;
408 }
409 consumeToken(Level);
410 }
411 return false;
412 }
413
414 void consumeToken(unsigned Level) {
415 Annotations[Index].ParenLevel = Level;
416 unsigned CurrentIndex = Index;
417 next();
418 switch (Tokens[CurrentIndex].Tok.getKind()) {
419 case tok::l_paren:
420 parseParens(Level + 1);
421 break;
422 case tok::l_square:
423 parseSquare(Level + 1);
424 break;
425 case tok::less:
426 if (parseAngle(Level + 1))
427 Annotations[CurrentIndex].Type = TokenAnnotation::TT_TemplateOpener;
428 else {
429 Annotations[CurrentIndex].Type = TokenAnnotation::TT_BinaryOperator;
430 Index = CurrentIndex + 1;
431 }
432 break;
433 case tok::greater:
434 Annotations[CurrentIndex].Type = TokenAnnotation::TT_BinaryOperator;
435 break;
436 case tok::kw_operator:
437 if (!Tokens[Index].Tok.is(tok::l_paren))
438 Annotations[Index].Type = TokenAnnotation::TT_OverloadedOperator;
439 next();
440 break;
441 case tok::question:
442 parseConditional(Level);
443 break;
444 default:
445 break;
446 }
447 }
448
449 void parseLine() {
450 while (Index < Tokens.size()) {
451 consumeToken(0);
452 }
453 }
454
455 void next() {
456 ++Index;
457 }
458
459 private:
Daniel Jasperf7935112012-12-03 18:12:45 +0000460 const SmallVector<FormatToken, 16> &Tokens;
461 std::vector<TokenAnnotation> &Annotations;
462 unsigned Index;
463 };
464
465 void annotate() {
466 Annotations.clear();
467 for (int i = 0, e = Line.Tokens.size(); i != e; ++i) {
468 Annotations.push_back(TokenAnnotation());
469 }
470
Manuel Klimek6a5619d2012-12-03 20:55:42 +0000471 AnnotatingParser Parser(Line.Tokens, Annotations);
Daniel Jasperf7935112012-12-03 18:12:45 +0000472 Parser.parseLine();
473
474 determineTokenTypes();
475
476 for (int i = 1, e = Line.Tokens.size(); i != e; ++i) {
477 TokenAnnotation &Annotation = Annotations[i];
478
479 Annotation.CanBreakBefore =
480 canBreakBetween(Line.Tokens[i - 1], Line.Tokens[i]);
481
482 if (Line.Tokens[i].Tok.is(tok::colon)) {
483 if (Line.Tokens[0].Tok.is(tok::kw_case) || i == e - 1) {
484 Annotation.SpaceRequiredBefore = false;
485 } else {
486 Annotation.SpaceRequiredBefore = TokenAnnotation::TT_ConditionalExpr;
487 }
488 } else if (Annotations[i - 1].Type == TokenAnnotation::TT_UnaryOperator) {
489 Annotation.SpaceRequiredBefore = false;
490 } else if (Annotation.Type == TokenAnnotation::TT_UnaryOperator) {
491 Annotation.SpaceRequiredBefore =
492 Line.Tokens[i - 1].Tok.isNot(tok::l_paren);
493 } else if (Line.Tokens[i - 1].Tok.is(tok::greater) &&
494 Line.Tokens[i].Tok.is(tok::greater)) {
495 if (Annotation.Type == TokenAnnotation::TT_TemplateOpener &&
496 Annotations[i - 1].Type == TokenAnnotation::TT_TemplateOpener)
497 Annotation.SpaceRequiredBefore = Style.SplitTemplateClosingGreater;
498 else
499 Annotation.SpaceRequiredBefore = false;
500 } else if (
501 Annotation.Type == TokenAnnotation::TT_BinaryOperator ||
502 Annotations[i - 1].Type == TokenAnnotation::TT_BinaryOperator) {
503 Annotation.SpaceRequiredBefore = true;
504 } else if (
505 Annotations[i - 1].Type == TokenAnnotation::TT_TemplateOpener &&
506 Line.Tokens[i].Tok.is(tok::l_paren)) {
507 Annotation.SpaceRequiredBefore = false;
508 } else {
509 Annotation.SpaceRequiredBefore =
510 spaceRequiredBetween(Line.Tokens[i - 1].Tok, Line.Tokens[i].Tok);
511 }
512
513 if (Annotations[i - 1].Type == TokenAnnotation::TT_LineComment ||
514 (Line.Tokens[i].Tok.is(tok::string_literal) &&
515 Line.Tokens[i - 1].Tok.is(tok::string_literal))) {
516 Annotation.MustBreakBefore = true;
517 }
518
519 if (Annotation.MustBreakBefore)
520 Annotation.CanBreakBefore = true;
521 }
522 }
523
524 const std::vector<TokenAnnotation> &getAnnotations() {
525 return Annotations;
526 }
527
528private:
529 void determineTokenTypes() {
530 for (int i = 0, e = Line.Tokens.size(); i != e; ++i) {
531 TokenAnnotation &Annotation = Annotations[i];
532 const FormatToken &Tok = Line.Tokens[i];
533
534 if (Tok.Tok.is(tok::star) || Tok.Tok.is(tok::amp))
535 Annotation.Type = determineStarAmpUsage(i);
536 else if (Tok.Tok.is(tok::minus) && Line.Tokens[i - 1].Tok.is(tok::equal))
537 Annotation.Type = TokenAnnotation::TT_UnaryOperator;
538 else if (isBinaryOperator(Line.Tokens[i]))
539 Annotation.Type = TokenAnnotation::TT_BinaryOperator;
540 else if (Tok.Tok.is(tok::comment)) {
541 StringRef Data(SourceMgr.getCharacterData(Tok.Tok.getLocation()),
542 Tok.Tok.getLength());
543 if (Data.startswith("//"))
544 Annotation.Type = TokenAnnotation::TT_LineComment;
545 else
546 Annotation.Type = TokenAnnotation::TT_BlockComment;
547 }
548 }
549 }
550
551 bool isBinaryOperator(const FormatToken &Tok) {
552 switch (Tok.Tok.getKind()) {
553 case tok::equal:
554 case tok::equalequal:
555 case tok::star:
556 //case tok::amp:
557 case tok::plus:
558 case tok::slash:
559 case tok::minus:
560 case tok::ampamp:
561 case tok::pipe:
562 case tok::pipepipe:
563 case tok::percent:
564 return true;
565 default:
566 return false;
567 }
568 }
569
570 TokenAnnotation::TokenType determineStarAmpUsage(unsigned Index) {
571 if (Index == Annotations.size())
572 return TokenAnnotation::TT_Unknown;
573
574 if (Index == 0 || Line.Tokens[Index - 1].Tok.is(tok::l_paren) ||
575 Line.Tokens[Index - 1].Tok.is(tok::comma) ||
576 Annotations[Index - 1].Type == TokenAnnotation::TT_BinaryOperator)
577 return TokenAnnotation::TT_UnaryOperator;
578
579 if (Line.Tokens[Index - 1].Tok.isLiteral() ||
580 Line.Tokens[Index + 1].Tok.isLiteral())
581 return TokenAnnotation::TT_BinaryOperator;
582
583 return TokenAnnotation::TT_PointerOrReference;
584 }
585
586 bool isIfForOrWhile(Token Tok) {
587 return Tok.is(tok::kw_if) || Tok.is(tok::kw_for) || Tok.is(tok::kw_while);
588 }
589
590 bool spaceRequiredBetween(Token Left, Token Right) {
591 if (Left.is(tok::kw_template) && Right.is(tok::less))
592 return true;
593 if (Left.is(tok::arrow) || Right.is(tok::arrow))
594 return false;
595 if (Left.is(tok::exclaim) || Left.is(tok::tilde))
596 return false;
597 if (Left.is(tok::less) || Right.is(tok::greater) || Right.is(tok::less))
598 return false;
599 if (Left.is(tok::amp) || Left.is(tok::star))
600 return Right.isLiteral() || Style.PointerAndReferenceBindToType;
601 if (Right.is(tok::star) && Left.is(tok::l_paren))
602 return false;
603 if (Right.is(tok::amp) || Right.is(tok::star))
604 return Left.isLiteral() || !Style.PointerAndReferenceBindToType;
605 if (Left.is(tok::l_square) || Right.is(tok::l_square) ||
606 Right.is(tok::r_square))
607 return false;
608 if (Left.is(tok::coloncolon) || Right.is(tok::coloncolon))
609 return false;
610 if (Left.is(tok::period) || Right.is(tok::period))
611 return false;
612 if (Left.is(tok::colon) || Right.is(tok::colon))
613 return true;
614 if ((Left.is(tok::plusplus) && Right.isAnyIdentifier()) ||
615 (Left.isAnyIdentifier() && Right.is(tok::plusplus)) ||
616 (Left.is(tok::minusminus) && Right.isAnyIdentifier()) ||
617 (Left.isAnyIdentifier() && Right.is(tok::minusminus)))
618 return false;
619 if (Left.is(tok::l_paren))
620 return false;
621 if (Left.is(tok::hash))
622 return false;
623 if (Right.is(tok::r_paren) || Right.is(tok::semi) || Right.is(tok::comma))
624 return false;
625 if (Right.is(tok::l_paren)) {
626 return !Left.isAnyIdentifier() || isIfForOrWhile(Left);
627 }
628 return true;
629 }
630
631 bool canBreakBetween(const FormatToken &Left, const FormatToken &Right) {
632 if (Right.Tok.is(tok::r_paren))
633 return false;
634 if (isBinaryOperator(Left))
635 return true;
636 return Right.Tok.is(tok::colon) || Left.Tok.is(tok::comma) || Left.Tok.is(
637 tok::semi) || Left.Tok.is(tok::equal) || Left.Tok.is(tok::ampamp) ||
638 (Left.Tok.is(tok::l_paren) && !Right.Tok.is(tok::r_paren));
639 }
640
641 const UnwrappedLine &Line;
642 FormatStyle Style;
643 SourceManager &SourceMgr;
644 std::vector<TokenAnnotation> Annotations;
645};
646
647class Formatter : public UnwrappedLineConsumer {
648public:
649 Formatter(const FormatStyle &Style, Lexer &Lex, SourceManager &SourceMgr,
650 const std::vector<CharSourceRange> &Ranges)
651 : Style(Style),
652 Lex(Lex),
653 SourceMgr(SourceMgr),
654 Ranges(Ranges) {
655 }
656
657 tooling::Replacements format() {
658 UnwrappedLineParser Parser(Lex, SourceMgr, *this);
659 Parser.parse();
660 return Replaces;
661 }
662
663private:
664 virtual void formatUnwrappedLine(const UnwrappedLine &TheLine) {
665 if (TheLine.Tokens.size() == 0)
666 return;
667
668 CharSourceRange LineRange =
669 CharSourceRange::getTokenRange(TheLine.Tokens.front().Tok.getLocation(),
670 TheLine.Tokens.back().Tok.getLocation());
671
672 for (unsigned i = 0, e = Ranges.size(); i != e; ++i) {
673 if (SourceMgr.isBeforeInTranslationUnit(LineRange.getEnd(),
674 Ranges[i].getBegin()) ||
675 SourceMgr.isBeforeInTranslationUnit(Ranges[i].getEnd(),
676 LineRange.getBegin()))
677 continue;
678
679 TokenAnnotator Annotator(TheLine, Style, SourceMgr);
680 Annotator.annotate();
681 UnwrappedLineFormatter Formatter(Style, SourceMgr, TheLine,
682 Annotator.getAnnotations(), Replaces);
683 Formatter.format();
684 return;
685 }
686 }
687
688 FormatStyle Style;
689 Lexer &Lex;
690 SourceManager &SourceMgr;
691 tooling::Replacements Replaces;
692 std::vector<CharSourceRange> Ranges;
693};
694
695tooling::Replacements reformat(const FormatStyle &Style, Lexer &Lex,
696 SourceManager &SourceMgr,
697 std::vector<CharSourceRange> Ranges) {
698 Formatter formatter(Style, Lex, SourceMgr, Ranges);
699 return formatter.format();
700}
701
702} // namespace format
703} // namespace clang