Skip to content

Commit 61cb485

Browse files
committed
[clang-format] Keep the ObjC selector name and @selector together
Fixes #36459. after ```Objective-C - (void)test { if ([object respondsToSelector:@selector( selectorNameThatIsReallyLong:param1:param2:)]) return; } ``` before ```Objective-C - (void)test { if ([object respondsToSelector:@selector (selectorNameThatIsReallyLong:param1:param2:)]) return; } ``` Before this patch, the `ObjCMethodExpr` type was assigned to many kinds of tokens. The rule for allowing breaking the line before the colon on line TokenAnnotator.cpp:6290 was intended for method declarations and calls. It matched the parenthesis following `@selector` by mistake. To fix the problem, this patch adds a new type for `@selector`. Most of the special things in the code related to the old type is intended for other constructs. So most of the code related to the old type is not changed in this patch.
1 parent d45a135 commit 61cb485

File tree

5 files changed

+56
-12
lines changed

5 files changed

+56
-12
lines changed

clang/lib/Format/Format.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3199,7 +3199,7 @@ class ObjCHeaderStyleGuesser : public TokenAnalyzer {
31993199
Keywords.kw_NS_OPTIONS, TT_ObjCBlockLBrace,
32003200
TT_ObjCBlockLParen, TT_ObjCDecl, TT_ObjCForIn,
32013201
TT_ObjCMethodExpr, TT_ObjCMethodSpecifier,
3202-
TT_ObjCProperty)) {
3202+
TT_ObjCProperty, TT_ObjCSelector)) {
32033203
LLVM_DEBUG(llvm::dbgs()
32043204
<< "Detected ObjC at location "
32053205
<< FormatTok->Tok.getLocation().printToString(

clang/lib/Format/FormatToken.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,17 @@ namespace format {
127127
TYPE(ObjCBlockLParen) \
128128
TYPE(ObjCDecl) \
129129
TYPE(ObjCForIn) \
130+
/* The square brackets surrounding a method call, the colon separating the \
131+
* method or parameter name and the argument inside the square brackets, and \
132+
* the colon separating the method or parameter name and the type inside the \
133+
* method declaration. */ \
130134
TYPE(ObjCMethodExpr) \
135+
/* The '+' or '-' at the start of the line. */ \
131136
TYPE(ObjCMethodSpecifier) \
132137
TYPE(ObjCProperty) \
138+
/* The parentheses following '@selector' and the colon following the method \
139+
* or parameter name inside the parentheses. */ \
140+
TYPE(ObjCSelector) \
133141
TYPE(ObjCStringLiteral) \
134142
TYPE(OverloadedOperator) \
135143
TYPE(OverloadedOperatorLParen) \
@@ -146,6 +154,9 @@ namespace format {
146154
TYPE(RequiresExpression) \
147155
TYPE(RequiresExpressionLBrace) \
148156
TYPE(RequiresExpressionLParen) \
157+
/* The hash key in languages that have hash literals, not including the \
158+
* field name in the C++ struct literal. Also the method or parameter name \
159+
* in the Objective-C method declaration or call. */ \
149160
TYPE(SelectorName) \
150161
TYPE(StartOfName) \
151162
TYPE(StatementAttributeLikeMacro) \

clang/lib/Format/TokenAnnotator.cpp

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -321,13 +321,13 @@ class AnnotatingParser {
321321
return parseUntouchableParens();
322322
}
323323

324-
bool StartsObjCMethodExpr = false;
324+
bool StartsObjCSelector = false;
325325
if (!Style.isVerilog()) {
326326
if (FormatToken *MaybeSel = OpeningParen.Previous) {
327327
// @selector( starts a selector.
328328
if (MaybeSel->is(tok::objc_selector) && MaybeSel->Previous &&
329329
MaybeSel->Previous->is(tok::at)) {
330-
StartsObjCMethodExpr = true;
330+
StartsObjCSelector = true;
331331
}
332332
}
333333
}
@@ -451,10 +451,8 @@ class AnnotatingParser {
451451
}
452452
}
453453

454-
if (StartsObjCMethodExpr) {
455-
Contexts.back().ColonIsObjCMethodExpr = true;
456-
OpeningParen.setType(TT_ObjCMethodExpr);
457-
}
454+
if (StartsObjCSelector)
455+
OpeningParen.setType(TT_ObjCSelector);
458456

459457
// MightBeFunctionType and ProbablyFunctionType are used for
460458
// function pointer and reference types as well as Objective-C
@@ -513,8 +511,8 @@ class AnnotatingParser {
513511
}
514512
}
515513

516-
if (StartsObjCMethodExpr) {
517-
CurrentToken->setType(TT_ObjCMethodExpr);
514+
if (StartsObjCSelector) {
515+
CurrentToken->setType(TT_ObjCSelector);
518516
if (Contexts.back().FirstObjCSelectorName) {
519517
Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName =
520518
Contexts.back().LongestObjCSelectorName;
@@ -1454,7 +1452,7 @@ class AnnotatingParser {
14541452
Next->Next->is(tok::colon)))) {
14551453
// This handles a special macro in ObjC code where selectors including
14561454
// the colon are passed as macro arguments.
1457-
Tok->setType(TT_ObjCMethodExpr);
1455+
Tok->setType(TT_ObjCSelector);
14581456
}
14591457
break;
14601458
case tok::pipe:
@@ -4609,7 +4607,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
46094607
return false;
46104608
}
46114609
if (Left.is(tok::colon))
4612-
return Left.isNot(TT_ObjCMethodExpr);
4610+
return !Left.isOneOf(TT_ObjCSelector, TT_ObjCMethodExpr);
46134611
if (Left.is(tok::coloncolon))
46144612
return false;
46154613
if (Left.is(tok::less) || Right.isOneOf(tok::greater, tok::less)) {
@@ -5465,7 +5463,7 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
54655463
// `private:` and `public:`.
54665464
if (!Right.getNextNonComment())
54675465
return false;
5468-
if (Right.is(TT_ObjCMethodExpr))
5466+
if (Right.isOneOf(TT_ObjCSelector, TT_ObjCMethodExpr))
54695467
return false;
54705468
if (Left.is(tok::question))
54715469
return false;
@@ -6289,6 +6287,7 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
62896287
return Style.BreakInheritanceList == FormatStyle::BILS_AfterColon;
62906288
if (Right.is(TT_InheritanceColon))
62916289
return Style.BreakInheritanceList != FormatStyle::BILS_AfterColon;
6290+
// When the method parameter has no name, allow breaking before the colon.
62926291
if (Right.is(TT_ObjCMethodExpr) && Right.isNot(tok::r_square) &&
62936292
Left.isNot(TT_SelectorName)) {
62946293
return true;

clang/unittests/Format/FormatTestObjC.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -763,6 +763,12 @@ TEST_F(FormatTestObjC, FormatObjCMethodExpr) {
763763
" backing:NSBackingStoreBuffered\n"
764764
" defer:NO]);\n"
765765
"}");
766+
verifyFormat(R"(- (void)test {
767+
if ([object
768+
respondsToSelector:@selector(
769+
selectorNameThatIsReallyLong:param1:param2:)])
770+
return;
771+
})");
766772
verifyFormat("[contentsContainer replaceSubview:[subviews objectAtIndex:0]\n"
767773
" with:contentsNativeView];");
768774

clang/unittests/Format/TokenAnnotatorTest.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1929,6 +1929,34 @@ TEST_F(TokenAnnotatorTest, UnderstandsObjCMethodExpr) {
19291929
ASSERT_EQ(Tokens.size(), 20u) << Tokens;
19301930
EXPECT_TOKEN(Tokens[9], tok::l_square, TT_ObjCMethodExpr);
19311931
EXPECT_TOKEN(Tokens[15], tok::greater, TT_BinaryOperator);
1932+
Tokens = annotate("a = @selector(name:);");
1933+
ASSERT_EQ(Tokens.size(), 10u) << Tokens;
1934+
EXPECT_TOKEN(Tokens[4], tok::l_paren, TT_ObjCSelector);
1935+
EXPECT_TOKEN(Tokens[6], tok::colon, TT_ObjCSelector);
1936+
EXPECT_TOKEN(Tokens[7], tok::r_paren, TT_ObjCSelector);
1937+
Tokens =
1938+
annotate("[object respondsToSelector:@selector(name:param1:param2:)\n"
1939+
" respondsToSelector:@selector(name:param1:param2:)];");
1940+
ASSERT_EQ(Tokens.size(), 29u) << Tokens;
1941+
EXPECT_TOKEN(Tokens[0], tok::l_square, TT_ObjCMethodExpr);
1942+
EXPECT_TOKEN(Tokens[3], tok::colon, TT_ObjCMethodExpr);
1943+
EXPECT_TOKEN(Tokens[6], tok::l_paren, TT_ObjCSelector);
1944+
EXPECT_TOKEN(Tokens[8], tok::colon, TT_ObjCSelector);
1945+
EXPECT_TOKEN(Tokens[10], tok::colon, TT_ObjCSelector);
1946+
EXPECT_TOKEN(Tokens[12], tok::colon, TT_ObjCSelector);
1947+
EXPECT_TOKEN(Tokens[13], tok::r_paren, TT_ObjCSelector);
1948+
EXPECT_TOKEN(Tokens[15], tok::colon, TT_ObjCMethodExpr);
1949+
EXPECT_TOKEN(Tokens[18], tok::l_paren, TT_ObjCSelector);
1950+
EXPECT_TOKEN(Tokens[20], tok::colon, TT_ObjCSelector);
1951+
EXPECT_TOKEN(Tokens[22], tok::colon, TT_ObjCSelector);
1952+
EXPECT_TOKEN(Tokens[24], tok::colon, TT_ObjCSelector);
1953+
EXPECT_TOKEN(Tokens[25], tok::r_paren, TT_ObjCSelector);
1954+
EXPECT_TOKEN(Tokens[26], tok::r_square, TT_ObjCMethodExpr);
1955+
Tokens = annotate("[a b:c];");
1956+
ASSERT_EQ(Tokens.size(), 8u) << Tokens;
1957+
EXPECT_TOKEN(Tokens[0], tok::l_square, TT_ObjCMethodExpr);
1958+
EXPECT_TOKEN(Tokens[3], tok::colon, TT_ObjCMethodExpr);
1959+
EXPECT_TOKEN(Tokens[5], tok::r_square, TT_ObjCMethodExpr);
19321960
}
19331961

19341962
TEST_F(TokenAnnotatorTest, UnderstandsObjCMethodDecl) {

0 commit comments

Comments
 (0)