forked from OSchip/llvm-project
[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
This commit is contained in:
parent
4155c8f1f3
commit
ff747be4d5
|
@ -56,6 +56,8 @@ static bool startsNextParameter(const FormatToken &Current,
|
|||
if (Current.is(TT_CtorInitializerComma) &&
|
||||
Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma)
|
||||
return true;
|
||||
if (Style.Language == FormatStyle::LK_Proto && Current.is(TT_SelectorName))
|
||||
return true;
|
||||
return Previous.is(tok::comma) && !Current.isTrailingComment() &&
|
||||
((Previous.isNot(TT_CtorInitializerComma) ||
|
||||
Style.BreakConstructorInitializers !=
|
||||
|
@ -499,6 +501,13 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
|
|||
}
|
||||
}
|
||||
|
||||
static bool lessOpensProtoMessageField(const FormatToken &LessTok,
|
||||
const LineState &State) {
|
||||
assert(LessTok.is(tok::less));
|
||||
return LessTok.NestingLevel > 0 ||
|
||||
(LessTok.Previous && LessTok.Previous->is(tok::equal));
|
||||
}
|
||||
|
||||
unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
|
||||
bool DryRun) {
|
||||
FormatToken &Current = *State.NextToken;
|
||||
|
@ -641,6 +650,9 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
|
|||
// before the corresponding } or ].
|
||||
if (PreviousNonComment &&
|
||||
(PreviousNonComment->isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) ||
|
||||
(Style.Language == FormatStyle::LK_Proto &&
|
||||
PreviousNonComment->is(tok::less) &&
|
||||
lessOpensProtoMessageField(*PreviousNonComment, State)) ||
|
||||
(PreviousNonComment->is(TT_TemplateString) &&
|
||||
PreviousNonComment->opensScope())))
|
||||
State.Stack.back().BreakBeforeClosingBrace = true;
|
||||
|
@ -682,7 +694,9 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
|
|||
if (NextNonComment->is(tok::l_brace) && NextNonComment->BlockKind == BK_Block)
|
||||
return Current.NestingLevel == 0 ? State.FirstIndent
|
||||
: State.Stack.back().Indent;
|
||||
if (Current.isOneOf(tok::r_brace, tok::r_square) && State.Stack.size() > 1) {
|
||||
if ((Current.isOneOf(tok::r_brace, tok::r_square) ||
|
||||
(Current.is(tok::greater) && Style.Language == FormatStyle::LK_Proto)) &&
|
||||
State.Stack.size() > 1) {
|
||||
if (Current.closesBlockOrBlockTypeList(Style))
|
||||
return State.Stack[State.Stack.size() - 2].NestedBlockIndent;
|
||||
if (Current.MatchingParen &&
|
||||
|
@ -1035,7 +1049,9 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State,
|
|||
bool BreakBeforeParameter = false;
|
||||
unsigned NestedBlockIndent = std::max(State.Stack.back().StartOfFunctionCall,
|
||||
State.Stack.back().NestedBlockIndent);
|
||||
if (Current.isOneOf(tok::l_brace, TT_ArrayInitializerLSquare)) {
|
||||
if (Current.isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) ||
|
||||
(Style.Language == FormatStyle::LK_Proto && Current.is(tok::less) &&
|
||||
lessOpensProtoMessageField(Current, State))) {
|
||||
if (Current.opensBlockOrBlockTypeList(Style)) {
|
||||
NewIndent = Style.IndentWidth +
|
||||
std::min(State.Column, State.Stack.back().NestedBlockIndent);
|
||||
|
|
|
@ -465,7 +465,8 @@ struct FormatToken {
|
|||
return is(TT_ArrayInitializerLSquare) ||
|
||||
(is(tok::l_brace) &&
|
||||
(BlockKind == BK_Block || is(TT_DictLiteral) ||
|
||||
(!Style.Cpp11BracedListStyle && NestingLevel == 0)));
|
||||
(!Style.Cpp11BracedListStyle && NestingLevel == 0))) ||
|
||||
(is(tok::less) && Style.Language == FormatStyle::LK_Proto);
|
||||
}
|
||||
|
||||
/// \brief Same as opensBlockOrBlockTypeList, but for the closing token.
|
||||
|
|
|
@ -89,7 +89,8 @@ private:
|
|||
continue;
|
||||
}
|
||||
if (CurrentToken->isOneOf(tok::r_paren, tok::r_square, tok::r_brace) ||
|
||||
(CurrentToken->isOneOf(tok::colon, tok::question) && InExprContext))
|
||||
(CurrentToken->isOneOf(tok::colon, tok::question) && InExprContext &&
|
||||
Style.Language != FormatStyle::LK_Proto))
|
||||
return false;
|
||||
// If a && or || is found and interpreted as a binary operator, this set
|
||||
// of angles is likely part of something like "a < b && c > d". If the
|
||||
|
@ -103,6 +104,14 @@ private:
|
|||
!Line.startsWith(tok::kw_template))
|
||||
return false;
|
||||
updateParameterCount(Left, CurrentToken);
|
||||
if (Style.Language == FormatStyle::LK_Proto) {
|
||||
if (FormatToken *Previous = CurrentToken->getPreviousNonComment()) {
|
||||
if (CurrentToken->is(tok::colon) ||
|
||||
(CurrentToken->isOneOf(tok::l_brace, tok::less) &&
|
||||
Previous->isNot(tok::colon)))
|
||||
Previous->Type = TT_SelectorName;
|
||||
}
|
||||
}
|
||||
if (!consumeToken())
|
||||
return false;
|
||||
}
|
||||
|
@ -440,7 +449,7 @@ private:
|
|||
if (CurrentToken->isOneOf(tok::r_paren, tok::r_square))
|
||||
return false;
|
||||
updateParameterCount(Left, CurrentToken);
|
||||
if (CurrentToken->isOneOf(tok::colon, tok::l_brace)) {
|
||||
if (CurrentToken->isOneOf(tok::colon, tok::l_brace, tok::less)) {
|
||||
FormatToken *Previous = CurrentToken->getPreviousNonComment();
|
||||
if (((CurrentToken->is(tok::colon) &&
|
||||
(!Contexts.back().ColonIsDictLiteral || !Style.isCpp())) ||
|
||||
|
@ -2549,10 +2558,16 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
|
|||
// deliberate choice and might have aligned the contents of the string
|
||||
// literal accordingly. Thus, we try keep existing line breaks.
|
||||
return Right.NewlinesBefore > 0;
|
||||
if (Right.Previous->is(tok::l_brace) && Right.NestingLevel == 1 &&
|
||||
Style.Language == FormatStyle::LK_Proto)
|
||||
// Don't put enums onto single lines in protocol buffers.
|
||||
if ((Right.Previous->is(tok::l_brace) ||
|
||||
(Right.Previous->is(tok::less) &&
|
||||
Right.Previous->Previous &&
|
||||
Right.Previous->Previous->is(tok::equal))
|
||||
) &&
|
||||
Right.NestingLevel == 1 && Style.Language == FormatStyle::LK_Proto) {
|
||||
// Don't put enums or option definitions onto single lines in protocol
|
||||
// buffers.
|
||||
return true;
|
||||
}
|
||||
if (Right.is(TT_InlineASMBrace))
|
||||
return Right.HasUnescapedNewline;
|
||||
if (isAllmanBrace(Left) || isAllmanBrace(Right))
|
||||
|
|
|
@ -1176,9 +1176,11 @@ void UnwrappedLineParser::parseStructuralElement() {
|
|||
}
|
||||
|
||||
nextToken();
|
||||
if (FormatTok->Tok.is(tok::l_brace)) {
|
||||
if (FormatTok->Tok.is(tok::l_brace))
|
||||
parseBracedList();
|
||||
}
|
||||
else if (Style.Language == FormatStyle::LK_Proto &&
|
||||
FormatTok->Tok.is(tok::less))
|
||||
parseBracedList(/*ClosingBraceKind=*/tok::greater);
|
||||
break;
|
||||
case tok::l_square:
|
||||
parseSquare();
|
||||
|
@ -1346,7 +1348,8 @@ bool UnwrappedLineParser::tryToParseBracedList() {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons) {
|
||||
bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons,
|
||||
tok::TokenKind ClosingBraceKind) {
|
||||
bool HasError = false;
|
||||
nextToken();
|
||||
|
||||
|
@ -1375,6 +1378,10 @@ bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons) {
|
|||
parseChildBlock();
|
||||
}
|
||||
}
|
||||
if (FormatTok->Tok.getKind() == ClosingBraceKind) {
|
||||
nextToken();
|
||||
return !HasError;
|
||||
}
|
||||
switch (FormatTok->Tok.getKind()) {
|
||||
case tok::caret:
|
||||
nextToken();
|
||||
|
@ -1401,9 +1408,6 @@ bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons) {
|
|||
FormatTok->BlockKind = BK_BracedInit;
|
||||
parseBracedList();
|
||||
break;
|
||||
case tok::r_brace:
|
||||
nextToken();
|
||||
return !HasError;
|
||||
case tok::semi:
|
||||
// JavaScript (or more precisely TypeScript) can have semicolons in braced
|
||||
// lists (in so-called TypeMemberLists). Thus, the semicolon cannot be
|
||||
|
|
|
@ -93,7 +93,8 @@ private:
|
|||
void readTokenWithJavaScriptASI();
|
||||
void parseStructuralElement();
|
||||
bool tryToParseBracedList();
|
||||
bool parseBracedList(bool ContinueOnSemicolons = false);
|
||||
bool parseBracedList(bool ContinueOnSemicolons = false,
|
||||
tok::TokenKind ClosingBraceKind = tok::r_brace);
|
||||
void parseParens();
|
||||
void parseSquare();
|
||||
void parseIfThenElse();
|
||||
|
|
|
@ -207,6 +207,142 @@ TEST_F(FormatTestProto, FormatsOptions) {
|
|||
" field_c: \"OK\",\n"
|
||||
" msg_field: <field_d: 123>\n"
|
||||
"};");
|
||||
|
||||
verifyFormat("option (MyProto.options) = {\n"
|
||||
" msg_field: <>\n"
|
||||
" field_c: \"OK\",\n"
|
||||
" msg_field: <field_d: 123>\n"
|
||||
" field_e: OK\n"
|
||||
" msg_field: <field_d: 12>\n"
|
||||
"};");
|
||||
|
||||
verifyFormat("option (MyProto.options) = <\n"
|
||||
" field_a: OK\n"
|
||||
" field_b: \"OK\"\n"
|
||||
" field_c: 1\n"
|
||||
" field_d: 12.5\n"
|
||||
" field_e: OK\n"
|
||||
">;");
|
||||
|
||||
verifyFormat("option (MyProto.options) = <\n"
|
||||
" field_a: OK,\n"
|
||||
" field_b: \"OK\",\n"
|
||||
" field_c: 1,\n"
|
||||
" field_d: 12.5,\n"
|
||||
" field_e: OK,\n"
|
||||
">;");
|
||||
|
||||
verifyFormat("option (MyProto.options) = <\n"
|
||||
" field_a: \"OK\"\n"
|
||||
" msg_field: {field_b: OK}\n"
|
||||
" field_g: OK\n"
|
||||
" field_g: OK\n"
|
||||
" field_g: OK\n"
|
||||
">;");
|
||||
|
||||
verifyFormat("option (MyProto.options) = <\n"
|
||||
" field_a: \"OK\"\n"
|
||||
" msg_field<\n"
|
||||
" field_b: OK\n"
|
||||
" field_c: OK\n"
|
||||
" field_d: OK\n"
|
||||
" field_e: OK\n"
|
||||
" field_f: OK\n"
|
||||
" >\n"
|
||||
" field_g: OK\n"
|
||||
">;");
|
||||
|
||||
verifyFormat("option (MyProto.options) = <\n"
|
||||
" field_a: \"OK\"\n"
|
||||
" msg_field<\n"
|
||||
" field_b: OK,\n"
|
||||
" field_c: OK,\n"
|
||||
" field_d: OK,\n"
|
||||
" field_e: OK,\n"
|
||||
" field_f: OK\n"
|
||||
" >\n"
|
||||
" field_g: OK\n"
|
||||
">;");
|
||||
|
||||
verifyFormat("option (MyProto.options) = <\n"
|
||||
" field_a: \"OK\"\n"
|
||||
" msg_field: <\n"
|
||||
" field_b: OK\n"
|
||||
" field_c: OK\n"
|
||||
" field_d: OK\n"
|
||||
" field_e: OK\n"
|
||||
" field_f: OK\n"
|
||||
" >\n"
|
||||
" field_g: OK\n"
|
||||
">;");
|
||||
|
||||
verifyFormat("option (MyProto.options) = <\n"
|
||||
" field_a: \"OK\"\n"
|
||||
" msg_field: {\n"
|
||||
" field_b: OK\n"
|
||||
" field_c: OK\n"
|
||||
" field_d: OK\n"
|
||||
" field_e: OK\n"
|
||||
" field_f: OK\n"
|
||||
" }\n"
|
||||
" field_g: OK\n"
|
||||
">;");
|
||||
|
||||
verifyFormat("option (MyProto.options) = <\n"
|
||||
" field_a: \"OK\"\n"
|
||||
" msg_field{\n"
|
||||
" field_b: OK\n"
|
||||
" field_c: OK\n"
|
||||
" field_d: OK\n"
|
||||
" field_e: OK\n"
|
||||
" field_f: OK\n"
|
||||
" }\n"
|
||||
" field_g: OK\n"
|
||||
">;");
|
||||
|
||||
verifyFormat("option (MyProto.options) = {\n"
|
||||
" field_a: \"OK\"\n"
|
||||
" msg_field<\n"
|
||||
" field_b: OK\n"
|
||||
" field_c: OK\n"
|
||||
" field_d: OK\n"
|
||||
" field_e: OK\n"
|
||||
" field_f: OK\n"
|
||||
" >\n"
|
||||
" field_g: OK\n"
|
||||
"};");
|
||||
|
||||
verifyFormat("option (MyProto.options) = {\n"
|
||||
" field_a: \"OK\"\n"
|
||||
" msg_field: <\n"
|
||||
" field_b: OK\n"
|
||||
" field_c: OK\n"
|
||||
" field_d: OK\n"
|
||||
" field_e: OK\n"
|
||||
" field_f: OK\n"
|
||||
" >\n"
|
||||
" field_g: OK\n"
|
||||
"};");
|
||||
|
||||
verifyFormat("option (MyProto.options) = <\n"
|
||||
" field_a: \"OK\"\n"
|
||||
" msg_field{\n"
|
||||
" field_b: OK\n"
|
||||
" field_c: OK\n"
|
||||
" field_d: OK\n"
|
||||
" msg_field<\n"
|
||||
" field_A: 1\n"
|
||||
" field_B: 2\n"
|
||||
" field_C: 3\n"
|
||||
" field_D: 4\n"
|
||||
" field_E: 5\n"
|
||||
" >\n"
|
||||
" msg_field<field_A: 1 field_B: 2 field_C: 3 field_D: 4>\n"
|
||||
" field_e: OK\n"
|
||||
" field_f: OK\n"
|
||||
" }\n"
|
||||
" field_g: OK\n"
|
||||
">;");
|
||||
}
|
||||
|
||||
TEST_F(FormatTestProto, FormatsService) {
|
||||
|
|
Loading…
Reference in New Issue