diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index ccc59cd6fc1959..6c5556a9439178 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -2301,6 +2301,10 @@ the configuration (without a prefix: ``Auto``). **PenaltyExcessCharacter** (``unsigned``) The penalty for each character outside of the column limit. +**PenaltyIndentedWhitespace** (``unsigned``) + Penalty for each character of whitespace indentation + (counted relative to leading non-whitespace column). + **PenaltyReturnTypeOnItsOwnLine** (``unsigned``) Penalty for putting the return type of a function onto its own line. diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index 587e588525dfaf..dab4cbbbdfe1c1 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -1913,6 +1913,10 @@ struct FormatStyle { /// line. unsigned PenaltyReturnTypeOnItsOwnLine; + /// Penalty for each character of whitespace indentation + /// (counted relative to leading non-whitespace column). + unsigned PenaltyIndentedWhitespace; + /// The ``&`` and ``*`` alignment style. enum PointerAlignmentStyle { /// Align pointer to the left. diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp index d811f0f9e531b0..9db42b6c4a708c 100644 --- a/clang/lib/Format/ContinuationIndenter.cpp +++ b/clang/lib/Format/ContinuationIndenter.cpp @@ -785,6 +785,22 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State, State.Column = getNewLineColumn(State); + // Add Penalty proportional to amount of whitespace away from FirstColumn + // This tends to penalize several lines that are far-right indented, + // and prefers a line-break prior to such a block, e.g: + // + // Constructor() : + // member(value), looooooooooooooooong_member( + // looooooooooong_call(param_1, param_2, param_3)) + // would then become + // Constructor() : + // member(value), + // looooooooooooooooong_member( + // looooooooooong_call(param_1, param_2, param_3)) + if (State.Column > State.FirstIndent) + Penalty += + Style.PenaltyIndentedWhitespace * (State.Column - State.FirstIndent); + // Indent nested blocks relative to this column, unless in a very specific // JavaScript special case where: // diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 1c566c9ea49d47..235621c4f9aa82 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -590,6 +590,8 @@ template <> struct MappingTraits { IO.mapOptional("PenaltyExcessCharacter", Style.PenaltyExcessCharacter); IO.mapOptional("PenaltyReturnTypeOnItsOwnLine", Style.PenaltyReturnTypeOnItsOwnLine); + IO.mapOptional("PenaltyIndentedWhitespace", + Style.PenaltyIndentedWhitespace); IO.mapOptional("PointerAlignment", Style.PointerAlignment); IO.mapOptional("RawStringFormats", Style.RawStringFormats); IO.mapOptional("ReflowComments", Style.ReflowComments); @@ -968,6 +970,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.PenaltyReturnTypeOnItsOwnLine = 60; LLVMStyle.PenaltyBreakBeforeFirstCallParameter = 19; LLVMStyle.PenaltyBreakTemplateDeclaration = prec::Relational; + LLVMStyle.PenaltyIndentedWhitespace = 0; LLVMStyle.DisableFormat = false; LLVMStyle.SortIncludes = true; diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index 3d4e3e445c780c..7addb5220ae772 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -17214,6 +17214,28 @@ TEST_F(FormatTest, LikelyUnlikely) { Style); } +TEST_F(FormatTest, PenaltyIndentedWhitespace) { + verifyFormat("Constructor()\n" + " : aaaaaa(aaaaaa), aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n" + " aaaa(aaaaaaaaaaaaaaaaaa, " + "aaaaaaaaaaaaaaaaaat))"); + verifyFormat("Constructor()\n" + " : aaaaaaaaaaaaa(aaaaaa), " + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaa)"); + + FormatStyle StyleWithWhitespacePenalty = getLLVMStyle(); + StyleWithWhitespacePenalty.PenaltyIndentedWhitespace = 5; + verifyFormat("Constructor()\n" + " : aaaaaa(aaaaaa),\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n" + " aaaa(aaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaat))", + StyleWithWhitespacePenalty); + verifyFormat("Constructor()\n" + " : aaaaaaaaaaaaa(aaaaaa), " + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaa)", + StyleWithWhitespacePenalty); +} + TEST_F(FormatTest, LLVMDefaultStyle) { FormatStyle Style = getLLVMStyle(); verifyFormat("extern \"C\" {\n"