diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index dc34094b5053a9..2991f8697a90aa 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -380,6 +380,29 @@ the configuration (without a prefix: ``Auto``). /* A comment. */ double e = 4; + * ``bool AlignBlockComments`` Only for ``AlignConsecutiveDeclarations``. Whether block comments + are aligned in declarations. + + .. code-block:: c++ + + true: + bool someLongFunction(int /*a*/, + bool b, + const std::string& c); + + const bool ret = someLongFunction(4 /*a*/, + true /*b*/, + str /*c*/); + + false: + bool someLongFunction(int /*a*/, + bool b, + const std::string& c); + + const bool ret = someLongFunction(4 /*a*/, + true /*b*/, + str /*c*/); + * ``bool AlignCompound`` Only for ``AlignConsecutiveAssignments``. Whether compound assignments like ``+=`` are aligned along with ``=``. @@ -538,6 +561,29 @@ the configuration (without a prefix: ``Auto``). /* A comment. */ double e = 4; + * ``bool AlignBlockComments`` Only for ``AlignConsecutiveDeclarations``. Whether block comments + are aligned in declarations. + + .. code-block:: c++ + + true: + bool someLongFunction(int /*a*/, + bool b, + const std::string& c); + + const bool ret = someLongFunction(4 /*a*/, + true /*b*/, + str /*c*/); + + false: + bool someLongFunction(int /*a*/, + bool b, + const std::string& c); + + const bool ret = someLongFunction(4 /*a*/, + true /*b*/, + str /*c*/); + * ``bool AlignCompound`` Only for ``AlignConsecutiveAssignments``. Whether compound assignments like ``+=`` are aligned along with ``=``. @@ -696,6 +742,29 @@ the configuration (without a prefix: ``Auto``). /* A comment. */ double e = 4; + * ``bool AlignBlockComments`` Only for ``AlignConsecutiveDeclarations``. Whether block comments + are aligned in declarations. + + .. code-block:: c++ + + true: + bool someLongFunction(int /*a*/, + bool b, + const std::string& c); + + const bool ret = someLongFunction(4 /*a*/, + true /*b*/, + str /*c*/); + + false: + bool someLongFunction(int /*a*/, + bool b, + const std::string& c); + + const bool ret = someLongFunction(4 /*a*/, + true /*b*/, + str /*c*/); + * ``bool AlignCompound`` Only for ``AlignConsecutiveAssignments``. Whether compound assignments like ``+=`` are aligned along with ``=``. @@ -855,6 +924,29 @@ the configuration (without a prefix: ``Auto``). /* A comment. */ double e = 4; + * ``bool AlignBlockComments`` Only for ``AlignConsecutiveDeclarations``. Whether block comments + are aligned in declarations. + + .. code-block:: c++ + + true: + bool someLongFunction(int /*a*/, + bool b, + const std::string& c); + + const bool ret = someLongFunction(4 /*a*/, + true /*b*/, + str /*c*/); + + false: + bool someLongFunction(int /*a*/, + bool b, + const std::string& c); + + const bool ret = someLongFunction(4 /*a*/, + true /*b*/, + str /*c*/); + * ``bool AlignCompound`` Only for ``AlignConsecutiveAssignments``. Whether compound assignments like ``+=`` are aligned along with ``=``. @@ -1133,6 +1225,29 @@ the configuration (without a prefix: ``Auto``). /* A comment. */ double e = 4; + * ``bool AlignBlockComments`` Only for ``AlignConsecutiveDeclarations``. Whether block comments + are aligned in declarations. + + .. code-block:: c++ + + true: + bool someLongFunction(int /*a*/, + bool b, + const std::string& c); + + const bool ret = someLongFunction(4 /*a*/, + true /*b*/, + str /*c*/); + + false: + bool someLongFunction(int /*a*/, + bool b, + const std::string& c); + + const bool ret = someLongFunction(4 /*a*/, + true /*b*/, + str /*c*/); + * ``bool AlignCompound`` Only for ``AlignConsecutiveAssignments``. Whether compound assignments like ``+=`` are aligned along with ``=``. @@ -1289,6 +1404,29 @@ the configuration (without a prefix: ``Auto``). /* A comment. */ double e = 4; + * ``bool AlignBlockComments`` Only for ``AlignConsecutiveDeclarations``. Whether block comments + are aligned in declarations. + + .. code-block:: c++ + + true: + bool someLongFunction(int /*a*/, + bool b, + const std::string& c); + + const bool ret = someLongFunction(4 /*a*/, + true /*b*/, + str /*c*/); + + false: + bool someLongFunction(int /*a*/, + bool b, + const std::string& c); + + const bool ret = someLongFunction(4 /*a*/, + true /*b*/, + str /*c*/); + * ``bool AlignCompound`` Only for ``AlignConsecutiveAssignments``. Whether compound assignments like ``+=`` are aligned along with ``=``. @@ -1445,6 +1583,29 @@ the configuration (without a prefix: ``Auto``). /* A comment. */ double e = 4; + * ``bool AlignBlockComments`` Only for ``AlignConsecutiveDeclarations``. Whether block comments + are aligned in declarations. + + .. code-block:: c++ + + true: + bool someLongFunction(int /*a*/, + bool b, + const std::string& c); + + const bool ret = someLongFunction(4 /*a*/, + true /*b*/, + str /*c*/); + + false: + bool someLongFunction(int /*a*/, + bool b, + const std::string& c); + + const bool ret = someLongFunction(4 /*a*/, + true /*b*/, + str /*c*/); + * ``bool AlignCompound`` Only for ``AlignConsecutiveAssignments``. Whether compound assignments like ``+=`` are aligned along with ``=``. diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 999c88455b64a5..e0e6ac33d85ca9 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -901,6 +901,7 @@ clang-format ``Never``, and ``true`` to ``Always``. - Adds ``RemoveEmptyLinesInUnwrappedLines`` option. - Adds ``KeepFormFeed`` option and set it to ``true`` for ``GNU`` style. +- Adds ``AlignBlockComments`` option. libclang -------- diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index ea6b414618c1d0..1827375aceb1bf 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -214,6 +214,28 @@ struct FormatStyle { /// double e = 4; /// \endcode bool AcrossComments; + /// Only for ``AlignConsecutiveDeclarations``. Whether block comments + /// are aligned in declarations. + /// \code + /// true: + /// bool someLongFunction(int /*a*/, + /// bool b, + /// const std::string& c); + /// + /// const bool ret = someLongFunction(4 /*a*/, + /// true /*b*/, + /// str /*c*/); + /// + /// false: + /// bool someLongFunction(int /*a*/, + /// bool b, + /// const std::string& c); + /// + /// const bool ret = someLongFunction(4 /*a*/, + /// true /*b*/, + /// str /*c*/); + /// \endcode + bool AlignBlockComments; /// Only for ``AlignConsecutiveAssignments``. Whether compound assignments /// like ``+=`` are aligned along with ``=``. /// \code @@ -278,6 +300,7 @@ struct FormatStyle { bool operator==(const AlignConsecutiveStyle &R) const { return Enabled == R.Enabled && AcrossEmptyLines == R.AcrossEmptyLines && AcrossComments == R.AcrossComments && + AlignBlockComments == R.AlignBlockComments && AlignCompound == R.AlignCompound && AlignFunctionDeclarations == R.AlignFunctionDeclarations && AlignFunctionPointers == R.AlignFunctionPointers && diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 0cf4cdbeab31f3..dca001f50e8b0e 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -48,35 +48,50 @@ template <> struct MappingTraits { IO.enumCase(Value, "Consecutive", FormatStyle::AlignConsecutiveStyle( {/*Enabled=*/true, /*AcrossEmptyLines=*/false, - /*AcrossComments=*/false, /*AlignCompound=*/false, + /*AcrossComments=*/false, + /*AlignBlockComments=*/false, + /*AlignCompound=*/false, /*AlignFunctionDeclarations=*/true, - /*AlignFunctionPointers=*/false, /*PadOperators=*/true})); + /*AlignFunctionPointers=*/false, + /*PadOperators=*/true})); IO.enumCase(Value, "AcrossEmptyLines", FormatStyle::AlignConsecutiveStyle( {/*Enabled=*/true, /*AcrossEmptyLines=*/true, - /*AcrossComments=*/false, /*AlignCompound=*/false, + /*AcrossComments=*/false, + /*AlignBlockComments=*/false, + /*AlignCompound=*/false, /*AlignFunctionDeclarations=*/true, - /*AlignFunctionPointers=*/false, /*PadOperators=*/true})); + /*AlignFunctionPointers=*/false, + /*PadOperators=*/true})); IO.enumCase(Value, "AcrossComments", FormatStyle::AlignConsecutiveStyle( {/*Enabled=*/true, /*AcrossEmptyLines=*/false, - /*AcrossComments=*/true, /*AlignCompound=*/false, + /*AcrossComments=*/true, + /*AlignBlockComments=*/false, + /*AlignCompound=*/false, /*AlignFunctionDeclarations=*/true, - /*AlignFunctionPointers=*/false, /*PadOperators=*/true})); + /*AlignFunctionPointers=*/false, + /*PadOperators=*/true})); IO.enumCase(Value, "AcrossEmptyLinesAndComments", FormatStyle::AlignConsecutiveStyle( {/*Enabled=*/true, /*AcrossEmptyLines=*/true, - /*AcrossComments=*/true, /*AlignCompound=*/false, + /*AcrossComments=*/true, + /*AlignBlockComments=*/false, + /*AlignCompound=*/false, /*AlignFunctionDeclarations=*/true, - /*AlignFunctionPointers=*/false, /*PadOperators=*/true})); + /*AlignFunctionPointers=*/false, + /*PadOperators=*/true})); // For backward compatibility. IO.enumCase(Value, "true", FormatStyle::AlignConsecutiveStyle( {/*Enabled=*/true, /*AcrossEmptyLines=*/false, - /*AcrossComments=*/false, /*AlignCompound=*/false, + /*AcrossComments=*/false, + /*AlignBlockComments=*/false, + /*AlignCompound=*/false, /*AlignFunctionDeclarations=*/true, - /*AlignFunctionPointers=*/false, /*PadOperators=*/true})); + /*AlignFunctionPointers=*/false, + /*PadOperators=*/true})); IO.enumCase(Value, "false", FormatStyle::AlignConsecutiveStyle({})); } @@ -84,6 +99,7 @@ template <> struct MappingTraits { IO.mapOptional("Enabled", Value.Enabled); IO.mapOptional("AcrossEmptyLines", Value.AcrossEmptyLines); IO.mapOptional("AcrossComments", Value.AcrossComments); + IO.mapOptional("AlignBlockComments", Value.AlignBlockComments); IO.mapOptional("AlignCompound", Value.AlignCompound); IO.mapOptional("AlignFunctionDeclarations", Value.AlignFunctionDeclarations); diff --git a/clang/lib/Format/WhitespaceManager.cpp b/clang/lib/Format/WhitespaceManager.cpp index b1e43f0313dbfe..48f677fcf96176 100644 --- a/clang/lib/Format/WhitespaceManager.cpp +++ b/clang/lib/Format/WhitespaceManager.cpp @@ -1005,6 +1005,12 @@ void WhitespaceManager::alignConsecutiveTableGenDefinitions() { TT_InheritanceColon); } +static bool shouldAlignBlockComment(const FormatToken &Tok) { + return Tok.is(TT_BlockComment) && Tok.Previous && + !Tok.Previous->isOneOf(TT_StartOfName, TT_BlockComment) && Tok.Next && + Tok.Next->isOneOf(tok::comma, tok::r_paren, TT_BlockComment); +} + void WhitespaceManager::alignConsecutiveDeclarations() { if (!Style.AlignConsecutiveDeclarations.Enabled) return; @@ -1022,7 +1028,10 @@ void WhitespaceManager::alignConsecutiveDeclarations() { if (C.Tok->is(TT_FunctionDeclarationName)) return Style.AlignConsecutiveDeclarations.AlignFunctionDeclarations; if (C.Tok->isNot(TT_StartOfName)) - return false; + if (!Style.AlignConsecutiveDeclarations.AlignBlockComments || + !shouldAlignBlockComment(*C.Tok)) { + return false; + } if (C.Tok->Previous && C.Tok->Previous->is(TT_StatementAttributeLikeMacro)) return false; diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp index 7fc7492271668b..f84b78863efc9b 100644 --- a/clang/unittests/Format/ConfigParseTest.cpp +++ b/clang/unittests/Format/ConfigParseTest.cpp @@ -307,29 +307,29 @@ TEST(ConfigParseTest, ParsesConfiguration) { #FIELD ": Consecutive", FIELD, \ FormatStyle::AlignConsecutiveStyle( \ {/*Enabled=*/true, /*AcrossEmptyLines=*/false, \ - /*AcrossComments=*/false, /*AlignCompound=*/false, \ - /*AlignFunctionDeclarations=*/true, \ + /*AcrossComments=*/false, /*AlignBlockComments=*/false, \ + /*AlignCompound=*/false, /*AlignFunctionDeclarations=*/true, \ /*AlignFunctionPointers=*/false, /*PadOperators=*/true})); \ CHECK_PARSE( \ #FIELD ": AcrossEmptyLines", FIELD, \ FormatStyle::AlignConsecutiveStyle( \ {/*Enabled=*/true, /*AcrossEmptyLines=*/true, \ - /*AcrossComments=*/false, /*AlignCompound=*/false, \ - /*AlignFunctionDeclarations=*/true, \ + /*AcrossComments=*/false, /*AlignBlockComments=*/false, \ + /*AlignCompound=*/false, /*AlignFunctionDeclarations=*/true, \ /*AlignFunctionPointers=*/false, /*PadOperators=*/true})); \ CHECK_PARSE( \ #FIELD ": AcrossComments", FIELD, \ FormatStyle::AlignConsecutiveStyle( \ {/*Enabled=*/true, /*AcrossEmptyLines=*/false, \ - /*AcrossComments=*/true, /*AlignCompound=*/false, \ - /*AlignFunctionDeclarations=*/true, \ + /*AcrossComments=*/true, /*AlignBlockComments=*/false, \ + /*AlignCompound=*/false, /*AlignFunctionDeclarations=*/true, \ /*AlignFunctionPointers=*/false, /*PadOperators=*/true})); \ CHECK_PARSE( \ #FIELD ": AcrossEmptyLinesAndComments", FIELD, \ FormatStyle::AlignConsecutiveStyle( \ {/*Enabled=*/true, /*AcrossEmptyLines=*/true, \ - /*AcrossComments=*/true, /*AlignCompound=*/false, \ - /*AlignFunctionDeclarations=*/true, \ + /*AcrossComments=*/true, /*AlignBlockComments=*/false, \ + /*AlignCompound=*/false, /*AlignFunctionDeclarations=*/true, \ /*AlignFunctionPointers=*/false, /*PadOperators=*/true})); \ /* For backwards compability, false / true should still parse */ \ CHECK_PARSE(#FIELD ": false", FIELD, \ @@ -337,14 +337,15 @@ TEST(ConfigParseTest, ParsesConfiguration) { CHECK_PARSE( \ #FIELD ": true", FIELD, \ FormatStyle::AlignConsecutiveStyle( \ - {/*Enabled=*/true, /*AcrossEmptyLines=*/false, \ - /*AcrossComments=*/false, /*AlignCompound=*/false, \ - /*AlignFunctionDeclarations=*/true, \ + {/*Enabled=*/true, /*AlignBlockComments=*/false, \ + /*AcrossEmptyLines=*/false, /*AcrossComments=*/false, \ + /*AlignCompound=*/false, /*AlignFunctionDeclarations=*/true, \ /*AlignFunctionPointers=*/false, /*PadOperators=*/true})); \ \ CHECK_PARSE_NESTED_BOOL(FIELD, Enabled); \ CHECK_PARSE_NESTED_BOOL(FIELD, AcrossEmptyLines); \ CHECK_PARSE_NESTED_BOOL(FIELD, AcrossComments); \ + CHECK_PARSE_NESTED_BOOL(FIELD, AlignBlockComments); \ CHECK_PARSE_NESTED_BOOL(FIELD, AlignCompound); \ CHECK_PARSE_NESTED_BOOL(FIELD, AlignFunctionDeclarations); \ CHECK_PARSE_NESTED_BOOL(FIELD, AlignFunctionPointers); \ diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index 250e51b5421664..6ace1a6e534cb5 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -20030,6 +20030,52 @@ TEST_F(FormatTest, AlignConsecutiveDeclarations) { Alignment); } +TEST_F(FormatTest, AlignConsecutiveDeclarationsBlockComments) { + auto Style = getLLVMStyle(); + Style.AlignConsecutiveDeclarations.Enabled = true; + Style.AlignConsecutiveDeclarations.AlignBlockComments = true; + Style.BinPackParameters = FormatStyle::BPPS_OnePerLine; + Style.BinPackArguments = false; + + verifyFormat( + "bool SomeLongMethodName(int longParameterNameA,\n" + " bool /*longParameterNameB*/,\n" + " const std::string &longParameterNameC);", + "bool SomeLongMethodName(int longParameterNameA,\n" + " bool /*longParameterNameB*/,\n" + " const std::string &longParameterNameC);", + Style); + + verifyFormat( + "const bool ret = SomeLongMethodName(4 /*parameterNameA*/,\n" + " true /*longParameterNameB*/,\n" + " str /*longestParameterNameC*/);", + "const bool ret = SomeLongMethodName(4 /*parameterNameA*/,\n" + " true /*longParameterNameB*/,\n" + " str /*longestParameterNameC*/);", + Style); + + verifyNoChange("/*,\n" + "This is a multi-line block comment.\n" + "That is not part of a function declaration.\n" + "*/\n" + "static void SomeLongMethodName()", + Style); + + verifyNoChange("static const unsigned int c_cMediaEntranceEntries = 31;\n" + "static const unsigned int c_cMediaEmphasisEntries = 4 /* " + "media effects */ + 12;\n" + "static const unsigned int c_cMediaExitEntries = 32;", + Style); + + verifyNoChange( + "static bool SomeLongMethodName(int longParameterNameA,\n" + " bool longParameterNameB " + "/*=false*/,\n" + " std::string &longParameterNameC);", + Style); +} + TEST_F(FormatTest, AlignConsecutiveShortCaseStatements) { FormatStyle Alignment = getLLVMStyle(); Alignment.AllowShortCaseLabelsOnASingleLine = true; @@ -20270,14 +20316,16 @@ TEST_F(FormatTest, AlignWithLineBreaks) { EXPECT_EQ(Style.AlignConsecutiveAssignments, FormatStyle::AlignConsecutiveStyle( {/*Enabled=*/false, /*AcrossEmptyLines=*/false, - /*AcrossComments=*/false, /*AlignCompound=*/false, + /*AcrossComments=*/false, /*AlignBlockComments=*/false, + /*AlignCompound=*/false, /*AlignFunctionDeclarations=*/false, /*AlignFunctionPointers=*/false, /*PadOperators=*/true})); EXPECT_EQ(Style.AlignConsecutiveDeclarations, FormatStyle::AlignConsecutiveStyle( {/*Enabled=*/false, /*AcrossEmptyLines=*/false, - /*AcrossComments=*/false, /*AlignCompound=*/false, + /*AcrossComments=*/false, /*AlignBlockComments=*/false, + /*AlignCompound=*/false, /*AlignFunctionDeclarations=*/true, /*AlignFunctionPointers=*/false, /*PadOperators=*/false}));