Skip to content

Commit 90d3a13

Browse files
committed
Use records for the formatter's plain value types
Six of the types Immutables generated in open-java-format were plain values: State's BreakState, LevelState and TokState, Level's SplitsBreaks, OpsBuilder's OpsOutput and InputMetadata. They are records now. The call sites use their constructors instead of builders and of(...) factories, and the accessors keep their names. InputMetadata keeps @immutable, which Error Prone now checks against the record's components instead of skipping a generated class. That needed BlankLineWanted to say it is immutable as well, and it is: its two subclasses hold an Optional<Boolean> and an ImmutableList<BreakTag>. OpenOp, Break and State stay on Immutables. OpenOp and Break extend HasUniqueId, whose per-instance id orders the formatter's persistent collections, and a record cannot extend a class. State copies itself through its builder in a dozen places. The 15,747 files of the JDK 21 sources format exactly as before.
1 parent 0e13e32 commit 90d3a13

6 files changed

Lines changed: 37 additions & 115 deletions

File tree

‎open-java-format/src/main/java/com/palantir/javaformat/OpsBuilder.java‎

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import com.google.common.collect.ImmutableList;
2121
import com.google.common.collect.Iterables;
2222
import com.google.common.collect.Multimap;
23+
import com.google.errorprone.annotations.Immutable;
2324
import com.palantir.javaformat.Indent.Const;
2425
import com.palantir.javaformat.Input.Tok;
2526
import com.palantir.javaformat.doc.Break;
@@ -35,14 +36,9 @@
3536
import com.palantir.javaformat.java.FormatterDiagnostic;
3637
import com.palantir.javaformat.java.InputMetadata;
3738
import com.palantir.javaformat.java.InputMetadataBuilder;
38-
import java.lang.annotation.ElementType;
39-
import java.lang.annotation.Retention;
40-
import java.lang.annotation.RetentionPolicy;
41-
import java.lang.annotation.Target;
4239
import java.util.ArrayList;
4340
import java.util.List;
4441
import java.util.Optional;
45-
import org.immutables.value.Value;
4642

