<div dir="ltr">Not yet. Feel free to file bugs with examples (I don't really have ObjC code at my disposal)...</div><div class="gmail_extra"><br><br><div class="gmail_quote">On Tue, Feb 5, 2013 at 4:06 PM, Nico Weber <span dir="ltr"><<a href="mailto:thakis@chromium.org" target="_blank">thakis@chromium.org</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Nice!<br>
<div><div class="h5"><br>
On Tue, Feb 5, 2013 at 2:07 AM, Daniel Jasper <<a href="mailto:djasper@google.com">djasper@google.com</a>> wrote:<br>
> Author: djasper<br>
> Date: Tue Feb 5 04:07:47 2013<br>
> New Revision: 174364<br>
><br>
> URL: <a href="http://llvm.org/viewvc/llvm-project?rev=174364&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=174364&view=rev</a><br>
> Log:<br>
> Initial support for formatting ObjC method declarations/calls.<br>
><br>
> We can now format stuff like:<br>
> - (void)doSomethingWith:(GTMFoo *)theFoo<br>
> rect:(NSRect)theRect<br>
> interval:(float)theInterval {<br>
> [myObject doFooWith:arg1 //<br>
> name:arg2<br>
> error:arg3];<br>
><br>
> }<br>
><br>
> This seems to fix everything mentioned in <a href="http://llvm.org/PR14939" target="_blank">llvm.org/PR14939</a>.<br>
><br>
> Modified:<br>
> cfe/trunk/lib/Format/Format.cpp<br>
> cfe/trunk/lib/Format/TokenAnnotator.cpp<br>
> cfe/trunk/lib/Format/TokenAnnotator.h<br>
> cfe/trunk/unittests/Format/FormatTest.cpp<br>
><br>
> Modified: cfe/trunk/lib/Format/Format.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/Format.cpp?rev=174364&r1=174363&r2=174364&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/Format.cpp?rev=174364&r1=174363&r2=174364&view=diff</a><br>
> ==============================================================================<br>
> --- cfe/trunk/lib/Format/Format.cpp (original)<br>
> +++ cfe/trunk/lib/Format/Format.cpp Tue Feb 5 04:07:47 2013<br>
> @@ -268,7 +268,7 @@ private:<br>
> : Indent(Indent), LastSpace(LastSpace), AssignmentColumn(0),<br>
> FirstLessLess(0), BreakBeforeClosingBrace(false), QuestionColumn(0),<br>
> AvoidBinPacking(AvoidBinPacking), BreakAfterComma(false),<br>
> - HasMultiParameterLine(HasMultiParameterLine) {<br>
> + HasMultiParameterLine(HasMultiParameterLine), ColonPos(0) {<br>
> }<br>
><br>
> /// \brief The position to which a specific parenthesis level needs to be<br>
> @@ -312,6 +312,9 @@ private:<br>
> /// \brief This context already has a line with more than one parameter.<br>
> bool HasMultiParameterLine;<br>
><br>
> + /// \brief The position of the colon in an ObjC method declaration/call.<br>
> + unsigned ColonPos;<br>
> +<br>
> bool operator<(const ParenState &Other) const {<br>
> if (Indent != Other.Indent)<br>
> return Indent < Other.Indent;<br>
> @@ -331,6 +334,8 @@ private:<br>
> return BreakAfterComma;<br>
> if (HasMultiParameterLine != Other.HasMultiParameterLine)<br>
> return HasMultiParameterLine;<br>
> + if (ColonPos != Other.ColonPos)<br>
> + return ColonPos < Other.ColonPos;<br>
> return false;<br>
> }<br>
> };<br>
> @@ -427,6 +432,17 @@ private:<br>
> } else if (Previous.Type == TT_BinaryOperator &&<br>
> State.Stack.back().AssignmentColumn != 0) {<br>
> State.Column = State.Stack.back().AssignmentColumn;<br>
> + } else if (Current.Type == TT_ObjCSelectorName) {<br>
> + if (State.Stack.back().ColonPos > Current.FormatTok.TokenLength) {<br>
> + State.Column =<br>
> + State.Stack.back().ColonPos - Current.FormatTok.TokenLength;<br>
> + } else {<br>
> + State.Column = State.Stack.back().Indent;<br>
> + State.Stack.back().ColonPos =<br>
> + State.Column + Current.FormatTok.TokenLength;<br>
> + }<br>
> + } else if (Previous.Type == TT_ObjCMethodExpr) {<br>
> + State.Column = State.Stack.back().Indent + 4;<br>
> } else {<br>
> State.Column = State.Stack[ParenLevel].Indent;<br>
> }<br>
> @@ -461,6 +477,17 @@ private:<br>
> if (!DryRun)<br>
> Whitespaces.replaceWhitespace(Current, 0, Spaces, State.Column, Style);<br>
><br>
> + if (Current.Type == TT_ObjCSelectorName &&<br>
> + State.Stack.back().ColonPos == 0) {<br>
> + if (State.Stack.back().Indent + Current.LongestObjCSelectorName ><br>
> + State.Column + Spaces + Current.FormatTok.TokenLength)<br>
> + State.Stack.back().ColonPos =<br>
> + State.Stack.back().Indent + Current.LongestObjCSelectorName;<br>
> + else<br>
> + State.Stack.back().ColonPos =<br>
> + State.Column + Spaces + Current.LongestObjCSelectorName;<br>
> + }<br>
> +<br>
> // FIXME: Do we need to do this for assignments nested in other<br>
> // expressions?<br>
> if (RootToken.isNot(tok::kw_for) && ParenLevel == 0 &&<br>
> @@ -699,6 +726,9 @@ private:<br>
> State.Stack.back().BreakAfterComma &&<br>
> !isTrailingComment(*State.NextToken))<br>
> return true;<br>
> + if (State.NextToken->Type == TT_ObjCSelectorName &&<br>
> + State.Stack.back().ColonPos != 0)<br>
> + return true;<br>
> if ((State.NextToken->Type == TT_CtorInitializerColon ||<br>
> (State.NextToken->Parent->ClosesTemplateDeclaration &&<br>
> State.Stack.size() == 1)))<br>
><br>
> Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=174364&r1=174363&r2=174364&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=174364&r1=174363&r2=174364&view=diff</a><br>
> ==============================================================================<br>
> --- cfe/trunk/lib/Format/TokenAnnotator.cpp (original)<br>
> +++ cfe/trunk/lib/Format/TokenAnnotator.cpp Tue Feb 5 04:07:47 2013<br>
> @@ -20,15 +20,6 @@<br>
> namespace clang {<br>
> namespace format {<br>
><br>
> -/// \brief Returns if a token is an Objective-C selector name.<br>
> -///<br>
> -/// For example, "bar" is a selector name in [foo bar:(4 + 5)].<br>
> -static bool isObjCSelectorName(const AnnotatedToken &Tok) {<br>
> - return Tok.is(tok::identifier) && !Tok.Children.empty() &&<br>
> - Tok.Children[0].is(tok::colon) &&<br>
> - Tok.Children[0].Type == TT_ObjCMethodExpr;<br>
> -}<br>
> -<br>
> static bool isBinaryOperator(const AnnotatedToken &Tok) {<br>
> // Comma is a binary operator, but does not behave as such wrt. formatting.<br>
> return getPrecedence(Tok) > prec::Comma;<br>
> @@ -65,6 +56,7 @@ public:<br>
> AnnotatingParser(SourceManager &SourceMgr, Lexer &Lex, AnnotatedLine &Line)<br>
> : SourceMgr(SourceMgr), Lex(Lex), Line(Line), CurrentToken(&Line.First),<br>
> KeywordVirtualFound(false), ColonIsObjCMethodExpr(false),<br>
> + LongestObjCSelectorName(0), FirstObjCSelectorName(NULL),<br>
<br>
</div></div>Does this handle nested selectors? E.g.<br>
<br>
[contentsContainer replaceSubview:[subviews objectAtIndex:0]<br>
with:contentsNativeView];<br>
<div class="HOEnZb"><div class="h5"><br>
<br>
> ColonIsForRangeExpr(false), IsExpression(false),<br>
> LookForFunctionName(Line.MustBeDeclaration), BindingStrength(1) {<br>
> }<br>
> @@ -82,6 +74,8 @@ public:<br>
><br>
> void markStart(AnnotatedToken &Left) {<br>
> P.ColonIsObjCMethodExpr = true;<br>
> + P.LongestObjCSelectorName = 0;<br>
> + P.FirstObjCSelectorName = NULL;<br>
> Left.Type = TT_ObjCMethodExpr;<br>
> }<br>
><br>
> @@ -168,8 +162,13 @@ public:<br>
> Left->MatchingParen = CurrentToken;<br>
> CurrentToken->MatchingParen = Left;<br>
><br>
> - if (StartsObjCMethodExpr)<br>
> + if (StartsObjCMethodExpr) {<br>
> objCSelector.markEnd(*CurrentToken);<br>
> + if (FirstObjCSelectorName != NULL) {<br>
> + FirstObjCSelectorName->LongestObjCSelectorName =<br>
> + LongestObjCSelectorName;<br>
> + }<br>
> + }<br>
><br>
> next();<br>
> return true;<br>
> @@ -221,6 +220,9 @@ public:<br>
> }<br>
> Left->MatchingParen = CurrentToken;<br>
> CurrentToken->MatchingParen = Left;<br>
> + if (FirstObjCSelectorName != NULL)<br>
> + FirstObjCSelectorName->LongestObjCSelectorName =<br>
> + LongestObjCSelectorName;<br>
> next();<br>
> return true;<br>
> }<br>
> @@ -295,12 +297,19 @@ public:<br>
> break;<br>
> case tok::colon:<br>
> // Colons from ?: are handled in parseConditional().<br>
> - if (Tok->Parent->is(tok::r_paren))<br>
> + if (Tok->Parent->is(tok::r_paren)) {<br>
> Tok->Type = TT_CtorInitializerColon;<br>
> - else if (ColonIsObjCMethodExpr)<br>
> + } else if (ColonIsObjCMethodExpr ||<br>
> + Line.First.Type == TT_ObjCMethodSpecifier) {<br>
> Tok->Type = TT_ObjCMethodExpr;<br>
> - else if (ColonIsForRangeExpr)<br>
> + Tok->Parent->Type = TT_ObjCSelectorName;<br>
> + if (Tok->Parent->FormatTok.TokenLength > LongestObjCSelectorName)<br>
> + LongestObjCSelectorName = Tok->Parent->FormatTok.TokenLength;<br>
> + if (FirstObjCSelectorName == NULL)<br>
> + FirstObjCSelectorName = Tok->Parent;<br>
> + } else if (ColonIsForRangeExpr) {<br>
> Tok->Type = TT_RangeBasedForLoopColon;<br>
> + }<br>
> break;<br>
> case tok::kw_if:<br>
> case tok::kw_while:<br>
> @@ -452,6 +461,13 @@ public:<br>
> if (PeriodsAndArrows >= 2 && CanBeBuilderTypeStmt)<br>
> return LT_BuilderTypeCall;<br>
><br>
> + if (Line.First.Type == TT_ObjCMethodSpecifier) {<br>
> + if (FirstObjCSelectorName != NULL)<br>
> + FirstObjCSelectorName->LongestObjCSelectorName =<br>
> + LongestObjCSelectorName;<br>
> + return LT_ObjCMethodDecl;<br>
> + }<br>
> +<br>
> return LT_Other;<br>
> }<br>
><br>
> @@ -474,6 +490,8 @@ private:<br>
> AnnotatedToken *CurrentToken;<br>
> bool KeywordVirtualFound;<br>
> bool ColonIsObjCMethodExpr;<br>
> + unsigned LongestObjCSelectorName;<br>
> + AnnotatedToken *FirstObjCSelectorName;<br>
> bool ColonIsForRangeExpr;<br>
> bool IsExpression;<br>
> bool LookForFunctionName;<br>
> @@ -725,9 +743,9 @@ unsigned TokenAnnotator::splitPenalty(co<br>
><br>
> // In Objective-C method expressions, prefer breaking before "param:" over<br>
> // breaking after it.<br>
> - if (isObjCSelectorName(Right))<br>
> + if (Right.Type == TT_ObjCSelectorName)<br>
> return 0;<br>
> - if (Right.is(tok::colon) && Right.Type == TT_ObjCMethodExpr)<br>
> + if (Left.is(tok::colon) && Left.Type == TT_ObjCMethodExpr)<br>
> return 20;<br>
><br>
> if (Left.is(tok::l_paren) || Left.is(tok::l_square) ||<br>
> @@ -885,7 +903,7 @@ bool TokenAnnotator::canBreakBefore(cons<br>
> return false;<br>
> if (Left.is(tok::colon) && Left.Type == TT_ObjCMethodExpr)<br>
> return true;<br>
> - if (isObjCSelectorName(Right))<br>
> + if (Right.Type == TT_ObjCSelectorName)<br>
> return true;<br>
> if (Left.ClosesTemplateDeclaration)<br>
> return true;<br>
><br>
> Modified: cfe/trunk/lib/Format/TokenAnnotator.h<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.h?rev=174364&r1=174363&r2=174364&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.h?rev=174364&r1=174363&r2=174364&view=diff</a><br>
> ==============================================================================<br>
> --- cfe/trunk/lib/Format/TokenAnnotator.h (original)<br>
> +++ cfe/trunk/lib/Format/TokenAnnotator.h Tue Feb 5 04:07:47 2013<br>
> @@ -40,6 +40,7 @@ enum TokenType {<br>
> TT_ObjCMethodSpecifier,<br>
> TT_ObjCMethodExpr,<br>
> TT_ObjCProperty,<br>
> + TT_ObjCSelectorName,<br>
> TT_OverloadedOperator,<br>
> TT_PointerOrReference,<br>
> TT_PureVirtualSpecifier,<br>
> @@ -69,7 +70,8 @@ public:<br>
> : FormatTok(FormatTok), Type(TT_Unknown), SpaceRequiredBefore(false),<br>
> CanBreakBefore(false), MustBreakBefore(false),<br>
> ClosesTemplateDeclaration(false), MatchingParen(NULL),<br>
> - ParameterCount(1), BindingStrength(0), SplitPenalty(0), Parent(NULL) {<br>
> + ParameterCount(1), BindingStrength(0), SplitPenalty(0),<br>
> + LongestObjCSelectorName(0), Parent(NULL) {<br>
> }<br>
><br>
> bool is(tok::TokenKind Kind) const { return <a href="http://FormatTok.Tok.is" target="_blank">FormatTok.Tok.is</a>(Kind); }<br>
> @@ -109,6 +111,10 @@ public:<br>
> /// \brief Penalty for inserting a line break before this token.<br>
> unsigned SplitPenalty;<br>
><br>
> + /// \brief If this is the first ObjC selector name in an ObjC method<br>
> + /// definition or call, this contains the length of the longest name.<br>
> + unsigned LongestObjCSelectorName;<br>
> +<br>
> std::vector<AnnotatedToken> Children;<br>
> AnnotatedToken *Parent;<br>
><br>
><br>
> Modified: cfe/trunk/unittests/Format/FormatTest.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTest.cpp?rev=174364&r1=174363&r2=174364&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTest.cpp?rev=174364&r1=174363&r2=174364&view=diff</a><br>
> ==============================================================================<br>
> --- cfe/trunk/unittests/Format/FormatTest.cpp (original)<br>
> +++ cfe/trunk/unittests/Format/FormatTest.cpp Tue Feb 5 04:07:47 2013<br>
> @@ -1979,20 +1979,18 @@ TEST_F(FormatTest, FormatForObjectiveCMe<br>
> format("- (void)sendAction:(SEL)aSelector to:(id)anObject forAllCells:(BOOL)flag;"));<br>
><br>
> // Very long objectiveC method declaration.<br>
> - EXPECT_EQ(<br>
> - "- (NSUInteger)indexOfObject:(id)anObject inRange:(NSRange)range\n "<br>
> - "outRange:(NSRange)out_range outRange1:(NSRange)out_range1\n "<br>
> - "outRange2:(NSRange)out_range2 outRange3:(NSRange)out_range3\n "<br>
> - "outRange4:(NSRange)out_range4 outRange5:(NSRange)out_range5\n "<br>
> - "outRange6:(NSRange)out_range6 outRange7:(NSRange)out_range7\n "<br>
> - "outRange8:(NSRange)out_range8 outRange9:(NSRange)out_range9;",<br>
> - format(<br>
> - "- (NSUInteger)indexOfObject:(id)anObject inRange:(NSRange)range "<br>
> - "outRange:(NSRange) out_range outRange1:(NSRange) out_range1 "<br>
> - "outRange2:(NSRange) out_range2 outRange3:(NSRange) out_range3 "<br>
> - "outRange4:(NSRange) out_range4 outRange5:(NSRange) out_range5 "<br>
> - "outRange6:(NSRange) out_range6 outRange7:(NSRange) out_range7 "<br>
> - "outRange8:(NSRange) out_range8 outRange9:(NSRange) out_range9;"));<br>
> + verifyFormat("- (NSUInteger)indexOfObject:(id)anObject\n"<br>
> + " inRange:(NSRange)range\n"<br>
> + " outRange:(NSRange)out_range\n"<br>
> + " outRange1:(NSRange)out_range1\n"<br>
> + " outRange2:(NSRange)out_range2\n"<br>
> + " outRange3:(NSRange)out_range3\n"<br>
> + " outRange4:(NSRange)out_range4\n"<br>
> + " outRange5:(NSRange)out_range5\n"<br>
> + " outRange6:(NSRange)out_range6\n"<br>
> + " outRange7:(NSRange)out_range7\n"<br>
> + " outRange8:(NSRange)out_range8\n"<br>
> + " outRange9:(NSRange)out_range9;");<br>
><br>
> verifyFormat("- (int)sum:(vector<int>)numbers;");<br>
> verifyGoogleFormat("- (void)setDelegate:(id<Protocol>)delegate;");<br>
> @@ -2218,6 +2216,18 @@ TEST_F(FormatTest, FormatObjCProtocol) {<br>
> "@end\n");<br>
> }<br>
><br>
> +TEST_F(FormatTest, FormatObjCMethodDeclarations) {<br>
> + verifyFormat("- (void)doSomethingWith:(GTMFoo *)theFoo\n"<br>
> + " rect:(NSRect)theRect\n"<br>
> + " interval:(float)theInterval {\n"<br>
> + "}");<br>
> + verifyFormat("- (void)shortf:(GTMFoo *)theFoo\n"<br>
> + " longKeyword:(NSRect)theRect\n"<br>
> + " evenLongerKeyword:(float)theInterval\n"<br>
> + " error:(NSError **)theError {\n"<br>
> + "}");<br>
> +}<br>
> +<br>
> TEST_F(FormatTest, FormatObjCMethodExpr) {<br>
> verifyFormat("[foo bar:baz];");<br>
> verifyFormat("return [foo bar:baz];");<br>
> @@ -2266,7 +2276,7 @@ TEST_F(FormatTest, FormatObjCMethodExpr)<br>
> verifyFormat("[cond ? obj1 : obj2 methodWithParam:param]");<br>
> verifyFormat("[button setAction:@selector(zoomOut:)];");<br>
> verifyFormat("[color getRed:&r green:&g blue:&b alpha:&a];");<br>
> -<br>
> +<br>
> verifyFormat("arr[[self indexForFoo:a]];");<br>
> verifyFormat("throw [self errorFor:a];");<br>
> verifyFormat("@throw [self errorFor:a];");<br>
> @@ -2275,12 +2285,27 @@ TEST_F(FormatTest, FormatObjCMethodExpr)<br>
> // which would be at 80 columns.<br>
> verifyFormat(<br>
> "void f() {\n"<br>
> - " if ((self = [super initWithContentRect:contentRect styleMask:styleMask\n"<br>
> - " backing:NSBackingStoreBuffered defer:YES]))");<br>
> -<br>
> + " if ((self = [super initWithContentRect:contentRect\n"<br>
> + " styleMask:styleMask\n"<br>
> + " backing:NSBackingStoreBuffered\n"<br>
> + " defer:YES]))");<br>
> +<br>
> verifyFormat("[foo checkThatBreakingAfterColonWorksOk:\n"<br>
> - " [bar ifItDoes:reduceOverallLineLengthLikeInThisCase]];");<br>
> -<br>
> + " [bar ifItDoes:reduceOverallLineLengthLikeInThisCase]];");<br>
> +<br>
> + verifyFormat("[myObj short:arg1 // Force line break\n"<br>
> + " longKeyword:arg2\n"<br>
> + " evenLongerKeyword:arg3\n"<br>
> + " error:arg4];");<br>
> + verifyFormat(<br>
> + "void f() {\n"<br>
> + " popup_window_.reset([[RenderWidgetPopupWindow alloc]\n"<br>
> + " initWithContentRect:NSMakeRect(origin_global.x, origin_global.y,\n"<br>
> + " pos.width(), pos.height())\n"<br>
> + " styleMask:NSBorderlessWindowMask\n"<br>
> + " backing:NSBackingStoreBuffered\n"<br>
> + " defer:NO]);\n"<br>
> + "}");<br>
> }<br>
><br>
> TEST_F(FormatTest, ObjCAt) {<br>
><br>
><br>
> _______________________________________________<br>
> cfe-commits mailing list<br>
> <a href="mailto:cfe-commits@cs.uiuc.edu">cfe-commits@cs.uiuc.edu</a><br>
> <a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
</div></div></blockquote></div><br></div>