Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion clang/lib/Format/Format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3199,7 +3199,7 @@ class ObjCHeaderStyleGuesser : public TokenAnalyzer {
Keywords.kw_NS_OPTIONS, TT_ObjCBlockLBrace,
TT_ObjCBlockLParen, TT_ObjCDecl, TT_ObjCForIn,
TT_ObjCMethodExpr, TT_ObjCMethodSpecifier,
TT_ObjCProperty)) {
TT_ObjCProperty, TT_ObjCSelector)) {
LLVM_DEBUG(llvm::dbgs()
<< "Detected ObjC at location "
<< FormatTok->Tok.getLocation().printToString(
Expand Down
11 changes: 11 additions & 0 deletions clang/lib/Format/FormatToken.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,17 @@ namespace format {
TYPE(ObjCBlockLParen) \
TYPE(ObjCDecl) \
TYPE(ObjCForIn) \
/* The square brackets surrounding a method call, the colon separating the \
* method or parameter name and the argument inside the square brackets, and \
* the colon separating the method or parameter name and the type inside the \
* method declaration. */ \
TYPE(ObjCMethodExpr) \
/* The '+' or '-' at the start of the line. */ \
TYPE(ObjCMethodSpecifier) \
TYPE(ObjCProperty) \
/* The parentheses following '@selector' and the colon following the method \
* or parameter name inside the parentheses. */ \
TYPE(ObjCSelector) \
TYPE(ObjCStringLiteral) \
TYPE(OverloadedOperator) \
TYPE(OverloadedOperatorLParen) \
Expand All @@ -146,6 +154,9 @@ namespace format {
TYPE(RequiresExpression) \
TYPE(RequiresExpressionLBrace) \
TYPE(RequiresExpressionLParen) \
/* The hash key in languages that have hash literals, not including the \
* field name in the C++ struct literal. Also the method or parameter name \
* in the Objective-C method declaration or call. */ \
TYPE(SelectorName) \
TYPE(StartOfName) \
TYPE(StatementAttributeLikeMacro) \
Expand Down
21 changes: 10 additions & 11 deletions clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -321,13 +321,13 @@ class AnnotatingParser {
return parseUntouchableParens();
}

bool StartsObjCMethodExpr = false;
bool StartsObjCSelector = false;
if (!Style.isVerilog()) {
if (FormatToken *MaybeSel = OpeningParen.Previous) {
// @selector( starts a selector.
if (MaybeSel->is(tok::objc_selector) && MaybeSel->Previous &&
MaybeSel->Previous->is(tok::at)) {
StartsObjCMethodExpr = true;
StartsObjCSelector = true;
}
}
}
Expand Down Expand Up @@ -451,10 +451,8 @@ class AnnotatingParser {
}
}

if (StartsObjCMethodExpr) {
Contexts.back().ColonIsObjCMethodExpr = true;
OpeningParen.setType(TT_ObjCMethodExpr);
}
if (StartsObjCSelector)
OpeningParen.setType(TT_ObjCSelector);

// MightBeFunctionType and ProbablyFunctionType are used for
// function pointer and reference types as well as Objective-C
Expand Down Expand Up @@ -513,8 +511,8 @@ class AnnotatingParser {
}
}

if (StartsObjCMethodExpr) {
CurrentToken->setType(TT_ObjCMethodExpr);
if (StartsObjCSelector) {
CurrentToken->setType(TT_ObjCSelector);
if (Contexts.back().FirstObjCSelectorName) {
Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName =
Contexts.back().LongestObjCSelectorName;
Expand Down Expand Up @@ -1454,7 +1452,7 @@ class AnnotatingParser {
Next->Next->is(tok::colon)))) {
// This handles a special macro in ObjC code where selectors including
// the colon are passed as macro arguments.
Tok->setType(TT_ObjCMethodExpr);
Tok->setType(TT_ObjCSelector);
}
break;
case tok::pipe:
Expand Down Expand Up @@ -4609,7 +4607,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
return false;
}
if (Left.is(tok::colon))
return Left.isNot(TT_ObjCMethodExpr);
return !Left.isOneOf(TT_ObjCSelector, TT_ObjCMethodExpr);
if (Left.is(tok::coloncolon))
return false;
if (Left.is(tok::less) || Right.isOneOf(tok::greater, tok::less)) {
Expand Down Expand Up @@ -5465,7 +5463,7 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
// `private:` and `public:`.
if (!Right.getNextNonComment())
return false;
if (Right.is(TT_ObjCMethodExpr))
if (Right.isOneOf(TT_ObjCSelector, TT_ObjCMethodExpr))
return false;
if (Left.is(tok::question))
return false;
Expand Down Expand Up @@ -6289,6 +6287,7 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
return Style.BreakInheritanceList == FormatStyle::BILS_AfterColon;
if (Right.is(TT_InheritanceColon))
return Style.BreakInheritanceList != FormatStyle::BILS_AfterColon;
// When the method parameter has no name, allow breaking before the colon.
if (Right.is(TT_ObjCMethodExpr) && Right.isNot(tok::r_square) &&
Left.isNot(TT_SelectorName)) {
return true;
Expand Down
6 changes: 6 additions & 0 deletions clang/unittests/Format/FormatTestObjC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -763,6 +763,12 @@ TEST_F(FormatTestObjC, FormatObjCMethodExpr) {
" backing:NSBackingStoreBuffered\n"
" defer:NO]);\n"
"}");
verifyFormat(R"(- (void)test {
if ([object
respondsToSelector:@selector(
selectorNameThatIsReallyLong:param1:param2:)])
return;
})");
verifyFormat("[contentsContainer replaceSubview:[subviews objectAtIndex:0]\n"
" with:contentsNativeView];");

Expand Down
28 changes: 28 additions & 0 deletions clang/unittests/Format/TokenAnnotatorTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1929,6 +1929,34 @@ TEST_F(TokenAnnotatorTest, UnderstandsObjCMethodExpr) {
ASSERT_EQ(Tokens.size(), 20u) << Tokens;
EXPECT_TOKEN(Tokens[9], tok::l_square, TT_ObjCMethodExpr);
EXPECT_TOKEN(Tokens[15], tok::greater, TT_BinaryOperator);
Tokens = annotate("a = @selector(name:);");
ASSERT_EQ(Tokens.size(), 10u) << Tokens;
EXPECT_TOKEN(Tokens[4], tok::l_paren, TT_ObjCSelector);
EXPECT_TOKEN(Tokens[6], tok::colon, TT_ObjCSelector);
EXPECT_TOKEN(Tokens[7], tok::r_paren, TT_ObjCSelector);
Tokens =
annotate("[object respondsToSelector:@selector(name:param1:param2:)\n"
" respondsToSelector:@selector(name:param1:param2:)];");
ASSERT_EQ(Tokens.size(), 29u) << Tokens;
EXPECT_TOKEN(Tokens[0], tok::l_square, TT_ObjCMethodExpr);
EXPECT_TOKEN(Tokens[3], tok::colon, TT_ObjCMethodExpr);
EXPECT_TOKEN(Tokens[6], tok::l_paren, TT_ObjCSelector);
EXPECT_TOKEN(Tokens[8], tok::colon, TT_ObjCSelector);
EXPECT_TOKEN(Tokens[10], tok::colon, TT_ObjCSelector);
EXPECT_TOKEN(Tokens[12], tok::colon, TT_ObjCSelector);
EXPECT_TOKEN(Tokens[13], tok::r_paren, TT_ObjCSelector);
EXPECT_TOKEN(Tokens[15], tok::colon, TT_ObjCMethodExpr);
EXPECT_TOKEN(Tokens[18], tok::l_paren, TT_ObjCSelector);
EXPECT_TOKEN(Tokens[20], tok::colon, TT_ObjCSelector);
EXPECT_TOKEN(Tokens[22], tok::colon, TT_ObjCSelector);
EXPECT_TOKEN(Tokens[24], tok::colon, TT_ObjCSelector);
EXPECT_TOKEN(Tokens[25], tok::r_paren, TT_ObjCSelector);
EXPECT_TOKEN(Tokens[26], tok::r_square, TT_ObjCMethodExpr);
Tokens = annotate("[a b:c];");
ASSERT_EQ(Tokens.size(), 8u) << Tokens;
EXPECT_TOKEN(Tokens[0], tok::l_square, TT_ObjCMethodExpr);
EXPECT_TOKEN(Tokens[3], tok::colon, TT_ObjCMethodExpr);
EXPECT_TOKEN(Tokens[5], tok::r_square, TT_ObjCMethodExpr);
}

TEST_F(TokenAnnotatorTest, UnderstandsObjCMethodDecl) {
Expand Down