From ce1a053126fcdb70c8bcacdec83b7f2e9786515e Mon Sep 17 00:00:00 2001 From: Hannes Braun Date: Wed, 22 Oct 2025 21:05:04 +0200 Subject: [PATCH] [clang-format] Fix brace wrapping for Java records The brace wrapping for Java records should now behave similar to classes. --- clang/lib/Format/UnwrappedLineFormatter.cpp | 8 +++++--- clang/lib/Format/UnwrappedLineParser.cpp | 12 ++++++++---- clang/unittests/Format/FormatTestJava.cpp | 13 +++++++++++++ 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp index ac9c81d4416c9..d31d656a63fc5 100644 --- a/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -285,7 +285,8 @@ class LineJoiner { if (Tok && Tok->is(tok::kw_typedef)) Tok = Tok->getNextNonComment(); if (Tok && Tok->isOneOf(tok::kw_class, tok::kw_struct, tok::kw_union, - tok::kw_extern, Keywords.kw_interface)) { + tok::kw_extern, Keywords.kw_interface, + Keywords.kw_record)) { return !Style.BraceWrapping.SplitEmptyRecord && EmptyBlock ? tryMergeSimpleBlock(I, E, Limit) : 0; @@ -498,7 +499,8 @@ class LineJoiner { ShouldMerge = Style.AllowShortEnumsOnASingleLine; } else if (TheLine->Last->is(TT_CompoundRequirementLBrace)) { ShouldMerge = Style.AllowShortCompoundRequirementOnASingleLine; - } else if (TheLine->Last->isOneOf(TT_ClassLBrace, TT_StructLBrace)) { + } else if (TheLine->Last->isOneOf(TT_ClassLBrace, TT_StructLBrace, + TT_RecordLBrace)) { // NOTE: We use AfterClass (whereas AfterStruct exists) for both classes // and structs, but it seems that wrapping is still handled correctly // elsewhere. @@ -507,7 +509,7 @@ class LineJoiner { !Style.BraceWrapping.SplitEmptyRecord); } else if (TheLine->InPPDirective || TheLine->First->isNoneOf(tok::kw_class, tok::kw_enum, - tok::kw_struct)) { + tok::kw_struct, Keywords.kw_record)) { // Try to merge a block with left brace unwrapped that wasn't yet // covered. ShouldMerge = !Style.BraceWrapping.AfterFunction || diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index 5e2584edac8f4..8b7dd02d548af 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -948,7 +948,11 @@ static bool isIIFE(const UnwrappedLine &Line, } static bool ShouldBreakBeforeBrace(const FormatStyle &Style, - const FormatToken &InitialToken) { + const FormatToken &InitialToken, + const bool IsJavaRecord) { + if (IsJavaRecord) + return Style.BraceWrapping.AfterClass; + tok::TokenKind Kind = InitialToken.Tok.getKind(); if (InitialToken.is(TT_NamespaceMacro)) Kind = tok::kw_namespace; @@ -3200,7 +3204,7 @@ void UnwrappedLineParser::parseNamespace() { if (FormatTok->is(tok::l_brace)) { FormatTok->setFinalizedType(TT_NamespaceLBrace); - if (ShouldBreakBeforeBrace(Style, InitialToken)) + if (ShouldBreakBeforeBrace(Style, InitialToken, /*IsJavaRecord=*/false)) addUnwrappedLine(); unsigned AddLevels = @@ -3865,7 +3869,7 @@ bool UnwrappedLineParser::parseEnum() { } if (!Style.AllowShortEnumsOnASingleLine && - ShouldBreakBeforeBrace(Style, InitialToken)) { + ShouldBreakBeforeBrace(Style, InitialToken, /*IsJavaRecord=*/false)) { addUnwrappedLine(); } // Parse enum body. @@ -4160,7 +4164,7 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr, bool IsJavaRecord) { if (ParseAsExpr) { parseChildBlock(); } else { - if (ShouldBreakBeforeBrace(Style, InitialToken)) + if (ShouldBreakBeforeBrace(Style, InitialToken, IsJavaRecord)) addUnwrappedLine(); unsigned AddLevels = Style.IndentAccessModifiers ? 2u : 1u; diff --git a/clang/unittests/Format/FormatTestJava.cpp b/clang/unittests/Format/FormatTestJava.cpp index 1416614bae29a..3cc97e2dc0b2e 100644 --- a/clang/unittests/Format/FormatTestJava.cpp +++ b/clang/unittests/Format/FormatTestJava.cpp @@ -848,6 +848,19 @@ TEST_F(FormatTestJava, TextBlock) { " Pat Q. Smith"); } +TEST_F(FormatTestJava, BreakAfterRecord) { + auto Style = getLLVMStyle(FormatStyle::LK_Java); + Style.EmptyLineBeforeAccessModifier = FormatStyle::ELBAMS_Never; + Style.BreakBeforeBraces = FormatStyle::BS_Custom; + Style.BraceWrapping.AfterClass = true; + Style.BraceWrapping.SplitEmptyRecord = true; + + verifyFormat("public record Foo(int i)\n" + "{\n" + "}", + "public record Foo(int i) {}", Style); +} + } // namespace } // namespace test } // namespace format