diff options
Diffstat (limited to 'clang')
| -rw-r--r-- | clang/lib/Format/ContinuationIndenter.cpp | 3 | ||||
| -rw-r--r-- | clang/lib/Format/TokenAnnotator.cpp | 21 | ||||
| -rw-r--r-- | clang/unittests/Format/FormatTestTextProto.cpp | 18 | 
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  | 

