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

Reply via email to