summaryrefslogtreecommitdiffstats
path: root/clang
diff options
context:
space:
mode:
authorBen Hamilton <benhamilton@google.com>2018-04-05 15:26:25 +0000
committerBen Hamilton <benhamilton@google.com>2018-04-05 15:26:25 +0000
commit1462e8440f429d61d48f3161f89e5f3336d45dfc (patch)
treef8e46999e3e12189de706e4b96d3b67cc70046c3 /clang
parentf90ad9cdac9edc7f3b4268681d5d7ff2532565cc (diff)
downloadbcm5719-llvm-1462e8440f429d61d48f3161f89e5f3336d45dfc.tar.gz
bcm5719-llvm-1462e8440f429d61d48f3161f89e5f3336d45dfc.zip
[clang-format] Support lightweight Objective-C generics
Summary: Previously, `clang-format` didn't understand lightweight Objective-C generics, which have the form: ``` @interface Foo <KeyType, ValueTypeWithConstraint : Foo, AnotherValueTypeWithGenericConstraint: Bar<Baz>, ... > ... ``` The lightweight generic specifier list appears before the base class, if present, but because it starts with < like the protocol specifier list, `UnwrappedLineParser` was getting confused and failed to parse interfaces with both generics and protocol lists: ``` @interface Foo <KeyType> : NSObject <NSCopying> ``` Since the parsed line would be incomplete, the format result would be very confused (e.g., https://bugs.llvm.org/show_bug.cgi?id=24381). This fixes the issue by explicitly parsing the ObjC lightweight generic conformance list, so the line is fully parsed. Fixes: https://bugs.llvm.org/show_bug.cgi?id=24381 Test Plan: New tests added. Ran tests with: % make -j16 FormatTests && ./tools/clang/unittests/Format/FormatTests Reviewers: djasper, jolesiak Reviewed By: djasper Subscribers: klimek, cfe-commits Differential Revision: https://reviews.llvm.org/D45185 llvm-svn: 329298
Diffstat (limited to 'clang')
-rw-r--r--clang/lib/Format/UnwrappedLineParser.cpp35
-rw-r--r--clang/unittests/Format/FormatTestObjC.cpp12
2 files changed, 44 insertions, 3 deletions
diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp
index 5ab5cc46cdc..be7e2bbabac 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -2122,9 +2122,13 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) {
void UnwrappedLineParser::parseObjCProtocolList() {
assert(FormatTok->Tok.is(tok::less) && "'<' expected.");
- do
+ do {
nextToken();
- while (!eof() && FormatTok->Tok.isNot(tok::greater));
+ // Early exit in case someone forgot a close angle.
+ if (FormatTok->isOneOf(tok::semi, tok::l_brace) ||
+ FormatTok->Tok.isObjCAtKeyword(tok::objc_end))
+ return;
+ } while (!eof() && FormatTok->Tok.isNot(tok::greater));
nextToken(); // Skip '>'.
}
@@ -2155,7 +2159,32 @@ void UnwrappedLineParser::parseObjCInterfaceOrImplementation() {
nextToken();
nextToken(); // interface name
- // @interface can be followed by either a base class, or a category.
+ // @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<ValueType : id <NSCopying, NSSecureCoding>> :
+ // NSObject <NSCopying, NSSecureCoding>
+ //
+ // 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 '>'.
+ }
if (FormatTok->Tok.is(tok::colon)) {
nextToken();
nextToken(); // base class name
diff --git a/clang/unittests/Format/FormatTestObjC.cpp b/clang/unittests/Format/FormatTestObjC.cpp
index 5ea05f45928..fe86cfe8ce9 100644
--- a/clang/unittests/Format/FormatTestObjC.cpp
+++ b/clang/unittests/Format/FormatTestObjC.cpp
@@ -299,6 +299,18 @@ TEST_F(FormatTestObjC, FormatObjCInterface) {
"+ (id)init;\n"
"@end");
+ verifyFormat("@interface Foo <Baz : Blech> : Bar <Baz, Quux> {\n"
+ " int _i;\n"
+ "}\n"
+ "+ (id)init;\n"
+ "@end");
+
+ verifyFormat("@interface Foo <Bar : Baz <Blech>> : Xyzzy <Corge> {\n"
+ " int _i;\n"
+ "}\n"
+ "+ (id)init;\n"
+ "@end");
+
verifyFormat("@interface Foo (HackStuff) {\n"
" int _i;\n"
"}\n"
OpenPOWER on IntegriCloud