Add objective-C style formatting to clang format and

use it to format xml declaration tags. 
// rdar://12378714

llvm-svn: 170727
This commit is contained in:
Fariborz Jahanian 2012-12-20 19:54:13 +00:00
parent 4cfb5b9e64
commit 68a542aea7
8 changed files with 96 additions and 38 deletions

View File

@ -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))

View File

@ -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>

View File

@ -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&lt;MyProto&gt; {\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

View File

@ -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&gt;2#T#T@comment_to_xml_conversion_11</USR><Declaration>template &lt;typename T = int, typename U = int&gt; class comment_to_xml_conversion_11 {\n}\ntemplate &lt;typename T, typename U&gt; 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&gt;2#T#T@comment_to_xml_conversion_11</USR><Declaration>template &lt;typename T = int,\n typename U = int&gt; class comment_to_xml_conversion_11 {\n}\ntemplate &lt;typename T, typename U&gt; class comment_to_xml_conversion_11 {\n}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Class>]
/// Aaa.
template<typename T>

View File

@ -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

View File

@ -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.

View File

@ -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();

View File

@ -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