Skip to content

Commit

Permalink
[clang-format] Fix an ObjC regression introduced with new [[likely]][…
Browse files Browse the repository at this point in the history
…[unlikely]] support in if/else clauses

Summary:
{D80144} introduce an ObjC regression

Only parse the `[]` if what follows is really an attribute

Reviewers: krasimir, JakeMerdichAMD

Reviewed By: krasimir

Subscribers: rdwampler, aaron.ballman, curdeius, cfe-commits

Tags: #clang, #clang-format

Differential Revision: https://reviews.llvm.org/D80547
  • Loading branch information
mydeveloperday committed May 26, 2020
1 parent 2c7d632 commit 8f1156a
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 2 deletions.
49 changes: 47 additions & 2 deletions clang/lib/Format/UnwrappedLineParser.cpp
Expand Up @@ -1962,7 +1962,7 @@ void UnwrappedLineParser::parseIfThenElse() {
if (FormatTok->Tok.is(tok::l_paren))
parseParens();
// handle [[likely]] / [[unlikely]]
if (FormatTok->is(tok::l_square))
if (FormatTok->is(tok::l_square) && tryToParseSimpleAttribute())
parseSquare();
bool NeedsUnwrappedLine = false;
if (FormatTok->Tok.is(tok::l_brace)) {
Expand All @@ -1981,7 +1981,7 @@ void UnwrappedLineParser::parseIfThenElse() {
if (FormatTok->Tok.is(tok::kw_else)) {
nextToken();
// handle [[likely]] / [[unlikely]]
if (FormatTok->is(tok::l_square))
if (FormatTok->Tok.is(tok::l_square) && tryToParseSimpleAttribute())
parseSquare();
if (FormatTok->Tok.is(tok::l_brace)) {
CompoundStatementIndenter Indenter(this, Style, Line->Level);
Expand Down Expand Up @@ -2343,6 +2343,51 @@ bool UnwrappedLineParser::parseEnum() {
// "} n, m;" will end up in one unwrapped line.
}

namespace {
// A class used to set and restore the Token position when peeking
// ahead in the token source.
class ScopedTokenPosition {
unsigned StoredPosition;
FormatTokenSource *Tokens;

public:
ScopedTokenPosition(FormatTokenSource *Tokens) : Tokens(Tokens) {
assert(Tokens && "Tokens expected to not be null");
StoredPosition = Tokens->getPosition();
}

~ScopedTokenPosition() { Tokens->setPosition(StoredPosition); }
};
} // namespace

// Look to see if we have [[ by looking ahead, if
// its not then rewind to the original position.
bool UnwrappedLineParser::tryToParseSimpleAttribute() {
ScopedTokenPosition AutoPosition(Tokens);
FormatToken *Tok = Tokens->getNextToken();
// We already read the first [ check for the second.
if (Tok && !Tok->is(tok::l_square)) {
return false;
}
// Double check that the attribute is just something
// fairly simple.
while (Tok) {
if (Tok->is(tok::r_square)) {
break;
}
Tok = Tokens->getNextToken();
}
Tok = Tokens->getNextToken();
if (Tok && !Tok->is(tok::r_square)) {
return false;
}
Tok = Tokens->getNextToken();
if (Tok && Tok->is(tok::semi)) {
return false;
}
return true;
}

void UnwrappedLineParser::parseJavaEnumBody() {
// Determine whether the enum is simple, i.e. does not have a semicolon or
// constants with class bodies. Simple enums can be formatted like braced
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Format/UnwrappedLineParser.h
Expand Up @@ -134,6 +134,7 @@ class UnwrappedLineParser {
bool tryToParseLambdaIntroducer();
bool tryToParsePropertyAccessor();
void tryToParseJSFunction();
bool tryToParseSimpleAttribute();
void addUnwrappedLine();
bool eof() const;
// LevelDifference is the difference of levels after and before the current
Expand Down
5 changes: 5 additions & 0 deletions clang/unittests/Format/FormatTest.cpp
Expand Up @@ -16513,6 +16513,11 @@ TEST_F(FormatTest, LikelyUnlikely) {
" return 42;\n"
"}\n",
Style);

verifyFormat("if (argc > 5) [[gnu::unused]] {\n"
" return 29;\n"
"}",
Style);
}

TEST_F(FormatTest, LLVMDefaultStyle) {
Expand Down
19 changes: 19 additions & 0 deletions clang/unittests/Format/FormatTestObjC.cpp
Expand Up @@ -1434,6 +1434,25 @@ TEST_F(FormatTestObjC, BreakLineBeforeNestedBlockParam) {
" }]");
}

TEST_F(FormatTestObjC, IfNotUnlikely) {
Style = getGoogleStyle(FormatStyle::LK_ObjC);

verifyFormat("if (argc < 5) [obj func:arg];");
verifyFormat("if (argc < 5) [[obj1 method1:arg1] method2:arg2];");
verifyFormat("if (argc < 5) [[foo bar] baz:i[0]];");
verifyFormat("if (argc < 5) [[foo bar] baz:i[0]][1];");

verifyFormat("if (argc < 5)\n"
" [obj func:arg];\n"
"else\n"
" [obj func:arg2];");

verifyFormat("if (argc < 5) [[unlikely]]\n"
" [obj func:arg];\n"
"else [[likely]]\n"
" [obj func:arg2];");
}

} // end namespace
} // end namespace format
} // end namespace clang

0 comments on commit 8f1156a

Please sign in to comment.