From fd36f0b5046de20c220e5f53e5e8394fb9bfea2b Mon Sep 17 00:00:00 2001 From: Daniel Jasper Date: Sat, 12 Nov 2016 07:38:22 +0000 Subject: [PATCH] clang-format: Support ObjC selectors with unnamed parameters. This fixes llvm.org/PR28063. llvm-svn: 286715 --- clang/lib/Format/ContinuationIndenter.cpp | 5 +++++ clang/lib/Format/TokenAnnotator.cpp | 37 +++++++++++++++++++++++-------- clang/unittests/Format/FormatTest.cpp | 20 +++++++++++++++++ 3 files changed, 53 insertions(+), 9 deletions(-) diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp index f7f0fd5..e74515e 100644 --- a/clang/lib/Format/ContinuationIndenter.cpp +++ b/clang/lib/Format/ContinuationIndenter.cpp @@ -177,6 +177,9 @@ bool ContinuationIndenter::mustBreak(const LineState &State) { ((Style.AllowShortFunctionsOnASingleLine != FormatStyle::SFS_All) || Style.BreakConstructorInitializersBeforeComma || Style.ColumnLimit != 0)) return true; + 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 && State.Stack.back().BreakBeforeParameter) return true; @@ -671,6 +674,8 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) { return State.Stack.back().ColonPos - NextNonComment->ColumnWidth; return State.Stack.back().Indent; } + if (NextNonComment->is(tok::colon) && NextNonComment->is(TT_ObjCMethodExpr)) + return State.Stack.back().ColonPos; if (NextNonComment->is(TT_ArraySubscriptLSquare)) { if (State.Stack.back().StartOfArraySubscripts != 0) return State.Stack.back().StartOfArraySubscripts; diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index d64daa6..b241fe9 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -316,8 +316,8 @@ private: (Contexts.back().CanBeExpression || Contexts.back().IsExpression || Contexts.back().InTemplateArgument); - bool StartsObjCMethodExpr = !CppArrayTemplates && - Style.Language == FormatStyle::LK_Cpp && + bool StartsObjCMethodExpr = + !CppArrayTemplates && Style.Language == FormatStyle::LK_Cpp && Contexts.back().CanBeExpression && Left->isNot(TT_LambdaLSquare) && CurrentToken->isNot(tok::l_brace) && (!Parent || @@ -519,12 +519,21 @@ private: } else if (Contexts.back().ColonIsObjCMethodExpr || Line.startsWith(TT_ObjCMethodSpecifier)) { Tok->Type = TT_ObjCMethodExpr; - Tok->Previous->Type = TT_SelectorName; - if (Tok->Previous->ColumnWidth > - Contexts.back().LongestObjCSelectorName) - Contexts.back().LongestObjCSelectorName = Tok->Previous->ColumnWidth; - if (!Contexts.back().FirstObjCSelectorName) - Contexts.back().FirstObjCSelectorName = Tok->Previous; + const FormatToken *BeforePrevious = Tok->Previous->Previous; + if (!BeforePrevious || + !(BeforePrevious->is(TT_CastRParen) || + (BeforePrevious->is(TT_ObjCMethodExpr) && + BeforePrevious->is(tok::colon))) || + BeforePrevious->is(tok::r_square) || + Contexts.back().LongestObjCSelectorName == 0) { + Tok->Previous->Type = TT_SelectorName; + if (Tok->Previous->ColumnWidth > + Contexts.back().LongestObjCSelectorName) + Contexts.back().LongestObjCSelectorName = + Tok->Previous->ColumnWidth; + if (!Contexts.back().FirstObjCSelectorName) + Contexts.back().FirstObjCSelectorName = Tok->Previous; + } } else if (Contexts.back().ColonIsForRangeExpr) { Tok->Type = TT_RangeBasedForLoopColon; } else if (CurrentToken && CurrentToken->is(tok::numeric_constant)) { @@ -1224,6 +1233,13 @@ private: if (!LeftOfParens) return false; + // Certain token types inside the parentheses mean that this can't be a + // cast. + for (const FormatToken *Token = Tok.MatchingParen->Next; Token != &Tok; + Token = Token->Next) + if (Token->is(TT_BinaryOperator)) + return false; + // If the following token is an identifier or 'this', this is a cast. All // cases where this can be something else are handled above. if (Tok.Next->isOneOf(tok::identifier, tok::kw_this)) @@ -2497,10 +2513,13 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, return !Style.BreakBeforeTernaryOperators; if (Right.is(TT_InheritanceColon)) return true; + if (Right.is(TT_ObjCMethodExpr) && !Right.is(tok::r_square) && + Left.isNot(TT_SelectorName)) + return true; if (Right.is(tok::colon) && !Right.isOneOf(TT_CtorInitializerColon, TT_InlineASMColon)) return false; - if (Left.is(tok::colon) && (Left.isOneOf(TT_DictLiteral, TT_ObjCMethodExpr))) + if (Left.is(tok::colon) && Left.isOneOf(TT_DictLiteral, TT_ObjCMethodExpr)) return true; if (Right.is(TT_SelectorName) || (Right.is(tok::identifier) && Right.Next && Right.Next->is(TT_ObjCMethodExpr))) diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index 0056436..9ce888d 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -7555,6 +7555,20 @@ TEST_F(FormatTest, FormatObjCMethodDeclarations) { " aShortf:(NSRect)theRect {\n" "}", continuationStyle); + + // Format pairs correctly. + verifyFormat("- (void)drawRectOn:(id)surface\n" + " ofSize:(aaaaaaaa)height\n" + " :(size_t)width\n" + " atOrigin:(size_t)x\n" + " :(size_t)y\n" + " aaaaa:(a)yyy\n" + " bbb:(d)cccc;"); + verifyFormat("- (void)drawRectOn:(id)surface ofSize:(aaa)height:(bbb)width;"); + verifyFormat("- (void)drawRectOn:(id)surface\n" + " ofSize:(size_t)height\n" + " :(size_t)width;", + getLLVMStyleWithColumns(60)); } TEST_F(FormatTest, FormatObjCMethodExpr) { @@ -7757,6 +7771,12 @@ TEST_F(FormatTest, FormatObjCMethodExpr) { " aaa:aaa];"); verifyFormat("bool a = ([aaaaaaaa aaaaa] == aaaaaaaaaaaaaaaaa ||\n" " [aaaaaaaa aaaaa] == aaaaaaaaaaaaaaaaaaaa);"); + + // Formats pair-parameters. + verifyFormat("[I drawRectOn:surface ofSize:aa:bbb atOrigin:cc:dd];"); + verifyFormat("[I drawRectOn:surface //\n" + " ofSize:aa:bbb\n" + " atOrigin:cc:dd];"); } TEST_F(FormatTest, ObjCAt) { -- 2.7.4