From: Nico Weber Date: Wed, 9 Jan 2013 20:25:35 +0000 (+0000) Subject: Formatter: Add support for @interface. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=27d1367871a6eab347346497e87ea1adb2fd15a5;p=clang Formatter: Add support for @interface. Previously: @interface Foo + (id)init; @end Now: @interface Foo + (id)init; @end Some tweaking remains, but this is a good first step. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@171995 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp index 99d5f6279d..131d982906 100644 --- a/lib/Format/UnwrappedLineParser.cpp +++ b/lib/Format/UnwrappedLineParser.cpp @@ -208,6 +208,8 @@ void UnwrappedLineParser::parseStructuralElement() { case tok::objc_package: case tok::objc_private: return parseAccessSpecifier(); + case tok::objc_interface: + return parseObjCInterface(); default: break; } @@ -494,6 +496,46 @@ void UnwrappedLineParser::parseStructOrClass() { } while (!eof()); } +void UnwrappedLineParser::parseObjCInterface() { + nextToken(); + nextToken(); // interface name + + // @interface can be followed by either a base class, or a category. + if (FormatTok.Tok.is(tok::colon)) { + nextToken(); + nextToken(); // base class name + } else if (FormatTok.Tok.is(tok::l_paren)) + // 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 instance variables are present, keep the '{' on the first line too. + if (FormatTok.Tok.is(tok::l_brace)) + parseBlock(); + + // With instance variables, this puts '}' on its own line. Without instance + // variables, this ends the @interface line. + addUnwrappedLine(); + + // Read everything up to the @end. + do { + if (FormatTok.Tok.isObjCAtKeyword(tok::objc_end)) { + nextToken(); + addUnwrappedLine(); + break; + } + + parseStructuralElement(); + } while (!eof()); +} + void UnwrappedLineParser::addUnwrappedLine() { if (!RootTokenInitialized) return; diff --git a/lib/Format/UnwrappedLineParser.h b/lib/Format/UnwrappedLineParser.h index 500054fe9a..28ef235190 100644 --- a/lib/Format/UnwrappedLineParser.h +++ b/lib/Format/UnwrappedLineParser.h @@ -142,6 +142,7 @@ private: void parseAccessSpecifier(); void parseEnum(); void parseStructOrClass(); + void parseObjCInterface(); void addUnwrappedLine(); bool eof() const; void nextToken(); diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp index c21ff24834..4decf94c76 100644 --- a/unittests/Format/FormatTest.cpp +++ b/unittests/Format/FormatTest.cpp @@ -443,34 +443,6 @@ TEST_F(FormatTest, FormatObjCTryCatch) { "}"); } -TEST_F(FormatTest, FormatObjCInterface) { - verifyFormat("@interface Foo : NSObject {\n" - "@public\n" - " int field1;\n" - "@protected\n" - " int field2;\n" - "@private\n" - " int field3;\n" - "@package\n" - " int field4;\n" - "}\n" - "+ (id)init;\n" - "@end"); - - verifyGoogleFormat("@interface Foo : NSObject {\n" - " @public\n" - " int field1;\n" - " @protected\n" - " int field2;\n" - " @private\n" - " int field3;\n" - " @package\n" - " int field4;\n" - "}\n" - "+ (id)init;\n" - "@end"); -} - TEST_F(FormatTest, StaticInitializers) { verifyFormat("static SomeClass SC = { 1, 'a' };"); @@ -1180,6 +1152,103 @@ TEST_F(FormatTest, FormatObjCBlocks) { verifyFormat("int (^Block1) (int, int) = ^(int i, int j)"); } +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" + "@protected\n" + " int field2;\n" + "@private\n" + " int field3;\n" + "@package\n" + " int field4;\n" + "}\n" + "+ (id)init;\n" + "@end"); + + // FIXME: In LLVM style, there should be a space before '<' for protocols. + verifyGoogleFormat("@interface Foo : NSObject {\n" + " @public\n" + " int field1;\n" + " @protected\n" + " int field2;\n" + " @private\n" + " int field3;\n" + " @package\n" + " int field4;\n" + "}\n" + "+ (id)init;\n" + "@end"); + + verifyFormat("@interface Foo\n" + "+ (id)init;\n" + "// Look, a comment!\n" + "- (int)answerWith:(int)i;\n" + "@end"); + + verifyFormat("@interface Foo\n" + "@end"); + + verifyFormat("@interface Foo : Bar\n" + "+ (id)init;\n" + "@end"); + + verifyFormat("@interface Foo : Bar\n" + "+ (id)init;\n" + "@end"); + + // FIXME: there should be a space before '(' for categories. + verifyFormat("@interface Foo(HackStuff)\n" + "+ (id)init;\n" + "@end"); + + verifyFormat("@interface Foo()\n" + "+ (id)init;\n" + "@end"); + + verifyFormat("@interface Foo(HackStuff)\n" + "+ (id)init;\n" + "@end"); + + verifyFormat("@interface Foo {\n" + " int _i;\n" + "}\n" + "+ (id)init;\n" + "@end"); + + verifyFormat("@interface Foo : Bar {\n" + " int _i;\n" + "}\n" + "+ (id)init;\n" + "@end"); + + verifyFormat("@interface Foo : Bar {\n" + " int _i;\n" + "}\n" + "+ (id)init;\n" + "@end"); + + verifyFormat("@interface Foo(HackStuff) {\n" + " int _i;\n" + "}\n" + "+ (id)init;\n" + "@end"); + + verifyFormat("@interface Foo() {\n" + " int _i;\n" + "}\n" + "+ (id)init;\n" + "@end"); + + verifyFormat("@interface Foo(HackStuff) {\n" + " int _i;\n" + "}\n" + "+ (id)init;\n" + "@end"); +} + TEST_F(FormatTest, ObjCAt) { verifyFormat("@autoreleasepool"); verifyFormat("@catch");