summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/lib/Format/ContinuationIndenter.cpp3
-rw-r--r--clang/lib/Format/TokenAnnotator.cpp21
-rw-r--r--clang/unittests/Format/FormatTestTextProto.cpp18
3 files changed, 39 insertions, 3 deletions
diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp
index 294c58d6219..1a5a6deb042 100644
--- a/clang/lib/Format/ContinuationIndenter.cpp
+++ b/clang/lib/Format/ContinuationIndenter.cpp
@@ -379,7 +379,8 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
if (Current.is(TT_ObjCMethodExpr) && !Previous.is(TT_SelectorName) &&
State.Line->startsWith(TT_ObjCMethodSpecifier))
return true;
- if (Current.is(TT_SelectorName) && State.Stack.back().ObjCSelectorNameFound &&
+ if (Current.is(TT_SelectorName) && !Previous.is(tok::at) &&
+ State.Stack.back().ObjCSelectorNameFound &&
State.Stack.back().BreakBeforeParameter)
return true;
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index 3280f25fef0..68ea02296b7 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -2949,15 +2949,32 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
//
// Be careful to exclude the case [proto.ext] { ... } since the `]` is
// the TT_SelectorName there, but we don't want to break inside the brackets.
+ //
+ // Another edge case is @submessage { key: value }, which is a common
+ // substitution placeholder. In this case we want to keep `@` and `submessage`
+ // together.
+ //
// We ensure elsewhere that extensions are always on their own line.
if ((Style.Language == FormatStyle::LK_Proto ||
Style.Language == FormatStyle::LK_TextProto) &&
Right.is(TT_SelectorName) && !Right.is(tok::r_square) && Right.Next) {
+ // Keep `@submessage` together in:
+ // @submessage { key: value }
+ if (Right.Previous && Right.Previous->is(tok::at))
+ return false;
// Look for the scope opener after selector in cases like:
// selector { ...
// selector: { ...
- FormatToken *LBrace =
- Right.Next->is(tok::colon) ? Right.Next->Next : Right.Next;
+ // selector: @base { ...
+ FormatToken *LBrace = Right.Next;
+ if (LBrace && LBrace->is(tok::colon)) {
+ LBrace = LBrace->Next;
+ if (LBrace && LBrace->is(tok::at)) {
+ LBrace = LBrace->Next;
+ if (LBrace)
+ LBrace = LBrace->Next;
+ }
+ }
if (LBrace &&
// The scope opener is one of {, [, <:
// selector { ... }
diff --git a/clang/unittests/Format/FormatTestTextProto.cpp b/clang/unittests/Format/FormatTestTextProto.cpp
index 9c4e1a85205..0875bd8925d 100644
--- a/clang/unittests/Format/FormatTestTextProto.cpp
+++ b/clang/unittests/Format/FormatTestTextProto.cpp
@@ -717,5 +717,23 @@ TEST_F(FormatTestTextProto, FormatsCommentsAtEndOfFile) {
"# endfile comment");
}
+TEST_F(FormatTestTextProto, KeepsAmpersandsNextToKeys) {
+ verifyFormat("@tmpl { field: 1 }");
+ verifyFormat("@placeholder: 1");
+ verifyFormat("@name <>");
+ verifyFormat("submessage: @base { key: value }");
+ verifyFormat("submessage: @base {\n"
+ " key: value\n"
+ " item: {}\n"
+ "}");
+ verifyFormat("submessage: {\n"
+ " msg: @base {\n"
+ " yolo: {}\n"
+ " key: value\n"
+ " }\n"
+ " key: value\n"
+ "}");
+}
+
} // end namespace tooling
} // end namespace clang
OpenPOWER on IntegriCloud