MyDeveloperDay created this revision. MyDeveloperDay added reviewers: krasimir, JakeMerdichAMD, mitchell-stellar, owenpan, sylvestre.ledru. MyDeveloperDay added projects: clang, clang-format. MyDeveloperDay retitled this revision from "[clang-format] Incorrectly indents [[nodiscard]] attribute funtions after a macro without semicolon" to "[clang-format] [PR45614] Incorrectly indents [[nodiscard]] attribute funtions after a macro without semicolon". MyDeveloperDay added a reviewer: Abpostelnicu.
https://bugs.llvm.org/show_bug.cgi?id=45614 `[[nodiscard]]` after a macro doesn't behave the same as an __attribute__ resulting in incorrect indentation This revision corrects that behavior MACRO __attribute__((warn_unused_result)) int f3(); // ok MACRO [[nodiscard]] int f4(); // bad: unexpectedly indented! See original Mozilla bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1629756 Before: class FooWidget : public nsBaseWidget { public: FooWidget(); NS_DECL_ISUPPORTS_INHERITED [[nodiscard]] nsresult FunctionOne(); [[nodiscard]] nsresult FunctionTwo(); }; After: class FooWidget : public nsBaseWidget { public: FooWidget(); NS_DECL_ISUPPORTS_INHERITED [[nodiscard]] nsresult FunctionOne(); [[nodiscard]] nsresult FunctionTwo(); }; https://reviews.llvm.org/D79990 Files: clang/lib/Format/UnwrappedLineParser.cpp clang/unittests/Format/FormatTest.cpp
Index: clang/unittests/Format/FormatTest.cpp =================================================================== --- clang/unittests/Format/FormatTest.cpp +++ clang/unittests/Format/FormatTest.cpp @@ -7672,6 +7672,37 @@ MultiLineFunctions); } +TEST_F(FormatTest, AttributesAfterMacro) { + FormatStyle Style = getLLVMStyle(); + verifyFormat("MACRO;\n" + "__attribute__((maybe_unused)) int foo() {\n" + " //...\n" + "}"); + + verifyFormat("MACRO;\n" + "[[nodiscard]] int foo() {\n" + " //...\n" + "}"); + + EXPECT_EQ("MACRO\n\n" + "__attribute__((maybe_unused)) int foo() {\n" + " //...\n" + "}", + format("MACRO\n\n" + "__attribute__((maybe_unused)) int foo() {\n" + " //...\n" + "}")); + + EXPECT_EQ("MACRO\n\n" + "[[nodiscard]] int foo() {\n" + " //...\n" + "}", + format("MACRO\n\n" + "[[nodiscard]] int foo() {\n" + " //...\n" + "}")); +} + TEST_F(FormatTest, AttributePenaltyBreaking) { FormatStyle Style = getLLVMStyle(); verifyFormat("void ABCDEFGH::ABCDEFGHIJKLMN(\n" Index: clang/lib/Format/UnwrappedLineParser.cpp =================================================================== --- clang/lib/Format/UnwrappedLineParser.cpp +++ clang/lib/Format/UnwrappedLineParser.cpp @@ -903,30 +903,30 @@ // Here we blacklist certain tokens that are not usually the first token in an // unwrapped line. This is used in attempt to distinguish macro calls without // trailing semicolons from other constructs split to several lines. -static bool tokenCanStartNewLine(const clang::Token &Tok) { +static bool tokenCanStartNewLine(const FormatToken *Tok) { // Semicolon can be a null-statement, l_square can be a start of a macro or // a C++11 attribute, but this doesn't seem to be common. - return Tok.isNot(tok::semi) && Tok.isNot(tok::l_brace) && - Tok.isNot(tok::l_square) && + return Tok->isNot(tok::semi) && Tok->isNot(tok::l_brace) && + Tok->isNot(TT_AttributeSquare) && // Tokens that can only be used as binary operators and a part of // overloaded operator names. - Tok.isNot(tok::period) && Tok.isNot(tok::periodstar) && - Tok.isNot(tok::arrow) && Tok.isNot(tok::arrowstar) && - Tok.isNot(tok::less) && Tok.isNot(tok::greater) && - Tok.isNot(tok::slash) && Tok.isNot(tok::percent) && - Tok.isNot(tok::lessless) && Tok.isNot(tok::greatergreater) && - Tok.isNot(tok::equal) && Tok.isNot(tok::plusequal) && - Tok.isNot(tok::minusequal) && Tok.isNot(tok::starequal) && - Tok.isNot(tok::slashequal) && Tok.isNot(tok::percentequal) && - Tok.isNot(tok::ampequal) && Tok.isNot(tok::pipeequal) && - Tok.isNot(tok::caretequal) && Tok.isNot(tok::greatergreaterequal) && - Tok.isNot(tok::lesslessequal) && + Tok->isNot(tok::period) && Tok->isNot(tok::periodstar) && + Tok->isNot(tok::arrow) && Tok->isNot(tok::arrowstar) && + Tok->isNot(tok::less) && Tok->isNot(tok::greater) && + Tok->isNot(tok::slash) && Tok->isNot(tok::percent) && + Tok->isNot(tok::lessless) && Tok->isNot(tok::greatergreater) && + Tok->isNot(tok::equal) && Tok->isNot(tok::plusequal) && + Tok->isNot(tok::minusequal) && Tok->isNot(tok::starequal) && + Tok->isNot(tok::slashequal) && Tok->isNot(tok::percentequal) && + Tok->isNot(tok::ampequal) && Tok->isNot(tok::pipeequal) && + Tok->isNot(tok::caretequal) && Tok->isNot(tok::greatergreaterequal) && + Tok->isNot(tok::lesslessequal) && // Colon is used in labels, base class lists, initializer lists, // range-based for loops, ternary operator, but should never be the // first token in an unwrapped line. - Tok.isNot(tok::colon) && + Tok->isNot(tok::colon) && // 'noexcept' is a trailing annotation. - Tok.isNot(tok::kw_noexcept); + Tok->isNot(tok::kw_noexcept); } static bool mustBeJSIdent(const AdditionalKeywords &Keywords, @@ -1441,7 +1441,7 @@ : CommentsBeforeNextToken.front()->NewlinesBefore > 0; if (FollowedByNewline && (Text.size() >= 5 || FunctionLike) && - tokenCanStartNewLine(FormatTok->Tok) && Text == Text.upper()) { + tokenCanStartNewLine(FormatTok) && Text == Text.upper()) { addUnwrappedLine(); return; }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits