Skip to content

Commit ff747be

Browse files
committedJun 27, 2017
[clang-format] Support <>-style proto message fields
Summary: This patch adds support for <>-style proto message fields inside proto options. Previously these were wrongly treated as binary operators and as such were working only by chance for a limited number of cases. Reviewers: djasper Reviewed By: djasper Subscribers: cfe-commits, klimek Differential Revision: https://reviews.llvm.org/D34621 llvm-svn: 306406
1 parent 4155c8f commit ff747be

File tree

6 files changed

+188
-15
lines changed

6 files changed

+188
-15
lines changed
 

‎clang/lib/Format/ContinuationIndenter.cpp

+18-2
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ static bool startsNextParameter(const FormatToken &Current,
5656
if (Current.is(TT_CtorInitializerComma) &&
5757
Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma)
5858
return true;
59+
if (Style.Language == FormatStyle::LK_Proto && Current.is(TT_SelectorName))
60+
return true;
5961
return Previous.is(tok::comma) && !Current.isTrailingComment() &&
6062
((Previous.isNot(TT_CtorInitializerComma) ||
6163
Style.BreakConstructorInitializers !=
@@ -499,6 +501,13 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
499501
}
500502
}
501503

504+
static bool lessOpensProtoMessageField(const FormatToken &LessTok,
505+
const LineState &State) {
506+
assert(LessTok.is(tok::less));
507+
return LessTok.NestingLevel > 0 ||
508+
(LessTok.Previous && LessTok.Previous->is(tok::equal));
509+
}
510+
502511
unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
503512
bool DryRun) {
504513
FormatToken &Current = *State.NextToken;
@@ -641,6 +650,9 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
641650
// before the corresponding } or ].
642651
if (PreviousNonComment &&
643652
(PreviousNonComment->isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) ||
653+
(Style.Language == FormatStyle::LK_Proto &&
654+
PreviousNonComment->is(tok::less) &&
655+
lessOpensProtoMessageField(*PreviousNonComment, State)) ||
644656
(PreviousNonComment->is(TT_TemplateString) &&
645657
PreviousNonComment->opensScope())))
646658
State.Stack.back().BreakBeforeClosingBrace = true;
@@ -682,7 +694,9 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
682694
if (NextNonComment->is(tok::l_brace) && NextNonComment->BlockKind == BK_Block)
683695
return Current.NestingLevel == 0 ? State.FirstIndent
684696
: State.Stack.back().Indent;
685-
if (Current.isOneOf(tok::r_brace, tok::r_square) && State.Stack.size() > 1) {
697+
if ((Current.isOneOf(tok::r_brace, tok::r_square) ||
698+
(Current.is(tok::greater) && Style.Language == FormatStyle::LK_Proto)) &&
699+
State.Stack.size() > 1) {
686700
if (Current.closesBlockOrBlockTypeList(Style))
687701
return State.Stack[State.Stack.size() - 2].NestedBlockIndent;
688702
if (Current.MatchingParen &&
@@ -1035,7 +1049,9 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State,
10351049
bool BreakBeforeParameter = false;
10361050
unsigned NestedBlockIndent = std::max(State.Stack.back().StartOfFunctionCall,
10371051
State.Stack.back().NestedBlockIndent);
1038-
if (Current.isOneOf(tok::l_brace, TT_ArrayInitializerLSquare)) {
1052+
if (Current.isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) ||
1053+
(Style.Language == FormatStyle::LK_Proto && Current.is(tok::less) &&
1054+
lessOpensProtoMessageField(Current, State))) {
10391055
if (Current.opensBlockOrBlockTypeList(Style)) {
10401056
NewIndent = Style.IndentWidth +
10411057
std::min(State.Column, State.Stack.back().NestedBlockIndent);

‎clang/lib/Format/FormatToken.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -465,7 +465,8 @@ struct FormatToken {
465465
return is(TT_ArrayInitializerLSquare) ||
466466
(is(tok::l_brace) &&
467467
(BlockKind == BK_Block || is(TT_DictLiteral) ||
468-
(!Style.Cpp11BracedListStyle && NestingLevel == 0)));
468+
(!Style.Cpp11BracedListStyle && NestingLevel == 0))) ||
469+
(is(tok::less) && Style.Language == FormatStyle::LK_Proto);
469470
}
470471

471472
/// \brief Same as opensBlockOrBlockTypeList, but for the closing token.

‎clang/lib/Format/TokenAnnotator.cpp

+20-5
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@ class AnnotatingParser {
8989
continue;
9090
}
9191
if (CurrentToken->isOneOf(tok::r_paren, tok::r_square, tok::r_brace) ||
92-
(CurrentToken->isOneOf(tok::colon, tok::question) && InExprContext))
92+
(CurrentToken->isOneOf(tok::colon, tok::question) && InExprContext &&
93+
Style.Language != FormatStyle::LK_Proto))
9394
return false;
9495
// If a && or || is found and interpreted as a binary operator, this set
9596
// of angles is likely part of something like "a < b && c > d". If the
@@ -103,6 +104,14 @@ class AnnotatingParser {
103104
!Line.startsWith(tok::kw_template))
104105
return false;
105106
updateParameterCount(Left, CurrentToken);
107+
if (Style.Language == FormatStyle::LK_Proto) {
108+
if (FormatToken *Previous = CurrentToken->getPreviousNonComment()) {
109+
if (CurrentToken->is(tok::colon) ||
110+
(CurrentToken->isOneOf(tok::l_brace, tok::less) &&
111+
Previous->isNot(tok::colon)))
112+
Previous->Type = TT_SelectorName;
113+
}
114+
}
106115
if (!consumeToken())
107116
return false;
108117
}
@@ -440,7 +449,7 @@ class AnnotatingParser {
440449
if (CurrentToken->isOneOf(tok::r_paren, tok::r_square))
441450
return false;
442451
updateParameterCount(Left, CurrentToken);
443-
if (CurrentToken->isOneOf(tok::colon, tok::l_brace)) {
452+
if (CurrentToken->isOneOf(tok::colon, tok::l_brace, tok::less)) {
444453
FormatToken *Previous = CurrentToken->getPreviousNonComment();
445454
if (((CurrentToken->is(tok::colon) &&
446455
(!Contexts.back().ColonIsDictLiteral || !Style.isCpp())) ||
@@ -2549,10 +2558,16 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
25492558
// deliberate choice and might have aligned the contents of the string
25502559
// literal accordingly. Thus, we try keep existing line breaks.
25512560
return Right.NewlinesBefore > 0;
2552-
if (Right.Previous->is(tok::l_brace) && Right.NestingLevel == 1 &&
2553-
Style.Language == FormatStyle::LK_Proto)
2554-
// Don't put enums onto single lines in protocol buffers.
2561+
if ((Right.Previous->is(tok::l_brace) ||
2562+
(Right.Previous->is(tok::less) &&
2563+
Right.Previous->Previous &&
2564+
Right.Previous->Previous->is(tok::equal))
2565+
) &&
2566+
Right.NestingLevel == 1 && Style.Language == FormatStyle::LK_Proto) {
2567+
// Don't put enums or option definitions onto single lines in protocol
2568+
// buffers.
25552569
return true;
2570+
}
25562571
if (Right.is(TT_InlineASMBrace))
25572572
return Right.HasUnescapedNewline;
25582573
if (isAllmanBrace(Left) || isAllmanBrace(Right))

‎clang/lib/Format/UnwrappedLineParser.cpp

+10-6
Original file line numberDiff line numberDiff line change
@@ -1176,9 +1176,11 @@ void UnwrappedLineParser::parseStructuralElement() {
11761176
}
11771177

11781178
nextToken();
1179-
if (FormatTok->Tok.is(tok::l_brace)) {
1179+
if (FormatTok->Tok.is(tok::l_brace))
11801180
parseBracedList();
1181-
}
1181+
else if (Style.Language == FormatStyle::LK_Proto &&
1182+
FormatTok->Tok.is(tok::less))
1183+
parseBracedList(/*ClosingBraceKind=*/tok::greater);
11821184
break;
11831185
case tok::l_square:
11841186
parseSquare();
@@ -1346,7 +1348,8 @@ bool UnwrappedLineParser::tryToParseBracedList() {
13461348
return true;
13471349
}
13481350

1349-
bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons) {
1351+
bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons,
1352+
tok::TokenKind ClosingBraceKind) {
13501353
bool HasError = false;
13511354
nextToken();
13521355

@@ -1375,6 +1378,10 @@ bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons) {
13751378
parseChildBlock();
13761379
}
13771380
}
1381+
if (FormatTok->Tok.getKind() == ClosingBraceKind) {
1382+
nextToken();
1383+
return !HasError;
1384+
}
13781385
switch (FormatTok->Tok.getKind()) {
13791386
case tok::caret:
13801387
nextToken();
@@ -1401,9 +1408,6 @@ bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons) {
14011408
FormatTok->BlockKind = BK_BracedInit;
14021409
parseBracedList();
14031410
break;
1404-
case tok::r_brace:
1405-
nextToken();
1406-
return !HasError;
14071411
case tok::semi:
14081412
// JavaScript (or more precisely TypeScript) can have semicolons in braced
14091413
// lists (in so-called TypeMemberLists). Thus, the semicolon cannot be

‎clang/lib/Format/UnwrappedLineParser.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,8 @@ class UnwrappedLineParser {
9393
void readTokenWithJavaScriptASI();
9494
void parseStructuralElement();
9595
bool tryToParseBracedList();
96-
bool parseBracedList(bool ContinueOnSemicolons = false);
96+
bool parseBracedList(bool ContinueOnSemicolons = false,
97+
tok::TokenKind ClosingBraceKind = tok::r_brace);
9798
void parseParens();
9899
void parseSquare();
99100
void parseIfThenElse();

‎clang/unittests/Format/FormatTestProto.cpp

+136
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,142 @@ TEST_F(FormatTestProto, FormatsOptions) {
207207
" field_c: \"OK\",\n"
208208
" msg_field: <field_d: 123>\n"
209209
"};");
210+
211+
verifyFormat("option (MyProto.options) = {\n"
212+
" msg_field: <>\n"
213+
" field_c: \"OK\",\n"
214+
" msg_field: <field_d: 123>\n"
215+
" field_e: OK\n"
216+
" msg_field: <field_d: 12>\n"
217+
"};");
218+
219+
verifyFormat("option (MyProto.options) = <\n"
220+
" field_a: OK\n"
221+
" field_b: \"OK\"\n"
222+
" field_c: 1\n"
223+
" field_d: 12.5\n"
224+
" field_e: OK\n"
225+
">;");
226+
227+
verifyFormat("option (MyProto.options) = <\n"
228+
" field_a: OK,\n"
229+
" field_b: \"OK\",\n"
230+
" field_c: 1,\n"
231+
" field_d: 12.5,\n"
232+
" field_e: OK,\n"
233+
">;");
234+
235+
verifyFormat("option (MyProto.options) = <\n"
236+
" field_a: \"OK\"\n"
237+
" msg_field: {field_b: OK}\n"
238+
" field_g: OK\n"
239+
" field_g: OK\n"
240+
" field_g: OK\n"
241+
">;");
242+
243+
verifyFormat("option (MyProto.options) = <\n"
244+
" field_a: \"OK\"\n"
245+
" msg_field<\n"
246+
" field_b: OK\n"
247+
" field_c: OK\n"
248+
" field_d: OK\n"
249+
" field_e: OK\n"
250+
" field_f: OK\n"
251+
" >\n"
252+
" field_g: OK\n"
253+
">;");
254+
255+
verifyFormat("option (MyProto.options) = <\n"
256+
" field_a: \"OK\"\n"
257+
" msg_field<\n"
258+
" field_b: OK,\n"
259+
" field_c: OK,\n"
260+
" field_d: OK,\n"
261+
" field_e: OK,\n"
262+
" field_f: OK\n"
263+
" >\n"
264+
" field_g: OK\n"
265+
">;");
266+
267+
verifyFormat("option (MyProto.options) = <\n"
268+
" field_a: \"OK\"\n"
269+
" msg_field: <\n"
270+
" field_b: OK\n"
271+
" field_c: OK\n"
272+
" field_d: OK\n"
273+
" field_e: OK\n"
274+
" field_f: OK\n"
275+
" >\n"
276+
" field_g: OK\n"
277+
">;");
278+
279+
verifyFormat("option (MyProto.options) = <\n"
280+
" field_a: \"OK\"\n"
281+
" msg_field: {\n"
282+
" field_b: OK\n"
283+
" field_c: OK\n"
284+
" field_d: OK\n"
285+
" field_e: OK\n"
286+
" field_f: OK\n"
287+
" }\n"
288+
" field_g: OK\n"
289+
">;");
290+
291+
verifyFormat("option (MyProto.options) = <\n"
292+
" field_a: \"OK\"\n"
293+
" msg_field{\n"
294+
" field_b: OK\n"
295+
" field_c: OK\n"
296+
" field_d: OK\n"
297+
" field_e: OK\n"
298+
" field_f: OK\n"
299+
" }\n"
300+
" field_g: OK\n"
301+
">;");
302+
303+
verifyFormat("option (MyProto.options) = {\n"
304+
" field_a: \"OK\"\n"
305+
" msg_field<\n"
306+
" field_b: OK\n"
307+
" field_c: OK\n"
308+
" field_d: OK\n"
309+
" field_e: OK\n"
310+
" field_f: OK\n"
311+
" >\n"
312+
" field_g: OK\n"
313+
"};");
314+
315+
verifyFormat("option (MyProto.options) = {\n"
316+
" field_a: \"OK\"\n"
317+
" msg_field: <\n"
318+
" field_b: OK\n"
319+
" field_c: OK\n"
320+
" field_d: OK\n"
321+
" field_e: OK\n"
322+
" field_f: OK\n"
323+
" >\n"
324+
" field_g: OK\n"
325+
"};");
326+
327+
verifyFormat("option (MyProto.options) = <\n"
328+
" field_a: \"OK\"\n"
329+
" msg_field{\n"
330+
" field_b: OK\n"
331+
" field_c: OK\n"
332+
" field_d: OK\n"
333+
" msg_field<\n"
334+
" field_A: 1\n"
335+
" field_B: 2\n"
336+
" field_C: 3\n"
337+
" field_D: 4\n"
338+
" field_E: 5\n"
339+
" >\n"
340+
" msg_field<field_A: 1 field_B: 2 field_C: 3 field_D: 4>\n"
341+
" field_e: OK\n"
342+
" field_f: OK\n"
343+
" }\n"
344+
" field_g: OK\n"
345+
">;");
210346
}
211347

212348
TEST_F(FormatTestProto, FormatsService) {

0 commit comments

Comments
 (0)
Please sign in to comment.