From 307e0914ac6c51b7ed461dbd8d66a3c3c02b5b61 Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Thu, 24 Sep 2026 22:46:29 +0300 Subject: [PATCH] Keep the space between a unary minus and a negative literal javac folds a minus in front of a decimal literal into the literal itself, so "- -1" parses as one unary minus applied to the literal "-1". The check that keeps a space between two prefix operators only looked for a nested unary expression, so the output was "--1": the decrement operator on a literal, which does not compile. "- -x" was fine, the literal case was not. This ports google/google-java-format#576 by Liam Miller-Cushon: a literal whose source starts with "-" counts as a unary minus in that check. The golden B183431894 comes from upstream, with the expected output in this project's style. The 15,747 files of the JDK 21 sources format exactly as before. --- .../javaformat/java/JavaInputAstVisitor.java | 29 ++++++++++++++----- .../javaformat/java/testdata/B183431894.input | 4 +++ .../java/testdata/B183431894.output | 4 +++ 3 files changed, 30 insertions(+), 7 deletions(-) create mode 100644 open-java-format/src/test/resources/com/palantir/javaformat/java/testdata/B183431894.input create mode 100644 open-java-format/src/test/resources/com/palantir/javaformat/java/testdata/B183431894.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 0fd3569d8..62b334807 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 @@ -1663,11 +1663,7 @@ public Void visitMemberSelect(MemberSelectTree node, Void unused) { public Void visitLiteral(LiteralTree node, Void unused) { sync(node); String sourceForNode = getSourceForNode(node, getCurrentPath()); - // A negative numeric literal -n is usually represented as unary minus on n, - // but that doesn't work for integer or long MIN_VALUE. The parser works - // around that by representing it directly as a signed literal (with no - // unary minus), but the lexer still expects two tokens. - if (sourceForNode.startsWith("-")) { + if (isUnaryMinusLiteral(sourceForNode)) { token("-"); sourceForNode = sourceForNode.substring(1).trim(); } @@ -1675,6 +1671,14 @@ public Void visitLiteral(LiteralTree node, Void unused) { return null; } + // A negative numeric literal -n is usually represented as unary minus on n, + // but that doesn't work for integer or long MIN_VALUE. The parser works + // around that by representing it directly as a signed literal (with no + // unary minus), but the lexer still expects two tokens. + private static boolean isUnaryMinusLiteral(String literalTreeSource) { + return literalTreeSource.startsWith("-"); + } + private void visitPackage(ExpressionTree packageName, List packageAnnotations) { if (!packageAnnotations.isEmpty()) { for (AnnotationTree annotation : packageAnnotations) { @@ -1759,10 +1763,10 @@ private boolean ambiguousUnaryOperator(UnaryTree node, String operatorName) { default: return false; } - if (!(node.getExpression() instanceof UnaryTree)) { + JCTree.Tag tag = unaryTag(node.getExpression()); + if (tag == null) { return false; } - JCTree.Tag tag = ((JCTree) node.getExpression()).getTag(); if (tag.isPostUnaryOp()) { return false; } @@ -1772,6 +1776,17 @@ private boolean ambiguousUnaryOperator(UnaryTree node, String operatorName) { return true; } + private JCTree.Tag unaryTag(ExpressionTree expression) { + if (expression instanceof UnaryTree) { + return ((JCTree) expression).getTag(); + } + if (expression instanceof LiteralTree + && isUnaryMinusLiteral(getSourceForNode(expression, getCurrentPath()))) { + return JCTree.Tag.MINUS; + } + return null; + } + @Override public Void visitPrimitiveType(PrimitiveTypeTree node, Void unused) { sync(node); diff --git a/open-java-format/src/test/resources/com/palantir/javaformat/java/testdata/B183431894.input b/open-java-format/src/test/resources/com/palantir/javaformat/java/testdata/B183431894.input new file mode 100644 index 000000000..7c220d519 --- /dev/null +++ b/open-java-format/src/test/resources/com/palantir/javaformat/java/testdata/B183431894.input @@ -0,0 +1,4 @@ +class B183431894 { + int a = - -1; + int d = + +1; +} diff --git a/open-java-format/src/test/resources/com/palantir/javaformat/java/testdata/B183431894.output b/open-java-format/src/test/resources/com/palantir/javaformat/java/testdata/B183431894.output new file mode 100644 index 000000000..2250359ba --- /dev/null +++ b/open-java-format/src/test/resources/com/palantir/javaformat/java/testdata/B183431894.output @@ -0,0 +1,4 @@ +class B183431894 { + int a = - -1; + int d = + +1; +}