Formatter: Initial support for formatting Objective-C method expressions.
This follows the approach suggested by djasper in PR14911: When a '[' is
seen that's at the start of a line, follows a binary operator, or follows one
of : [ ( return throw, that '[' and its closing ']' are marked as
TT_ObjCMethodExpr and every ':' in that range that isn't part of a ternary
?: is marked as TT_ObjCMethodExpr as well.
Update the layout routines to not output spaces around ':' tokens that are
marked TT_ObjCMethodExpr, and only allow breaking after such tokens, not
before.
Before:
[self adjustButton : closeButton_ ofKind : NSWindowCloseButton];
Now:
[self adjustButton:closeButton_ ofKind:NSWindowCloseButton];
llvm-svn: 172304
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index aa534b9..0c486e0 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -39,6 +39,7 @@
TT_ObjCBlockLParen,
TT_ObjCDecl,
TT_ObjCMethodSpecifier,
+ TT_ObjCMethodExpr,
TT_ObjCSelectorStart,
TT_ObjCProperty,
TT_OverloadedOperator,
@@ -613,7 +614,8 @@
class AnnotatingParser {
public:
AnnotatingParser(AnnotatedToken &RootToken)
- : CurrentToken(&RootToken), KeywordVirtualFound(false) {}
+ : CurrentToken(&RootToken), KeywordVirtualFound(false),
+ ColonIsObjCMethodExpr(false) {}
bool parseAngle() {
while (CurrentToken != NULL) {
@@ -651,8 +653,34 @@
}
bool parseSquare() {
+ if (!CurrentToken)
+ return false;
+
+ // A '[' could be an index subscript (after an indentifier or after
+ // ')' or ']'), or it could be the start of an Objective-C method
+ // expression.
+ AnnotatedToken *LSquare = CurrentToken->Parent;
+ bool StartsObjCMethodExpr =
+ !LSquare->Parent || LSquare->Parent->is(tok::colon) ||
+ LSquare->Parent->is(tok::l_square) ||
+ LSquare->Parent->is(tok::l_paren) ||
+ LSquare->Parent->is(tok::kw_return) ||
+ LSquare->Parent->is(tok::kw_throw) ||
+ getBinOpPrecedence(LSquare->Parent->FormatTok.Tok.getKind(),
+ true, true) > prec::Unknown;
+
+ bool ColonWasObjCMethodExpr = ColonIsObjCMethodExpr;
+ if (StartsObjCMethodExpr) {
+ ColonIsObjCMethodExpr = true;
+ LSquare->Type = TT_ObjCMethodExpr;
+ }
+
while (CurrentToken != NULL) {
if (CurrentToken->is(tok::r_square)) {
+ if (StartsObjCMethodExpr) {
+ ColonIsObjCMethodExpr = ColonWasObjCMethodExpr;
+ CurrentToken->Type = TT_ObjCMethodExpr;
+ }
next();
return true;
}
@@ -716,6 +744,11 @@
if (Tok->Parent == NULL)
Tok->Type = TT_ObjCMethodSpecifier;
break;
+ case tok::colon:
+ // Colons from ?: are handled in parseConditional().
+ if (ColonIsObjCMethodExpr)
+ Tok->Type = TT_ObjCMethodExpr;
+ break;
case tok::l_paren: {
bool ParensWereObjCReturnType =
Tok->Parent && Tok->Parent->Type == TT_ObjCMethodSpecifier;
@@ -841,6 +874,7 @@
private:
AnnotatedToken *CurrentToken;
bool KeywordVirtualFound;
+ bool ColonIsObjCMethodExpr;
};
void createAnnotatedTokens(AnnotatedToken &Current) {
@@ -1048,8 +1082,9 @@
Style.PointerAndReferenceBindToType;
if (Right.is(tok::star) && Left.is(tok::l_paren))
return false;
- if (Left.is(tok::l_square) || Right.is(tok::l_square) ||
- Right.is(tok::r_square))
+ if (Left.is(tok::l_square) || Right.is(tok::r_square))
+ return false;
+ if (Right.is(tok::l_square) && Right.Type != TT_ObjCMethodExpr)
return false;
if (Left.is(tok::coloncolon) ||
(Right.is(tok::coloncolon) &&
@@ -1057,8 +1092,10 @@
return false;
if (Left.is(tok::period) || Right.is(tok::period))
return false;
- if (Left.is(tok::colon) || Right.is(tok::colon))
- return true;
+ if (Left.is(tok::colon))
+ return Left.Type != TT_ObjCMethodExpr;
+ if (Right.is(tok::colon))
+ return Right.Type != TT_ObjCMethodExpr;
if (Left.is(tok::l_paren))
return false;
if (Right.is(tok::l_paren)) {
@@ -1106,7 +1143,8 @@
if (Tok.Parent->Type == TT_OverloadedOperator)
return false;
if (Tok.is(tok::colon))
- return RootToken.isNot(tok::kw_case) && (!Tok.Children.empty());
+ return RootToken.isNot(tok::kw_case) && !Tok.Children.empty() &&
+ Tok.Type != TT_ObjCMethodExpr;
if (Tok.Parent->Type == TT_UnaryOperator ||
Tok.Parent->Type == TT_CastRParen)
return false;
@@ -1148,6 +1186,10 @@
// Don't break at ':' if identifier before it can beak.
return false;
}
+ if (Right.is(tok::colon) && Right.Type == TT_ObjCMethodExpr)
+ return false;
+ if (Left.is(tok::colon) && Left.Type == TT_ObjCMethodExpr)
+ return true;
if (Left.ClosesTemplateDeclaration)
return true;
if (Left.Type == TT_PointerOrReference || Left.Type == TT_TemplateCloser ||