diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp index 45bd97d88dcbadb507564704a529f9ff1d4a6e7c..29cbc3624cd940eb83cd8ca77e1df0fe6b0ec534 100644 --- a/lib/Format/Format.cpp +++ b/lib/Format/Format.cpp @@ -39,7 +39,8 @@ struct TokenAnnotation { TT_ConditionalExpr, TT_CtorInitializerColon, TT_LineComment, - TT_BlockComment + TT_BlockComment, + TT_ObjCMethodSpecifier }; TokenType Type; @@ -225,7 +226,8 @@ private: State.LastSpace[ParenLevel] = State.Indent[ParenLevel]; if (Current.Tok.is(tok::colon) && - Annotations[Index].Type != TokenAnnotation::TT_ConditionalExpr) + Annotations[Index].Type != TokenAnnotation::TT_ConditionalExpr && + Annotations[0].Type != TokenAnnotation::TT_ObjCMethodSpecifier) State.Indent[ParenLevel] += 2; } else { unsigned Spaces = Annotations[Index].SpaceRequiredBefore ? 1 : 0; @@ -547,7 +549,9 @@ public: Parser.parseLine(); determineTokenTypes(); - + bool IsObjCMethodDecl = + (Line.Tokens.size() > 0 && + (Annotations[0].Type == TokenAnnotation::TT_ObjCMethodSpecifier)); for (int i = 1, e = Line.Tokens.size(); i != e; ++i) { TokenAnnotation &Annotation = Annotations[i]; @@ -557,10 +561,37 @@ public: if (Annotation.Type == TokenAnnotation::TT_CtorInitializerColon) { Annotation.MustBreakBefore = true; Annotation.SpaceRequiredBefore = true; + } else if (IsObjCMethodDecl && + Line.Tokens[i].Tok.is(tok::identifier) && + (i != e-1) && Line.Tokens[i+1].Tok.is(tok::colon) && + Line.Tokens[i-1].Tok.is(tok::identifier)) { + Annotation.CanBreakBefore = true; + Annotation.SpaceRequiredBefore = true; + } else if (IsObjCMethodDecl && + Line.Tokens[i].Tok.is(tok::identifier) && + Line.Tokens[i-1].Tok.is(tok::l_paren) && + Line.Tokens[i-2].Tok.is(tok::colon)) { + // Don't break this identifier as ':' or identifier + // before it will break. + Annotation.CanBreakBefore = false; + } else if (Line.Tokens[i].Tok.is(tok::at) && + Line.Tokens[i-2].Tok.is(tok::at)) { + // Don't put two objc's '@' on the same line. This could happen, + // as in, @optinal @property ... + Annotation.MustBreakBefore = true; } else if (Line.Tokens[i].Tok.is(tok::colon)) { Annotation.SpaceRequiredBefore = - Line.Tokens[0].Tok.isNot(tok::kw_case) && i != e - 1; - } else if (Annotations[i - 1].Type == TokenAnnotation::TT_UnaryOperator) { + Line.Tokens[0].Tok.isNot(tok::kw_case) && !IsObjCMethodDecl && + (i != e - 1); + // Don't break at ':' if identifier before it can beak. + if (IsObjCMethodDecl && + Line.Tokens[i-1].Tok.is(tok::identifier) && + Annotations[i-1].CanBreakBefore) + Annotation.CanBreakBefore = false; + } else if (Annotations[i - 1].Type == + TokenAnnotation::TT_ObjCMethodSpecifier) + Annotation.SpaceRequiredBefore = true; + else if (Annotations[i - 1].Type == TokenAnnotation::TT_UnaryOperator) { Annotation.SpaceRequiredBefore = false; } else if (Annotation.Type == TokenAnnotation::TT_UnaryOperator) { Annotation.SpaceRequiredBefore = @@ -584,7 +615,17 @@ public: } else if (Line.Tokens[i].Tok.is(tok::less) && Line.Tokens[0].Tok.is(tok::hash)) { Annotation.SpaceRequiredBefore = true; - } else { + } else if (IsObjCMethodDecl && + Line.Tokens[i - 1].Tok.is(tok::r_paren) && + Line.Tokens[i].Tok.is(tok::identifier)) + // Don't space between ')' and <id> + Annotation.SpaceRequiredBefore = false; + else if (IsObjCMethodDecl && + Line.Tokens[i - 1].Tok.is(tok::colon) && + Line.Tokens[i].Tok.is(tok::l_paren)) + // Don't space between ':' and '(' + Annotation.SpaceRequiredBefore = false; + else { Annotation.SpaceRequiredBefore = spaceRequiredBetween(Line.Tokens[i - 1].Tok, Line.Tokens[i].Tok); } @@ -618,6 +659,9 @@ private: if (Tok.Tok.is(tok::star) || Tok.Tok.is(tok::amp)) Annotation.Type = determineStarAmpUsage(i, AssignmentEncountered); + else if ((Tok.Tok.is(tok::minus) || Tok.Tok.is(tok::plus)) && + Tok.Tok.isAtStartOfLine()) + Annotation.Type = TokenAnnotation::TT_ObjCMethodSpecifier; else if (isUnaryOperator(i)) Annotation.Type = TokenAnnotation::TT_UnaryOperator; else if (isBinaryOperator(Line.Tokens[i])) @@ -711,6 +755,8 @@ private: return false; if (Left.is(tok::exclaim) || Left.is(tok::tilde)) return false; + if (Left.is(tok::at) && Right.is(tok::identifier)) + return false; if (Left.is(tok::less) || Right.is(tok::greater) || Right.is(tok::less)) return false; if (Right.is(tok::amp) || Right.is(tok::star)) diff --git a/test/Index/comment-c-decls.c b/test/Index/comment-c-decls.c index e91f9b93ebe31cb66c3321d14ff80cb2a1060f50..862b2a2379490f4e55cc0e4a1cbb5dea782c094d 100644 --- a/test/Index/comment-c-decls.c +++ b/test/Index/comment-c-decls.c @@ -101,4 +101,4 @@ int (^Block) (int i, int j); *\brief block declaration */ int (^Block1) (int i, int j) = ^(int i, int j) { return i + j; }; -// CHECK: <Declaration>int (^Block1)(int, int) = ^(int i, int j){ }</Declaration> +// CHECK: <Declaration>int (^ Block1) (int, int) = ^ (int i, int j) {\n}</Declaration> diff --git a/test/Index/comment-objc-decls.m b/test/Index/comment-objc-decls.m index d037e05db2f3756dc9d95901b51f654e3e6c22ce..6682ea320f4745bb8ac0eac7652a1ef741e6bba4 100644 --- a/test/Index/comment-objc-decls.m +++ b/test/Index/comment-objc-decls.m @@ -31,9 +31,9 @@ + ClassMethodMyProto; @end // CHECK: <Declaration>@protocol MyProto\n@end</Declaration> -// CHECK: <Declaration>- (unsigned int) MethodMyProto:(id)anObject inRange:(unsigned int)range;</Declaration> -// CHECK: <Declaration>@optional\n@property ( readwrite,copy,atomic ) id PropertyMyProto;</Declaration> -// CHECK: <Declaration>+ (id) ClassMethodMyProto;</Declaration> +// CHECK: <Declaration>- (unsigned int)MethodMyProto:(id)anObject inRange:(unsigned int)range;</Declaration> +// CHECK: <Declaration>@optional\n @property(readwrite, copy, atomic) id PropertyMyProto;</Declaration> +// CHECK: <Declaration>+ (id)ClassMethodMyProto;</Declaration> /** * \brief NSObject is the root class. @@ -45,7 +45,7 @@ id IvarNSObject; } @end -// CHECK: Declaration>@interface NSObject{\n id IvarNSObject;\n}\n@end</Declaration> +// CHECK: Declaration>@interface NSObject {\n id IvarNSObject;\n}\n@end</Declaration> // CHECK: <Declaration>id IvarNSObject</Declaration> /** @@ -75,9 +75,9 @@ @end // CHECK: <Declaration>@interface MyClass : NSObject<MyProto> {\n id IvarMyClass;\n}\n@end</Declaration> // CHECK: <Declaration>id IvarMyClass</Declaration> -// CHECK: <Declaration>- (id) MethodMyClass;</Declaration> -// CHECK: <Declaration>+ (id) ClassMethodMyClass;</Declaration> -// CHECK: <Declaration>@property ( readwrite,copy,atomic ) id PropertyMyClass;</Declaration +// CHECK: <Declaration>- (id)MethodMyClass;</Declaration> +// CHECK: <Declaration>+ (id)ClassMethodMyClass;</Declaration> +// CHECK: <Declaration>@property(readwrite, copy, atomic) id PropertyMyClass;</Declaration /** * \brief - This is class extension of MyClass @@ -90,7 +90,7 @@ id IvarMyClassExtension; } @end -// CHECK: <Declaration>@interface MyClass()\n{\n id IvarMyClassExtension;\n}\n@end</Declaration> +// CHECK: <Declaration>@interface MyClass() {\n id IvarMyClassExtension;\n}\n@end</Declaration> // CHECK: <Declaration>id IvarMyClassExtension</Declaration> @@ -109,10 +109,10 @@ @property (copy) id PropertyMyClassCategory; @end // CHECK: <Declaration>@interface MyClass(Category)\n@end</Declaration> -// CHECK: <Declaration>- (void) MethodMyClassCategory;</Declaration> -// CHECK: <Declaration>@property ( readwrite,copy,atomic ) id PropertyMyClassCategory;</Declaration> -// CHECK: <Declaration>- (id) PropertyMyClassCategory;</Declaration> -// CHECK: <Declaration>- (void) setPropertyMyClassCategory:(id)arg;</Declaration> +// CHECK: <Declaration>- (void)MethodMyClassCategory;</Declaration> +// CHECK: <Declaration>@property(readwrite, copy, atomic) id PropertyMyClassCategory;</Declaration> +// CHECK: <Declaration>- (id)PropertyMyClassCategory;</Declaration> +// CHECK: <Declaration>- (void)setPropertyMyClassCategory:(id)arg;</Declaration> /// @implementation's @@ -139,10 +139,10 @@ return 0; } @end -// CHECK: <Declaration>@implementation MyClass{\n id IvarPrivateToMyClassImpl;\n id _PropertyMyClass;\n}\n@end</Declaration> +// CHECK: <Declaration>@implementation MyClass {\n id IvarPrivateToMyClassImpl;\n id _PropertyMyClass;\n}\n@end</Declaration> // CHECK: <Declaration>id IvarPrivateToMyClassImpl</Declaration> -// CHECK: <Declaration>- (id) MethodMyClass;</Declaration> -// CHECK: <Declaration>+ (id) ClassMethodMyClass;</Declaration> +// CHECK: <Declaration>- (id)MethodMyClass;</Declaration> +// CHECK: <Declaration>+ (id)ClassMethodMyClass;</Declaration> /** * \brief MyClass (Category) is implementation of private to MyClass. @@ -163,9 +163,9 @@ - (void) setPropertyMyClassCategory : (id) arg {} @end // CHECK: <Declaration>@implementation MyClass(Category)\n@end</Declaration> -// CHECK: <Declaration>- (void) MethodMyClassCategory;</Declaration> -// CHECK: <Declaration>- (id) PropertyMyClassCategory;</Declaration> -// CHECK: <Declaration>- (void) setPropertyMyClassCategory:(id)arg;</Declaration> +// CHECK: <Declaration>- (void)MethodMyClassCategory;</Declaration> +// CHECK: <Declaration>- (id)PropertyMyClassCategory;</Declaration> +// CHECK: <Declaration>- (void)setPropertyMyClassCategory:(id)arg;</Declaration> /** * \brief NSObject implementation diff --git a/test/Index/comment-to-html-xml-conversion.cpp b/test/Index/comment-to-html-xml-conversion.cpp index 2809415c6cccf8cf552b995f51d91261ff3b5916..d753f353f4a373ae31810bce937f31680a7a7891 100644 --- a/test/Index/comment-to-html-xml-conversion.cpp +++ b/test/Index/comment-to-html-xml-conversion.cpp @@ -670,7 +670,7 @@ void comment_to_xml_conversion_10(int aaa, int bbb); template<typename T, typename U> class comment_to_xml_conversion_11 { }; -// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:7: ClassTemplate=comment_to_xml_conversion_11:{{.*}} FullCommentAsXML=[<Class templateKind="template" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="7"><Name>comment_to_xml_conversion_11</Name><USR>c:@CT>2#T#T@comment_to_xml_conversion_11</USR><Declaration>template <typename T = int, typename U = int> class comment_to_xml_conversion_11 {\n}\ntemplate <typename T, typename U> class comment_to_xml_conversion_11 {\n}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Class>] +// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:7: ClassTemplate=comment_to_xml_conversion_11:{{.*}} FullCommentAsXML=[<Class templateKind="template" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="7"><Name>comment_to_xml_conversion_11</Name><USR>c:@CT>2#T#T@comment_to_xml_conversion_11</USR><Declaration>template <typename T = int,\n typename U = int> class comment_to_xml_conversion_11 {\n}\ntemplate <typename T, typename U> class comment_to_xml_conversion_11 {\n}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Class>] /// Aaa. template<typename T> diff --git a/test/Index/format-comment-cdecls.c b/test/Index/format-comment-cdecls.c index 989ce5c022ed00c5d803a6ac5dba7fcd27c3c306..f282d2bb87e4be63656d5adca152e63c2f88b327 100644 --- a/test/Index/format-comment-cdecls.c +++ b/test/Index/format-comment-cdecls.c @@ -1,6 +1,5 @@ // RUN: rm -rf %t // RUN: mkdir %t -// RUN: env LIBCLANG_ACTIVATE_FORMAT=1 \ // RUN: c-index-test -test-load-source all -comments-xml-schema=%S/../../bindings/xml/comment-xml-schema.rng -target x86_64-apple-darwin10 %s \ // RUN: | FileCheck %s diff --git a/test/Index/overriding-method-comments.mm b/test/Index/overriding-method-comments.mm index 899b31d8013aa62ab581f4c4091e664a65949562..46ead4f6425686459bd2bde9d0221653a501c387 100644 --- a/test/Index/overriding-method-comments.mm +++ b/test/Index/overriding-method-comments.mm @@ -19,7 +19,7 @@ - (void)METH:(id)AAA; @end -// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-3]]" column="1"><Name>METH:</Name><USR>c:objc(cs)Root(im)METH:</USR><Declaration>- (void) METH:(id)AAA;</Declaration><Parameters><Parameter><Name>AAA</Name><Index>0</Index><Direction isExplicit="1">in</Direction><Discussion><Para> ZZZ </Para></Discussion></Parameter></Parameters></Function>] +// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-3]]" column="1"><Name>METH:</Name><USR>c:objc(cs)Root(im)METH:</USR><Declaration>- (void)METH:(id)AAA;</Declaration><Parameters><Parameter><Name>AAA</Name><Index>0</Index><Direction isExplicit="1">in</Direction><Discussion><Para> ZZZ </Para></Discussion></Parameter></Parameters></Function>] @interface Sub : Root @end @@ -28,13 +28,13 @@ - (void)METH:(id)BBB; @end -// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-3]]" column="1"><Name>METH:</Name><USR>c:objc(cs)Root(im)METH:</USR><Declaration>- (void) METH:(id)BBB;</Declaration><Parameters><Parameter><Name>BBB</Name><Index>0</Index><Direction isExplicit="1">in</Direction><Discussion><Para> ZZZ </Para></Discussion></Parameter></Parameters></Function>] +// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-3]]" column="1"><Name>METH:</Name><USR>c:objc(cs)Root(im)METH:</USR><Declaration>- (void)METH:(id)BBB;</Declaration><Parameters><Parameter><Name>BBB</Name><Index>0</Index><Direction isExplicit="1">in</Direction><Discussion><Para> ZZZ </Para></Discussion></Parameter></Parameters></Function>] @implementation Sub(CAT) - (void)METH:(id)III {} @end -// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-3]]" column="1"><Name>METH:</Name><USR>c:objc(cs)Root(im)METH:</USR><Declaration>- (void) METH:(id)III;</Declaration><Parameters><Parameter><Name>III</Name><Index>0</Index><Direction isExplicit="1">in</Direction><Discussion><Para> ZZZ </Para></Discussion></Parameter></Parameters></Function>] +// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-3]]" column="1"><Name>METH:</Name><USR>c:objc(cs)Root(im)METH:</USR><Declaration>- (void)METH:(id)III;</Declaration><Parameters><Parameter><Name>III</Name><Index>0</Index><Direction isExplicit="1">in</Direction><Discussion><Para> ZZZ </Para></Discussion></Parameter></Parameters></Function>] @interface Redec : Root @end @@ -48,13 +48,13 @@ - (void)EXT_METH:(id)AAA : (double)BBB : (int)CCC; @end -// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-3]]" column="1"><Name>EXT_METH:::</Name><USR>c:objc(cs)Redec(im)EXT_METH:::</USR><Declaration>- (void) EXT_METH:(id)AAA :(double)BBB :(int)CCC;</Declaration><Parameters><Parameter><Name>AAA</Name><Index>0</Index><Direction isExplicit="1">in</Direction><Discussion><Para> input value </Para></Discussion></Parameter><Parameter><Name>BBB</Name><Index>1</Index><Direction isExplicit="1">in</Direction><Discussion><Para> 2nd input value is double </Para></Discussion></Parameter><Parameter><Name>CCC</Name><Index>2</Index><Direction isExplicit="1">out</Direction><Discussion><Para> output value is int </Para></Discussion></Parameter></Parameters></Function>] +// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-3]]" column="1"><Name>EXT_METH:::</Name><USR>c:objc(cs)Redec(im)EXT_METH:::</USR><Declaration>- (void)EXT_METH:(id)AAA:(double)BBB:(int)CCC;</Declaration><Parameters><Parameter><Name>AAA</Name><Index>0</Index><Direction isExplicit="1">in</Direction><Discussion><Para> input value </Para></Discussion></Parameter><Parameter><Name>BBB</Name><Index>1</Index><Direction isExplicit="1">in</Direction><Discussion><Para> 2nd input value is double </Para></Discussion></Parameter><Parameter><Name>CCC</Name><Index>2</Index><Direction isExplicit="1">out</Direction><Discussion><Para> output value is int </Para></Discussion></Parameter></Parameters></Function>] @implementation Redec - (void)EXT_METH:(id)PPP : (double)QQQ : (int)RRR {} @end -// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-3]]" column="1"><Name>EXT_METH:::</Name><USR>c:objc(cs)Redec(im)EXT_METH:::</USR><Declaration>- (void) EXT_METH:(id)PPP :(double)QQQ :(int)RRR;</Declaration><Parameters><Parameter><Name>PPP</Name><Index>0</Index><Direction isExplicit="1">in</Direction><Discussion><Para> input value </Para></Discussion></Parameter><Parameter><Name>QQQ</Name><Index>1</Index><Direction isExplicit="1">in</Direction><Discussion><Para> 2nd input value is double </Para></Discussion></Parameter><Parameter><Name>RRR</Name><Index>2</Index><Direction isExplicit="1">out</Direction><Discussion><Para> output value is int </Para></Discussion></Parameter></Parameters></Function>] +// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-3]]" column="1"><Name>EXT_METH:::</Name><USR>c:objc(cs)Redec(im)EXT_METH:::</USR><Declaration>- (void)EXT_METH:(id)PPP:(double)QQQ:(int)RRR;</Declaration><Parameters><Parameter><Name>PPP</Name><Index>0</Index><Direction isExplicit="1">in</Direction><Discussion><Para> input value </Para></Discussion></Parameter><Parameter><Name>QQQ</Name><Index>1</Index><Direction isExplicit="1">in</Direction><Discussion><Para> 2nd input value is double </Para></Discussion></Parameter><Parameter><Name>RRR</Name><Index>2</Index><Direction isExplicit="1">out</Direction><Discussion><Para> output value is int </Para></Discussion></Parameter></Parameters></Function>] struct Base { /// \brief Does something. diff --git a/tools/libclang/CXComment.cpp b/tools/libclang/CXComment.cpp index caf6a857f09b9fa5151a9b21f253f040c81626ef..754f79612bf0976a5c70de830b30498d13be861a 100644 --- a/tools/libclang/CXComment.cpp +++ b/tools/libclang/CXComment.cpp @@ -917,12 +917,6 @@ void getSourceTextOfDeclaration(const DeclInfo *ThisDecl, void CommentASTToXMLConverter::formatTextOfDeclaration( const DeclInfo *DI, SmallString<128> &Declaration) { - // FIXME. This conditional is TEMPORARY. We don't want to break multiple - // large tests each time Format.cpp changes. This condition will - // go away and formatting will happen for all declarations. - if (!getenv("LIBCLANG_ACTIVATE_FORMAT")) - return; - // FIXME. formatting API expects null terminated input string. // There might be more efficient way of doing this. std::string StringDecl = Declaration.str(); diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp index c9cd825277c0f32c8a6d222d8dc2d397e73b3516..53253f0c79f437dd6d5fb6b47cfad781659a480d 100644 --- a/unittests/Format/FormatTest.cpp +++ b/unittests/Format/FormatTest.cpp @@ -667,5 +667,24 @@ TEST_F(FormatTest, IncorrectCodeErrorDetection) { } +TEST_F(FormatTest, FormatForObjectiveCMethodDecls) { + verifyFormat("- (void)sendAction:(SEL)aSelector to:(BOOL)anObject;"); + EXPECT_EQ("- (NSUInteger)indexOfObject:(id)anObject;", + format("-(NSUInteger)indexOfObject:(id)anObject;")); + EXPECT_EQ("- (NSInteger)Mthod1;", + format("-(NSInteger)Mthod1;")); + EXPECT_EQ("+ (id)Mthod2;", format("+(id)Mthod2;")); + EXPECT_EQ("- (NSInteger)Method3:(id)anObject;", + format("-(NSInteger)Method3:(id)anObject;")); + EXPECT_EQ("- (NSInteger)Method4:(id)anObject;", + format("-(NSInteger)Method4:(id)anObject;")); + EXPECT_EQ("- (NSInteger)Method5:(id)anObject:(id)AnotherObject;", + format("-(NSInteger)Method5:(id)anObject:(id)AnotherObject;")); + EXPECT_EQ("- (id)Method6:(id)A:(id)B:(id)C:(id)D;", + format("- (id)Method6:(id)A:(id)B:(id)C:(id)D;")); + EXPECT_EQ("- (void)sendAction:(SEL)aSelector to:(id)anObject forAllCells:(BOOL)flag;", + format("- (void)sendAction:(SEL)aSelector to:(id)anObject forAllCells:(BOOL)flag;")); +} + } // end namespace tooling } // end namespace clang