From 3007b385fa0b20bf48fae04c6b1a0e417a72ecd0 Mon Sep 17 00:00:00 2001 From: Ben Hamilton Date: Fri, 29 Jun 2018 15:26:37 +0000 Subject: [PATCH] [clang-format/ObjC] Fix NS_SWIFT_NAME(foo(bar:baz:)) after ObjC method decl Summary: In D44638, I partially fixed `NS_SWIFT_NAME(foo(bar:baz:))`-style annotations on C functions, but didn't add a test for Objective-C method declarations. For ObjC method declarations which are annotated with `NS_SWIFT_NAME(...)`, we currently fail to annotate the final component of the selector name as `TT_SelectorName`. Because the token type is left unknown, clang-format will happily cause a compilation error when it changes the following: ``` @interface Foo - (void)doStuffWithFoo:(id)name bar:(id)bar baz:(id)baz NS_SWIFT_NAME(doStuff(withFoo:bar:baz:)); @end ``` to: ``` @interface Foo - (void)doStuffWithFoo:(id)name bar:(id)bar baz:(id)baz NS_SWIFT_NAME(doStuff(withFoo:bar:baz :)); @end ``` (note the linebreak before the final `:`). The logic which decides whether or not to annotate the token before a `:` with `TT_SelectorName` is pretty fragile, and has to handle some pretty odd cases like pair-parameters: ``` [I drawRectOn:surface ofSize:aa:bbb atOrigin:cc:dd]; ``` So, to minimize the effect of this change, I decided to only annotate unknown identifiers before a `:` as `TT_SelectorName` for Objective-C declaration lines. Test Plan: New tests included. Confirmed tests failed before change and passed after change. Ran tests with: % make -j16 FormatTests && ./tools/clang/unittests/Format/FormatTests Reviewers: djasper, krasimir, jolesiak Reviewed By: krasimir Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D48679 llvm-svn: 335983 --- clang/lib/Format/TokenAnnotator.cpp | 8 +++++++- clang/unittests/Format/FormatTestObjC.cpp | 8 ++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 68ea02296b7d..ec8d3517256e 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -698,13 +698,19 @@ private: Line.startsWith(TT_ObjCMethodSpecifier)) { Tok->Type = TT_ObjCMethodExpr; const FormatToken *BeforePrevious = Tok->Previous->Previous; + // Ensure we tag all identifiers in method declarations as + // TT_SelectorName. + bool UnknownIdentifierInMethodDeclaration = + Line.startsWith(TT_ObjCMethodSpecifier) && + Tok->Previous->is(tok::identifier) && Tok->Previous->is(TT_Unknown); if (!BeforePrevious || // FIXME(bug 36976): ObjC return types shouldn't use TT_CastRParen. !(BeforePrevious->is(TT_CastRParen) || (BeforePrevious->is(TT_ObjCMethodExpr) && BeforePrevious->is(tok::colon))) || BeforePrevious->is(tok::r_square) || - Contexts.back().LongestObjCSelectorName == 0) { + Contexts.back().LongestObjCSelectorName == 0 || + UnknownIdentifierInMethodDeclaration) { Tok->Previous->Type = TT_SelectorName; if (!Contexts.back().FirstObjCSelectorName) Contexts.back().FirstObjCSelectorName = Tok->Previous; diff --git a/clang/unittests/Format/FormatTestObjC.cpp b/clang/unittests/Format/FormatTestObjC.cpp index 58559eabe85c..9d086551b253 100644 --- a/clang/unittests/Format/FormatTestObjC.cpp +++ b/clang/unittests/Format/FormatTestObjC.cpp @@ -923,6 +923,14 @@ TEST_F(FormatTestObjC, ObjCSnippets) { verifyFormat("@property(assign, nonatomic) CGFloat hoverAlpha;"); verifyFormat("@property(assign, getter=isEditable) BOOL editable;"); + Style.ColumnLimit = 50; + verifyFormat("@interface Foo\n" + "- (void)doStuffWithFoo:(id)name\n" + " bar:(id)bar\n" + " baz:(id)baz\n" + " NS_SWIFT_NAME(doStuff(withFoo:bar:baz:));\n" + "@end"); + Style = getMozillaStyle(); verifyFormat("@property (assign, getter=isEditable) BOOL editable;"); verifyFormat("@property BOOL editable;");