Skip to content

Commit 345f873

Browse files
committed
[clang-format/ObjC] Use getIdentifierInfo() instead of tok::identifier
Summary: Previously, we checked tokens for `tok::identifier` to see if they were identifiers inside an Objective-C selector. However, this missed C++ keywords like `new` and `delete`. To fix this, this diff uses `getIdentifierInfo()` to find identifiers or keywords inside Objective-C selectors. 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/D46143 llvm-svn: 331067
1 parent 47aece1 commit 345f873

File tree

2 files changed

+33
-5
lines changed

2 files changed

+33
-5
lines changed

clang/lib/Format/TokenAnnotator.cpp

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,21 @@ namespace format {
2525

2626
namespace {
2727

28+
/// \brief Returns \c true if the token can be used as an identifier in
29+
/// an Objective-C \c @selector, \c false otherwise.
30+
///
31+
/// Because getFormattingLangOpts() always lexes source code as
32+
/// Objective-C++, C++ keywords like \c new and \c delete are
33+
/// lexed as tok::kw_*, not tok::identifier, even for Objective-C.
34+
///
35+
/// For Objective-C and Objective-C++, both identifiers and keywords
36+
/// are valid inside @selector(...) (or a macro which
37+
/// invokes @selector(...)). So, we allow treat any identifier or
38+
/// keyword as a potential Objective-C selector component.
39+
static bool canBeObjCSelectorComponent(const FormatToken &Tok) {
40+
return Tok.Tok.getIdentifierInfo() != nullptr;
41+
}
42+
2843
/// \brief A parser that gathers additional information about tokens.
2944
///
3045
/// The \c TokenAnnotator tries to match parenthesis and square brakets and
@@ -703,9 +718,10 @@ class AnnotatingParser {
703718
Tok->Type = TT_CtorInitializerColon;
704719
else
705720
Tok->Type = TT_InheritanceColon;
706-
} else if (Tok->Previous->is(tok::identifier) && Tok->Next &&
721+
} else if (canBeObjCSelectorComponent(*Tok->Previous) && Tok->Next &&
707722
(Tok->Next->isOneOf(tok::r_paren, tok::comma) ||
708-
Tok->Next->startsSequence(tok::identifier, tok::colon))) {
723+
(canBeObjCSelectorComponent(*Tok->Next) && Tok->Next->Next &&
724+
Tok->Next->Next->is(tok::colon)))) {
709725
// This handles a special macro in ObjC code where selectors including
710726
// the colon are passed as macro arguments.
711727
Tok->Type = TT_ObjCMethodExpr;
@@ -1346,7 +1362,7 @@ class AnnotatingParser {
13461362
TT_LeadingJavaAnnotation)) {
13471363
Current.Type = Current.Previous->Type;
13481364
}
1349-
} else if (Current.isOneOf(tok::identifier, tok::kw_new) &&
1365+
} else if (canBeObjCSelectorComponent(Current) &&
13501366
// FIXME(bug 36976): ObjC return types shouldn't use TT_CastRParen.
13511367
Current.Previous && Current.Previous->is(TT_CastRParen) &&
13521368
Current.Previous->MatchingParen &&
@@ -2650,7 +2666,7 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
26502666
if (Line.Type == LT_ObjCMethodDecl) {
26512667
if (Left.is(TT_ObjCMethodSpecifier))
26522668
return true;
2653-
if (Left.is(tok::r_paren) && Right.isOneOf(tok::identifier, tok::kw_new))
2669+
if (Left.is(tok::r_paren) && canBeObjCSelectorComponent(Right))
26542670
// Don't space between ')' and <id> or ')' and 'new'. 'new' is not a
26552671
// keyword in Objective-C, and '+ (instancetype)new;' is a standard class
26562672
// method declaration.
@@ -3128,6 +3144,7 @@ void TokenAnnotator::printDebugInfo(const AnnotatedLine &Line) {
31283144
for (unsigned i = 0, e = Tok->FakeLParens.size(); i != e; ++i)
31293145
llvm::errs() << Tok->FakeLParens[i] << "/";
31303146
llvm::errs() << " FakeRParens=" << Tok->FakeRParens;
3147+
llvm::errs() << " II=" << Tok->Tok.getIdentifierInfo();
31313148
llvm::errs() << " Text='" << Tok->TokenText << "'\n";
31323149
if (!Tok->Next)
31333150
assert(Tok == Line.Last);

clang/unittests/Format/FormatTestObjC.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -945,7 +945,7 @@ TEST_F(FormatTestObjC, ObjCForIn) {
945945
" }]) {\n}");
946946
}
947947

948-
TEST_F(FormatTestObjC, ObjCNew) {
948+
TEST_F(FormatTestObjC, ObjCCxxKeywords) {
949949
verifyFormat("+ (instancetype)new {\n"
950950
" return nil;\n"
951951
"}\n");
@@ -954,6 +954,17 @@ TEST_F(FormatTestObjC, ObjCNew) {
954954
"}\n");
955955
verifyFormat("SEL NewSelector(void) { return @selector(new); }\n");
956956
verifyFormat("SEL MacroSelector(void) { return MACRO(new); }\n");
957+
verifyFormat("+ (instancetype)delete {\n"
958+
" return nil;\n"
959+
"}\n");
960+
verifyFormat("+ (instancetype)myDelete {\n"
961+
" return [self delete];\n"
962+
"}\n");
963+
verifyFormat("SEL DeleteSelector(void) { return @selector(delete); }\n");
964+
verifyFormat("SEL MacroSelector(void) { return MACRO(delete); }\n");
965+
verifyFormat("MACRO(new:)\n");
966+
verifyFormat("MACRO(delete:)\n");
967+
verifyFormat("foo = @{MACRO(new:) : MACRO(delete:)}\n");
957968
}
958969

959970
TEST_F(FormatTestObjC, ObjCLiterals) {

0 commit comments

Comments
 (0)