diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index 0c13dbeaca31..0bafd6c7730c 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -59,6 +59,10 @@ struct FormatStyle { /// \brief Add a space in front of an Objective-C protocol list, i.e. use /// Foo instead of Foo. bool ObjCSpaceBeforeProtocolList; + + /// \brief Add a space in front method return types, i.e. use + /// + (id)init instead of +(id) init + bool ObjCSpaceBeforeReturnType; }; /// \brief Returns a format style complying with the LLVM coding standards: diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index f84d3c5bc7a6..87b996a7823b 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -39,6 +39,7 @@ enum TokenType { TT_ObjCBlockLParen, TT_ObjCDecl, TT_ObjCMethodSpecifier, + TT_ObjCSelectorStart, TT_ObjCProperty, TT_OverloadedOperator, TT_PointerOrReference, @@ -107,6 +108,7 @@ FormatStyle getLLVMStyle() { LLVMStyle.IndentCaseLabels = false; LLVMStyle.SpacesBeforeTrailingComments = 1; LLVMStyle.ObjCSpaceBeforeProtocolList = true; + LLVMStyle.ObjCSpaceBeforeReturnType = true; return LLVMStyle; } @@ -120,6 +122,7 @@ FormatStyle getGoogleStyle() { GoogleStyle.IndentCaseLabels = true; GoogleStyle.SpacesBeforeTrailingComments = 2; GoogleStyle.ObjCSpaceBeforeProtocolList = false; + GoogleStyle.ObjCSpaceBeforeReturnType = false; return GoogleStyle; } @@ -680,14 +683,26 @@ public: AnnotatedToken *Tok = CurrentToken; next(); switch (Tok->FormatTok.Tok.getKind()) { - case tok::l_paren: + case tok::plus: + case tok::minus: + // At the start of the line, +/- specific ObjectiveC method + // declarations. + if (Tok->Parent == NULL) + Tok->Type = TT_ObjCMethodSpecifier; + break; + case tok::l_paren: { + bool ParensWereObjCReturnType = + Tok->Parent && Tok->Parent->Type == TT_ObjCMethodSpecifier; if (!parseParens()) return false; if (CurrentToken != NULL && CurrentToken->is(tok::colon)) { CurrentToken->Type = TT_CtorInitializerColon; next(); + } else if (CurrentToken != NULL && ParensWereObjCReturnType) { + CurrentToken->Type = TT_ObjCSelectorStart; + next(); } - break; + } break; case tok::l_square: if (!parseSquare()) return false; @@ -948,10 +963,6 @@ private: } TokenType determinePlusMinusCaretUsage(const AnnotatedToken &Tok) { - // At the start of the line, +/- specific ObjectiveC method declarations. - if (Tok.Parent == NULL) - return TT_ObjCMethodSpecifier; - // Use heuristics to recognize unary operators. if (Tok.Parent->is(tok::equal) || Tok.Parent->is(tok::l_paren) || Tok.Parent->is(tok::comma) || Tok.Parent->is(tok::l_square) || @@ -1044,7 +1055,9 @@ private: if (Tok.is(tok::colon)) return false; if (Tok.Parent->Type == TT_ObjCMethodSpecifier) - return true; + return Style.ObjCSpaceBeforeReturnType || Tok.isNot(tok::l_paren); + if (Tok.Type == TT_ObjCSelectorStart) + return !Style.ObjCSpaceBeforeReturnType; if (Tok.Parent->is(tok::r_paren) && Tok.is(tok::identifier)) // Don't space between ')' and return false; diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index deb668d984cb..1d6cff152dbc 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -1178,10 +1178,18 @@ TEST_F(FormatTest, FormatForObjectiveCMethodDecls) { "outRange8:(NSRange) out_range8 outRange9:(NSRange) out_range9;")); verifyFormat("- (int)sum:(vector)numbers;"); - verifyGoogleFormat("- (void)setDelegate:(id)delegate;"); + verifyGoogleFormat("-(void) setDelegate:(id)delegate;"); // FIXME: In LLVM style, there should be a space in front of a '<' for ObjC // protocol lists (but not for template classes): //verifyFormat("- (void)setDelegate:(id )delegate;"); + + verifyFormat("- (int(*)())foo:(int(*)())f;"); + verifyGoogleFormat("-(int(*)()) foo:(int(*)())foo;"); + + // If there's no return type (very rare in practice!), LLVM and Google style + // agree. + verifyFormat("- foo:(int)f;"); + verifyGoogleFormat("- foo:(int)foo;"); } TEST_F(FormatTest, FormatObjCBlocks) { @@ -1191,7 +1199,6 @@ TEST_F(FormatTest, FormatObjCBlocks) { TEST_F(FormatTest, FormatObjCInterface) { // FIXME: Handle comments like in "@interface /* wait for it */ Foo", PR14875 - // FIXME: In google style, it's "+(id) init", not "+ (id)init". verifyFormat("@interface Foo : NSObject {\n" "@public\n" " int field1;\n" @@ -1215,7 +1222,7 @@ TEST_F(FormatTest, FormatObjCInterface) { " @package\n" " int field4;\n" "}\n" - "+ (id)init;\n" + "+(id) init;\n" "@end"); verifyFormat("@interface Foo\n" @@ -1238,7 +1245,7 @@ TEST_F(FormatTest, FormatObjCInterface) { "@end"); verifyGoogleFormat("@interface Foo : Bar\n" - "+ (id)init;\n" + "+(id) init;\n" "@end"); verifyFormat("@interface Foo (HackStuff)\n" @@ -1254,7 +1261,7 @@ TEST_F(FormatTest, FormatObjCInterface) { "@end"); verifyGoogleFormat("@interface Foo (HackStuff)\n" - "+ (id)init;\n" + "+(id) init;\n" "@end"); verifyFormat("@interface Foo {\n" @@ -1318,7 +1325,7 @@ TEST_F(FormatTest, FormatObjCImplementation) { " @package\n" " int field4;\n" "}\n" - "+ (id)init {}\n" + "+(id) init {}\n" "@end"); verifyFormat("@implementation Foo\n" @@ -1369,7 +1376,7 @@ TEST_F(FormatTest, FormatObjCProtocol) { "@end"); verifyGoogleFormat("@protocol MyProtocol\n" - "- (NSUInteger)numberOfThings;\n" + "-(NSUInteger) numberOfThings;\n" "@end"); verifyFormat("@protocol Foo;\n"