From 7c7ad1d96b2cc1b4249470f9d9eec78dc22f0227 Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Fri, 19 Nov 2021 09:05:29 -0800 Subject: [PATCH] Update handling of pattern matching in switch for AST changes in Java 17, in particular the addition of CaseTree#getLabels, which returns a single `DefaultCaseLabelTree` to represent the default case. https://github.com/google/google-java-format/issues/683 https://github.com/google/google-java-format/issues/684 PiperOrigin-RevId: 411074295 --- .../java/java14/Java14InputAstVisitor.java | 20 +++++++-- .../java/FormatterIntegrationTest.java | 45 ++++++------------- .../googlejavaformat/java/testdata/I683.input | 14 ++++++ .../java/testdata/I683.output | 15 +++++++ .../googlejavaformat/java/testdata/I684.input | 14 ++++++ .../java/testdata/I684.output | 14 ++++++ 6 files changed, 86 insertions(+), 36 deletions(-) create mode 100644 core/src/test/resources/com/google/googlejavaformat/java/testdata/I683.input create mode 100644 core/src/test/resources/com/google/googlejavaformat/java/testdata/I683.output create mode 100644 core/src/test/resources/com/google/googlejavaformat/java/testdata/I684.input create mode 100644 core/src/test/resources/com/google/googlejavaformat/java/testdata/I684.output diff --git a/core/src/main/java/com/google/googlejavaformat/java/java14/Java14InputAstVisitor.java b/core/src/main/java/com/google/googlejavaformat/java/java14/Java14InputAstVisitor.java index 3facbd711..890687fe2 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/java14/Java14InputAstVisitor.java +++ b/core/src/main/java/com/google/googlejavaformat/java/java14/Java14InputAstVisitor.java @@ -15,6 +15,7 @@ package com.google.googlejavaformat.java.java14; import static com.google.common.collect.ImmutableList.toImmutableList; +import static com.google.common.collect.Iterables.getOnlyElement; import com.google.common.base.Verify; import com.google.common.collect.ImmutableList; @@ -27,7 +28,6 @@ import com.sun.source.tree.CaseTree; import com.sun.source.tree.ClassTree; import com.sun.source.tree.CompilationUnitTree; -import com.sun.source.tree.ExpressionTree; import com.sun.source.tree.InstanceOfTree; import com.sun.source.tree.ModifiersTree; import com.sun.source.tree.ModuleTree; @@ -59,6 +59,7 @@ public class Java14InputAstVisitor extends JavaInputAstVisitor { maybeGetMethod(BindingPatternTree.class, "getType"); private static final Method BINDING_PATTERN_TREE_GET_BINDING = maybeGetMethod(BindingPatternTree.class, "getBinding"); + private static final Method CASE_TREE_GET_LABELS = maybeGetMethod(CaseTree.class, "getLabels"); public Java14InputAstVisitor(OpsBuilder builder, int indentMultiplier) { super(builder, indentMultiplier); @@ -247,14 +248,25 @@ public Void visitCase(CaseTree node, Void unused) { sync(node); markForPartialFormat(); builder.forcedBreak(); - if (node.getExpressions().isEmpty()) { + List labels; + boolean isDefault; + if (CASE_TREE_GET_LABELS != null) { + labels = (List) invoke(CASE_TREE_GET_LABELS, node); + isDefault = + labels.size() == 1 + && getOnlyElement(labels).getKind().name().equals("DEFAULT_CASE_LABEL"); + } else { + labels = node.getExpressions(); + isDefault = labels.isEmpty(); + } + if (isDefault) { token("default", plusTwo); } else { token("case", plusTwo); - builder.open(node.getExpressions().size() > 1 ? plusFour : ZERO); + builder.open(labels.size() > 1 ? plusFour : ZERO); builder.space(); boolean first = true; - for (ExpressionTree expression : node.getExpressions()) { + for (Tree expression : labels) { if (!first) { token(","); builder.breakOp(" "); diff --git a/core/src/test/java/com/google/googlejavaformat/java/FormatterIntegrationTest.java b/core/src/test/java/com/google/googlejavaformat/java/FormatterIntegrationTest.java index edbb12b6e..22202e98a 100644 --- a/core/src/test/java/com/google/googlejavaformat/java/FormatterIntegrationTest.java +++ b/core/src/test/java/com/google/googlejavaformat/java/FormatterIntegrationTest.java @@ -14,8 +14,7 @@ package com.google.googlejavaformat.java; -import static com.google.common.base.StandardSystemProperty.JAVA_CLASS_VERSION; -import static com.google.common.base.StandardSystemProperty.JAVA_SPECIFICATION_VERSION; +import static com.google.common.collect.MoreCollectors.toOptional; import static com.google.common.io.Files.getFileExtension; import static com.google.common.io.Files.getNameWithoutExtension; import static java.nio.charset.StandardCharsets.UTF_8; @@ -23,7 +22,7 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableMultimap; import com.google.common.io.CharStreams; import com.google.common.reflect.ClassPath; import com.google.common.reflect.ClassPath.ResourceInfo; @@ -31,12 +30,12 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; -import java.lang.reflect.Method; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.TreeMap; import org.junit.Test; import org.junit.runner.RunWith; @@ -47,12 +46,13 @@ @RunWith(Parameterized.class) public class FormatterIntegrationTest { - private static final ImmutableSet JAVA14_TESTS = - ImmutableSet.of("I477", "Records", "RSLs", "Var", "ExpressionSwitch", "I574", "I594"); - - private static final ImmutableSet JAVA15_TESTS = ImmutableSet.of("I603"); - - private static final ImmutableSet JAVA16_TESTS = ImmutableSet.of("I588"); + private static final ImmutableMultimap VERSIONED_TESTS = + ImmutableMultimap.builder() + .putAll(14, "I477", "Records", "RSLs", "Var", "ExpressionSwitch", "I574", "I594") + .putAll(15, "I603") + .putAll(16, "I588") + .putAll(17, "I683", "I684") + .build(); @Parameters(name = "{index}: {0}") public static Iterable data() throws IOException { @@ -91,13 +91,9 @@ public static Iterable data() throws IOException { String input = inputs.get(fileName); assertTrue("unmatched input", outputs.containsKey(fileName)); String expectedOutput = outputs.get(fileName); - if (JAVA14_TESTS.contains(fileName) && getMajor() < 14) { - continue; - } - if (JAVA15_TESTS.contains(fileName) && getMajor() < 15) { - continue; - } - if (JAVA16_TESTS.contains(fileName) && getMajor() < 16) { + Optional version = + VERSIONED_TESTS.inverse().get(fileName).stream().collect(toOptional()); + if (version.isPresent() && Runtime.version().feature() < version.get()) { continue; } testInputs.add(new Object[] {fileName, input, expectedOutput}); @@ -105,21 +101,6 @@ public static Iterable data() throws IOException { return testInputs; } - private static int getMajor() { - try { - Method versionMethod = Runtime.class.getMethod("version"); - Object version = versionMethod.invoke(null); - return (int) version.getClass().getMethod("major").invoke(version); - } catch (Exception e) { - // continue below - } - int version = (int) Double.parseDouble(JAVA_CLASS_VERSION.value()); - if (49 <= version && version <= 52) { - return version - (49 - 5); - } - throw new IllegalStateException("Unknown Java version: " + JAVA_SPECIFICATION_VERSION.value()); - } - private final String name; private final String input; private final String expected; diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/I683.input b/core/src/test/resources/com/google/googlejavaformat/java/testdata/I683.input new file mode 100644 index 000000000..9104f1903 --- /dev/null +++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/I683.input @@ -0,0 +1,14 @@ +interface Test { + + static class Test1 implements Test{} + static class Test2 implements Test{} + + public static void main(String[] args) { + Test test = new Test1(); + switch (test) { + case Test1 test1 -> {} + case Test2 test2 -> {} + default -> throw new IllegalStateException("Unexpected value: " + test); + } + } +} diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/I683.output b/core/src/test/resources/com/google/googlejavaformat/java/testdata/I683.output new file mode 100644 index 000000000..5b9c4665a --- /dev/null +++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/I683.output @@ -0,0 +1,15 @@ +interface Test { + + static class Test1 implements Test {} + + static class Test2 implements Test {} + + public static void main(String[] args) { + Test test = new Test1(); + switch (test) { + case Test1 test1 -> {} + case Test2 test2 -> {} + default -> throw new IllegalStateException("Unexpected value: " + test); + } + } +} diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/I684.input b/core/src/test/resources/com/google/googlejavaformat/java/testdata/I684.input new file mode 100644 index 000000000..cbce0ddd5 --- /dev/null +++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/I684.input @@ -0,0 +1,14 @@ +package example; + +import example.model.SealedInterface; +import example.model.TypeA; +import example.model.TypeB; + +public class Main { + public void apply(SealedInterface sealedInterface) { + switch(sealedInterface) { + case TypeA a -> System.out.println("A!"); + case TypeB b -> System.out.println("B!"); + } + } +} diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/I684.output b/core/src/test/resources/com/google/googlejavaformat/java/testdata/I684.output new file mode 100644 index 000000000..4e5e9b4be --- /dev/null +++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/I684.output @@ -0,0 +1,14 @@ +package example; + +import example.model.SealedInterface; +import example.model.TypeA; +import example.model.TypeB; + +public class Main { + public void apply(SealedInterface sealedInterface) { + switch (sealedInterface) { + case TypeA a -> System.out.println("A!"); + case TypeB b -> System.out.println("B!"); + } + } +}