Formatting: Add support for @protocol.
Pull pieces of the @interface code into reusable methods.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@172001 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp
index 131d982..688937c 100644
--- a/lib/Format/UnwrappedLineParser.cpp
+++ b/lib/Format/UnwrappedLineParser.cpp
@@ -210,6 +210,8 @@
return parseAccessSpecifier();
case tok::objc_interface:
return parseObjCInterface();
+ case tok::objc_protocol:
+ return parseObjCProtocol();
default:
break;
}
@@ -496,6 +498,25 @@
} while (!eof());
}
+void UnwrappedLineParser::parseObjCProtocolList() {
+ assert(FormatTok.Tok.is(tok::less) && "'<' expected.");
+ do
+ nextToken();
+ while (!eof() && FormatTok.Tok.isNot(tok::greater));
+ nextToken(); // Skip '>'.
+}
+
+void UnwrappedLineParser::parseObjCUntilAtEnd() {
+ do {
+ if (FormatTok.Tok.isObjCAtKeyword(tok::objc_end)) {
+ nextToken();
+ addUnwrappedLine();
+ break;
+ }
+ parseStructuralElement();
+ } while (!eof());
+}
+
void UnwrappedLineParser::parseObjCInterface() {
nextToken();
nextToken(); // interface name
@@ -508,13 +529,8 @@
// Skip category, if present.
parseParens();
- // Skip protocol list, if present.
- if (FormatTok.Tok.is(tok::less)) {
- do
- nextToken();
- while (!eof() && FormatTok.Tok.isNot(tok::greater));
- nextToken(); // Skip '>'.
- }
+ if (FormatTok.Tok.is(tok::less))
+ parseObjCProtocolList();
// If instance variables are present, keep the '{' on the first line too.
if (FormatTok.Tok.is(tok::l_brace))
@@ -524,16 +540,24 @@
// variables, this ends the @interface line.
addUnwrappedLine();
- // Read everything up to the @end.
- do {
- if (FormatTok.Tok.isObjCAtKeyword(tok::objc_end)) {
- nextToken();
- addUnwrappedLine();
- break;
- }
+ parseObjCUntilAtEnd();
+}
- parseStructuralElement();
- } while (!eof());
+void UnwrappedLineParser::parseObjCProtocol() {
+ nextToken();
+ nextToken(); // protocol name
+
+ if (FormatTok.Tok.is(tok::less))
+ parseObjCProtocolList();
+
+ // Check for protocol declaration.
+ if (FormatTok.Tok.is(tok::semi)) {
+ nextToken();
+ return addUnwrappedLine();
+ }
+
+ addUnwrappedLine();
+ parseObjCUntilAtEnd();
}
void UnwrappedLineParser::addUnwrappedLine() {
diff --git a/lib/Format/UnwrappedLineParser.h b/lib/Format/UnwrappedLineParser.h
index 28ef235..303afc2 100644
--- a/lib/Format/UnwrappedLineParser.h
+++ b/lib/Format/UnwrappedLineParser.h
@@ -142,7 +142,10 @@
void parseAccessSpecifier();
void parseEnum();
void parseStructOrClass();
+ void parseObjCProtocolList();
+ void parseObjCUntilAtEnd();
void parseObjCInterface();
+ void parseObjCProtocol();
void addUnwrappedLine();
bool eof() const;
void nextToken();
diff --git a/test/Index/comment-objc-decls.m b/test/Index/comment-objc-decls.m
index 4b9a4bc..4c9f878 100644
--- a/test/Index/comment-objc-decls.m
+++ b/test/Index/comment-objc-decls.m
@@ -30,7 +30,7 @@
*/
+ ClassMethodMyProto;
@end
-// CHECK: <Declaration>@protocol MyProto @end</Declaration>
+// 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>
diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp
index 4decf94..e06544a 100644
--- a/unittests/Format/FormatTest.cpp
+++ b/unittests/Format/FormatTest.cpp
@@ -1249,6 +1249,21 @@
"@end");
}
+TEST_F(FormatTest, FormatObjCProtocol) {
+ verifyFormat("@protocol Foo\n"
+ "@property(weak) id delegate;\n"
+ "- (NSUInteger)numberOfThings;\n"
+ "@end");
+
+ // FIXME: In LLVM style, there should be a space before '<' for protocols.
+ verifyFormat("@protocol MyProtocol<NSObject>\n"
+ "- (NSUInteger)numberOfThings;\n"
+ "@end");
+
+ verifyFormat("@protocol Foo;\n"
+ "@protocol Bar;\n");
+}
+
TEST_F(FormatTest, ObjCAt) {
verifyFormat("@autoreleasepool");
verifyFormat("@catch");