Skip to content

Commit f4c2d57

Browse files
committed
[clang-format] Don't detect call to ObjC class method as C++11 attribute specifier
Summary: Previously, clang-format detected something like the following as a C++11 attribute specifier. @[[NSArray class]] instead of an array with an Objective-C method call inside. In general, when the attribute specifier checking runs, if it sees 2 identifiers in a row, it decides that the square brackets represent an Objective-C method call. However, here, `class` is tokenized as a keyword instead of an identifier, so this check fails. To fix this, the attribute specifier first checks whether the first square bracket has an "@" before it. If it does, then that square bracket is not the start of a attribute specifier because it is an Objective-C array literal. (The assumption is that @[[.*]] is not valid C/C++.) Contributed by rkgibson2. Reviewers: benhamilton Reviewed By: benhamilton Subscribers: aaron.ballman, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D64632 llvm-svn: 366267
1 parent fdc61bc commit f4c2d57

File tree

2 files changed

+11
-1
lines changed

2 files changed

+11
-1
lines changed

clang/lib/Format/TokenAnnotator.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,10 @@ class AnnotatingParser {
388388
bool isCpp11AttributeSpecifier(const FormatToken &Tok) {
389389
if (!Style.isCpp() || !Tok.startsSequence(tok::l_square, tok::l_square))
390390
return false;
391+
// The first square bracket is part of an ObjC array literal
392+
if (Tok.Previous && Tok.Previous->is(tok::at)) {
393+
return false;
394+
}
391395
const FormatToken *AttrTok = Tok.Next->Next;
392396
if (!AttrTok)
393397
return false;
@@ -400,7 +404,7 @@ class AnnotatingParser {
400404
while (AttrTok && !AttrTok->startsSequence(tok::r_square, tok::r_square)) {
401405
// ObjC message send. We assume nobody will use : in a C++11 attribute
402406
// specifier parameter, although this is technically valid:
403-
// [[foo(:)]]
407+
// [[foo(:)]].
404408
if (AttrTok->is(tok::colon) ||
405409
AttrTok->startsSequence(tok::identifier, tok::identifier) ||
406410
AttrTok->startsSequence(tok::r_paren, tok::identifier))

clang/unittests/Format/FormatTest.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7027,6 +7027,12 @@ TEST_F(FormatTest, UnderstandsSquareAttributes) {
70277027
// On the other hand, we still need to correctly find array subscripts.
70287028
verifyFormat("int a = std::vector<int>{1, 2, 3}[0];");
70297029

7030+
// Make sure that we do not mistake Objective-C method inside array literals
7031+
// as attributes, even if those method names are also keywords.
7032+
verifyFormat("@[ [foo bar] ];");
7033+
verifyFormat("@[ [NSArray class] ];");
7034+
verifyFormat("@[ [foo enum] ];");
7035+
70307036
// Make sure we do not parse attributes as lambda introducers.
70317037
FormatStyle MultiLineFunctions = getLLVMStyle();
70327038
MultiLineFunctions.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None;

0 commit comments

Comments
 (0)