Skip to content

Commit 52b1515

Browse files
committed
Enables layouting unwrapped lines around preprocessor directives.
Previously, we'd always start at indent level 0 after a preprocessor directive, now we layout the following snippet (column limit 69) as follows: functionCallTo(someOtherFunction( withSomeParameters, whichInSequence, areLongerThanALine(andAnotherCall, B withMoreParamters, whichStronglyInfluenceTheLayout), andMoreParameters), trailing); Note that the different jumping indent is a different issue that will be addressed separately. This is the first step towards handling #ifdef->#else->#endif chains correctly. llvm-svn: 171974
1 parent 864ef31 commit 52b1515

File tree

4 files changed

+104
-42
lines changed

4 files changed

+104
-42
lines changed

clang/lib/Format/Format.cpp

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -803,18 +803,21 @@ class TokenAnnotator {
803803
void calculateExtraInformation(AnnotatedToken &Current) {
804804
Current.SpaceRequiredBefore = spaceRequiredBefore(Current);
805805

806-
if (Current.Type == TT_CtorInitializerColon || Current.Parent->Type ==
807-
TT_LineComment || (Current.is(tok::string_literal) &&
808-
Current.Parent->is(tok::string_literal))) {
809-
Current.MustBreakBefore = true;
810-
} else if (Current.is(tok::at) && Current.Parent->Parent->is(tok::at)) {
811-
// Don't put two objc's '@' on the same line. This could happen,
812-
// as in, @optional @property ...
806+
if (Current.FormatTok.MustBreakBefore) {
813807
Current.MustBreakBefore = true;
814808
} else {
815-
Current.MustBreakBefore = false;
809+
if (Current.Type == TT_CtorInitializerColon || Current.Parent->Type ==
810+
TT_LineComment || (Current.is(tok::string_literal) &&
811+
Current.Parent->is(tok::string_literal))) {
812+
Current.MustBreakBefore = true;
813+
} else if (Current.is(tok::at) && Current.Parent->Parent->is(tok::at)) {
814+
// Don't put two objc's '@' on the same line. This could happen,
815+
// as in, @optional @property ...
816+
Current.MustBreakBefore = true;
817+
} else {
818+
Current.MustBreakBefore = false;
819+
}
816820
}
817-
818821
Current.CanBreakBefore = Current.MustBreakBefore || canBreakBefore(Current);
819822

820823
if (!Current.Children.empty())

clang/lib/Format/UnwrappedLineParser.cpp

Lines changed: 48 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,9 @@ class ScopedMacroState : public FormatTokenSource {
7474
UnwrappedLineParser::UnwrappedLineParser(const FormatStyle &Style,
7575
FormatTokenSource &Tokens,
7676
UnwrappedLineConsumer &Callback)
77-
: RootTokenInitialized(false), Style(Style), Tokens(&Tokens),
78-
Callback(Callback) {
77+
: Line(new UnwrappedLine), RootTokenInitialized(false),
78+
LastInCurrentLine(NULL), MustBreakBeforeNextToken(false), Style(Style),
79+
Tokens(&Tokens), Callback(Callback) {
7980
}
8081

8182
bool UnwrappedLineParser::parse() {
@@ -126,9 +127,9 @@ bool UnwrappedLineParser::parseBlock(unsigned AddLevels) {
126127

127128
addUnwrappedLine();
128129

129-
Line.Level += AddLevels;
130+
Line->Level += AddLevels;
130131
parseLevel(/*HasOpeningBrace=*/true);
131-
Line.Level -= AddLevels;
132+
Line->Level -= AddLevels;
132133

133134
if (!FormatTok.Tok.is(tok::r_brace))
134135
return true;
@@ -139,7 +140,7 @@ bool UnwrappedLineParser::parseBlock(unsigned AddLevels) {
139140

140141
void UnwrappedLineParser::parsePPDirective() {
141142
assert(FormatTok.Tok.is(tok::hash) && "'#' expected");
142-
ScopedMacroState MacroState(Line, Tokens, FormatTok);
143+
ScopedMacroState MacroState(*Line, Tokens, FormatTok);
143144
nextToken();
144145

145146
if (FormatTok.Tok.getIdentifierInfo() == NULL) {
@@ -169,7 +170,7 @@ void UnwrappedLineParser::parsePPDefine() {
169170
parseParens();
170171
}
171172
addUnwrappedLine();
172-
Line.Level = 1;
173+
Line->Level = 1;
173174

174175
// Errors during a preprocessor directive can only affect the layout of the
175176
// preprocessor directive, and thus we ignore them. An alternative approach
@@ -319,9 +320,9 @@ void UnwrappedLineParser::parseIfThenElse() {
319320
NeedsUnwrappedLine = true;
320321
} else {
321322
addUnwrappedLine();
322-
++Line.Level;
323+
++Line->Level;
323324
parseStructuralElement();
324-
--Line.Level;
325+
--Line->Level;
325326
}
326327
if (FormatTok.Tok.is(tok::kw_else)) {
327328
nextToken();
@@ -332,9 +333,9 @@ void UnwrappedLineParser::parseIfThenElse() {
332333
parseIfThenElse();
333334
} else {
334335
addUnwrappedLine();
335-
++Line.Level;
336+
++Line->Level;
336337
parseStructuralElement();
337-
--Line.Level;
338+
--Line->Level;
338339
}
339340
} else if (NeedsUnwrappedLine) {
340341
addUnwrappedLine();
@@ -363,9 +364,9 @@ void UnwrappedLineParser::parseForOrWhileLoop() {
363364
addUnwrappedLine();
364365
} else {
365366
addUnwrappedLine();
366-
++Line.Level;
367+
++Line->Level;
367368
parseStructuralElement();
368-
--Line.Level;
369+
--Line->Level;
369370
}
370371
}
371372

@@ -376,9 +377,9 @@ void UnwrappedLineParser::parseDoWhile() {
376377
parseBlock();
377378
} else {
378379
addUnwrappedLine();
379-
++Line.Level;
380+
++Line->Level;
380381
parseStructuralElement();
381-
--Line.Level;
382+
--Line->Level;
382383
}
383384

384385
// FIXME: Add error handling.
@@ -395,14 +396,14 @@ void UnwrappedLineParser::parseLabel() {
395396
// FIXME: remove all asserts.
396397
assert(FormatTok.Tok.is(tok::colon) && "':' expected");
397398
nextToken();
398-
unsigned OldLineLevel = Line.Level;
399-
if (Line.Level > 0)
400-
--Line.Level;
399+
unsigned OldLineLevel = Line->Level;
400+
if (Line->Level > 0)
401+
--Line->Level;
401402
if (FormatTok.Tok.is(tok::l_brace)) {
402403
parseBlock();
403404
}
404405
addUnwrappedLine();
405-
Line.Level = OldLineLevel;
406+
Line->Level = OldLineLevel;
406407
}
407408

408409
void UnwrappedLineParser::parseCaseLabel() {
@@ -423,9 +424,9 @@ void UnwrappedLineParser::parseSwitch() {
423424
addUnwrappedLine();
424425
} else {
425426
addUnwrappedLine();
426-
Line.Level += (Style.IndentCaseLabels ? 2 : 1);
427+
Line->Level += (Style.IndentCaseLabels ? 2 : 1);
427428
parseStructuralElement();
428-
Line.Level -= (Style.IndentCaseLabels ? 2 : 1);
429+
Line->Level -= (Style.IndentCaseLabels ? 2 : 1);
429430
}
430431
}
431432

@@ -444,7 +445,7 @@ void UnwrappedLineParser::parseEnum() {
444445
case tok::l_brace:
445446
nextToken();
446447
addUnwrappedLine();
447-
++Line.Level;
448+
++Line->Level;
448449
parseComments();
449450
break;
450451
case tok::l_paren:
@@ -458,7 +459,7 @@ void UnwrappedLineParser::parseEnum() {
458459
case tok::r_brace:
459460
if (HasContents)
460461
addUnwrappedLine();
461-
--Line.Level;
462+
--Line->Level;
462463
nextToken();
463464
break;
464465
case tok::semi:
@@ -501,8 +502,9 @@ void UnwrappedLineParser::addUnwrappedLine() {
501502
FormatTok.Tok.is(tok::comment)) {
502503
nextToken();
503504
}
504-
Callback.consumeUnwrappedLine(Line);
505+
Callback.consumeUnwrappedLine(*Line);
505506
RootTokenInitialized = false;
507+
LastInCurrentLine = NULL;
506508
}
507509

508510
bool UnwrappedLineParser::eof() const {
@@ -513,26 +515,42 @@ void UnwrappedLineParser::nextToken() {
513515
if (eof())
514516
return;
515517
if (RootTokenInitialized) {
518+
assert(LastInCurrentLine->Children.empty());
516519
LastInCurrentLine->Children.push_back(FormatTok);
517520
LastInCurrentLine = &LastInCurrentLine->Children.back();
518521
} else {
519-
Line.RootToken = FormatTok;
522+
Line->RootToken = FormatTok;
520523
RootTokenInitialized = true;
521-
LastInCurrentLine = &Line.RootToken;
524+
LastInCurrentLine = &Line->RootToken;
525+
}
526+
if (MustBreakBeforeNextToken) {
527+
LastInCurrentLine->MustBreakBefore = true;
528+
MustBreakBeforeNextToken = false;
522529
}
523530
readToken();
524531
}
525532

526533
void UnwrappedLineParser::readToken() {
527534
FormatTok = Tokens->getNextToken();
528-
while (!Line.InPPDirective && FormatTok.Tok.is(tok::hash) &&
535+
while (!Line->InPPDirective && FormatTok.Tok.is(tok::hash) &&
529536
((FormatTok.NewlinesBefore > 0 && FormatTok.HasUnescapedNewline) ||
530537
FormatTok.IsFirst)) {
531-
// FIXME: This is incorrect - the correct way is to create a
532-
// data structure that will construct the parts around the preprocessor
533-
// directive as a structured \c UnwrappedLine.
534-
addUnwrappedLine();
538+
UnwrappedLine* StoredLine = Line.take();
539+
Line.reset(new UnwrappedLine(*StoredLine));
540+
assert(LastInCurrentLine == NULL || LastInCurrentLine->Children.empty());
541+
FormatToken *StoredLastInCurrentLine = LastInCurrentLine;
542+
bool PreviousInitialized = RootTokenInitialized;
543+
RootTokenInitialized = false;
544+
LastInCurrentLine = NULL;
545+
535546
parsePPDirective();
547+
548+
assert(!RootTokenInitialized);
549+
Line.reset(StoredLine);
550+
RootTokenInitialized = PreviousInitialized;
551+
LastInCurrentLine = StoredLastInCurrentLine;
552+
assert(LastInCurrentLine == NULL || LastInCurrentLine->Children.empty());
553+
MustBreakBeforeNextToken = true;
536554
}
537555
}
538556

clang/lib/Format/UnwrappedLineParser.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ namespace format {
3434
struct FormatToken {
3535
FormatToken()
3636
: NewlinesBefore(0), HasUnescapedNewline(false), WhiteSpaceLength(0),
37-
TokenLength(0), IsFirst(false) {
37+
TokenLength(0), IsFirst(false), MustBreakBefore(false) {
3838
}
3939

4040
/// \brief The \c Token.
@@ -68,6 +68,12 @@ struct FormatToken {
6868
/// \brief Indicates that this is the first token.
6969
bool IsFirst;
7070

71+
/// \brief Whether there must be a line break before this token.
72+
///
73+
/// This happens for example when a preprocessor directive ended directly
74+
/// before the token.
75+
bool MustBreakBefore;
76+
7177
// FIXME: We currently assume that there is exactly one token in this vector
7278
// except for the very last token that does not have any children.
7379
/// \brief All tokens that logically follow this token.
@@ -144,10 +150,11 @@ class UnwrappedLineParser {
144150
// FIXME: We are constantly running into bugs where Line.Level is incorrectly
145151
// subtracted from beyond 0. Introduce a method to subtract from Line.Level
146152
// and use that everywhere in the Parser.
147-
UnwrappedLine Line;
153+
llvm::OwningPtr<UnwrappedLine> Line;
148154
bool RootTokenInitialized;
149155
FormatToken *LastInCurrentLine;
150156
FormatToken FormatTok;
157+
bool MustBreakBeforeNextToken;
151158

152159
const FormatStyle &Style;
153160
FormatTokenSource *Tokens;

clang/unittests/Format/FormatTest.cpp

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,17 +46,24 @@ class FormatTest : public ::testing::Test {
4646
std::string messUp(llvm::StringRef Code) {
4747
std::string MessedUp(Code.str());
4848
bool InComment = false;
49+
bool InPreprocessorDirective = false;
4950
bool JustReplacedNewline = false;
5051
for (unsigned i = 0, e = MessedUp.size() - 1; i != e; ++i) {
5152
if (MessedUp[i] == '/' && MessedUp[i + 1] == '/') {
5253
if (JustReplacedNewline)
5354
MessedUp[i - 1] = '\n';
5455
InComment = true;
56+
} else if (MessedUp[i] == '#' && JustReplacedNewline) {
57+
MessedUp[i - 1] = '\n';
58+
InPreprocessorDirective = true;
5559
} else if (MessedUp[i] == '\\' && MessedUp[i + 1] == '\n') {
5660
MessedUp[i] = ' ';
61+
MessedUp[i + 1] = ' ';
5762
} else if (MessedUp[i] == '\n') {
5863
if (InComment) {
5964
InComment = false;
65+
} else if (InPreprocessorDirective) {
66+
InPreprocessorDirective = false;
6067
} else {
6168
JustReplacedNewline = true;
6269
MessedUp[i] = ' ';
@@ -84,6 +91,14 @@ class FormatTest : public ::testing::Test {
8491
}
8592
};
8693

94+
TEST_F(FormatTest, MessUp) {
95+
EXPECT_EQ("1 2 3", messUp("1 2 3"));
96+
EXPECT_EQ("1 2 3\n", messUp("1\n2\n3\n"));
97+
EXPECT_EQ("a\n//b\nc", messUp("a\n//b\nc"));
98+
EXPECT_EQ("a\n#b\nc", messUp("a\n#b\nc"));
99+
EXPECT_EQ("a\n#b c d\ne", messUp("a\n#b\\\nc\\\nd\ne"));
100+
}
101+
87102
//===----------------------------------------------------------------------===//
88103
// Basic function tests.
89104
//===----------------------------------------------------------------------===//
@@ -545,7 +560,9 @@ TEST_F(FormatTest, LayoutSingleUnwrappedLineInMacro) {
545560
}
546561

547562
TEST_F(FormatTest, MacroDefinitionInsideStatement) {
548-
EXPECT_EQ("int x,\n#define A\ny;", format("int x,\n#define A\ny;"));
563+
EXPECT_EQ("int x,\n"
564+
"#define A\n"
565+
" y;", format("int x,\n#define A\ny;"));
549566
}
550567

551568
TEST_F(FormatTest, HashInMacroDefinition) {
@@ -609,6 +626,23 @@ TEST_F(FormatTest, MixingPreprocessorDirectivesAndNormalCode) {
609626
" aLooooooooooooooooooooooonPaaaaaaaaaaaaaaaaaaaaarmmmm);\n"));
610627
}
611628

629+
TEST_F(FormatTest, LayoutStatementsAroundPreprocessorDirectives) {
630+
EXPECT_EQ("int\n"
631+
"#define A\n"
632+
" a;",
633+
format("int\n#define A\na;"));
634+
verifyFormat(
635+
"functionCallTo(someOtherFunction(\n"
636+
" withSomeParameters, whichInSequence,\n"
637+
" areLongerThanALine(andAnotherCall,\n"
638+
"#define A \\\n"
639+
" B\n"
640+
" withMoreParamters,\n"
641+
" whichStronglyInfluenceTheLayout),\n"
642+
" andMoreParameters),\n"
643+
" trailing);", getLLVMStyleWithColumns(69));
644+
}
645+
612646
//===----------------------------------------------------------------------===//
613647
// Line break tests.
614648
//===----------------------------------------------------------------------===//

0 commit comments

Comments
 (0)