forked from OSchip/llvm-project
[clang-format] Improve detection of Objective-C block types
Summary: Previously, clang-format would detect the following as an Objective-C block type: FOO(^); when it actually must be a C or C++ macro dealing with an XOR statement or an XOR operator overload. According to the Clang Block Language Spec: https://clang.llvm.org/docs/BlockLanguageSpec.html block types are of the form: int (^)(char, float) and block variables of block type are of the form: void (^blockReturningVoidWithVoidArgument)(void); int (^blockReturningIntWithIntAndCharArguments)(int, char); void (^arrayOfTenBlocksReturningVoidWithIntArgument[10])(int); This tightens up the detection so we don't unnecessarily detect C macros which pass in the XOR operator. Depends On D43904 Test Plan: New tests added. Ran tests with: make -j12 FormatTests && ./tools/clang/unittests/Format/FormatTests Reviewers: krasimir, jolesiak, djasper Reviewed By: djasper Subscribers: djasper, cfe-commits, klimek Differential Revision: https://reviews.llvm.org/D43906 llvm-svn: 327285
This commit is contained in:
parent
b060ad870f
commit
788a2227b7
|
@ -141,10 +141,7 @@ private:
|
|||
Contexts.size() == 2 && Contexts[0].ColonIsForRangeExpr;
|
||||
|
||||
bool StartsObjCMethodExpr = false;
|
||||
if (CurrentToken->is(tok::caret)) {
|
||||
// (^ can start a block type.
|
||||
Left->Type = TT_ObjCBlockLParen;
|
||||
} else if (FormatToken *MaybeSel = Left->Previous) {
|
||||
if (FormatToken *MaybeSel = Left->Previous) {
|
||||
// @selector( starts a selector.
|
||||
if (MaybeSel->isObjCAtKeyword(tok::objc_selector) && MaybeSel->Previous &&
|
||||
MaybeSel->Previous->is(tok::at)) {
|
||||
|
@ -210,8 +207,16 @@ private:
|
|||
Left->Type = TT_ObjCMethodExpr;
|
||||
}
|
||||
|
||||
// MightBeFunctionType and ProbablyFunctionType are used for
|
||||
// function pointer and reference types as well as Objective-C
|
||||
// block types:
|
||||
//
|
||||
// void (*FunctionPointer)(void);
|
||||
// void (&FunctionReference)(void);
|
||||
// void (^ObjCBlock)(void);
|
||||
bool MightBeFunctionType = !Contexts[Contexts.size() - 2].IsExpression;
|
||||
bool ProbablyFunctionType = CurrentToken->isOneOf(tok::star, tok::amp);
|
||||
bool ProbablyFunctionType =
|
||||
CurrentToken->isOneOf(tok::star, tok::amp, tok::caret);
|
||||
bool HasMultipleLines = false;
|
||||
bool HasMultipleParametersOnALine = false;
|
||||
bool MightBeObjCForRangeLoop =
|
||||
|
@ -248,7 +253,8 @@ private:
|
|||
if (MightBeFunctionType && ProbablyFunctionType && CurrentToken->Next &&
|
||||
(CurrentToken->Next->is(tok::l_paren) ||
|
||||
(CurrentToken->Next->is(tok::l_square) && Line.MustBeDeclaration)))
|
||||
Left->Type = TT_FunctionTypeLParen;
|
||||
Left->Type = Left->Next->is(tok::caret) ? TT_ObjCBlockLParen
|
||||
: TT_FunctionTypeLParen;
|
||||
Left->MatchingParen = CurrentToken;
|
||||
CurrentToken->MatchingParen = Left;
|
||||
|
||||
|
|
|
@ -12128,6 +12128,22 @@ TEST_F(FormatTest, GuessLanguageWithCpp11AttributeSpecifiers) {
|
|||
EXPECT_EQ(FormatStyle::LK_Cpp, guessLanguage("foo.h", "[[foo::bar, ...]]"));
|
||||
}
|
||||
|
||||
TEST_F(FormatTest, GuessLanguageWithCaret) {
|
||||
EXPECT_EQ(FormatStyle::LK_Cpp, guessLanguage("foo.h", "FOO(^);"));
|
||||
EXPECT_EQ(FormatStyle::LK_Cpp, guessLanguage("foo.h", "FOO(^, Bar);"));
|
||||
EXPECT_EQ(FormatStyle::LK_ObjC,
|
||||
guessLanguage("foo.h", "int(^)(char, float);"));
|
||||
EXPECT_EQ(FormatStyle::LK_ObjC,
|
||||
guessLanguage("foo.h", "int(^foo)(char, float);"));
|
||||
EXPECT_EQ(FormatStyle::LK_ObjC,
|
||||
guessLanguage("foo.h", "int(^foo[10])(char, float);"));
|
||||
EXPECT_EQ(FormatStyle::LK_ObjC,
|
||||
guessLanguage("foo.h", "int(^foo[kNumEntries])(char, float);"));
|
||||
EXPECT_EQ(
|
||||
FormatStyle::LK_ObjC,
|
||||
guessLanguage("foo.h", "int(^foo[(kNumEntries + 10)])(char, float);"));
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
} // end namespace format
|
||||
} // end namespace clang
|
||||
|
|
|
@ -845,6 +845,15 @@ TEST_F(FormatTestObjC, ObjCAt) {
|
|||
verifyFormat("@ /*foo*/ interface");
|
||||
}
|
||||
|
||||
TEST_F(FormatTestObjC, ObjCBlockTypesAndVariables) {
|
||||
verifyFormat("void DoStuffWithBlockType(int (^)(char));");
|
||||
verifyFormat("int (^foo)(char, float);");
|
||||
verifyFormat("int (^foo[10])(char, float);");
|
||||
verifyFormat("int (^foo[kNumEntries])(char, float);");
|
||||
verifyFormat("int (^foo[kNumEntries + 10])(char, float);");
|
||||
verifyFormat("int (^foo[(kNumEntries + 10)])(char, float);");
|
||||
}
|
||||
|
||||
TEST_F(FormatTestObjC, ObjCSnippets) {
|
||||
verifyFormat("@autoreleasepool {\n"
|
||||
" foo();\n"
|
||||
|
|
Loading…
Reference in New Issue