From: mydeveloperday Date: Tue, 26 May 2020 17:47:56 +0000 (+0100) Subject: [clang-format] Fix an ObjC regression introduced with new [[likely]][[unlikely]]... X-Git-Tag: llvmorg-12-init~5115 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=8f1156a7d004d97e9f75484a00dc4278698fd8ea;p=platform%2Fupstream%2Fllvm.git [clang-format] Fix an ObjC regression introduced with new [[likely]][[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 --- diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index 03b6e0c..b8da2c2 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -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)) { @@ -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); @@ -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 diff --git a/clang/lib/Format/UnwrappedLineParser.h b/clang/lib/Format/UnwrappedLineParser.h index 8d4118a..8b3aa4c 100644 --- a/clang/lib/Format/UnwrappedLineParser.h +++ b/clang/lib/Format/UnwrappedLineParser.h @@ -134,6 +134,7 @@ private: bool tryToParseLambdaIntroducer(); bool tryToParsePropertyAccessor(); void tryToParseJSFunction(); + bool tryToParseSimpleAttribute(); void addUnwrappedLine(); bool eof() const; // LevelDifference is the difference of levels after and before the current diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index a3b70bf..eea0b36 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -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) { diff --git a/clang/unittests/Format/FormatTestObjC.cpp b/clang/unittests/Format/FormatTestObjC.cpp index d73d090..28d33dc 100644 --- a/clang/unittests/Format/FormatTestObjC.cpp +++ b/clang/unittests/Format/FormatTestObjC.cpp @@ -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