From b58f5c6865a3849b98191b971c85c65d9e9f3d38 Mon Sep 17 00:00:00 2001 From: Alex Abashev Date: Fri, 25 Sep 2026 12:16:12 +0300 Subject: [PATCH 1/2] Measure the whole type of a cast before inlining a chain onto it In sun.rmi.transport.tcp.TCPTransport the cast (PrivilegedAction) came out cut between "<" and "String", with the lambda it applies to on a third line, while the call around it stayed on one line (#60): static final Log tcpLog = Log.getLog( "sun.rmi.transport.tcp", "tcp", LogStream.parseLevel(AccessController.doPrivileged((PrivilegedAction< String>) () -> System.getProperty("sun.rmi.transport.tcp.logLevel")))); The arguments of getLog are inlined when a prefix of the last one fits, and CountWidthUntilBreakVisitor measures that prefix up to the first break inside the last level. visitTypeCast declares its level ACCEPT_INLINE_CHAIN, which means that first break is the one before the operand. The first break was the one visitParameterizedType emits after "<", so the prefix ended at "(PrivilegedAction<", fit, and the type had to take the break because "String>)" did not fit behind it. A wildcard bound, an intersection type and an annotated type offer breaks of their own in the same place and split the same way. The cast's level now has PartialInlineability.IF_FIRST_LEVEL_FITS, what visitDotWithPrefix uses for the same purpose: the visitor counts the whole first inner level, which is the rest of the type up to the break before the operand, when it fits. A chain is inlined onto a cast only if the type fits behind it. Here it does not, the chain is not inlined, and the arguments break one per line, as they do when the type is not parameterized. The type stays breakable for a cast that does not fit on a line at all, so the golden C keeps its output. The golden holds the statement above, the same cast one call shallower, which fit and does not change, and a method reference, two type arguments, a wildcard bound, a qualified name, an intersection type and an annotated type in the cast. Of the 15,747 files of the JDK 21 sources, that one statement in TCPTransport is the only one that formats differently, and its new output is stable. --- .../javaformat/java/JavaInputAstVisitor.java | 16 +++++-- ...f-issue-60-cast-type-in-inline-chain.input | 33 +++++++++++++ ...-issue-60-cast-type-in-inline-chain.output | 47 +++++++++++++++++++ 3 files changed, 92 insertions(+), 4 deletions(-) create mode 100644 open-java-format/src/test/resources/com/palantir/javaformat/java/testdata/ojf-issue-60-cast-type-in-inline-chain.input create mode 100644 open-java-format/src/test/resources/com/palantir/javaformat/java/testdata/ojf-issue-60-cast-type-in-inline-chain.output diff --git a/open-java-format/src/main/java/com/palantir/javaformat/java/JavaInputAstVisitor.java b/open-java-format/src/main/java/com/palantir/javaformat/java/JavaInputAstVisitor.java index 4eb5b00ef..5f51b33ee 100644 --- a/open-java-format/src/main/java/com/palantir/javaformat/java/JavaInputAstVisitor.java +++ b/open-java-format/src/main/java/com/palantir/javaformat/java/JavaInputAstVisitor.java @@ -678,10 +678,18 @@ public Void visitBreak(BreakTree node, Void unused) { @Override public Void visitTypeCast(TypeCastTree node, Void unused) { sync(node); - builder.open( - plusFour, - BreakBehaviours.preferBreakingLastInnerLevel(true), - LastLevelBreakability.ACCEPT_INLINE_CHAIN); + // An inline chain that ends at this level must have room for the whole type before the break in front of the + // operand. Without IF_FIRST_LEVEL_FITS the chain measured the type up to its first break, the one after the + // "<" of a parameterized type, and once inlined the type itself had to take that break: "(PrivilegedAction<" + // at the end of one line and "String>)" on the next. The type stays breakable for the rare cast that does not + // fit on a line at all. + builder.open(OpenOp.builder() + .debugName("typeCast") + .plusIndent(plusFour) + .breakBehaviour(BreakBehaviours.preferBreakingLastInnerLevel(true)) + .breakabilityIfLastLevel(LastLevelBreakability.ACCEPT_INLINE_CHAIN) + .partialInlineability(PartialInlineability.IF_FIRST_LEVEL_FITS) + .build()); token("("); scan(node.getType(), null); token(")"); diff --git a/open-java-format/src/test/resources/com/palantir/javaformat/java/testdata/ojf-issue-60-cast-type-in-inline-chain.input b/open-java-format/src/test/resources/com/palantir/javaformat/java/testdata/ojf-issue-60-cast-type-in-inline-chain.input new file mode 100644 index 000000000..d145ba61a --- /dev/null +++ b/open-java-format/src/test/resources/com/palantir/javaformat/java/testdata/ojf-issue-60-cast-type-in-inline-chain.input @@ -0,0 +1,33 @@ +class TCPTransport { + @SuppressWarnings("removal") + static final Log tcpLog = Log.getLog("sun.rmi.transport.tcp", "tcp", + LogStream.parseLevel(AccessController.doPrivileged( + (PrivilegedAction) () -> System.getProperty("sun.rmi.transport.tcp.logLevel")))); + + static final Level level = LogStream.parseLevel(AccessController.doPrivileged( + (PrivilegedAction) () -> System.getProperty("sun.rmi.transport.tcp.logLevel.and.some.more"))); + + static final Log methodReference = Log.getLog("sun.rmi.transport.tcp", "tcp", + LogStream.parseLevel(AccessController.doPrivileged( + (PrivilegedAction) SomeVeryLongClassNameToFillTheLine::getTheTcpLogLevelProperty))); + + static final Log twoTypeArguments = Log.getLog("sun.rmi.transport.tcp", "tcp", + LogStream.parseLevel(AccessController.doPrivileged( + (Function) s -> System.getProperty("sun.rmi.transport.tcp.logLevel.x")))); + + static final Log nested = Log.getLog("sun.rmi.transport.tcp", "tcp", + LogStream.parseLevel(AccessController.doPrivileged( + (Map>) () -> System.getProperty("sun.rmi.transport.tcp.lv")))); + + static final Log qualified = Log.getLog("sun.rmi.transport.tcp", "tcp", + LogStream.parseLevel(AccessController.doPrivileged( + (java.util.function.Function) s -> System.getProperty("sun.rmi.logLevel")))); + + static final Log intersection = Log.getLog("sun.rmi.transport.tcp", "tcp", + LogStream.parseLevel(AccessController.doPrivileged( + (Runnable & java.io.Serializable) () -> System.getProperty("sun.rmi.transport.tcp.logLevelxx")))); + + static final Log annotated = Log.getLog("sun.rmi.transport.tcp", "tcp", + LogStream.parseLevel(AccessController.doPrivileged( + (Function<@Nullable String, Integer[]>) s -> System.getProperty("sun.rmi.transport.tcp.lvl")))); +} diff --git a/open-java-format/src/test/resources/com/palantir/javaformat/java/testdata/ojf-issue-60-cast-type-in-inline-chain.output b/open-java-format/src/test/resources/com/palantir/javaformat/java/testdata/ojf-issue-60-cast-type-in-inline-chain.output new file mode 100644 index 000000000..c179a2667 --- /dev/null +++ b/open-java-format/src/test/resources/com/palantir/javaformat/java/testdata/ojf-issue-60-cast-type-in-inline-chain.output @@ -0,0 +1,47 @@ +class TCPTransport { + @SuppressWarnings("removal") + static final Log tcpLog = Log.getLog( + "sun.rmi.transport.tcp", + "tcp", + LogStream.parseLevel(AccessController.doPrivileged( + (PrivilegedAction) () -> System.getProperty("sun.rmi.transport.tcp.logLevel")))); + + static final Level level = LogStream.parseLevel(AccessController.doPrivileged( + (PrivilegedAction) () -> System.getProperty("sun.rmi.transport.tcp.logLevel.and.some.more"))); + + static final Log methodReference = Log.getLog( + "sun.rmi.transport.tcp", + "tcp", + LogStream.parseLevel(AccessController.doPrivileged( + (PrivilegedAction) SomeVeryLongClassNameToFillTheLine::getTheTcpLogLevelProperty))); + + static final Log twoTypeArguments = Log.getLog( + "sun.rmi.transport.tcp", + "tcp", + LogStream.parseLevel(AccessController.doPrivileged( + (Function) s -> System.getProperty("sun.rmi.transport.tcp.logLevel.x")))); + + static final Log nested = Log.getLog( + "sun.rmi.transport.tcp", + "tcp", + LogStream.parseLevel(AccessController.doPrivileged( + (Map>) () -> System.getProperty("sun.rmi.transport.tcp.lv")))); + + static final Log qualified = Log.getLog( + "sun.rmi.transport.tcp", + "tcp", + LogStream.parseLevel(AccessController.doPrivileged( + (java.util.function.Function) s -> System.getProperty("sun.rmi.logLevel")))); + + static final Log intersection = Log.getLog( + "sun.rmi.transport.tcp", + "tcp", + LogStream.parseLevel(AccessController.doPrivileged( + (Runnable & java.io.Serializable) () -> System.getProperty("sun.rmi.transport.tcp.logLevelxx")))); + + static final Log annotated = Log.getLog( + "sun.rmi.transport.tcp", + "tcp", + LogStream.parseLevel(AccessController.doPrivileged( + (Function<@Nullable String, Integer[]>) s -> System.getProperty("sun.rmi.transport.tcp.lvl")))); +} From d564203602963c0a625747c454f817fcefb5565b Mon Sep 17 00:00:00 2001 From: Alex Abashev Date: Fri, 25 Sep 2026 15:19:43 +0300 Subject: [PATCH 2/2] Give the cast golden an input that has to be laid out afresh The input was the wanted output with the arguments joined onto one line, so the golden checked little besides the chain. Each statement now arrives in a different shape: the first one as the broken output the fix removes, the others on one line, or split at the "::", inside the type arguments, after "&" or before the lambda, with stray spaces around "<", ",", "::", "->" and "[ ]". The expected output does not change, and main still formats the input differently. --- ...f-issue-60-cast-type-in-inline-chain.input | 45 ++++++++++--------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/open-java-format/src/test/resources/com/palantir/javaformat/java/testdata/ojf-issue-60-cast-type-in-inline-chain.input b/open-java-format/src/test/resources/com/palantir/javaformat/java/testdata/ojf-issue-60-cast-type-in-inline-chain.input index d145ba61a..ef55c2ccc 100644 --- a/open-java-format/src/test/resources/com/palantir/javaformat/java/testdata/ojf-issue-60-cast-type-in-inline-chain.input +++ b/open-java-format/src/test/resources/com/palantir/javaformat/java/testdata/ojf-issue-60-cast-type-in-inline-chain.input @@ -1,33 +1,36 @@ class TCPTransport { @SuppressWarnings("removal") - static final Log tcpLog = Log.getLog("sun.rmi.transport.tcp", "tcp", - LogStream.parseLevel(AccessController.doPrivileged( - (PrivilegedAction) () -> System.getProperty("sun.rmi.transport.tcp.logLevel")))); + static final Log tcpLog = Log.getLog( + "sun.rmi.transport.tcp", "tcp", LogStream.parseLevel(AccessController.doPrivileged((PrivilegedAction< + String>) + () -> System.getProperty("sun.rmi.transport.tcp.logLevel")))); - static final Level level = LogStream.parseLevel(AccessController.doPrivileged( - (PrivilegedAction) () -> System.getProperty("sun.rmi.transport.tcp.logLevel.and.some.more"))); + static final Level level = LogStream.parseLevel(AccessController.doPrivileged((PrivilegedAction)()->System.getProperty("sun.rmi.transport.tcp.logLevel.and.some.more"))); - static final Log methodReference = Log.getLog("sun.rmi.transport.tcp", "tcp", - LogStream.parseLevel(AccessController.doPrivileged( - (PrivilegedAction) SomeVeryLongClassNameToFillTheLine::getTheTcpLogLevelProperty))); + static final Log methodReference = Log.getLog("sun.rmi.transport.tcp", + "tcp", + LogStream.parseLevel( + AccessController.doPrivileged( + ( PrivilegedAction ) + SomeVeryLongClassNameToFillTheLine + :: getTheTcpLogLevelProperty))); - static final Log twoTypeArguments = Log.getLog("sun.rmi.transport.tcp", "tcp", - LogStream.parseLevel(AccessController.doPrivileged( - (Function) s -> System.getProperty("sun.rmi.transport.tcp.logLevel.x")))); + static final Log twoTypeArguments = + Log.getLog("sun.rmi.transport.tcp", "tcp", LogStream.parseLevel(AccessController.doPrivileged((Function< String ,Integer >) s-> + System.getProperty("sun.rmi.transport.tcp.logLevel.x")))); - static final Log nested = Log.getLog("sun.rmi.transport.tcp", "tcp", - LogStream.parseLevel(AccessController.doPrivileged( - (Map>) () -> System.getProperty("sun.rmi.transport.tcp.lv")))); + static final Log nested = Log.getLog("sun.rmi.transport.tcp", "tcp", LogStream.parseLevel(AccessController.doPrivileged((Map>) () -> System.getProperty("sun.rmi.transport.tcp.lv")))); static final Log qualified = Log.getLog("sun.rmi.transport.tcp", "tcp", - LogStream.parseLevel(AccessController.doPrivileged( - (java.util.function.Function) s -> System.getProperty("sun.rmi.logLevel")))); + LogStream.parseLevel(AccessController.doPrivileged((java.util.function. + Function) s -> System.getProperty("sun.rmi.logLevel")))); - static final Log intersection = Log.getLog("sun.rmi.transport.tcp", "tcp", - LogStream.parseLevel(AccessController.doPrivileged( - (Runnable & java.io.Serializable) () -> System.getProperty("sun.rmi.transport.tcp.logLevelxx")))); + static final Log intersection = Log.getLog("sun.rmi.transport.tcp", "tcp", LogStream.parseLevel( + AccessController.doPrivileged((Runnable + &java.io.Serializable) () -> System.getProperty("sun.rmi.transport.tcp.logLevelxx")))); static final Log annotated = Log.getLog("sun.rmi.transport.tcp", "tcp", - LogStream.parseLevel(AccessController.doPrivileged( - (Function<@Nullable String, Integer[]>) s -> System.getProperty("sun.rmi.transport.tcp.lvl")))); + LogStream.parseLevel(AccessController.doPrivileged((Function<@Nullable String, Integer [ ]>) + s -> System.getProperty("sun.rmi.transport.tcp.lvl")))); }