4743
/** An {@code OpsBuilder} creates a list of {@link Op}s, which is turned into a {@link Doc} by {@link DocBuilder}. */
4844
public final class OpsBuilder {
@@ -86,6 +82,7 @@ public Integer actualStartColumn(int position) {
8682
}
8783

8884
/** A request to add or remove a blank line in the output. */
85+
@Immutable
8986
public abstract static class BlankLineWanted {
9087

9188
/** Always emit a blank line. */
@@ -501,18 +498,7 @@ private static int getI(Input.Token token) {
501498

502499
private static final NonBreakingSpace SPACE = NonBreakingSpace.make();
503500

504-
@Target(ElementType.TYPE)
505-
@Retention(RetentionPolicy.SOURCE)
506-
@Value.Style(overshadowImplementation = true)
507-
@interface OpsOutputStyle {}
508-
509-
@OpsOutputStyle
510-
@Value.Immutable
511-
public interface OpsOutput {
512-
ImmutableList<Op> ops();
513-
514-
InputMetadata inputMetadata();
515-
}
501+
public record OpsOutput(ImmutableList<Op> ops, InputMetadata inputMetadata) {}
516502

517503
/** Build a list of {@link Op}s from the {@code OpsBuilder}. */
518504
public OpsOutput build() {
@@ -669,10 +655,7 @@ public OpsOutput build() {
669655
afterForcedBreak = isForcedBreak(op);
670656
}
671657
}
672-
return ImmutableOpsOutput.builder()
673-
.ops(newOps.build())
674-
.inputMetadata(inputMetadataBuilder.build())
675-
.build();
658+
return new OpsOutput(newOps.build(), inputMetadataBuilder.build());
676659
}
677660

678661
private static boolean isNonNlsComment(Input.Tok tokAfter) {

‎open-java-format/src/main/java/com/palantir/javaformat/doc/Comment.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ public State computeBreaks(
9696
int column = lastLineStart == 0 ? state.column() + lastLineLength : lastLineLength;
9797
return state.withColumn(column)
9898
.addNewLines(Iterators.size(Newlines.lineOffsetIterator(text)))
99-
.withTokState(this, ImmutableTokState.of(text));
99+
.withTokState(this, new State.TokState(text));
100100
}
101101

102102
@Override

‎open-java-format/src/main/java/com/palantir/javaformat/doc/Level.java‎

Lines changed: 14 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,6 @@
3636
import com.palantir.javaformat.doc.Obs.ExplorationNode;
3737
import com.palantir.javaformat.doc.Obs.LevelNode;
3838
import com.palantir.javaformat.doc.StartsWithBreakVisitor.Result;
39-
import java.lang.annotation.ElementType;
40-
import java.lang.annotation.Retention;
41-
import java.lang.annotation.RetentionPolicy;
42-
import java.lang.annotation.Target;
4339
import java.util.ArrayList;
4440
import java.util.HashSet;
4541
import java.util.List;
@@ -49,7 +45,6 @@
4945
import java.util.stream.Collector;
5046
import java.util.stream.Collectors;
5147
import java.util.stream.Stream;
52-
import org.immutables.value.Value;
5348

5449
/** A {@code Level} inside a {@link Doc}. */
5550
public final class Level extends Doc {
@@ -127,7 +122,7 @@ protected Range<Integer> computeRange() {
127122
@Override
128123
public State computeBreaks(CommentsHelper commentsHelper, int maxWidth, State state, Obs.ExplorationNode observer) {
129124
return tryToFitOnOneLine(maxWidth, state, docs)
130-
.map(newWidth -> state.withColumn(newWidth).withLevelState(this, ImmutableLevelState.of(true)))
125+
.map(newWidth -> state.withColumn(newWidth).withLevelState(this, new State.LevelState(true)))
131126
.orElseGet(() -> {
132127
Obs.LevelNode childLevel = observer.newChildNode(this, state);
133128
State newState =
@@ -631,19 +626,20 @@ private State tryToLayOutLevelOnOneLine(
631626
}
632627

633628
private static SplitsBreaks splitByBreaks(List<Doc> docs) {
634-
ImmutableSplitsBreaks.Builder builder = ImmutableSplitsBreaks.builder();
629+
ImmutableList.Builder<ImmutableList<Doc>> splits = ImmutableList.builder();
630+
ImmutableList.Builder<Break> breaks = ImmutableList.builder();
635631
ImmutableList.Builder<Doc> currentSplit = ImmutableList.builder();
636632
for (Doc doc : docs) {
637633
if (doc instanceof Break b) {
638-
builder.addSplits(currentSplit.build());
634+
splits.add(currentSplit.build());
639635
currentSplit = ImmutableList.builder();
640-
builder.addBreaks(b);
636+
breaks.add(b);
641637
} else {
642638
currentSplit.add(doc);
643639
}
644640
}
645-
builder.addSplits(currentSplit.build());
646-
return builder.build();
641+
splits.add(currentSplit.build());
642+
return new SplitsBreaks(splits.build(), breaks.build());
647643
}
648644

649645
/** Compute breaks for a {@link Level} that spans multiple lines. */
@@ -837,18 +833,11 @@ public String toString() {
837833
.toString();
838834
}
839835

840-
@Target(ElementType.TYPE)
841-
@Retention(RetentionPolicy.SOURCE)
842-
@Value.Style(overshadowImplementation = true)
843-
@interface SplitsBreaksStyle {}
844-
845-
@SplitsBreaksStyle
846-
@Value.Immutable
847-
interface SplitsBreaks {
848-
/** Groups of {@link Doc}s that are children of the current {@link Level}, separated by {@link Break}s. */
849-
ImmutableList<ImmutableList<Doc>> splits();
850-
851-
/** {@link Break}s between {@link Doc}s in the current {@link Level}. */
852-
ImmutableList<Break> breaks();
853-
}
836+
/**
837+
* The children of the current {@link Level}, cut at its {@link Break}s.
838+
*
839+
* @param splits groups of {@link Doc}s that are children of the current level, separated by breaks
840+
* @param breaks the breaks between those groups
841+
*/
842+
record SplitsBreaks(ImmutableList<ImmutableList<Doc>> splits, ImmutableList<Break> breaks) {}
854843
}

‎open-java-format/src/main/java/com/palantir/javaformat/doc/State.java‎

Lines changed: 10 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,8 @@
2222
import com.palantir.javaformat.Indent;
2323
import fj.data.Set;
2424
import fj.data.TreeMap;
25-
import java.lang.annotation.ElementType;
26-
import java.lang.annotation.Retention;
27-
import java.lang.annotation.RetentionPolicy;
28-
import java.lang.annotation.Target;
2925
import java.util.Objects;
3026
import org.immutables.value.Value;
31-
import org.immutables.value.Value.Parameter;
3227

3328
/** State for writing. */
3429
// Automatically suppressed to unblock enforcement in new code
@@ -95,7 +90,7 @@ public static State startingState() {
9590
}
9691

9792
public BreakState getBreakState(Break brk) {
98-
return breakStates().get(brk).orSome(ImmutableBreakState.of(false, -1));
93+
return breakStates().get(brk).orSome(new BreakState(false, -1));
9994
}
10095

10196
public boolean wasBreakTaken(BreakTag breakTag) {
@@ -163,7 +158,7 @@ State withBreak(Break brk, boolean broken) {
163158
.lastIndent(indent())
164159
.column(newColumn)
165160
.numLines(numLines() + 1)
166-
.breakStates(breakStates().set(brk, ImmutableBreakState.of(true, newColumn)))
161+
.breakStates(breakStates().set(brk, new BreakState(true, newColumn)))
167162
.build();
168163
} else {
169164
return builder.column(column() + brk.getFlat().length()).build();
@@ -249,44 +244,14 @@ public static Builder builder() {
249244
return new Builder();
250245
}
251246

252-
@Target(ElementType.TYPE)
253-
@Retention(RetentionPolicy.SOURCE)
254-
@Value.Style(overshadowImplementation = true)
255-
@interface BreakStateStyle {}
247+
record BreakState(boolean broken, int newIndent) {}
256248

257-
@BreakStateStyle
258-
@Value.Immutable
259-
@JsonSerialize(as = ImmutableBreakState.class)
260-
interface BreakState {
261-
@Parameter
262-
boolean broken();
263-
264-
@Parameter
265-
int newIndent();
266-
}
267-
268-
@Target(ElementType.TYPE)
269-
@Retention(RetentionPolicy.SOURCE)
270-
@Value.Style(overshadowImplementation = true)
271-
@interface LevelStateStyle {}
272-
273-
@LevelStateStyle
274-
@Value.Immutable
275-
interface LevelState {
276-
/** True if the entire {@link Level} fits on one line. */
277-
@Parameter
278-
boolean oneLine();
279-
}
280-
281-
@Target(ElementType.TYPE)
282-
@Retention(RetentionPolicy.SOURCE)
283-
@Value.Style(overshadowImplementation = true)
284-
@interface TokStateStyle {}
249+
/**
250+
* How a {@link Level} was laid out.
251+
*
252+
* @param oneLine true if the entire level fits on one line
253+
*/
254+
record LevelState(boolean oneLine) {}
285255

286-
@TokStateStyle
287-
@Value.Immutable
288-
interface TokState {
289-
@Parameter
290-
String text();
291-
}
256+
record TokState(String text) {}
292257
}

‎open-java-format/src/main/java/com/palantir/javaformat/java/InputMetadata.java‎

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,28 +19,16 @@
1919
import com.google.common.collect.ImmutableRangeSet;
2020
import com.google.errorprone.annotations.Immutable;
2121
import com.palantir.javaformat.OpsBuilder.BlankLineWanted;
22-
import org.immutables.value.Value;
23-
import org.immutables.value.Value.Default;
2422

2523
/**
2624
* Records metadata about the input, namely existing blank lines that we might want to preserve, as well as what ranges
2725
* can be partially formatted.
26+
*
27+
* @param blankLines remembers preferences from the input about whether blank lines are wanted or not at a given token
28+
* index
29+
* @param partialFormatRanges marks regions that can be partially formatted, used to determine the actual ranges that
30+
* will be formatted when ranges are requested
2831
*/
29-
// Automatically suppressed to unblock enforcement in new code
30-
@SuppressWarnings("ImmutablesStyle")
3132
@Immutable
32-
@Value.Immutable
33-
@Value.Style(overshadowImplementation = true)
34-
public interface InputMetadata {
35-
/** Remembers preferences from the input about whether blank lines are wanted or not at a given token index. */
36-
ImmutableMap<Integer, BlankLineWanted> blankLines();
37-
38-
/**
39-
* Marks regions that can be partially formatted, used to determine the actual ranges that will be formatted when
40-
* ranges are requested.
41-
*/
42-
@Default
43-
default ImmutableRangeSet<Integer> partialFormatRanges() {
44-
return ImmutableRangeSet.of();
45-
}
46-
}
33+
public record InputMetadata(
34+
ImmutableMap<Integer, BlankLineWanted> blankLines, ImmutableRangeSet<Integer> partialFormatRanges) {}

‎open-java-format/src/main/java/com/palantir/javaformat/java/InputMetadataBuilder.java‎

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,6 @@ public void markForPartialFormat(Input.Token start, Input.Token end) {
5151
}
5252

5353
public InputMetadata build() {
54-
return ImmutableInputMetadata.builder()
55-
.blankLines(ImmutableMap.copyOf(blankLines))
56-
.partialFormatRanges(ImmutableRangeSet.copyOf(partialFormatRanges))
57-
.build();
54+
return new InputMetadata(ImmutableMap.copyOf(blankLines), ImmutableRangeSet.copyOf(partialFormatRanges));
5855
}
5956
}

0 commit comments

Comments
 (0)