diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index 7075a6fe33f76..ab1f647481d07 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -2612,32 +2612,15 @@ void UnwrappedLineParser::parseObjCInterfaceOrImplementation() { // @interface can be followed by a lightweight generic // specialization list, then either a base class or a category. if (FormatTok->Tok.is(tok::less)) { - // Unlike protocol lists, generic parameterizations support - // nested angles: - // - // @interface Foo> : - // NSObject - // - // so we need to count how many open angles we have left. - unsigned NumOpenAngles = 1; - do { - nextToken(); - // Early exit in case someone forgot a close angle. - if (FormatTok->isOneOf(tok::semi, tok::l_brace) || - FormatTok->Tok.isObjCAtKeyword(tok::objc_end)) - break; - if (FormatTok->Tok.is(tok::less)) - ++NumOpenAngles; - else if (FormatTok->Tok.is(tok::greater)) { - assert(NumOpenAngles > 0 && "'>' makes NumOpenAngles negative"); - --NumOpenAngles; - } - } while (!eof() && NumOpenAngles != 0); - nextToken(); // Skip '>'. + parseObjCLightweightGenerics(); } if (FormatTok->Tok.is(tok::colon)) { nextToken(); nextToken(); // base class name + // The base class can also have lightweight generics applied to it. + if (FormatTok->Tok.is(tok::less)) { + parseObjCLightweightGenerics(); + } } else if (FormatTok->Tok.is(tok::l_paren)) // Skip category, if present. parseParens(); @@ -2658,6 +2641,32 @@ void UnwrappedLineParser::parseObjCInterfaceOrImplementation() { parseObjCUntilAtEnd(); } +void UnwrappedLineParser::parseObjCLightweightGenerics() { + assert(FormatTok->Tok.is(tok::less)); + // Unlike protocol lists, generic parameterizations support + // nested angles: + // + // @interface Foo> : + // NSObject + // + // so we need to count how many open angles we have left. + unsigned NumOpenAngles = 1; + do { + nextToken(); + // Early exit in case someone forgot a close angle. + if (FormatTok->isOneOf(tok::semi, tok::l_brace) || + FormatTok->Tok.isObjCAtKeyword(tok::objc_end)) + break; + if (FormatTok->Tok.is(tok::less)) + ++NumOpenAngles; + else if (FormatTok->Tok.is(tok::greater)) { + assert(NumOpenAngles > 0 && "'>' makes NumOpenAngles negative"); + --NumOpenAngles; + } + } while (!eof() && NumOpenAngles != 0); + nextToken(); // Skip '>'. +} + // Returns true for the declaration/definition form of @protocol, // false for the expression form. bool UnwrappedLineParser::parseObjCProtocol() { diff --git a/clang/lib/Format/UnwrappedLineParser.h b/clang/lib/Format/UnwrappedLineParser.h index 8b3aa4c84edba..d682b4d6acd85 100644 --- a/clang/lib/Format/UnwrappedLineParser.h +++ b/clang/lib/Format/UnwrappedLineParser.h @@ -118,6 +118,7 @@ class UnwrappedLineParser { // parses the record as a child block, i.e. if the class declaration is an // expression. void parseRecord(bool ParseAsExpr = false); + void parseObjCLightweightGenerics(); void parseObjCMethod(); void parseObjCProtocolList(); void parseObjCUntilAtEnd(); diff --git a/clang/unittests/Format/FormatTestObjC.cpp b/clang/unittests/Format/FormatTestObjC.cpp index f3be942ab9137..21b8d4701271a 100644 --- a/clang/unittests/Format/FormatTestObjC.cpp +++ b/clang/unittests/Format/FormatTestObjC.cpp @@ -328,6 +328,18 @@ TEST_F(FormatTestObjC, FormatObjCInterface) { "+ (id)init;\n" "@end"); + verifyFormat("@interface Foo> : Xyzzy {\n" + " int _i;\n" + "}\n" + "+ (id)init;\n" + "@end"); + + verifyFormat("@interface Foo : Bar \n" + "@end"); + + verifyFormat("@interface Foo : Bar \n" + "@end"); + verifyFormat("@interface Foo (HackStuff) {\n" " int _i;\n" "}\n" @@ -413,6 +425,10 @@ TEST_F(FormatTestObjC, FormatObjCInterface) { " fffffffffffff,\n" " fffffffffffff> {\n" "}"); + verifyFormat("@interface ggggggggggggg\n" + " : ggggggggggggg \n" + " \n" + "@end"); } TEST_F(FormatTestObjC, FormatObjCImplementation) {