You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@netbeans.apache.org by ak...@apache.org on 2021/09/15 09:03:02 UTC

[netbeans] branch master updated: [NETBEANS-5799] : Add support for Pattern Matching for switch (Preview) (#3007)

This is an automated email from the ASF dual-hosted git repository.

akhileshsingh pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/netbeans.git


The following commit(s) were added to refs/heads/master by this push:
     new c5cc187  [NETBEANS-5799] : Add support for Pattern Matching for switch (Preview) (#3007)
c5cc187 is described below

commit c5cc187caab00cb1f8a4fb265b329ccd8c31d0c9
Author: Akhilesh Singh <ak...@oracle.com>
AuthorDate: Wed Sep 15 14:32:42 2021 +0530

    [NETBEANS-5799] : Add support for Pattern Matching for switch (Preview) (#3007)
    
    * [NETBEANS-5799] : Added support for code completion, formatting, hints(partial), variable name suggestion and semantic highlighting.
---
 .../netbeans/modules/java/completion/BaseTask.java |    1 +
 .../java/completion/JavaCompletionTask.java        |   10 +-
 ...MembersSelect_GuardedPatternMatchingSwitch.pass |   15 +
 ...mbersSelect_GuardedPatternMatchingSwitch_1.pass |    9 +
 ...mbersSelect_GuardedPatternMatchingSwitch_2.pass |   51 +
 ...sSelect_ParenthesizedPatternMatchingSwitch.pass |   40 +
 ...elect_ParenthesizedPatternMatchingSwitch_1.pass |   62 ++
 ...on_VarNameSuggestion_PatternMatchingSwitch.pass |    2 +
 .../completion/data/SwitchPatternMatching.java}    |   31 +-
 .../JavaCompletionTask117FeaturesTest.java         |  116 +++
 .../base/semantic/SemanticHighlighterBase.java     |    2 +-
 .../java/editor/base/semantic/DetectorTest.java    |   40 +
 .../jdk/ConvertToSwitchPatternInstanceOf.java      |  187 ++++
 .../jdk/ConvertToSwitchPatternInstanceOfTest.java  |   78 ++
 .../org/netbeans/api/java/source/TreeMaker.java    |   24 +
 .../source/support/ErrorAwareTreePathScanner.java  |    7 +
 .../java/source/support/ErrorAwareTreeScanner.java |    7 +
 .../netbeans/modules/java/source/TreeShims.java    |   62 ++
 .../modules/java/source/builder/TreeFactory.java   |   29 +
 .../modules/java/source/pretty/VeryPretty.java     |   30 +-
 .../modules/java/source/save/CasualDiff.java       |    8 +
 .../modules/java/source/save/Reformatter.java      |  102 +-
 .../modules/java/source/save/FormatingTest.java    | 1013 ++++++++++++++++++++
 23 files changed, 1895 insertions(+), 31 deletions(-)

diff --git a/java/java.completion/src/org/netbeans/modules/java/completion/BaseTask.java b/java/java.completion/src/org/netbeans/modules/java/completion/BaseTask.java
index 74994da..a08521d 100644
--- a/java/java.completion/src/org/netbeans/modules/java/completion/BaseTask.java
+++ b/java/java.completion/src/org/netbeans/modules/java/completion/BaseTask.java
@@ -631,6 +631,7 @@ abstract class BaseTask extends UserTask {
             return null;
         }
 
+
     }
 
     private static boolean isCamelCasePrefix(String prefix) {
diff --git a/java/java.completion/src/org/netbeans/modules/java/completion/JavaCompletionTask.java b/java/java.completion/src/org/netbeans/modules/java/completion/JavaCompletionTask.java
index 43acc01..2e8db5f 100644
--- a/java/java.completion/src/org/netbeans/modules/java/completion/JavaCompletionTask.java
+++ b/java/java.completion/src/org/netbeans/modules/java/completion/JavaCompletionTask.java
@@ -2493,7 +2493,15 @@ public final class JavaCompletionTask<T> extends BaseTask {
             }
         } else {
             TokenSequence<JavaTokenId> ts = findLastNonWhitespaceToken(env, cst, offset);
-            if (ts != null && ts.token().id() != JavaTokenId.DEFAULT) {
+            if (ts != null && ts.token().id() == JavaTokenId.IDENTIFIER) {
+                for (ExpressionTree caseExpression : caseTreeList) {
+                    if (caseExpression != null && caseExpression.getKind() == Tree.Kind.IDENTIFIER) {
+                        TreePath tPath = new TreePath(path, caseExpression);
+                        insideExpression(env, tPath);
+                        return;
+                    }
+                }
+            } else if (ts != null && ts.token().id() != JavaTokenId.DEFAULT) {
                 localResult(env);
                 addKeywordsForBlock(env);
             }
diff --git a/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/17/AutoCompletion_MembersSelect_GuardedPatternMatchingSwitch.pass b/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/17/AutoCompletion_MembersSelect_GuardedPatternMatchingSwitch.pass
new file mode 100644
index 0000000..bb9bd18
--- /dev/null
+++ b/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/17/AutoCompletion_MembersSelect_GuardedPatternMatchingSwitch.pass
@@ -0,0 +1,15 @@
+public abstract char charAt(int arg0)
+public default IntStream chars()
+public default IntStream codePoints()
+public boolean equals(Object arg0)
+public final native Class<?> getClass()
+public native int hashCode()
+public default boolean isEmpty()
+public abstract int length()
+public final native void notify()
+public final native void notifyAll()
+public abstract CharSequence subSequence(int arg0, int arg1)
+public abstract String toString()
+public final void wait()
+public final native void wait(long arg0)
+public final void wait(long arg0, int arg1)
diff --git a/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/17/AutoCompletion_MembersSelect_GuardedPatternMatchingSwitch_1.pass b/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/17/AutoCompletion_MembersSelect_GuardedPatternMatchingSwitch_1.pass
new file mode 100644
index 0000000..9200f72
--- /dev/null
+++ b/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/17/AutoCompletion_MembersSelect_GuardedPatternMatchingSwitch_1.pass
@@ -0,0 +1,9 @@
+public boolean equals(Object arg0)
+public final native Class<?> getClass()
+public native int hashCode()
+public final native void notify()
+public final native void notifyAll()
+public String toString()
+public final void wait()
+public final native void wait(long arg0)
+public final void wait(long arg0, int arg1)
\ No newline at end of file
diff --git a/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/17/AutoCompletion_MembersSelect_GuardedPatternMatchingSwitch_2.pass b/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/17/AutoCompletion_MembersSelect_GuardedPatternMatchingSwitch_2.pass
new file mode 100644
index 0000000..f29c24e
--- /dev/null
+++ b/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/17/AutoCompletion_MembersSelect_GuardedPatternMatchingSwitch_2.pass
@@ -0,0 +1,51 @@
+public abstract boolean allMatch(IntPredicate arg0)
+public abstract boolean anyMatch(IntPredicate arg0)
+public abstract R collect(Supplier<R> arg0, ObjIntConsumer<R> arg1, BiConsumer<R, R> arg2)
+public boolean equals(Object arg0)
+public abstract boolean isParallel()
+public abstract boolean noneMatch(IntPredicate arg0)
+public abstract DoubleStream asDoubleStream()
+public abstract LongStream asLongStream()
+public abstract OptionalDouble average()
+public abstract Stream<Integer> boxed()
+public abstract void close()
+public abstract long count()
+public abstract IntStream distinct()
+public default IntStream dropWhile(IntPredicate arg0)
+public abstract IntStream filter(IntPredicate arg0)
+public abstract OptionalInt findAny()
+public abstract OptionalInt findFirst()
+public abstract IntStream flatMap(IntFunction<? extends IntStream> arg0)
+public abstract void forEach(IntConsumer arg0)
+public abstract void forEachOrdered(IntConsumer arg0)
+public final native Class<?> getClass()
+public native int hashCode()
+public abstract OfInt iterator()
+public abstract IntStream limit(long arg0)
+public abstract IntStream map(IntUnaryOperator arg0)
+public default IntStream mapMulti(IntMapMultiConsumer arg0)
+public abstract DoubleStream mapToDouble(IntToDoubleFunction arg0)
+public abstract LongStream mapToLong(IntToLongFunction arg0)
+public abstract Stream<U> mapToObj(IntFunction<? extends U> arg0)
+public abstract OptionalInt max()
+public abstract OptionalInt min()
+public final native void notify()
+public final native void notifyAll()
+public abstract IntStream onClose(Runnable arg0)
+public abstract IntStream parallel()
+public abstract IntStream peek(IntConsumer arg0)
+public abstract OptionalInt reduce(IntBinaryOperator arg0)
+public abstract int reduce(int arg0, IntBinaryOperator arg1)
+public abstract IntStream sequential()
+public abstract IntStream skip(long arg0)
+public abstract IntStream sorted()
+public abstract OfInt spliterator()
+public abstract int sum()
+public abstract IntSummaryStatistics summaryStatistics()
+public default IntStream takeWhile(IntPredicate arg0)
+public abstract int[] toArray()
+public String toString()
+public abstract IntStream unordered()
+public final void wait()
+public final native void wait(long arg0)
+public final void wait(long arg0, int arg1)
diff --git a/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/17/AutoCompletion_MembersSelect_ParenthesizedPatternMatchingSwitch.pass b/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/17/AutoCompletion_MembersSelect_ParenthesizedPatternMatchingSwitch.pass
new file mode 100644
index 0000000..10c56d9
--- /dev/null
+++ b/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/17/AutoCompletion_MembersSelect_ParenthesizedPatternMatchingSwitch.pass
@@ -0,0 +1,40 @@
+public abstract boolean add(Object arg0)
+public abstract void add(int arg0, Object arg1)
+public abstract boolean addAll(Collection arg0)
+public abstract boolean addAll(int arg0, Collection arg1)
+public abstract void clear()
+public abstract boolean contains(Object arg0)
+public abstract boolean containsAll(Collection arg0)
+public abstract boolean equals(Object arg0)
+public default void forEach(Consumer arg0)
+public abstract Object get(int arg0)
+public final native Class<?> getClass()
+public abstract int hashCode()
+public abstract int indexOf(Object arg0)
+public abstract boolean isEmpty()
+public abstract Iterator iterator()
+public abstract int lastIndexOf(Object arg0)
+public abstract ListIterator listIterator()
+public abstract ListIterator listIterator(int arg0)
+public final native void notify()
+public final native void notifyAll()
+public default Stream parallelStream()
+public abstract boolean remove(Object arg0)
+public abstract Object remove(int arg0)
+public abstract boolean removeAll(Collection arg0)
+public default boolean removeIf(Predicate arg0)
+public default void replaceAll(UnaryOperator arg0)
+public abstract boolean retainAll(Collection arg0)
+public abstract Object set(int arg0, Object arg1)
+public abstract int size()
+public default void sort(Comparator arg0)
+public default Spliterator spliterator()
+public default Stream stream()
+public abstract List subList(int arg0, int arg1)
+public abstract Object[] toArray()
+public default Object[] toArray(IntFunction arg0)
+public abstract Object[] toArray(Object[] arg0)
+public String toString()
+public final void wait()
+public final native void wait(long arg0)
+public final void wait(long arg0, int arg1)
\ No newline at end of file
diff --git a/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/17/AutoCompletion_MembersSelect_ParenthesizedPatternMatchingSwitch_1.pass b/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/17/AutoCompletion_MembersSelect_ParenthesizedPatternMatchingSwitch_1.pass
new file mode 100644
index 0000000..80d9da2
--- /dev/null
+++ b/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/17/AutoCompletion_MembersSelect_ParenthesizedPatternMatchingSwitch_1.pass
@@ -0,0 +1,62 @@
+public boolean equals(Object arg0)
+public default boolean isEmpty()
+public StringBuilder append(CharSequence arg0)
+public StringBuilder append(Object arg0)
+public StringBuilder append(String arg0)
+public StringBuilder append(StringBuffer arg0)
+public StringBuilder append(boolean arg0)
+public StringBuilder append(char arg0)
+public StringBuilder append(char[] arg0)
+public StringBuilder append(double arg0)
+public StringBuilder append(float arg0)
+public StringBuilder append(int arg0)
+public StringBuilder append(long arg0)
+public StringBuilder append(CharSequence arg0, int arg1, int arg2)
+public StringBuilder append(char[] arg0, int arg1, int arg2)
+public StringBuilder appendCodePoint(int arg0)
+public int capacity()
+public char charAt(int arg0)
+public IntStream chars()
+public int codePointAt(int arg0)
+public int codePointBefore(int arg0)
+public int codePointCount(int arg0, int arg1)
+public IntStream codePoints()
+public int compareTo(StringBuilder arg0)
+public StringBuilder delete(int arg0, int arg1)
+public StringBuilder deleteCharAt(int arg0)
+public void ensureCapacity(int arg0)
+public void getChars(int arg0, int arg1, char[] arg2, int arg3)
+public final native Class<?> getClass()
+public native int hashCode()
+public int indexOf(String arg0)
+public int indexOf(String arg0, int arg1)
+public StringBuilder insert(int arg0, CharSequence arg1)
+public StringBuilder insert(int arg0, Object arg1)
+public StringBuilder insert(int arg0, String arg1)
+public StringBuilder insert(int arg0, boolean arg1)
+public StringBuilder insert(int arg0, char arg1)
+public StringBuilder insert(int arg0, char[] arg1)
+public StringBuilder insert(int arg0, double arg1)
+public StringBuilder insert(int arg0, float arg1)
+public StringBuilder insert(int arg0, int arg1)
+public StringBuilder insert(int arg0, long arg1)
+public StringBuilder insert(int arg0, CharSequence arg1, int arg2, int arg3)
+public StringBuilder insert(int arg0, char[] arg1, int arg2, int arg3)
+public int lastIndexOf(String arg0)
+public int lastIndexOf(String arg0, int arg1)
+public int length()
+public final native void notify()
+public final native void notifyAll()
+public int offsetByCodePoints(int arg0, int arg1)
+public StringBuilder replace(int arg0, int arg1, String arg2)
+public StringBuilder reverse()
+public void setCharAt(int arg0, char arg1)
+public void setLength(int arg0)
+public CharSequence subSequence(int arg0, int arg1)
+public String substring(int arg0)
+public String substring(int arg0, int arg1)
+public String toString()
+public void trimToSize()
+public final void wait()
+public final native void wait(long arg0)
+public final void wait(long arg0, int arg1)
diff --git a/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/17/AutoCompletion_VarNameSuggestion_PatternMatchingSwitch.pass b/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/17/AutoCompletion_VarNameSuggestion_PatternMatchingSwitch.pass
new file mode 100644
index 0000000..d5fbcfc
--- /dev/null
+++ b/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/17/AutoCompletion_VarNameSuggestion_PatternMatchingSwitch.pass
@@ -0,0 +1,2 @@
+s
+string
\ No newline at end of file
diff --git a/java/java.source.base/src/org/netbeans/api/java/source/support/ErrorAwareTreePathScanner.java b/java/java.completion/test/unit/data/org/netbeans/modules/java/completion/data/SwitchPatternMatching.java
similarity index 60%
copy from java/java.source.base/src/org/netbeans/api/java/source/support/ErrorAwareTreePathScanner.java
copy to java/java.completion/test/unit/data/org/netbeans/modules/java/completion/data/SwitchPatternMatching.java
index a04e544..82cc419 100644
--- a/java/java.source.base/src/org/netbeans/api/java/source/support/ErrorAwareTreePathScanner.java
+++ b/java/java.completion/test/unit/data/org/netbeans/modules/java/completion/data/SwitchPatternMatching.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -16,20 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.netbeans.api.java.source.support;
 
-import com.sun.source.tree.ErroneousTree;
-import com.sun.source.util.TreePathScanner;
+package test;
 
-/**
- *
- * @author Jan Lahoda
- */
-public class ErrorAwareTreePathScanner<R,P> extends TreePathScanner<R,P> {
+import java.util.stream.IntStream;
 
-    @Override
-    public R visitErroneous(ErroneousTree et, P p) {
-        return scan(et.getErrorTrees(), p);
+public class Test{
+    
+     public void op(int a) {
+        Object obj = "test";
+        String result = switch (obj) {
+            case null, String  ->
+                "null & String";
+            case CharSequence s && s. && obj. && IntStream.of(1).max().->
+                "CharSequence";
+            case (java.util.List list && list. && new StringBuilder().ERROR. && java.util.ArrayList<String>.)->"list";
+            default ->
+                "default";
+        };
     }
-
-}
+}    
diff --git a/java/java.completion/test/unit/src/org/netbeans/modules/java/completion/JavaCompletionTask117FeaturesTest.java b/java/java.completion/test/unit/src/org/netbeans/modules/java/completion/JavaCompletionTask117FeaturesTest.java
new file mode 100644
index 0000000..436110d
--- /dev/null
+++ b/java/java.completion/test/unit/src/org/netbeans/modules/java/completion/JavaCompletionTask117FeaturesTest.java
@@ -0,0 +1,116 @@
+package org.netbeans.modules.java.completion;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.lang.model.SourceVersion;
+import javax.swing.event.ChangeListener;
+import org.netbeans.junit.NbTestSuite;
+import org.netbeans.modules.java.source.parsing.JavacParser;
+import org.netbeans.spi.java.queries.CompilerOptionsQueryImplementation;
+import org.openide.filesystems.FileObject;
+import org.openide.util.lookup.ServiceProvider;
+/**
+ *
+ * @author aksinsin
+ */
+public class JavaCompletionTask117FeaturesTest extends CompletionTestBase {
+
+    private static String SOURCE_LEVEL = "17"; //NOI18N
+
+    public JavaCompletionTask117FeaturesTest(String testName) {
+        super(testName);
+    }
+
+    public static NbTestSuite suite() {
+        NbTestSuite suite = new NbTestSuite();
+        try {
+            SourceVersion.valueOf("RELEASE_17"); //NOI18N
+            suite.addTestSuite(JavaCompletionTask117FeaturesTest.class);
+        } catch (IllegalArgumentException ex) {
+            //OK, no RELEASE_13, skip tests
+            suite.addTest(new JavaCompletionTask117FeaturesTest("noop")); //NOI18N
+        }
+        return suite;
+    }
+
+
+    public void testVariableNameSuggestion() throws Exception {
+        TestCompilerOptionsQueryImplementation.EXTRA_OPTIONS.add("--enable-preview");
+        performTest("SwitchPatternMatching", 1011, null, "AutoCompletion_VarNameSuggestion_PatternMatchingSwitch.pass", getLatestSource());
+    } 
+
+    public void testClassMembersAutoCompletion_GuardedPattern() throws Exception {
+        TestCompilerOptionsQueryImplementation.EXTRA_OPTIONS.add("--enable-preview");
+        performTest("SwitchPatternMatching", 1085, null, "AutoCompletion_MembersSelect_GuardedPatternMatchingSwitch.pass", getLatestSource());
+    }
+
+    public void testClassMembersAutoCompletion_GuardedPattern_1() throws Exception {
+        TestCompilerOptionsQueryImplementation.EXTRA_OPTIONS.add("--enable-preview");
+        performTest("SwitchPatternMatching", 1093, null, "AutoCompletion_MembersSelect_GuardedPatternMatchingSwitch_1.pass", getLatestSource());
+    }
+    public void testClassMembersAutoCompletion_GuardedPattern_2() throws Exception {
+        TestCompilerOptionsQueryImplementation.EXTRA_OPTIONS.add("--enable-preview");
+        performTest("SwitchPatternMatching", 1113, null, "AutoCompletion_MembersSelect_GuardedPatternMatchingSwitch_2.pass", getLatestSource());
+    }
+    public void testClassMembersAutoCompletion_ParanthesizedPattern() throws Exception {
+        TestCompilerOptionsQueryImplementation.EXTRA_OPTIONS.add("--enable-preview");
+        performTest("SwitchPatternMatching", 1200, null, "AutoCompletion_MembersSelect_ParenthesizedPatternMatchingSwitch.pass", getLatestSource());
+    }
+    public void testClassMembersAutoCompletion_ParanthesizedPattern_1() throws Exception {
+        TestCompilerOptionsQueryImplementation.EXTRA_OPTIONS.add("--enable-preview");
+        performTest("SwitchPatternMatching", 1224, null, "AutoCompletion_MembersSelect_ParenthesizedPatternMatchingSwitch_1.pass", getLatestSource());
+    }
+    public void noop() {
+    }
+
+    static {
+        JavacParser.DISABLE_SOURCE_LEVEL_DOWNGRADE = true;
+    }
+    
+    private String getLatestSource(){
+        return SourceVersion.latest().name().substring(SourceVersion.latest().name().indexOf("_")+1);
+    }
+    
+    @ServiceProvider(service = CompilerOptionsQueryImplementation.class, position = 100)
+    public static class TestCompilerOptionsQueryImplementation implements CompilerOptionsQueryImplementation {
+        private static final List<String> EXTRA_OPTIONS = new ArrayList<>();
+        
+        @Override
+        public CompilerOptionsQueryImplementation.Result getOptions(FileObject file) {
+            return new CompilerOptionsQueryImplementation.Result() {
+                @Override
+                public List<? extends String> getArguments() {
+                    return EXTRA_OPTIONS;
+                }
+
+                @Override
+                public void addChangeListener(ChangeListener listener) {
+                }
+
+                @Override
+                public void removeChangeListener(ChangeListener listener) {
+                }
+            };
+        }
+
+    }
+}
diff --git a/java/java.editor.base/src/org/netbeans/modules/java/editor/base/semantic/SemanticHighlighterBase.java b/java/java.editor.base/src/org/netbeans/modules/java/editor/base/semantic/SemanticHighlighterBase.java
index f235ffc..bc7c078 100644
--- a/java/java.editor.base/src/org/netbeans/modules/java/editor/base/semantic/SemanticHighlighterBase.java
+++ b/java/java.editor.base/src/org/netbeans/modules/java/editor/base/semantic/SemanticHighlighterBase.java
@@ -1015,7 +1015,7 @@ public abstract class SemanticHighlighterBase extends JavaParserResultTask {
             }
             return super.scan(tree, p);
         }
-        
+
         private void visitModifier(Tree tree) {
             tl.moveToOffset(sourcePositions.getStartPosition(info.getCompilationUnit(), tree));
             Token t = null;
diff --git a/java/java.editor.base/test/unit/src/org/netbeans/modules/java/editor/base/semantic/DetectorTest.java b/java/java.editor.base/test/unit/src/org/netbeans/modules/java/editor/base/semantic/DetectorTest.java
index 33f4553..4a00265 100644
--- a/java/java.editor.base/test/unit/src/org/netbeans/modules/java/editor/base/semantic/DetectorTest.java
+++ b/java/java.editor.base/test/unit/src/org/netbeans/modules/java/editor/base/semantic/DetectorTest.java
@@ -615,6 +615,46 @@ public class DetectorTest extends TestBase {
                 "[PACKAGE_PRIVATE, CLASS, DECLARATION], 1:17-1:22",
                 "[PACKAGE_PRIVATE, CLASS], 1:31-1:35");
     }
+
+    public void testSwitchPattern() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_17"); //NOI18N
+        } catch (IllegalArgumentException ex) {
+            //OK, no RELEASE_17, skip tests
+            return;
+        }
+        enablePreview();
+        performTest("TestSwitchPattern.java",
+                "public class TestSwitchPattern {\n"
+                + "    String strColor = \"color\";\n"
+                + "    void m1() {\n"
+                + "        Object obj = \"test\";\n"
+                + "        switch (obj) {\n"
+                + "            case String s && s.equals(strColor) -> System.out.println(\"same\");\n"
+                + "            case default -> System.out.println(\"default\");\n"
+                + "        }\n"
+                + "    }\n"
+                + "}",
+                "[PUBLIC, CLASS, DECLARATION], 0:13-0:30\n"
+                + "[PUBLIC, CLASS], 1:4-1:10\n"
+                + "[PACKAGE_PRIVATE, FIELD, DECLARATION], 1:11-1:19\n"
+                + "[PACKAGE_PRIVATE, METHOD, DECLARATION], 2:9-2:11\n"
+                + "[PUBLIC, CLASS], 3:8-3:14\n"
+                + "[LOCAL_VARIABLE, DECLARATION], 3:15-3:18\n"
+                + "[LOCAL_VARIABLE], 4:16-4:19\n"
+                + "[PUBLIC, CLASS], 5:17-5:23\n"
+                + "[LOCAL_VARIABLE, DECLARATION], 5:24-5:25\n"
+                + "[LOCAL_VARIABLE], 5:29-5:30\n"
+                + "[PUBLIC, METHOD], 5:31-5:37\n"
+                + "[PACKAGE_PRIVATE, FIELD], 5:38-5:46\n"
+                + "[PUBLIC, CLASS], 5:51-5:57\n"
+                + "[STATIC, PUBLIC, FIELD], 5:58-5:61\n"
+                + "[PUBLIC, METHOD], 5:62-5:69\n"
+                + "[PUBLIC, CLASS], 6:28-6:34\n"
+                + "[STATIC, PUBLIC, FIELD], 6:35-6:38\n"
+                + "[PUBLIC, METHOD], 6:39-6:46\n");
+    }
+
     public void testYield() throws Exception {
         enablePreview();
         performTest("YieldTest.java",
diff --git a/java/java.hints/src/org/netbeans/modules/java/hints/jdk/ConvertToSwitchPatternInstanceOf.java b/java/java.hints/src/org/netbeans/modules/java/hints/jdk/ConvertToSwitchPatternInstanceOf.java
new file mode 100644
index 0000000..85e22bd
--- /dev/null
+++ b/java/java.hints/src/org/netbeans/modules/java/hints/jdk/ConvertToSwitchPatternInstanceOf.java
@@ -0,0 +1,187 @@
+package org.netbeans.modules.java.hints.jdk;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import com.sun.source.tree.BlockTree;
+import com.sun.source.tree.CaseTree;
+import com.sun.source.tree.ExpressionStatementTree;
+import com.sun.source.tree.IdentifierTree;
+import com.sun.source.tree.IfTree;
+import com.sun.source.tree.InstanceOfTree;
+import com.sun.source.tree.ParenthesizedTree;
+import com.sun.source.tree.StatementTree;
+import com.sun.source.tree.SwitchTree;
+import com.sun.source.tree.ThrowTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.tree.VariableTree;
+import com.sun.source.util.TreePath;
+import com.sun.tools.javac.tree.JCTree;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.Name;
+import javax.lang.model.type.TypeMirror;
+import org.netbeans.api.java.source.CompilationInfo;
+import org.netbeans.api.java.source.TreeMaker;
+import org.netbeans.api.java.source.WorkingCopy;
+import org.netbeans.spi.editor.hints.ErrorDescription;
+import org.netbeans.spi.editor.hints.Fix;
+import org.netbeans.spi.java.hints.ErrorDescriptionFactory;
+import org.netbeans.spi.java.hints.Hint;
+import org.netbeans.spi.java.hints.HintContext;
+import org.netbeans.spi.java.hints.JavaFix;
+import org.netbeans.spi.java.hints.MatcherUtilities;
+import org.netbeans.spi.java.hints.TriggerPattern;
+import org.netbeans.spi.java.hints.TriggerPatterns;
+import org.netbeans.spi.java.hints.TriggerTreeKind;
+import org.openide.util.Exceptions;
+import org.openide.util.NbBundle;
+
+/**
+ *
+ * @author aksinsin
+ */
+@NbBundle.Messages({
+    "DN_ConvertToSwitchPatternInstanceOf=Convert to switch pattern matching <pattern>",
+    "DESC_ConvertToSwitchPatternInstanceOf=Convert to switch pattern matching <pattern>",
+    "ERR_ConvertToSwitchPatternInstanceOf=switch pattern matching <pattern> can be used here",
+    "FIX_ConvertToSwitchPatternInstanceOf=Use switch pattern matching <pattern>"
+})
+@Hint(displayName="#DN_ConvertToSwitchPatternInstanceOf", description="#DESC_ConvertToSwitchPatternInstanceOf", category="rules15",
+        minSourceVersion = "17")
+public class ConvertToSwitchPatternInstanceOf {
+
+    @TriggerPatterns({
+        @TriggerPattern(value = "if ($expr0 instanceof $typeI0) { $statements0$;} else if ($expr1 instanceof $typeI1) { $statements1$;} else $else$;")
+    })
+    public static ErrorDescription trivial(HintContext ctx) {
+        TreePath parent = ctx.getPath().getParentPath();
+        if (parent.getLeaf().getKind() == Tree.Kind.IF) {
+            return null;
+        }
+        Tree ifPath = ctx.getPath().getLeaf();
+        Name expr0 = ((IdentifierTree) ctx.getVariables().get("$expr0").getLeaf()).getName();
+        int matchVarIndex = 1;
+        while (ifPath != null && ifPath.getKind() == Tree.Kind.IF) {
+            matchVarIndex++;
+            IfTree it = (IfTree) ifPath;
+            if (MatcherUtilities.matches(ctx, new TreePath(ctx.getPath(), it.getCondition()), "($expr" + matchVarIndex + " instanceof $typeI" + matchVarIndex + ")", true)
+                    && MatcherUtilities.matches(ctx, new TreePath(ctx.getPath(), it.getThenStatement()), "{ $typeV" + matchVarIndex + " $var" + matchVarIndex + " = ($typeC" + matchVarIndex + ") $expr" + matchVarIndex + "; $other" + matchVarIndex + "$;}", true)) {
+                if (!((IdentifierTree) ctx.getVariables().get("$expr" + matchVarIndex).getLeaf()).getName().equals(expr0)) {
+                    return null;
+                }
+                for (TreePath tp : ctx.getMultiVariables().get("$other" + matchVarIndex + "$")) {
+                    if (tp.getLeaf().getKind() == Tree.Kind.BREAK || tp.getLeaf().getKind() == Tree.Kind.CONTINUE) {
+                        return null;
+                    }
+                }
+                TypeMirror typeI = ctx.getInfo().getTrees().getTypeMirror(ctx.getVariables().get("$typeI" + matchVarIndex + ""));
+                TypeMirror typeC = ctx.getInfo().getTrees().getTypeMirror(ctx.getVariables().get("$typeC" + matchVarIndex + ""));
+                if (!ctx.getInfo().getTypes().isSameType(typeI, typeC)) {
+                    System.err.println("different types (" + typeI + ", " + typeC + ") in " + ctx.getInfo().getFileObject());
+                    return null;
+                }
+            } else {
+                return null;
+            }
+            ifPath = it.getElseStatement();
+        }
+        if (ifPath != null && ifPath.getKind() == Tree.Kind.BLOCK) {
+            Fix fix = new FixImpl(ctx.getInfo(), ctx.getPath(), true, Collections.emptySet()).toEditorFix();
+            return ErrorDescriptionFactory.forName(ctx, ctx.getPath(), Bundle.ERR_ConvertToSwitchPatternInstanceOf(), fix);
+        } else {
+            return null;
+        }
+
+    }
+
+    private static final class FixImpl extends JavaFix {
+
+        private final boolean removeFirst;
+
+        public FixImpl(CompilationInfo info, TreePath main, boolean removeFirst, Set<TreePath> replaceOccurrences) {
+            super(info, main);
+            this.removeFirst = removeFirst;
+        }
+
+        @Override
+        protected String getText() {
+            return Bundle.FIX_ConvertToSwitchPatternInstanceOf();
+        }
+
+        @Override
+        protected void performRewrite(JavaFix.TransformationContext ctx) {
+            WorkingCopy wc = ctx.getWorkingCopy();
+            TreePath main = ctx.getPath();
+            List<CaseTree> ctl = new LinkedList<>();
+
+            Tree ifPath = ctx.getPath().getLeaf();
+            int matchVarIndex = 1;
+            List<IfTree> ifTrees = new ArrayList<>();
+            while (ifPath != null && ifPath.getKind() == Tree.Kind.IF) {
+                matchVarIndex++;
+                IfTree it = (IfTree) ifPath;
+                ifTrees.add(it);
+                ifPath = it.getElseStatement();
+            }
+
+            InstanceOfTree iot = null;
+            for (IfTree ifTree : ifTrees) {
+                List<Tree> caseBindPattern = new LinkedList<>();
+                iot = (InstanceOfTree) ((ParenthesizedTree) ifTree.getCondition()).getExpression();
+                StatementTree bt = ifTree.getThenStatement();
+                VariableTree var = (VariableTree) ((BlockTree) bt).getStatements().get(0);
+                StatementTree thenBlock = removeFirst ? wc.getTreeMaker().removeBlockStatement((BlockTree) bt, 0) : bt;
+                caseBindPattern.add(wc.getTreeMaker().BindingPattern(wc.getTreeMaker().Variable(wc.getTreeMaker().Modifiers(EnumSet.noneOf(Modifier.class)), var.getName().toString(), iot.getType(), null)));
+                BlockTree blockTree = (BlockTree) thenBlock;
+
+                Tree defaultTree = null;
+                defaultTree = blockTree.getStatements().size() == 1 && isValidCaseTree(blockTree.getStatements().get(0))? blockTree.getStatements().get(0) : thenBlock;
+
+                CaseTree casePatterns = wc.getTreeMaker().CasePatterns(caseBindPattern, defaultTree);
+                ctl.add(casePatterns);
+            }
+            List<Tree> caseDefaultLabel = new LinkedList<>();
+            caseDefaultLabel.add(wc.getTreeMaker().Identifier("default"));
+            BlockTree elseTree = (BlockTree) ifPath;
+            if (elseTree == null) {
+                elseTree = wc.getTreeMaker().Block(new ArrayList<>(), false);
+            }
+
+            Tree defaultTree = elseTree.getStatements().size() == 1 && isValidCaseTree(elseTree.getStatements().get(0))? elseTree.getStatements().get(0) : elseTree;
+            CaseTree casePatterns = wc.getTreeMaker().CasePatterns(caseDefaultLabel, defaultTree);
+            ctl.add(casePatterns);
+            wc.rewrite((IfTree) main.getLeaf(), wc.getTreeMaker().Switch(iot.getExpression(), ctl));
+        }
+
+    }
+
+    private static boolean isValidCaseTree(Tree tree){
+        return ((tree instanceof BlockTree)
+                || (tree instanceof ExpressionStatementTree)
+                || (tree instanceof ThrowTree)
+                || (tree instanceof CaseTree));
+    }
+}
+
diff --git a/java/java.hints/test/unit/src/org/netbeans/modules/java/hints/jdk/ConvertToSwitchPatternInstanceOfTest.java b/java/java.hints/test/unit/src/org/netbeans/modules/java/hints/jdk/ConvertToSwitchPatternInstanceOfTest.java
new file mode 100644
index 0000000..30b6eab
--- /dev/null
+++ b/java/java.hints/test/unit/src/org/netbeans/modules/java/hints/jdk/ConvertToSwitchPatternInstanceOfTest.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.hints.jdk;
+
+import org.netbeans.junit.NbTestCase;
+import org.netbeans.modules.java.hints.test.api.HintTest;
+import javax.lang.model.SourceVersion;
+
+/**
+ *
+ * @author aksinsin
+ */
+public class ConvertToSwitchPatternInstanceOfTest extends NbTestCase {
+    
+    public ConvertToSwitchPatternInstanceOfTest(String name) {
+        super(name);
+    }
+    
+    public void testSimple() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_17"); //NOI18N
+        } catch (IllegalArgumentException ex) {
+            //OK, no RELEASE_17, skip tests
+            return;
+        }
+        HintTest.create()
+                .input("package test;\n"
+                        + "public class Test {\n"
+                        + "    private void test(Object o) {\n"
+                        + "        if (o instanceof String) {\n"
+                        + "            String s = (String) o;\n"
+                        + "            System.out.println(s + \" String\");\n"
+                        + "        } else if (o instanceof StringBuilder) {\n"
+                        + "            StringBuilder sb = (StringBuilder) o;\n"
+                        + "            System.out.println(sb + \" StringBuilder\");\n"
+                        + "        } else if (o instanceof CharSequence) {\n"
+                        + "            CharSequence cs = (CharSequence) o;\n"
+                        + "            System.out.println(cs + \" CharSequence\");\n"
+                        + "        } else {\n"
+                        + "            System.out.println(\"else\");\n"
+                        + "        }\n"
+                        + "    }\n"
+                        + "}")
+                .sourceLevel(SourceVersion.latest().name())
+                .options("--enable-preview")
+                .run(ConvertToSwitchPatternInstanceOf.class)
+                .findWarning("3:8-3:10:verifier:" + Bundle.ERR_ConvertToSwitchPatternInstanceOf())
+                .applyFix()
+                .assertCompilable()
+                .assertOutput("package test;\n"
+                        + "public class Test {\n"
+                        + "    private void test(Object o) {\n"
+                        + "        switch (o) {\n"
+                        + "            case String s -> System.out.println(s + \" String\");\n"
+                        + "            case StringBuilder sb -> System.out.println(sb + \" StringBuilder\");\n"
+                        + "            case CharSequence cs -> System.out.println(cs + \" CharSequence\");\n"
+                        + "            case default -> System.out.println(\"else\");\n"
+                        + "        }\n"
+                        + "    }\n"
+                        + "}\n");
+    }
+}
diff --git a/java/java.source.base/src/org/netbeans/api/java/source/TreeMaker.java b/java/java.source.base/src/org/netbeans/api/java/source/TreeMaker.java
index f513299..97e455a 100644
--- a/java/java.source.base/src/org/netbeans/api/java/source/TreeMaker.java
+++ b/java/java.source.base/src/org/netbeans/api/java/source/TreeMaker.java
@@ -268,6 +268,30 @@ public final class TreeMaker {
     }
     
     /**
+     * Creates a new CaseTree for a rule case (case &lt;constants&gt; -> &lt;body&gt;).
+     *
+     * @param patterns the labels for this case statement.
+     * @param body the case's body
+     * @see com.sun.source.tree.CaseTree
+     * @since 2.39
+     */
+    public CaseTree CasePatterns(List<? extends Tree> patterns, Tree body) {
+        return delegate.CaseMultiplePatterns(patterns, body);
+    }
+    
+    /**
+     * Creates a new CaseTree.
+     *
+     * @param patterns the labels for this case statement.
+     * @param statements the list of statements.
+     * @see com.sun.source.tree.CaseTree
+     * @since 2.39
+     */
+    public CaseTree CasePatterns(List<? extends Tree> patterns, List<? extends StatementTree> statements) {
+        return delegate.CaseMultiplePatterns(patterns, statements);
+    }
+    
+    /**
      * Creates a new CatchTree.
      *
      * @param parameter the exception variable declaration.
diff --git a/java/java.source.base/src/org/netbeans/api/java/source/support/ErrorAwareTreePathScanner.java b/java/java.source.base/src/org/netbeans/api/java/source/support/ErrorAwareTreePathScanner.java
index a04e544..c1d97e6 100644
--- a/java/java.source.base/src/org/netbeans/api/java/source/support/ErrorAwareTreePathScanner.java
+++ b/java/java.source.base/src/org/netbeans/api/java/source/support/ErrorAwareTreePathScanner.java
@@ -19,7 +19,9 @@
 package org.netbeans.api.java.source.support;
 
 import com.sun.source.tree.ErroneousTree;
+import com.sun.source.tree.CaseTree;
 import com.sun.source.util.TreePathScanner;
+import org.netbeans.modules.java.source.TreeShims;
 
 /**
  *
@@ -32,4 +34,9 @@ public class ErrorAwareTreePathScanner<R,P> extends TreePathScanner<R,P> {
         return scan(et.getErrorTrees(), p);
     }
 
+    @Override
+    public R visitCase(CaseTree node, P p) {
+        scan(TreeShims.getLabels(node), p);
+        return super.visitCase(node, p);
+    }
 }
diff --git a/java/java.source.base/src/org/netbeans/api/java/source/support/ErrorAwareTreeScanner.java b/java/java.source.base/src/org/netbeans/api/java/source/support/ErrorAwareTreeScanner.java
index eebbcb5..16e0669 100644
--- a/java/java.source.base/src/org/netbeans/api/java/source/support/ErrorAwareTreeScanner.java
+++ b/java/java.source.base/src/org/netbeans/api/java/source/support/ErrorAwareTreeScanner.java
@@ -19,7 +19,9 @@
 package org.netbeans.api.java.source.support;
 
 import com.sun.source.tree.ErroneousTree;
+import com.sun.source.tree.CaseTree;
 import com.sun.source.util.TreeScanner;
+import org.netbeans.modules.java.source.TreeShims;
 
 /**
  *
@@ -32,4 +34,9 @@ public class ErrorAwareTreeScanner<R,P> extends TreeScanner<R,P> {
         return scan(et.getErrorTrees(), p);
     }
 
+    @Override
+    public R visitCase(CaseTree node, P p) {
+        scan(TreeShims.getLabels(node), p);
+        return super.visitCase(node, p);
+    }
 }
diff --git a/java/java.source.base/src/org/netbeans/modules/java/source/TreeShims.java b/java/java.source.base/src/org/netbeans/modules/java/source/TreeShims.java
index 4cb0807..fb9b24c 100644
--- a/java/java.source.base/src/org/netbeans/modules/java/source/TreeShims.java
+++ b/java/java.source.base/src/org/netbeans/modules/java/source/TreeShims.java
@@ -55,6 +55,10 @@ public class TreeShims {
     public static final String BINDING_VARIABLE = "BINDING_VARIABLE"; //NOI18N
     public static final String RECORD = "RECORD"; //NOI18N
     public static final int PATTERN_MATCHING_INSTANCEOF_PREVIEW_JDK_VERSION = 15; //NOI18N
+    public static final String DEFAULT_CASE_LABEL = "DEFAULT_CASE_LABEL"; //NOI18N
+    public static final String NULL_LITERAL = "NULL_LITERAL"; //NOI18N
+    public static final String PARENTHESIZED_PATTERN = "PARENTHESIZED_PATTERN"; //NOI18N
+    public static final String GUARDED_PATTERN = "GUARDED_PATTERN"; //NOI18N
     
     public static List<? extends ExpressionTree> getExpressions(CaseTree node) {
         try {
@@ -67,6 +71,17 @@ public class TreeShims {
         }
     }
 
+    public static List<? extends Tree> getLabels(CaseTree node) {
+        try {
+            Method getLabels = CaseTree.class.getDeclaredMethod("getLabels");
+            return (List<? extends Tree>) getLabels.invoke(node);
+        } catch (NoSuchMethodException ex) {
+            return null;
+        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
+            throw TreeShims.<RuntimeException>throwAny(ex);
+        }
+    }
+
     public static Tree getBody(CaseTree node) {
         try {
             Method getBody = CaseTree.class.getDeclaredMethod("getBody");
@@ -170,6 +185,49 @@ public class TreeShims {
             throw TreeShims.<RuntimeException>throwAny(ex);
         }
     }
+
+    public static Tree getGuardedPattern(Tree node) {
+        try {
+            Class gpt = Class.forName("com.sun.source.tree.GuardedPatternTree"); //NOI18N
+            return isJDKVersionRelease17_Or_Above()
+                    ? (Tree)gpt.getDeclaredMethod("getPattern").invoke(node)  //NOI18N
+                    : null;
+
+        } catch (NoSuchMethodException | ClassNotFoundException ex) {
+            return null;
+        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
+            throw TreeShims.<RuntimeException>throwAny(ex);
+        }
+    }
+
+    public static Tree getParenthesizedPattern(Tree node) {
+        try {
+            Class ppt = Class.forName("com.sun.source.tree.ParenthesizedPatternTree"); //NOI18N
+            return isJDKVersionRelease17_Or_Above()
+                    ? (Tree)ppt.getDeclaredMethod("getPattern").invoke(node)  //NOI18N
+                    : null;
+
+        } catch (NoSuchMethodException | ClassNotFoundException ex) {
+            return null;
+        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
+            throw TreeShims.<RuntimeException>throwAny(ex);
+        }
+    }
+
+    public static ExpressionTree getGuardedExpression(Tree node) {
+        try {
+            Class gpt = Class.forName("com.sun.source.tree.GuardedPatternTree"); //NOI18N
+            return isJDKVersionRelease17_Or_Above()
+                    ? (ExpressionTree)gpt.getDeclaredMethod("getExpression").invoke(node)  //NOI18N
+                    : null;
+
+        } catch (NoSuchMethodException | ClassNotFoundException ex) {
+            return null;
+        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
+            throw TreeShims.<RuntimeException>throwAny(ex);
+        }
+    }
+
     public static List<? extends Tree> getPermits(ClassTree node) {
         List<? extends Tree> perms = null;
         try {
@@ -322,6 +380,10 @@ public class TreeShims {
         return Integer.valueOf(SourceVersion.latest().name().split("_")[1]).compareTo(16) >= 0;
     }
 
+    public static boolean isJDKVersionRelease17_Or_Above(){
+        return Integer.valueOf(SourceVersion.latest().name().split("_")[1]).compareTo(17) >= 0;
+    }
+
     public static ModuleTree getModule(CompilationUnitTree cut) {
         try {
             return (ModuleTree) CompilationUnitTree.class.getDeclaredMethod("getModule").invoke(cut);
diff --git a/java/java.source.base/src/org/netbeans/modules/java/source/builder/TreeFactory.java b/java/java.source.base/src/org/netbeans/modules/java/source/builder/TreeFactory.java
index 32758b5..94cd00c 100644
--- a/java/java.source.base/src/org/netbeans/modules/java/source/builder/TreeFactory.java
+++ b/java/java.source.base/src/org/netbeans/modules/java/source/builder/TreeFactory.java
@@ -266,6 +266,35 @@ public class TreeFactory {
         }
     }
     
+    public CaseTree CaseMultiplePatterns(List<? extends Tree> expressions, Tree body) {
+        ListBuffer<JCStatement> lb = new ListBuffer<>();
+        lb.append(body instanceof ExpressionTree ? (JCStatement) Break((ExpressionTree) body) : (JCStatement) body);
+        ListBuffer<JCTree> exprs = new ListBuffer<>();
+        for (Tree t : expressions)
+            exprs.append((JCTree)t);
+        try {
+            Class<Enum> caseKind = (Class<Enum>) Class.forName("com.sun.source.tree.CaseTree$CaseKind", false, JCTree.class.getClassLoader());
+            return (CaseTree) make.getClass().getMethod("Case", caseKind, com.sun.tools.javac.util.List.class, com.sun.tools.javac.util.List.class, JCTree.class).invoke(make.at(NOPOS), Enum.valueOf(caseKind, "RULE"), exprs.toList(), lb.toList(), body);
+        } catch (Throwable t) {
+            throw throwAny(t);
+        }
+    }
+    
+    public CaseTree CaseMultiplePatterns(List<? extends Tree> expressions, List<? extends StatementTree> statements) {
+        ListBuffer<JCStatement> lb = new ListBuffer<JCStatement>();
+        for (StatementTree t : statements)
+            lb.append((JCStatement)t);
+        ListBuffer<JCTree> exprs = new ListBuffer<>();
+        for (Tree t : expressions)
+            exprs.append((JCTree)t);
+        try {
+            Class<Enum> caseKind = (Class<Enum>) Class.forName("com.sun.source.tree.CaseTree$CaseKind", false, JCTree.class.getClassLoader());
+            return (CaseTree) make.getClass().getMethod("Case", caseKind, com.sun.tools.javac.util.List.class, com.sun.tools.javac.util.List.class, JCTree.class).invoke(make.at(NOPOS), Enum.valueOf(caseKind, "STATEMENT"), exprs.toList(), lb.toList(), null);
+        } catch (Throwable t) {
+            throw throwAny(t);
+        }
+    }
+    
     public CatchTree Catch(VariableTree parameter, BlockTree block) {
         return make.at(NOPOS).Catch((JCVariableDecl)parameter, (JCBlock)block);
     }
diff --git a/java/java.source.base/src/org/netbeans/modules/java/source/pretty/VeryPretty.java b/java/java.source.base/src/org/netbeans/modules/java/source/pretty/VeryPretty.java
index 1470510..3a8e660 100644
--- a/java/java.source.base/src/org/netbeans/modules/java/source/pretty/VeryPretty.java
+++ b/java/java.source.base/src/org/netbeans/modules/java/source/pretty/VeryPretty.java
@@ -1337,18 +1337,29 @@ public final class VeryPretty extends JCTree.Visitor implements DocTreeVisitor<V
     public void visitCase(JCCase tree) {
         int old = cs.indentCasesFromSwitch() ? indent() : out.leftMargin;
         toLeftMargin();
-        java.util.List<JCExpression> patterns = CasualDiff.getCasePatterns(tree);
-	if (patterns.isEmpty()) {
-	    print("default");
-	} else {
-	    print("case ");
+        java.util.List<JCTree> labels = CasualDiff.getCaseLabelPatterns(tree);
+        if (labels.size() > 0) {
+            print("case ");
             String sep = "";
-            for (JCExpression pat : patterns) {
+            for (JCTree lab : labels) {
                 print(sep);
-                printNoParenExpr(pat);
+                printNoParenExpr(lab);
                 sep = ", "; //TODO: space or not should be a configuration setting
             }
-	}
+        } else {
+            java.util.List<JCExpression> patterns = CasualDiff.getCasePatterns(tree);
+            if (patterns.isEmpty()) {
+                print("default");
+            } else {
+                print("case ");
+                String sep = "";
+                for (JCExpression pat : patterns) {
+                    print(sep);
+                    printNoParenExpr(pat);
+                    sep = ", "; //TODO: space or not should be a configuration setting
+                }
+            }
+        }
         Object caseKind = CasualDiff.getCaseKind(tree);
         if (caseKind == null || !String.valueOf(caseKind).equals("RULE")) {
             print(':');
@@ -2084,6 +2095,9 @@ public final class VeryPretty extends JCTree.Visitor implements DocTreeVisitor<V
             } catch (RuntimeException ex) {
                 Exceptions.printStackTrace(ex);
             }
+        }else if ("DEFAULT_CASE_LABEL".equals(tree.getKind().name())) {
+            print("default");
+            return;
         }
 	print("(UNKNOWN: " + tree + ")");
 	newline();
diff --git a/java/java.source.base/src/org/netbeans/modules/java/source/save/CasualDiff.java b/java/java.source.base/src/org/netbeans/modules/java/source/save/CasualDiff.java
index 5b879c2..011af47 100644
--- a/java/java.source.base/src/org/netbeans/modules/java/source/save/CasualDiff.java
+++ b/java/java.source.base/src/org/netbeans/modules/java/source/save/CasualDiff.java
@@ -2078,6 +2078,14 @@ public class CasualDiff {
         }
     }
 
+    public static List<JCTree> getCaseLabelPatterns(JCCase cs) {
+        try {
+            return (List<JCTree>) CaseTree.class.getDeclaredMethod("getLabels").invoke(cs);
+        } catch (Throwable t) {
+            return Collections.emptyList();
+        }
+    }
+     
     public static Object getCaseKind(JCCase cs) {
         try {
             return CaseTree.class.getDeclaredMethod("getCaseKind").invoke(cs);
diff --git a/java/java.source.base/src/org/netbeans/modules/java/source/save/Reformatter.java b/java/java.source.base/src/org/netbeans/modules/java/source/save/Reformatter.java
index 585485d..18eea7f 100644
--- a/java/java.source.base/src/org/netbeans/modules/java/source/save/Reformatter.java
+++ b/java/java.source.base/src/org/netbeans/modules/java/source/save/Reformatter.java
@@ -594,6 +594,12 @@ public class Reformatter implements ReformatTask {
                     case TreeShims.BINDING_PATTERN:
                         ret = scanBindingPattern(tree, p);
                         break;
+                    case TreeShims.GUARDED_PATTERN:
+                        ret = scanGuardedPattern(tree, p);
+                        break;
+                    case TreeShims.PARENTHESIZED_PATTERN:
+                        ret = scanParenthesizedPattern(tree, p);
+                        break;
                     case TreeShims.RECORD:
                         ret = scanRecord((ClassTree) tree, p);
                         break;
@@ -2809,6 +2815,47 @@ public class Reformatter implements ReformatTask {
             return true;
         }
 
+        private Boolean scanGuardedPattern(Tree node, Void p) {
+            try {
+                Tree gpt = TreeShims.getGuardedPattern(node);
+                if (gpt != null) {
+                    if (scanParenthesizedPattern(gpt, p) == false) {
+                        Name name = TreeShims.getBinding(gpt);
+                        Tree type = TreeShims.getBindingPatternType(gpt);
+                        scan(type, p);
+                        if (name != null) {
+                            removeWhiteSpace(IDENTIFIER);
+                        }
+                    }
+                }
+            } catch (RuntimeException ex) {
+                return false;
+            }
+
+            ExpressionTree exprTree = TreeShims.getGuardedExpression(node);
+            if (exprTree != null) {
+                accept(IDENTIFIER);
+                removeWhiteSpace(IDENTIFIER);
+                scan(exprTree, p);
+            }
+            return true;
+        }
+
+        private Boolean scanParenthesizedPattern(Tree node, Void p) {
+            try {
+                Tree ppt = TreeShims.getParenthesizedPattern(node);
+                if (ppt != null) {
+                    if (scanGuardedPattern(ppt, p) == false) {
+                        scanBindingPattern(ppt, p);
+                    }
+                    removeWhiteSpace(IDENTIFIER);
+                }
+            } catch (RuntimeException ex) {
+                return false;
+            }
+            return true;
+        }
+
         private Boolean handleYield(Tree node, Void p) {
             ExpressionTree exprTree = TreeShims.getYieldValue(node);
             if (exprTree != null) {
@@ -2930,20 +2977,44 @@ public class Reformatter implements ReformatTask {
 
         @Override
         public Boolean visitCase(CaseTree node, Void p) {
-            List<? extends ExpressionTree> exprs = TreeShims.getExpressions(node);
-            if (exprs.size() > 0) {
+            List<? extends Tree> labels = TreeShims.getLabels(node);
+            if (labels != null && labels.size() > 0) {
+                if (tokens.token().id() == JavaTokenId.DEFAULT && labels.get(0).getKind().toString().equals(TreeShims.DEFAULT_CASE_LABEL)) {
+                    accept(DEFAULT);
+                } else {
+                    accept(CASE);
+                    space();
+                    for (Tree label : labels) {
+                        if (label.getKind().toString().equals(TreeShims.DEFAULT_CASE_LABEL)) {
+                            removeWhiteSpace(JavaTokenId.DEFAULT);
+                            accept(DEFAULT);
+                        } else if (label.getKind().toString().equals(TreeShims.BINDING_PATTERN)
+                                || label.getKind().toString().equals(TreeShims.PARENTHESIZED_PATTERN)
+                                || label.getKind().toString().equals(TreeShims.GUARDED_PATTERN)) {
+                            removeWhiteSpace(JavaTokenId.IDENTIFIER);
+                            scan(label, p);
+                        } else if (label.getKind().toString().equals(TreeShims.NULL_LITERAL)) {
+                            removeWhiteSpace(JavaTokenId.NULL);
+                            scan(label, p);
+                        } else {
+                            scan(label, p);
+                        }
+                    }
+                }
+            } else if (TreeShims.getExpressions(node).size() > 0) {
+                List<? extends ExpressionTree> exprs = TreeShims.getExpressions(node);
                 accept(CASE);
                 space();
-                for (ExpressionTree exp : exprs) {
+                exprs.forEach(exp -> {
                     scan(exp, p);
-                }
+                });
             } else {
                 accept(DEFAULT);
             }
             List<? extends StatementTree> statements = node.getStatements();
             Tree caseBody = null;
             if(statements != null)
-            accept(COLON);
+                accept(COLON);
             else {
                 space();
                 accept(ARROW);
@@ -2979,6 +3050,24 @@ public class Reformatter implements ReformatTask {
             return true;
         }
 
+        private void removeWhiteSpace(JavaTokenId forToken) {
+            do {
+                if (tokens.offset() >= endPos) {
+                    break;
+                }
+                if (tokens.token().id() == forToken) {
+                    break;
+                }
+                if (tokens.token().id() == WHITESPACE) {
+                    String text = tokens.token().text().toString();
+                    String ind = getIndent();
+                    if (!ind.equals(text)) {
+                        addDiff(new Diff(tokens.offset(), tokens.offset() + tokens.token().length(), " "));
+                    }
+                }
+            } while (tokens.moveNext());
+        }
+
         @Override
         public Boolean visitBreak(BreakTree node, Void p) {
             JavaTokenId token = accept(BREAK);
@@ -5637,5 +5726,4 @@ public class Reformatter implements ReformatTask {
             return "Diff<" + start + "," + end + ">:" + text; //NOI18N
         }
     }
-}
-
+}
\ No newline at end of file
diff --git a/java/java.source.base/test/unit/src/org/netbeans/modules/java/source/save/FormatingTest.java b/java/java.source.base/test/unit/src/org/netbeans/modules/java/source/save/FormatingTest.java
index 40846b2..2ce8bf9 100644
--- a/java/java.source.base/test/unit/src/org/netbeans/modules/java/source/save/FormatingTest.java
+++ b/java/java.source.base/test/unit/src/org/netbeans/modules/java/source/save/FormatingTest.java
@@ -1734,6 +1734,12 @@ public class FormatingTest extends NbTestCase {
     }
 
     public void testSwitch() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_17"); //NOI18N
+            return;
+        } catch (IllegalArgumentException ex) {
+            //OK,RELEASE_17, skip test
+        }
         testFile = new File(getWorkDir(), "Test.java");
         TestUtilities.copyStringToFile(testFile,
                 "package hierbas.del.litoral;\n\n"
@@ -1962,6 +1968,243 @@ public class FormatingTest extends NbTestCase {
         reformat(doc, content, golden);
         preferences.putBoolean("indentCasesFromSwitch", true);
     }
+
+    public void testSwitchOnJDK17() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_17"); //NOI18N
+        } catch (IllegalArgumentException ex) {
+            //OK, no RELEASE_17, skip test
+            return;
+        }
+        testFile = new File(getWorkDir(), "Test.java");
+        TestUtilities.copyStringToFile(testFile,
+                "package hierbas.del.litoral;\n\n"
+                + "public class Test {\n"
+                + "    public void taragui(int i) {\n"
+                + "    }\n"
+                + "}\n");
+        FileObject testSourceFO = FileUtil.toFileObject(testFile);
+        DataObject testSourceDO = DataObject.find(testSourceFO);
+        EditorCookie ec = (EditorCookie)testSourceDO.getCookie(EditorCookie.class);
+        final Document doc = ec.openDocument();
+        doc.putProperty(Language.class, JavaTokenId.language());
+        JavaSource testSource = JavaSource.forDocument(doc);
+        final String stmt =
+                "switch (i) {case 0: System.out.println(i); break; default: System.out.println(\"DEFAULT\");}";
+        Task<WorkingCopy> task = new Task<WorkingCopy>() {
+
+            @Override
+            public void run(WorkingCopy workingCopy) throws java.io.IOException {
+                workingCopy.toPhase(Phase.RESOLVED);
+                ClassTree clazz = (ClassTree)workingCopy.getCompilationUnit().getTypeDecls().get(0);
+                MethodTree method = (MethodTree)clazz.getMembers().get(1);
+                BlockTree block = method.getBody();
+                StatementTree statement = workingCopy.getTreeUtilities().parseStatement(stmt, new SourcePositions[1]);
+                workingCopy.rewrite(block, workingCopy.getTreeMaker().addBlockStatement(block, statement));
+            }
+        };
+        testSource.runModificationTask(task).commit();
+
+        Preferences preferences = MimeLookup.getLookup(JavaTokenId.language().mimeType()).lookup(Preferences.class);
+        preferences.putBoolean("spaceBeforeSwitchParen", false);
+        preferences.putBoolean("spaceWithinSwitchParens", true);
+        preferences.putBoolean("spaceBeforeSwitchLeftBrace", false);
+        testSource.runModificationTask(task).commit();
+        preferences.putBoolean("spaceBeforeSwitchParen", true);
+        preferences.putBoolean("spaceWithinSwitchParens", false);
+        preferences.putBoolean("spaceBeforeSwitchLeftBrace", true);
+
+        preferences.put("otherBracePlacement", CodeStyle.BracePlacement.NEW_LINE.name());
+        testSource.runModificationTask(task).commit();
+
+        preferences.put("otherBracePlacement", CodeStyle.BracePlacement.NEW_LINE_HALF_INDENTED.name());
+        testSource.runModificationTask(task).commit();
+
+        preferences.put("otherBracePlacement", CodeStyle.BracePlacement.NEW_LINE_INDENTED.name());
+        testSource.runModificationTask(task).commit();
+        preferences.put("otherBracePlacement", CodeStyle.BracePlacement.SAME_LINE.name());
+
+        preferences.putBoolean("indentCasesFromSwitch", false);
+        testSource.runModificationTask(task).commit();
+        preferences.putBoolean("indentCasesFromSwitch", true);
+
+        ec.saveDocument();
+        String res = TestUtilities.copyFileToString(testFile);
+        System.err.println(res);
+
+        String golden =
+                "package hierbas.del.litoral;\n\n"
+                + "public class Test {\n"
+                + "    public void taragui(int i) {\n"
+                + "        switch (i) {\n"
+                + "            case 0:\n"
+                + "                System.out.println(i);\n"
+                + "                break;\n"
+                + "            case default:\n"
+                + "                System.out.println(\"DEFAULT\");\n"
+                + "        }\n"
+                + "        switch( i ){\n"
+                + "            case 0:\n"
+                + "                System.out.println(i);\n"
+                + "                break;\n"
+                + "            case default:\n"
+                + "                System.out.println(\"DEFAULT\");\n"
+                + "        }\n"
+                + "        switch (i)\n"
+                + "        {\n"
+                + "            case 0:\n"
+                + "                System.out.println(i);\n"
+                + "                break;\n"
+                + "            case default:\n"
+                + "                System.out.println(\"DEFAULT\");\n"
+                + "        }\n"
+                + "        switch (i)\n"
+                + "          {\n"
+                + "            case 0:\n"
+                + "                System.out.println(i);\n"
+                + "                break;\n"
+                + "            case default:\n"
+                + "                System.out.println(\"DEFAULT\");\n"
+                + "          }\n"
+                + "        switch (i)\n"
+                + "            {\n"
+                + "            case 0:\n"
+                + "                System.out.println(i);\n"
+                + "                break;\n"
+                + "            case default:\n"
+                + "                System.out.println(\"DEFAULT\");\n"
+                + "            }\n"
+                + "        switch (i) {\n"
+                + "        case 0:\n"
+                + "            System.out.println(i);\n"
+                + "            break;\n"
+                + "        case default:\n"
+                + "            System.out.println(\"DEFAULT\");\n"
+                + "        }\n"
+                + "    }\n"
+                + "}\n";
+        assertEquals(golden, res);
+
+        String content =
+                "package hierbas.del.litoral;"
+                + "public class Test{"
+                + "public void taragui(int i){"
+                + "switch(i){"
+                + "case 0:"
+                + "System.out.println(i);"
+                + "break;"
+                + "default:"
+                + "System.out.println(\"DEFAULT\");"
+                + "}"
+                + "}"
+                + "}\n";
+
+        golden =
+                "package hierbas.del.litoral;\n\n"
+                + "public class Test {\n\n"
+                + "    public void taragui(int i) {\n"
+                + "        switch (i) {\n"
+                + "            case 0:\n"
+                + "                System.out.println(i);\n"
+                + "                break;\n"
+                + "            default:\n"
+                + "                System.out.println(\"DEFAULT\");\n"
+                + "        }\n"
+                + "    }\n"
+                + "}\n";
+        reformat(doc, content, golden);
+
+        golden =
+                "package hierbas.del.litoral;\n\n"
+                + "public class Test {\n\n"
+                + "    public void taragui(int i) {\n"
+                + "        switch( i ){\n"
+                + "            case 0:\n"
+                + "                System.out.println(i);\n"
+                + "                break;\n"
+                + "            default:\n"
+                + "                System.out.println(\"DEFAULT\");\n"
+                + "        }\n"
+                + "    }\n"
+                + "}\n";
+        preferences.putBoolean("spaceBeforeSwitchParen", false);
+        preferences.putBoolean("spaceWithinSwitchParens", true);
+        preferences.putBoolean("spaceBeforeSwitchLeftBrace", false);
+        reformat(doc, content, golden);
+        preferences.putBoolean("spaceBeforeSwitchParen", true);
+        preferences.putBoolean("spaceWithinSwitchParens", false);
+        preferences.putBoolean("spaceBeforeSwitchLeftBrace", true);
+
+        golden =
+                "package hierbas.del.litoral;\n\n"
+                + "public class Test {\n\n"
+                + "    public void taragui(int i) {\n"
+                + "        switch (i)\n"
+                + "        {\n"
+                + "            case 0:\n"
+                + "                System.out.println(i);\n"
+                + "                break;\n"
+                + "            default:\n"
+                + "                System.out.println(\"DEFAULT\");\n"
+                + "        }\n"
+                + "    }\n"
+                + "}\n";
+        preferences.put("otherBracePlacement", CodeStyle.BracePlacement.NEW_LINE.name());
+        reformat(doc, content, golden);
+
+        golden =
+                "package hierbas.del.litoral;\n\n"
+                + "public class Test {\n\n"
+                + "    public void taragui(int i) {\n"
+                + "        switch (i)\n"
+                + "          {\n"
+                + "            case 0:\n"
+                + "                System.out.println(i);\n"
+                + "                break;\n"
+                + "            default:\n"
+                + "                System.out.println(\"DEFAULT\");\n"
+                + "          }\n"
+                + "    }\n"
+                + "}\n";
+        preferences.put("otherBracePlacement", CodeStyle.BracePlacement.NEW_LINE_HALF_INDENTED.name());
+        reformat(doc, content, golden);
+
+        golden =
+                "package hierbas.del.litoral;\n\n"
+                + "public class Test {\n\n"
+                + "    public void taragui(int i) {\n"
+                + "        switch (i)\n"
+                + "            {\n"
+                + "            case 0:\n"
+                + "                System.out.println(i);\n"
+                + "                break;\n"
+                + "            default:\n"
+                + "                System.out.println(\"DEFAULT\");\n"
+                + "            }\n"
+                + "    }\n"
+                + "}\n";
+        preferences.put("otherBracePlacement", CodeStyle.BracePlacement.NEW_LINE_INDENTED.name());
+        reformat(doc, content, golden);
+        preferences.put("otherBracePlacement", CodeStyle.BracePlacement.SAME_LINE.name());
+
+        golden =
+                "package hierbas.del.litoral;\n\n"
+                + "public class Test {\n\n"
+                + "    public void taragui(int i) {\n"
+                + "        switch (i) {\n"
+                + "        case 0:\n"
+                + "            System.out.println(i);\n"
+                + "            break;\n"
+                + "        default:\n"
+                + "            System.out.println(\"DEFAULT\");\n"
+                + "        }\n"
+                + "    }\n"
+                + "}\n";
+        preferences.putBoolean("indentCasesFromSwitch", false);
+        reformat(doc, content, golden);
+        preferences.putBoolean("indentCasesFromSwitch", true);
+
+    }
     public void testRuleSwitch() throws Exception {
         testFile = new File(getWorkDir(), "Test.java");
         TestUtilities.copyStringToFile(testFile,
@@ -2362,6 +2605,776 @@ public class FormatingTest extends NbTestCase {
         reformat(doc, content, golden);
     }
 
+    public void testSwitchCaseNull() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_17"); //NOI18N
+        } catch (IllegalArgumentException ex) {
+            //OK, no RELEASE_17, skip test
+            return;
+        }
+        testFile = new File(getWorkDir(), "Test.java");
+        TestUtilities.copyStringToFile(testFile, "");
+        FileObject testSourceFO = FileUtil.toFileObject(testFile);
+        DataObject testSourceDO = DataObject.find(testSourceFO);
+        EditorCookie ec = (EditorCookie) testSourceDO.getCookie(EditorCookie.class);
+        final Document doc = ec.openDocument();
+        doc.putProperty(Language.class, JavaTokenId.language());
+        String content = "package p;"
+                + "public class Test{    \n"
+                + "void testSwitchCaseNull() {\n"
+                + "        Object str = \"pattern matching switch\";\n"
+                + "        switch (str) {\n"
+                + " case \n"
+                + "         null           ->                      System.out.println(\"case with null formatting\");\n"
+                + "            default ->\n"
+                + "                System.out.println(\"default formatting\");\n"
+                + "        }\n"
+                + "    }\n"
+                + "}";
+
+        String golden
+                = "package p;\n"
+                + "\n"
+                + "public class Test {\n"
+                + "\n"
+                + "    void testSwitchCaseNull() {\n"
+                + "        Object str = \"pattern matching switch\";\n"
+                + "        switch (str) {\n"
+                + "            case null ->\n"
+                + "                System.out.println(\"case with null formatting\");\n"
+                + "            default ->\n"
+                + "                System.out.println(\"default formatting\");\n"
+                + "        }\n"
+                + "    }\n"
+                + "}\n";
+        reformat(doc, content, golden);
+    }
+
+    public void testSwitchCaseDefault() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_17"); //NOI18N
+        } catch (IllegalArgumentException ex) {
+            //OK, no RELEASE_17, skip test
+            return;
+        }
+        testFile = new File(getWorkDir(), "Test.java");
+        TestUtilities.copyStringToFile(testFile, "");
+        FileObject testSourceFO = FileUtil.toFileObject(testFile);
+        DataObject testSourceDO = DataObject.find(testSourceFO);
+        EditorCookie ec = (EditorCookie) testSourceDO.getCookie(EditorCookie.class);
+        final Document doc = ec.openDocument();
+        doc.putProperty(Language.class, JavaTokenId.language());
+        String content = "package p;"
+                + "public class Test{    \n"
+                + " void testSwitchCaseDefault() {\n"
+                + "        Object str = \"pattern matching switch\";\n"
+                + "        switch (str) {\n"
+                + "            case\n"
+                + "          \n"
+                + " default\n"
+                + "                    ->\n"
+                + "                System.out.println(\"default formatting\");\n"
+                + "        }\n"
+                + "    }"
+                + "}";
+
+        String golden
+                = "package p;\n"
+                + "\n"
+                + "public class Test {\n"
+                + "\n"
+                + "    void testSwitchCaseDefault() {\n"
+                + "        Object str = \"pattern matching switch\";\n"
+                + "        switch (str) {\n"
+                + "            case default ->\n"
+                + "                System.out.println(\"default formatting\");\n"
+                + "        }\n"
+                + "    }\n"
+                + "}\n";
+        reformat(doc, content, golden);
+    }
+
+    public void testSwitchCaseNullAndDefault() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_17"); //NOI18N
+        } catch (IllegalArgumentException ex) {
+            //OK, no RELEASE_17, skip test
+            return;
+        }
+        testFile = new File(getWorkDir(), "Test.java");
+        TestUtilities.copyStringToFile(testFile, "");
+        FileObject testSourceFO = FileUtil.toFileObject(testFile);
+        DataObject testSourceDO = DataObject.find(testSourceFO);
+        EditorCookie ec = (EditorCookie) testSourceDO.getCookie(EditorCookie.class);
+        final Document doc = ec.openDocument();
+        doc.putProperty(Language.class, JavaTokenId.language());
+        String content = "package p;"
+                + "public class Test{    \n"
+                + "void testSwitchCaseNullAndDefault() {\n"
+                + "        Object str = \"pattern matching switch\";\n"
+                + "        switch (str) {\n"
+                + "   case \n"
+                + "null,        default         ->System.out.println(\"case with null and default formatting\");\n"
+                + "           \n"
+                + "        }\n"
+                + "    }"
+                + "}";
+
+        String golden
+                = "package p;\n"
+                + "\n"
+                + "public class Test {\n"
+                + "\n"
+                + "    void testSwitchCaseNullAndDefault() {\n"
+                + "        Object str = \"pattern matching switch\";\n"
+                + "        switch (str) {\n"
+                + "            case null, default ->\n"
+                + "                System.out.println(\"case with null and default formatting\");\n"
+                + "\n"
+                + "        }\n"
+                + "    }\n"
+                + "}\n";
+        reformat(doc, content, golden);
+    }
+
+    public void testSwitchCaseBindingPattern() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_17"); //NOI18N
+        } catch (IllegalArgumentException ex) {
+            //OK, no RELEASE_17, skip test
+            return;
+        }
+        testFile = new File(getWorkDir(), "Test.java");
+        TestUtilities.copyStringToFile(testFile, "");
+        FileObject testSourceFO = FileUtil.toFileObject(testFile);
+        DataObject testSourceDO = DataObject.find(testSourceFO);
+        EditorCookie ec = (EditorCookie) testSourceDO.getCookie(EditorCookie.class);
+        final Document doc = ec.openDocument();
+        doc.putProperty(Language.class, JavaTokenId.language());
+        String content = "package p;"
+                + "public class Test{    \n"
+                + " void testSwitchCaseBindingPattern() {\n"
+                + "        Object str = \"pattern matching switch\";\n"
+                + "        switch (str) {\n"
+                + "    case \n"
+                + "            String          \n"
+                + "            s \n"
+                + "            ->      System.out.println(\"case with binding pattern formatting\");\n"
+                + "            default ->\n"
+                + "                System.out.println(\"default formatting\");\n"
+                + "        }\n"
+                + "    }"
+                + "}";
+
+        String golden
+                = "package p;\n"
+                + "\n"
+                + "public class Test {\n"
+                + "\n"
+                + "    void testSwitchCaseBindingPattern() {\n"
+                + "        Object str = \"pattern matching switch\";\n"
+                + "        switch (str) {\n"
+                + "            case String s ->\n"
+                + "                System.out.println(\"case with binding pattern formatting\");\n"
+                + "            default ->\n"
+                + "                System.out.println(\"default formatting\");\n"
+                + "        }\n"
+                + "    }\n"
+                + "}\n"
+                + "";
+        reformat(doc, content, golden);
+    }
+
+    public void testSwitchCaseNullAndBindingPattern() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_17"); //NOI18N
+        } catch (IllegalArgumentException ex) {
+            //OK, no RELEASE_17, skip test
+            return;
+        }
+        testFile = new File(getWorkDir(), "Test.java");
+        TestUtilities.copyStringToFile(testFile, "");
+        FileObject testSourceFO = FileUtil.toFileObject(testFile);
+        DataObject testSourceDO = DataObject.find(testSourceFO);
+        EditorCookie ec = (EditorCookie) testSourceDO.getCookie(EditorCookie.class);
+        final Document doc = ec.openDocument();
+        doc.putProperty(Language.class, JavaTokenId.language());
+        String content = "package p;"
+                + "public class Test{    \n"
+                + "void testSwitchCaseNullAndBindingPattern() {\n"
+                + "        Object str = \"pattern matching switch\";\n"
+                + "        switch (str) {\n"
+                + "    case            null,\n"
+                + "            String          \n"
+                + "            s \n"
+                + "            ->      System.out.println(\"case with null and binding pattern formatting\");\n"
+                + "            default ->\n"
+                + "                System.out.println(\"default formatting\");\n"
+                + "        }\n"
+                + "    }"
+                + "}";
+
+        String golden
+                = "package p;\n"
+                + "\n"
+                + "public class Test {\n"
+                + "\n"
+                + "    void testSwitchCaseNullAndBindingPattern() {\n"
+                + "        Object str = \"pattern matching switch\";\n"
+                + "        switch (str) {\n"
+                + "            case null, String s ->\n"
+                + "                System.out.println(\"case with null and binding pattern formatting\");\n"
+                + "            default ->\n"
+                + "                System.out.println(\"default formatting\");\n"
+                + "        }\n"
+                + "    }\n"
+                + "}\n"
+                + "";
+        reformat(doc, content, golden);
+    }
+
+    public void testSwitchCaseGuardedPattern() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_17"); //NOI18N
+        } catch (IllegalArgumentException ex) {
+            //OK, no RELEASE_17, skip test
+            return;
+        }
+        testFile = new File(getWorkDir(), "Test.java");
+        TestUtilities.copyStringToFile(testFile, "");
+        FileObject testSourceFO = FileUtil.toFileObject(testFile);
+        DataObject testSourceDO = DataObject.find(testSourceFO);
+        EditorCookie ec = (EditorCookie) testSourceDO.getCookie(EditorCookie.class);
+        final Document doc = ec.openDocument();
+        doc.putProperty(Language.class, JavaTokenId.language());
+        String content = "package p;"
+                + "public class Test{    \n"
+                + "void testSwitchCaseGuardedPattern() {\n"
+                + "        Object str = \"pattern matching switch\";\n"
+                + "        switch (str) {\n"
+                + "case \n"
+                + "      String       s &&       s.length() == 1\n"
+                + "                    \n"
+                + "                    ->\n"
+                + "                System.out.println(\"case with guarded pattern formatting\");\n"
+                + "            default ->\n"
+                + "                System.out.println(\"default formatting\");\n"
+                + "        }\n"
+                + "    }"
+                + "}";
+
+        String golden
+                = "package p;\n"
+                + "\n"
+                + "public class Test {\n"
+                + "\n"
+                + "    void testSwitchCaseGuardedPattern() {\n"
+                + "        Object str = \"pattern matching switch\";\n"
+                + "        switch (str) {\n"
+                + "            case String s && s.length() == 1 ->\n"
+                + "                System.out.println(\"case with guarded pattern formatting\");\n"
+                + "            default ->\n"
+                + "                System.out.println(\"default formatting\");\n"
+                + "        }\n"
+                + "    }\n"
+                + "}\n"
+                + "";
+        reformat(doc, content, golden);
+    }
+
+    public void testSwitchCaseNullAndGuardedPattern() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_17"); //NOI18N
+        } catch (IllegalArgumentException ex) {
+            //OK, no RELEASE_17, skip test
+            return;
+        }
+        testFile = new File(getWorkDir(), "Test.java");
+        TestUtilities.copyStringToFile(testFile, "");
+        FileObject testSourceFO = FileUtil.toFileObject(testFile);
+        DataObject testSourceDO = DataObject.find(testSourceFO);
+        EditorCookie ec = (EditorCookie) testSourceDO.getCookie(EditorCookie.class);
+        final Document doc = ec.openDocument();
+        doc.putProperty(Language.class, JavaTokenId.language());
+        String content = "package p;"
+                + "public class Test{    \n"
+                + "void testSwitchCaseNullAndGuardedPattern() {\n"
+                + "        Object str = \"pattern matching switch\";\n"
+                + "        switch (str) {\n"
+                + "case            \n"
+                + "                    null,\n"
+                + "      String       s &&       s.length() == 1\n"
+                + "                    \n"
+                + "                    ->\n"
+                + "                System.out.println(\"case with null and guarded pattern formatting\");\n"
+                + "            default ->\n"
+                + "                System.out.println(\"default formatting\");\n"
+                + "        }\n"
+                + "    }"
+                + "}";
+
+        String golden
+                = "package p;\n"
+                + "\n"
+                + "public class Test {\n"
+                + "\n"
+                + "    void testSwitchCaseNullAndGuardedPattern() {\n"
+                + "        Object str = \"pattern matching switch\";\n"
+                + "        switch (str) {\n"
+                + "            case null, String s && s.length() == 1 ->\n"
+                + "                System.out.println(\"case with null and guarded pattern formatting\");\n"
+                + "            default ->\n"
+                + "                System.out.println(\"default formatting\");\n"
+                + "        }\n"
+                + "    }\n"
+                + "}\n"
+                + "";
+        reformat(doc, content, golden);
+    }
+
+    public void testSwitchCaseParenthesizedBindingPattern() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_17"); //NOI18N
+        } catch (IllegalArgumentException ex) {
+            //OK, no RELEASE_17, skip test
+            return;
+        }
+        testFile = new File(getWorkDir(), "Test.java");
+        TestUtilities.copyStringToFile(testFile, "");
+        FileObject testSourceFO = FileUtil.toFileObject(testFile);
+        DataObject testSourceDO = DataObject.find(testSourceFO);
+        EditorCookie ec = (EditorCookie) testSourceDO.getCookie(EditorCookie.class);
+        final Document doc = ec.openDocument();
+        doc.putProperty(Language.class, JavaTokenId.language());
+        String content = "package p;"
+                + "public class Test{    \n"
+                + "void testSwitchCaseParenthesizedBindingPattern() {\n"
+                + "        Object str = \"pattern matching switch\";\n"
+                + "        switch (str) {\n"
+                + "case \n"
+                + "        (String       \n"
+                + "        s )\n"
+                + "                    \n"
+                + "                    ->\n"
+                + "                System.out.println(\"case with Parenthesized Binding Pattern formatting\");\n"
+                + "            default ->\n"
+                + "                System.out.println(\"default formatting\");\n"
+                + "        }\n"
+                + "    } "
+                + "}";
+
+        String golden
+                = "package p;\n"
+                + "\n"
+                + "public class Test {\n"
+                + "\n"
+                + "    void testSwitchCaseParenthesizedBindingPattern() {\n"
+                + "        Object str = \"pattern matching switch\";\n"
+                + "        switch (str) {\n"
+                + "            case (String s ) ->\n"
+                + "                System.out.println(\"case with Parenthesized Binding Pattern formatting\");\n"
+                + "            default ->\n"
+                + "                System.out.println(\"default formatting\");\n"
+                + "        }\n"
+                + "    }\n"
+                + "}\n"
+                + "";
+        reformat(doc, content, golden);
+    }
+
+    public void testSwitchCaseNullAndParenthesizedBindingPattern() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_17"); //NOI18N
+        } catch (IllegalArgumentException ex) {
+            //OK, no RELEASE_17, skip test
+            return;
+        }
+        testFile = new File(getWorkDir(), "Test.java");
+        TestUtilities.copyStringToFile(testFile, "");
+        FileObject testSourceFO = FileUtil.toFileObject(testFile);
+        DataObject testSourceDO = DataObject.find(testSourceFO);
+        EditorCookie ec = (EditorCookie) testSourceDO.getCookie(EditorCookie.class);
+        final Document doc = ec.openDocument();
+        doc.putProperty(Language.class, JavaTokenId.language());
+        String content = "package p;"
+                + "public class Test{    \n"
+                + "void testSwitchCaseNullAndParenthesizedBindingPattern() {\n"
+                + "        Object str = \"pattern matching switch\";\n"
+                + "        switch (str) {\n"
+                + "case            null,\n"
+                + "        (String       \n"
+                + "        s )\n"
+                + "                    \n"
+                + "                    ->System.out.println(\"case with null and Parenthesized Binding Pattern formatting\");\n"
+                + "            default ->\n"
+                + "                System.out.println(\"default formatting\");\n"
+                + "        }\n"
+                + "    }"
+                + "}";
+
+        String golden
+                = "package p;\n"
+                + "\n"
+                + "public class Test {\n"
+                + "\n"
+                + "    void testSwitchCaseNullAndParenthesizedBindingPattern() {\n"
+                + "        Object str = \"pattern matching switch\";\n"
+                + "        switch (str) {\n"
+                + "            case null, (String s ) ->\n"
+                + "                System.out.println(\"case with null and Parenthesized Binding Pattern formatting\");\n"
+                + "            default ->\n"
+                + "                System.out.println(\"default formatting\");\n"
+                + "        }\n"
+                + "    }\n"
+                + "}\n"
+                + "";
+        reformat(doc, content, golden);
+    }
+
+    public void testSwitchCaseParenthesizedGuardedPattern() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_17"); //NOI18N
+        } catch (IllegalArgumentException ex) {
+            //OK, no RELEASE_17, skip test
+            return;
+        }
+        testFile = new File(getWorkDir(), "Test.java");
+        TestUtilities.copyStringToFile(testFile, "");
+        FileObject testSourceFO = FileUtil.toFileObject(testFile);
+        DataObject testSourceDO = DataObject.find(testSourceFO);
+        EditorCookie ec = (EditorCookie) testSourceDO.getCookie(EditorCookie.class);
+        final Document doc = ec.openDocument();
+        doc.putProperty(Language.class, JavaTokenId.language());
+        String content = "package p;"
+                + "public class Test{    \n"
+                + "void testSwitchCaseParenthesizedGuardedPattern() {\n"
+                + "        Object str = \"pattern matching switch\";\n"
+                + "        switch (str) {\n"
+                + "case \n"
+                + "        (String       \n"
+                + "        s       &&\n"
+                + "        s.length() == 1\n"
+                + "        )\n"
+                + "                    \n"
+                + "                    ->\n"
+                + "                System.out.println(\"case with Parenthesized Guarded Pattern formatting\");default ->\n"
+                + "                System.out.println(\"default formatting\");\n"
+                + "        }\n"
+                + "    }"
+                + "}";
+
+        String golden
+                = "package p;\n"
+                + "\n"
+                + "public class Test {\n"
+                + "\n"
+                + "    void testSwitchCaseParenthesizedGuardedPattern() {\n"
+                + "        Object str = \"pattern matching switch\";\n"
+                + "        switch (str) {\n"
+                + "            case (String s && s.length() == 1 ) ->\n"
+                + "                System.out.println(\"case with Parenthesized Guarded Pattern formatting\");\n"
+                + "            default ->\n"
+                + "                System.out.println(\"default formatting\");\n"
+                + "        }\n"
+                + "    }\n"
+                + "}\n"
+                + "";
+        reformat(doc, content, golden);
+    }
+
+    public void testSwitchCaseParenthesizedGuardedPatternAndNull() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_17"); //NOI18N
+        } catch (IllegalArgumentException ex) {
+            //OK, no RELEASE_17, skip test
+            return;
+        }
+        testFile = new File(getWorkDir(), "Test.java");
+        TestUtilities.copyStringToFile(testFile, "");
+        FileObject testSourceFO = FileUtil.toFileObject(testFile);
+        DataObject testSourceDO = DataObject.find(testSourceFO);
+        EditorCookie ec = (EditorCookie) testSourceDO.getCookie(EditorCookie.class);
+        final Document doc = ec.openDocument();
+        doc.putProperty(Language.class, JavaTokenId.language());
+        String content = "package p;"
+                + "public class Test{    \n"
+                + "void testSwitchCaseParenthesizedGuardedPatternAndNull() {\n"
+                + "        Object str = \"pattern matching switch\";\n"
+                + "        switch (str) {\n"
+                + "case \n"
+                + "        (String       \n"
+                + "        s       &&\n"
+                + "        s.length() == 1\n"
+                + "        ) , \n"
+                + "        null\n"
+                + "                    \n"
+                + "                    ->\n"
+                + "                System.out.println(\"case with Parenthesized Binding Pattern formatting\");default ->\n"
+                + "                System.out.println(\"default formatting\");\n"
+                + "        }\n"
+                + "    }"
+                + "}";
+
+        String golden
+                = "package p;\n"
+                + "\n"
+                + "public class Test {\n"
+                + "\n"
+                + "    void testSwitchCaseParenthesizedGuardedPatternAndNull() {\n"
+                + "        Object str = \"pattern matching switch\";\n"
+                + "        switch (str) {\n"
+                + "            case (String s && s.length() == 1 ) , null ->\n"
+                + "                System.out.println(\"case with Parenthesized Binding Pattern formatting\");\n"
+                + "            default ->\n"
+                + "                System.out.println(\"default formatting\");\n"
+                + "        }\n"
+                + "    }\n"
+                + "}\n"
+                + "";
+        reformat(doc, content, golden);
+    }
+   
+    public void testSwitchCaseGuardedPatternNestedParenthesizedPatternWithNull() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_17"); //NOI18N
+        } catch (IllegalArgumentException ex) {
+            //OK, no RELEASE_17, skip test
+            return;
+        }
+        testFile = new File(getWorkDir(), "Test.java");
+        TestUtilities.copyStringToFile(testFile, "");
+        FileObject testSourceFO = FileUtil.toFileObject(testFile);
+        DataObject testSourceDO = DataObject.find(testSourceFO);
+        EditorCookie ec = (EditorCookie) testSourceDO.getCookie(EditorCookie.class);
+        final Document doc = ec.openDocument();
+        doc.putProperty(Language.class, JavaTokenId.language());
+        String content = "package p;"
+                + "public class Test{    \n"
+                + "void testSwitchCaseGuardedPatternNestedParenthesizedPattern() {\n"
+                + "        Object str = \"pattern matching switch\";\n"
+                + "        switch (str) {\n"
+                + "case \n"
+                + "        (String       \n"
+                + "        s )      &&\n"
+                + "        s.length() == 1\n"
+                + "         , \n"
+                + "        null\n"
+                + "                    \n"
+                + "                    ->\n"
+                + "                System.out.println(\"SwitchCaseGuardedPatternNestedParenthesizedPattern\");default ->\n"
+                + "                System.out.println(\"default formatting\");\n"
+                + "        }\n"
+                + "    }"
+                + "}";
+
+        String golden
+                = "package p;\n"
+                + "\n"
+                + "public class Test {\n"
+                + "\n"
+                + "    void testSwitchCaseGuardedPatternNestedParenthesizedPattern() {\n"
+                + "        Object str = \"pattern matching switch\";\n"
+                + "        switch (str) {\n"
+                + "            case (String s ) && s.length() == 1 , null ->\n"
+                + "                System.out.println(\"SwitchCaseGuardedPatternNestedParenthesizedPattern\");\n"
+                + "            default ->\n"
+                + "                System.out.println(\"default formatting\");\n"
+                + "        }\n"
+                + "    }\n"
+                + "}\n"
+                + "";
+        reformat(doc, content, golden);
+    }
+    
+    public void testSwitchCaseGuardedPatternNestedParenthesizedPattern() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_17"); //NOI18N
+        } catch (IllegalArgumentException ex) {
+            //OK, no RELEASE_17, skip test
+            return;
+        }
+        testFile = new File(getWorkDir(), "Test.java");
+        TestUtilities.copyStringToFile(testFile, "");
+        FileObject testSourceFO = FileUtil.toFileObject(testFile);
+        DataObject testSourceDO = DataObject.find(testSourceFO);
+        EditorCookie ec = (EditorCookie) testSourceDO.getCookie(EditorCookie.class);
+        final Document doc = ec.openDocument();
+        doc.putProperty(Language.class, JavaTokenId.language());
+        String content = "package p;"
+                + "public class Test{    \n"
+                + "    void testSwitchCaseGuardedPatternNestedParenthesizedPattern() {\n"
+                + "        Object str = \"pattern matching switch\";\n"
+                + "        switch (str) {\n"
+                + "case (  \n"
+                + "                String s) && s.length() >= 2 && \n"
+                + "                \n"
+                + "                            (s.contains(\"@\") || s.contains(\"!\")) \n"
+                + "                \n"
+                + "                ->\n"
+                + "                String.format(\"Valid string value is %s\", s);default ->\n"
+                + "                System.out.println(\"default formatting\");\n"
+                + "        }\n"
+                + "    }\n"
+                + "}";
+
+        String golden
+                = "package p;\n"
+                + "\n"
+                + "public class Test {\n"
+                + "\n"
+                + "    void testSwitchCaseGuardedPatternNestedParenthesizedPattern() {\n"
+                + "        Object str = \"pattern matching switch\";\n"
+                + "        switch (str) {\n"
+                + "            case ( String s) && s.length() >= 2\n"
+                + "            && (s.contains(\"@\") || s.contains(\"!\")) ->\n"
+                + "                String.format(\"Valid string value is %s\", s);\n"
+                + "            default ->\n"
+                + "                System.out.println(\"default formatting\");\n"
+                + "        }\n"
+                + "    }\n"
+                + "}\n"
+                + "";
+        reformat(doc, content, golden);
+    }
+
+    public void testSwitchCaseAllPatterns() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_17"); //NOI18N
+        } catch (IllegalArgumentException ex) {
+            //OK, no RELEASE_17, skip test
+            return;
+        }
+        testFile = new File(getWorkDir(), "Test.java");
+        TestUtilities.copyStringToFile(testFile, "");
+        FileObject testSourceFO = FileUtil.toFileObject(testFile);
+        DataObject testSourceDO = DataObject.find(testSourceFO);
+        EditorCookie ec = (EditorCookie) testSourceDO.getCookie(EditorCookie.class);
+        final Document doc = ec.openDocument();
+        doc.putProperty(Language.class, JavaTokenId.language());
+        String content = "package p;"
+                + "public class Test{    \n"
+                + "    void testSwitchCaseAllPatterns() {\n"
+                + "        Object str = \"pattern matching switch\";\n"
+                + "        IntStream iso = IntStream.of(1, 2);\n"
+                + "        switch (str) {\n"
+                + "case null ->\n"
+                + "     System.out.println(\"case with null formatting\");\n"
+                + "  case String string\n"
+                + "          && (string.length()==  iso.filter(i -> i / 2 == 0).count() || string.length() == 0)\n"
+                + "          ->\n"
+                + "      System.out.println(\"case with pattern matching + condition + lambda expression formatting\");\n"
+                + "  case                  String s && s.length() == 1 ->System.out.println(\"case with pattern matching + condition formatting\");\n"
+                + "  case      (String s &&    true )-> \n"
+                + "      System.out.println(\"case with pattern matching + condition formatting\");\n"
+                + "  case CharSequence\n"
+                + "          s ->\n"
+                + "                System.out.println(\"case with pattern matching formatting\");\n"
+                + "            case\n"
+                + "                    default ->\n"
+                + "                System.out.println(\"default formatting\");\n"
+                + "\n"
+                + "        }\n"
+                + "    }"
+                + "}";
+
+        String golden
+                = "package p;\n"
+                + "\n"
+                + "public class Test {\n"
+                + "\n"
+                + "    void testSwitchCaseAllPatterns() {\n"
+                + "        Object str = \"pattern matching switch\";\n"
+                + "        IntStream iso = IntStream.of(1, 2);\n"
+                + "        switch (str) {\n"
+                + "            case null ->\n"
+                + "                System.out.println(\"case with null formatting\");\n"
+                + "            case String string && (string.length() == iso.filter(i -> i / 2 == 0).count() || string.length() == 0) ->\n"
+                + "                System.out.println(\"case with pattern matching + condition + lambda expression formatting\");\n"
+                + "            case String s && s.length() == 1 ->\n"
+                + "                System.out.println(\"case with pattern matching + condition formatting\");\n"
+                + "            case (String s && true ) ->\n"
+                + "                System.out.println(\"case with pattern matching + condition formatting\");\n"
+                + "            case CharSequence s ->\n"
+                + "                System.out.println(\"case with pattern matching formatting\");\n"
+                + "            case default ->\n"
+                + "                System.out.println(\"default formatting\");\n"
+                + "\n"
+                + "        }\n"
+                + "    }\n"
+                + "}\n"
+                + "";
+        reformat(doc, content, golden);
+    }
+
+    public void testSwitchCaseAllPatternsWithReturnValue() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_17"); //NOI18N
+        } catch (IllegalArgumentException ex) {
+            //OK, no RELEASE_17, skip test
+            return;
+        }
+        testFile = new File(getWorkDir(), "Test.java");
+        TestUtilities.copyStringToFile(testFile, "");
+        FileObject testSourceFO = FileUtil.toFileObject(testFile);
+        DataObject testSourceDO = DataObject.find(testSourceFO);
+        EditorCookie ec = (EditorCookie) testSourceDO.getCookie(EditorCookie.class);
+        final Document doc = ec.openDocument();
+        doc.putProperty(Language.class, JavaTokenId.language());
+        String content = "package p;"
+                + "public class Test{    \n"
+                + "void testSwitchCaseAllPatterns() {\n"
+                + "        Object str = \"pattern matching switch\";\n"
+                + "        IntStream iso = IntStream.of(1, 2);\n"
+                + "        String retVal = switch (str) {\n"
+                + "case null ->\n"
+                + "     \"case with null formatting\";\n"
+                + "  case String string\n"
+                + "          && (string.length()==  iso.filter(i -> i / 2 == 0).count() || string.length() == 0)\n"
+                + "          ->\n"
+                + "      \"case with pattern matching + condition + lambda expression formatting\";\n"
+                + "  case                  String s && s.length() == 1 ->\"case with pattern matching + condition formatting\";\n"
+                + "  case      (String s &&    true )-> \n"
+                + "      \"case with pattern matching + condition formatting\";\n"
+                + "  case CharSequence\n"
+                + "          s ->\n"
+                + "                \"case with pattern matching formatting\";\n"
+                + "            case\n"
+                + "                    default ->\n"
+                + "                \"default formatting\";\n"
+                + "\n"
+                + "        };\n"
+                + "    }"
+                + "}";
+
+        String golden
+                = "package p;\n"
+                + "\n"
+                + "public class Test {\n"
+                + "\n"
+                + "    void testSwitchCaseAllPatterns() {\n"
+                + "        Object str = \"pattern matching switch\";\n"
+                + "        IntStream iso = IntStream.of(1, 2);\n"
+                + "        String retVal = switch (str) {\n"
+                + "            case null ->\n"
+                + "                \"case with null formatting\";\n"
+                + "            case String string && (string.length() == iso.filter(i -> i / 2 == 0).count() || string.length() == 0) ->\n"
+                + "                \"case with pattern matching + condition + lambda expression formatting\";\n"
+                + "            case String s && s.length() == 1 ->\n"
+                + "                \"case with pattern matching + condition formatting\";\n"
+                + "            case (String s && true ) ->\n"
+                + "                \"case with pattern matching + condition formatting\";\n"
+                + "            case CharSequence s ->\n"
+                + "                \"case with pattern matching formatting\";\n"
+                + "            case default ->\n"
+                + "                \"default formatting\";\n"
+                + "\n"
+                + "        };\n"
+                + "    }\n"
+                + "}\n"
+                + "";
+        reformat(doc, content, golden);
+    }
+
     public void testDoWhile() throws Exception {
         testFile = new File(getWorkDir(), "Test.java");
         TestUtilities.copyStringToFile(testFile,

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@netbeans.apache.org
For additional commands, e-mail: commits-help@netbeans.apache.org

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists