From 68a542aea74dae882ea3dff2109e46bd0c5e61a1 Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Thu, 20 Dec 2012 19:54:13 +0000 Subject: [PATCH] Add objective-C style formatting to clang format and use it to format xml declaration tags. // rdar://12378714 llvm-svn: 170727 --- clang/lib/Format/Format.cpp | 58 +++++++++++++++++++--- clang/test/Index/comment-c-decls.c | 2 +- clang/test/Index/comment-objc-decls.m | 36 +++++++------- .../test/Index/comment-to-html-xml-conversion.cpp | 2 +- clang/test/Index/format-comment-cdecls.c | 1 - clang/test/Index/overriding-method-comments.mm | 10 ++-- clang/tools/libclang/CXComment.cpp | 6 --- clang/unittests/Format/FormatTest.cpp | 19 +++++++ 8 files changed, 96 insertions(+), 38 deletions(-) diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 45bd97d..29cbc36 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/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 + 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/clang/test/Index/comment-c-decls.c b/clang/test/Index/comment-c-decls.c index e91f9b9..862b2a2 100644 --- a/clang/test/Index/comment-c-decls.c +++ b/clang/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: int (^Block1)(int, int) = ^(int i, int j){ } +// CHECK: int (^ Block1) (int, int) = ^ (int i, int j) {\n} diff --git a/clang/test/Index/comment-objc-decls.m b/clang/test/Index/comment-objc-decls.m index d037e05..6682ea3 100644 --- a/clang/test/Index/comment-objc-decls.m +++ b/clang/test/Index/comment-objc-decls.m @@ -31,9 +31,9 @@ + ClassMethodMyProto; @end // CHECK: @protocol MyProto\n@end -// CHECK: - (unsigned int) MethodMyProto:(id)anObject inRange:(unsigned int)range; -// CHECK: @optional\n@property ( readwrite,copy,atomic ) id PropertyMyProto; -// CHECK: + (id) ClassMethodMyProto; +// CHECK: - (unsigned int)MethodMyProto:(id)anObject inRange:(unsigned int)range; +// CHECK: @optional\n @property(readwrite, copy, atomic) id PropertyMyProto; +// CHECK: + (id)ClassMethodMyProto; /** * \brief NSObject is the root class. @@ -45,7 +45,7 @@ id IvarNSObject; } @end -// CHECK: Declaration>@interface NSObject{\n id IvarNSObject;\n}\n@end +// CHECK: Declaration>@interface NSObject {\n id IvarNSObject;\n}\n@end // CHECK: id IvarNSObject /** @@ -75,9 +75,9 @@ @end // CHECK: @interface MyClass : NSObject<MyProto> {\n id IvarMyClass;\n}\n@end // CHECK: id IvarMyClass -// CHECK: - (id) MethodMyClass; -// CHECK: + (id) ClassMethodMyClass; -// CHECK: @property ( readwrite,copy,atomic ) id PropertyMyClass;- (id)MethodMyClass; +// CHECK: + (id)ClassMethodMyClass; +// CHECK: @property(readwrite, copy, atomic) id PropertyMyClass;@interface MyClass()\n{\n id IvarMyClassExtension;\n}\n@end +// CHECK: @interface MyClass() {\n id IvarMyClassExtension;\n}\n@end // CHECK: id IvarMyClassExtension @@ -109,10 +109,10 @@ @property (copy) id PropertyMyClassCategory; @end // CHECK: @interface MyClass(Category)\n@end -// CHECK: - (void) MethodMyClassCategory; -// CHECK: @property ( readwrite,copy,atomic ) id PropertyMyClassCategory; -// CHECK: - (id) PropertyMyClassCategory; -// CHECK: - (void) setPropertyMyClassCategory:(id)arg; +// CHECK: - (void)MethodMyClassCategory; +// CHECK: @property(readwrite, copy, atomic) id PropertyMyClassCategory; +// CHECK: - (id)PropertyMyClassCategory; +// CHECK: - (void)setPropertyMyClassCategory:(id)arg; /// @implementation's @@ -139,10 +139,10 @@ return 0; } @end -// CHECK: @implementation MyClass{\n id IvarPrivateToMyClassImpl;\n id _PropertyMyClass;\n}\n@end +// CHECK: @implementation MyClass {\n id IvarPrivateToMyClassImpl;\n id _PropertyMyClass;\n}\n@end // CHECK: id IvarPrivateToMyClassImpl -// CHECK: - (id) MethodMyClass; -// CHECK: + (id) ClassMethodMyClass; +// CHECK: - (id)MethodMyClass; +// CHECK: + (id)ClassMethodMyClass; /** * \brief MyClass (Category) is implementation of private to MyClass. @@ -163,9 +163,9 @@ - (void) setPropertyMyClassCategory : (id) arg {} @end // CHECK: @implementation MyClass(Category)\n@end -// CHECK: - (void) MethodMyClassCategory; -// CHECK: - (id) PropertyMyClassCategory; -// CHECK: - (void) setPropertyMyClassCategory:(id)arg; +// CHECK: - (void)MethodMyClassCategory; +// CHECK: - (id)PropertyMyClassCategory; +// CHECK: - (void)setPropertyMyClassCategory:(id)arg; /** * \brief NSObject implementation diff --git a/clang/test/Index/comment-to-html-xml-conversion.cpp b/clang/test/Index/comment-to-html-xml-conversion.cpp index 2809415..d753f35 100644 --- a/clang/test/Index/comment-to-html-xml-conversion.cpp +++ b/clang/test/Index/comment-to-html-xml-conversion.cpp @@ -670,7 +670,7 @@ void comment_to_xml_conversion_10(int aaa, int bbb); template class comment_to_xml_conversion_11 { }; -// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:7: ClassTemplate=comment_to_xml_conversion_11:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_11c:@CT>2#T#T@comment_to_xml_conversion_11template <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} Aaa.] +// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:7: ClassTemplate=comment_to_xml_conversion_11:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_11c:@CT>2#T#T@comment_to_xml_conversion_11template <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} Aaa.] /// Aaa. template diff --git a/clang/test/Index/format-comment-cdecls.c b/clang/test/Index/format-comment-cdecls.c index 989ce5c..f282d2b 100644 --- a/clang/test/Index/format-comment-cdecls.c +++ b/clang/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/clang/test/Index/overriding-method-comments.mm b/clang/test/Index/overriding-method-comments.mm index 899b31d..46ead4f 100644 --- a/clang/test/Index/overriding-method-comments.mm +++ b/clang/test/Index/overriding-method-comments.mm @@ -19,7 +19,7 @@ - (void)METH:(id)AAA; @end -// CHECK: FullCommentAsXML=[METH:c:objc(cs)Root(im)METH:- (void) METH:(id)AAA;AAA0in ZZZ ] +// CHECK: FullCommentAsXML=[METH:c:objc(cs)Root(im)METH:- (void)METH:(id)AAA;AAA0in ZZZ ] @interface Sub : Root @end @@ -28,13 +28,13 @@ - (void)METH:(id)BBB; @end -// CHECK: FullCommentAsXML=[METH:c:objc(cs)Root(im)METH:- (void) METH:(id)BBB;BBB0in ZZZ ] +// CHECK: FullCommentAsXML=[METH:c:objc(cs)Root(im)METH:- (void)METH:(id)BBB;BBB0in ZZZ ] @implementation Sub(CAT) - (void)METH:(id)III {} @end -// CHECK: FullCommentAsXML=[METH:c:objc(cs)Root(im)METH:- (void) METH:(id)III;III0in ZZZ ] +// CHECK: FullCommentAsXML=[METH:c:objc(cs)Root(im)METH:- (void)METH:(id)III;III0in ZZZ ] @interface Redec : Root @end @@ -48,13 +48,13 @@ - (void)EXT_METH:(id)AAA : (double)BBB : (int)CCC; @end -// CHECK: FullCommentAsXML=[EXT_METH:::c:objc(cs)Redec(im)EXT_METH:::- (void) EXT_METH:(id)AAA :(double)BBB :(int)CCC;AAA0in input value BBB1in 2nd input value is double CCC2out output value is int ] +// CHECK: FullCommentAsXML=[EXT_METH:::c:objc(cs)Redec(im)EXT_METH:::- (void)EXT_METH:(id)AAA:(double)BBB:(int)CCC;AAA0in input value BBB1in 2nd input value is double CCC2out output value is int ] @implementation Redec - (void)EXT_METH:(id)PPP : (double)QQQ : (int)RRR {} @end -// CHECK: FullCommentAsXML=[EXT_METH:::c:objc(cs)Redec(im)EXT_METH:::- (void) EXT_METH:(id)PPP :(double)QQQ :(int)RRR;PPP0in input value QQQ1in 2nd input value is double RRR2out output value is int ] +// CHECK: FullCommentAsXML=[EXT_METH:::c:objc(cs)Redec(im)EXT_METH:::- (void)EXT_METH:(id)PPP:(double)QQQ:(int)RRR;PPP0in input value QQQ1in 2nd input value is double RRR2out output value is int ] struct Base { /// \brief Does something. diff --git a/clang/tools/libclang/CXComment.cpp b/clang/tools/libclang/CXComment.cpp index caf6a85..754f796 100644 --- a/clang/tools/libclang/CXComment.cpp +++ b/clang/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/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index c9cd825..53253f0 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/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 -- 2.7.4