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/11/15 11:40:26 UTC
[netbeans] branch master updated: [NETBEANS-5799]: Pattern Matching for Switch hints (preview) (#3156)
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 e1b1b10 [NETBEANS-5799]: Pattern Matching for Switch hints (preview) (#3156)
e1b1b10 is described below
commit e1b1b10656a7914f3f5e79ff695756bc03f5bfd6
Author: Sandeep Mishra <72...@users.noreply.github.com>
AuthorDate: Mon Nov 15 17:10:16 2021 +0530
[NETBEANS-5799]: Pattern Matching for Switch hints (preview) (#3156)
* Added hints and test cases for pattern matching for switch
---
.../jdk/ConvertToSwitchPatternInstanceOf.java | 178 ++++++++-
.../jdk/ConvertToSwitchPatternInstanceOfTest.java | 424 ++++++++++++++++++++-
.../netbeans/modules/java/source/TreeShims.java | 11 +
.../modules/java/source/builder/TreeFactory.java | 1 +
4 files changed, 585 insertions(+), 29 deletions(-)
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
index 85e22bd..3777b88 100644
--- 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
@@ -1,5 +1,3 @@
-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
@@ -18,6 +16,8 @@ package org.netbeans.modules.java.hints.jdk;
* specific language governing permissions and limitations
* under the License.
*/
+package org.netbeans.modules.java.hints.jdk;
+
import com.sun.source.tree.BlockTree;
import com.sun.source.tree.CaseTree;
import com.sun.source.tree.ExpressionStatementTree;
@@ -45,6 +45,7 @@ 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.modules.java.source.TreeShims;
import org.netbeans.spi.editor.hints.ErrorDescription;
import org.netbeans.spi.editor.hints.Fix;
import org.netbeans.spi.java.hints.ErrorDescriptionFactory;
@@ -81,14 +82,15 @@ public class ConvertToSwitchPatternInstanceOf {
return null;
}
Tree ifPath = ctx.getPath().getLeaf();
- Name expr0 = ((IdentifierTree) ctx.getVariables().get("$expr0").getLeaf()).getName();
+ String expr0 = null;
+ expr0 = ctx.getVariables().get("$expr0").getLeaf().toString();
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)) {
+ if (!ctx.getVariables().get("$expr" + matchVarIndex).getLeaf().toString().equals(expr0)) {
return null;
}
for (TreePath tp : ctx.getMultiVariables().get("$other" + matchVarIndex + "$")) {
@@ -155,12 +157,105 @@ public class ConvertToSwitchPatternInstanceOf {
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 statementTree = blockTree.getStatements().size() == 1 && isValidCaseTree(blockTree.getStatements().get(0))? blockTree.getStatements().get(0) : thenBlock;
+ CaseTree caseMultipleSwitchPatterns = wc.getTreeMaker().CasePatterns(caseBindPattern, statementTree);
+ ctl.add(caseMultipleSwitchPatterns);
+ }
+ 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 caseMultipleSwitchPatterns = wc.getTreeMaker().CasePatterns(caseDefaultLabel, defaultTree);
+ ctl.add(caseMultipleSwitchPatterns);
+ wc.rewrite((IfTree) main.getLeaf(), wc.getTreeMaker().Switch(iot.getExpression(), ctl));
+ }
+
+ }
+
+ @TriggerPatterns({
+ @TriggerPattern(value = "if ($expr0 instanceof $typeI0 $var0) { $statements0$;} else if ($expr1 instanceof $typeI1 $var1) { $statements1$;} else $else$;")
+ })
+ public static ErrorDescription patternMatchToSwitch(HintContext ctx) {
+ TreePath parent = ctx.getPath().getParentPath();
+ if (parent.getLeaf().getKind() == Tree.Kind.IF) {
+ return null;
+ }
+ Tree ifPath = ctx.getPath().getLeaf();
+ String expr0 = null;
+ expr0 = ctx.getVariables().get("$expr0").getLeaf().toString();
+ 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 + " $var" + matchVarIndex + ")", true)
+ && MatcherUtilities.matches(ctx, new TreePath(ctx.getPath(), it.getThenStatement()), "{ $other" + matchVarIndex + "$;}", true)) {
+ if (ctx.getMultiVariables().get("$other" + matchVarIndex + "$").isEmpty()) {
+ return null;
+ }
+ if (!(ctx.getVariables().get("$expr" + matchVarIndex).getLeaf().toString().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;
+ }
+ }
+ } else {
+ return null;
+ }
+ ifPath = it.getElseStatement();
+ }
+
+ Fix fix = new FixPatternMatchToSwitch(ctx.getInfo(), ctx.getPath(), false, Collections.emptySet()).toEditorFix();
+ return ErrorDescriptionFactory.forName(ctx, ctx.getPath(), Bundle.ERR_ConvertToSwitchPatternInstanceOf(), fix);
+
+ }
+
+ private static final class FixPatternMatchToSwitch extends JavaFix {
+ private final boolean removeFirst;
+
+ public FixPatternMatchToSwitch(CompilationInfo info, TreePath main, boolean removeFirst, Set<TreePath> replaceOccurrences) {
+ super(info, main);
+ this.removeFirst = removeFirst;
+ }
+
+ @Override
+ protected String getText() {
+ return Bundle.FIX_ConvertToSwitchPatternInstanceOf();
+ }
- Tree defaultTree = null;
- defaultTree = blockTree.getStatements().size() == 1 && isValidCaseTree(blockTree.getStatements().get(0))? blockTree.getStatements().get(0) : thenBlock;
+ @Override
+ protected void performRewrite(JavaFix.TransformationContext ctx) {
+ WorkingCopy wc = ctx.getWorkingCopy();
+ TreePath main = ctx.getPath();
+ List<CaseTree> ctl = new LinkedList<>();
+ InstanceOfTree iot = null;
- CaseTree casePatterns = wc.getTreeMaker().CasePatterns(caseBindPattern, defaultTree);
- ctl.add(casePatterns);
+ 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();
+ }
+
+ for (IfTree ifTree : ifTrees) {
+ List<Tree> caseBindPattern = new LinkedList<>();
+ iot = (InstanceOfTree) ((ParenthesizedTree) ifTree.getCondition()).getExpression();
+ StatementTree bt = ifTree.getThenStatement();
+ StatementTree thenBlock = removeFirst ? wc.getTreeMaker().removeBlockStatement((BlockTree) bt, 0) : bt;
+ Tree pattern = TreeShims.getPattern(iot);
+ caseBindPattern.add(pattern);
+ BlockTree blockTree = (BlockTree) thenBlock;
+ Tree statementTree = blockTree.getStatements().size() == 1 && isValidCaseTree(blockTree.getStatements().get(0))? blockTree.getStatements().get(0) : thenBlock;
+ CaseTree caseMultipleSwitchPatterns = wc.getTreeMaker().CasePatterns(caseBindPattern, statementTree);
+ ctl.add(caseMultipleSwitchPatterns);
}
List<Tree> caseDefaultLabel = new LinkedList<>();
caseDefaultLabel.add(wc.getTreeMaker().Identifier("default"));
@@ -177,11 +272,72 @@ public class ConvertToSwitchPatternInstanceOf {
}
+
+ @TriggerTreeKind(Tree.Kind.SWITCH)
+ public static ErrorDescription switchPatternMatchToSwitchNull(HintContext ctx) {
+
+ SwitchTree switchTree = (SwitchTree) ctx.getPath().getLeaf();
+ boolean isPatternMatch = false;
+ isPatternMatch = TreeShims.isPatternMatch(switchTree);
+ if (!isPatternMatch) {
+ return null;
+ }
+ Tree expression = ((ParenthesizedTree) switchTree.getExpression()).getExpression();
+ Tree parent = (Tree) ctx.getPath().getParentPath().getLeaf();
+ int indexOf;
+ if (parent instanceof BlockTree) {
+ indexOf = ((BlockTree) parent).getStatements().indexOf(switchTree) - 1;
+ } else {
+ return null;
+ }
+ Tree ifTree = ((BlockTree) parent).getStatements().get(indexOf);
+ if ((!(ifTree instanceof IfTree) || !MatcherUtilities.matches(ctx, new TreePath(ctx.getPath(), ((IfTree) ifTree).getCondition()), "($expr0 == null)", true))
+ || !(ctx.getVariables().get("$expr0").getLeaf().toString().equals(expression.toString()))) {
+ return null;
+ }
+ Fix fix = new FixSwitchPatternMatchToSwitchNull(ctx.getInfo(), ctx.getPath().getParentPath(), indexOf).toEditorFix();
+ return ErrorDescriptionFactory.forTree(ctx, ifTree, Bundle.ERR_ConvertToSwitchPatternInstanceOf(), fix);
+
+ }
+
+ private static final class FixSwitchPatternMatchToSwitchNull extends JavaFix {
+
+ private final int indexOf;
+
+ public FixSwitchPatternMatchToSwitchNull(CompilationInfo info, TreePath path, int indexOf) {
+ super(info, path);
+ this.indexOf = indexOf;
+ }
+
+ @Override
+ protected String getText() {
+ return Bundle.FIX_ConvertToSwitchPatternInstanceOf();
+ }
+
+ @Override
+ protected void performRewrite(TransformationContext ctx) throws Exception {
+ WorkingCopy wc = ctx.getWorkingCopy();
+ TreePath main = ctx.getPath();
+ TreeMaker make = wc.getTreeMaker();
+ List<Tree> caseNullLabel = new LinkedList<>();
+ SwitchTree switchTree = (SwitchTree) ((BlockTree) main.getLeaf()).getStatements().get(indexOf + 1);
+
+ Tree ifTree = ((BlockTree) main.getLeaf()).getStatements().get(indexOf);
+ StatementTree thenStatement = ((IfTree) ifTree).getThenStatement();
+ caseNullLabel.add(wc.getTreeMaker().Identifier("null"));
+ BlockTree blockTree = (BlockTree)thenStatement;
+ Tree statementTree = blockTree.getStatements().size() == 1 && isValidCaseTree(blockTree.getStatements().get(0))? blockTree.getStatements().get(0) : blockTree;
+ CaseTree caseMultipleSwitchPatterns = wc.getTreeMaker().CasePatterns(caseNullLabel, statementTree);
+ SwitchTree insertSwitchCase = make.insertSwitchCase(switchTree, 0, caseMultipleSwitchPatterns);
+ wc.rewrite(switchTree, insertSwitchCase);
+ BlockTree removeBlockStatement = make.removeBlockStatement((BlockTree) main.getLeaf(), indexOf);
+ wc.rewrite(main.getLeaf(), removeBlockStatement);
+ }
+ }
+
private static boolean isValidCaseTree(Tree tree){
return ((tree instanceof BlockTree)
|| (tree instanceof ExpressionStatementTree)
- || (tree instanceof ThrowTree)
- || (tree instanceof CaseTree));
+ || (tree instanceof ThrowTree));
}
}
-
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
index 30b6eab..3659b3c 100644
--- 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
@@ -21,6 +21,7 @@ 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;
+import org.testng.annotations.Test;
/**
*
@@ -32,6 +33,7 @@ public class ConvertToSwitchPatternInstanceOfTest extends NbTestCase {
super(name);
}
+ @Test
public void testSimple() throws Exception {
try {
SourceVersion.valueOf("RELEASE_17"); //NOI18N
@@ -42,37 +44,423 @@ public class ConvertToSwitchPatternInstanceOfTest extends NbTestCase {
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"
+ + " private int test(Object o){\n"
+ + " if(o instanceof String){\n"
+ + " String s = (String)o;\n"
+ + " System.out.println(s);\n"
+ + " }else if(o instanceof Integer){\n"
+ + " Integer i = (Integer)o;\n"
+ + " System.out.println(i);\n"
+ + " }else{\n"
+ + " System.out.println(\"else\");\n"
+ + " }\n"
+ + " return -1;\n"
+ + " }\n"
+ + "}\n"
+ )
+ .sourceLevel("17")
+ .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 int test(Object o){\n"
+ + " switch (o) {\n"
+ + " case String s -> System.out.println(s);\n"
+ + " case Integer i -> System.out.println(i);\n"
+ + " case default -> System.out.println(\"else\");\n"
+ " }\n"
+ + " return -1;\n"
+ " }\n"
+ + "}\n");
+ }
+
+ @Test
+ public void testSimpleNoHint() 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 int test(Object o, Object p){\n"
+ + " if(o instanceof String){\n"
+ + " String s = (String)o;\n"
+ + " System.out.println(s);\n"
+ + " }else if(p instanceof Integer){\n"
+ + " Integer i = (Integer)p;\n"
+ + " System.out.println(i);\n"
+ + " }else{\n"
+ + " System.out.println(\"else\");\n"
+ + " }\n"
+ + " return -1;\n"
+ + " }\n"
+ + "}\n"
+ )
+ .sourceLevel("17")
+ .options("--enable-preview")
+ .run(ConvertToSwitchPatternInstanceOf.class)
+ .assertNotContainsWarnings("3:8-3:10:verifier:" + Bundle.ERR_ConvertToSwitchPatternInstanceOf());
+ }
+
+ @Test
+ public void testSimplePatternMatch() throws Exception {
+ try {
+ SourceVersion.valueOf("RELEASE_17");
+ } catch (IllegalArgumentException ex) {
+ //OK, skip test
+ return;
+ }
+ HintTest.create()
+ .input("package test;\n"
+ + "public class Test {\n"
+ + " static String formatter(Object o) {\n"
+ + " String formatted = \"unknown\";\n"
+ + " if (o instanceof Integer i) {\n"
+ + " formatted = String.format(\"int %d\", i);\n"
+ + " } else if (o instanceof Long l) {\n"
+ + " formatted = String.format(\"long %d\", l);\n"
+ + " } else if (o instanceof Double d) {\n"
+ + " formatted = String.format(\"double %f\", d);\n"
+ + " } else if (o instanceof String s) {\n"
+ + " formatted = String.format(\"String %s\", s);\n"
+ + " }\n"
+ + " return formatted;\n"
+ + " }"
+ + "}\n")
+ .sourceLevel(SourceVersion.latest().name())
+ .options("--enable-preview")
+ .run(ConvertToSwitchPatternInstanceOf.class)
+ .findWarning("4:8-4:10:verifier:" + Bundle.ERR_ConvertToSwitchPatternInstanceOf())
+ .applyFix()
+ .assertCompilable()
+ .assertOutput("package test;\n"
+ + "public class Test {\n"
+ + " static String formatter(Object o) {\n"
+ + " String formatted = \"unknown\";\n"
+ + " switch (o) {\n"
+ + " case Integer i -> formatted = String.format(\"int %d\", i);\n"
+ + " case Long l -> formatted = String.format(\"long %d\", l);\n"
+ + " case Double d -> formatted = String.format(\"double %f\", d);\n"
+ + " case String s -> formatted = String.format(\"String %s\", s);\n"
+ + " case default -> {\n"
+ + " }\n"
+ + " }\n"
+ + " return formatted;\n"
+ + " }\n"
+ + "}\n");
+ }
+
+ @Test
+ public void testSimplePatternMatchNoHint() throws Exception {
+ try {
+ SourceVersion.valueOf("RELEASE_17");
+ } catch (IllegalArgumentException ex) {
+ //OK, skip test
+ return;
+ }
+ HintTest.create()
+ .input("package test;\n"
+ + "public class Test {\n"
+ + " static String formatter(Object o, Object p) {\n"
+ + " String formatted = \"unknown\";\n"
+ + " if (o instanceof Integer i) {\n"
+ + " formatted = String.format(\"int %d\", i);\n"
+ + " } else if (o instanceof Long l) {\n"
+ + " formatted = String.format(\"long %d\", l);\n"
+ + " } else if (p instanceof Double d) {\n"
+ + " formatted = String.format(\"double %f\", p);\n"
+ + " } else if (o instanceof String s) {\n"
+ + " formatted = String.format(\"String %s\", s);\n"
+ + " }\n"
+ + " return formatted;\n"
+ + " }"
+ + "}\n")
+ .sourceLevel(SourceVersion.latest().name())
+ .options("--enable-preview")
+ .run(ConvertToSwitchPatternInstanceOf.class)
+ .assertNotContainsWarnings("4:8-4:10:verifier:" + Bundle.ERR_ConvertToSwitchPatternInstanceOf());
+ }
+
+ @Test
+ public void testSimpleSwitchWithNull() throws Exception {
+ try {
+ SourceVersion.valueOf("RELEASE_17");
+ } catch (IllegalArgumentException ex) {
+ //OK, skip test
+ return;
+ }
+ HintTest.create()
+ .input("package test;\n"
+ + "public class Test {\n"
+ + " private String formatter(Object o) {\n"
+ + " String formatted = \"unknown\";\n"
+ + " if (o == null) {\n"
+ + " formatted = \"null\";\n"
+ + " }\n"
+ + " switch (o) {\n"
+ + " case Integer i ->\n"
+ + " formatted = String.format(\"int %d\", i);\n"
+ + " case Long l ->\n"
+ + " formatted = String.format(\"long %d\", l);\n"
+ + " case Double d ->\n"
+ + " formatted = String.format(\"double %f\", d);\n"
+ + " case String s ->\n"
+ + " formatted = String.format(\"String %s\", s);\n"
+ + " case default -> formatted = \"unknown\";\n"
+ + " }\n"
+ + " return formatted;\n"
+ + " }"
+ + "}\n")
+ .sourceLevel(SourceVersion.latest().name())
+ .options("--enable-preview")
+ .run(ConvertToSwitchPatternInstanceOf.class)
+ .findWarning("4:8-4:24:verifier:" + Bundle.ERR_ConvertToSwitchPatternInstanceOf())
+ .applyFix()
+ .assertCompilable()
+ .assertOutput("package test;\n"
+ + "public class Test {\n"
+ + " private String formatter(Object o) {\n"
+ + " String formatted = \"unknown\";\n"
+ + " switch (o) {\n"
+ + " case null -> formatted = \"null\";\n"
+ + " case Integer i ->\n"
+ + " formatted = String.format(\"int %d\", i);\n"
+ + " case Long l ->\n"
+ + " formatted = String.format(\"long %d\", l);\n"
+ + " case Double d ->\n"
+ + " formatted = String.format(\"double %f\", d);\n"
+ + " case String s ->\n"
+ + " formatted = String.format(\"String %s\", s);\n"
+ + " case default -> \n"
+ + " formatted = \"unknown\";\n"
+ + " }\n"
+ + " return formatted;\n"
+ + " }\n"
+ + "}\n");
+ }
+
+ @Test
+ public void testSimpleSwitchWithNullNoHint() throws Exception {
+ try {
+ SourceVersion.valueOf("RELEASE_17");
+ } catch (IllegalArgumentException ex) {
+ //OK, skip test
+ return;
+ }
+ HintTest.create()
+ .input("package test;\n"
+ + "public class Test {\n"
+ + " private String formatter(Object o, Object p) {\n"
+ + " String formatted = \"unknown\";\n"
+ + " if (o == null) {\n"
+ + " formatted = \"null\";\n"
+ + " }\n"
+ + " switch (p) {\n"
+ + " case Integer i ->\n"
+ + " formatted = String.format(\"int %d\", i);\n"
+ + " case Long l ->\n"
+ + " formatted = String.format(\"long %d\", l);\n"
+ + " case Double d ->\n"
+ + " formatted = String.format(\"double %f\", d);\n"
+ + " case String s ->\n"
+ + " formatted = String.format(\"String %s\", s);\n"
+ + " case default -> formatted = \"unknown\";\n"
+ + " }\n"
+ + " return formatted;\n"
+ + " }"
+ + "}\n")
+ .sourceLevel(SourceVersion.latest().name())
+ .options("--enable-preview")
+ .run(ConvertToSwitchPatternInstanceOf.class)
+ .assertNotContainsWarnings("4:8-4:24:verifier:" + Bundle.ERR_ConvertToSwitchPatternInstanceOf());
+ }
+
+ @Test
+ public void testSingleStatementsStaticVariable() throws Exception {
+ try {
+ SourceVersion.valueOf("RELEASE_17");
+ } catch (IllegalArgumentException ex) {
+ //OK, skip test
+ return;
+ }
+ HintTest.create()
+ .input("package test;\n"
+ + "public class Test {\n"
+ + " private int formatter(Object o) {\n"
+ + " String formatted = \"unknown\";\n"
+ + " if (Test2.a instanceof String) { \n"
+ + " String s = (String) Test2.a;\n"
+ + " System.out.println(s);\n"
+ + " } else if (Test2.a instanceof Integer) {\n"
+ + " Integer i = (Integer) Test2.a;\n"
+ + " System.out.println(i);\n"
+ + " } else if (Test2.a instanceof Character) {\n"
+ + " Character c = (Character) Test2.a;\n"
+ + " return 1;\n"
+ + " } else {\n"
+ + " return 1;\n"
+ + " }\n"
+ + " return -1;\n"
+ + " }"
+ + "}\n"
+ + "class Test2{\n"
+ + " public static Object a;\n"
+ "}")
.sourceLevel(SourceVersion.latest().name())
.options("--enable-preview")
.run(ConvertToSwitchPatternInstanceOf.class)
- .findWarning("3:8-3:10:verifier:" + Bundle.ERR_ConvertToSwitchPatternInstanceOf())
+ .findWarning("4:8-4:10:verifier:" + Bundle.ERR_ConvertToSwitchPatternInstanceOf())
+ .applyFix()
+ .assertCompilable()
+ .assertOutput("package test;\n"
+ + "public class Test {\n"
+ + " private int formatter(Object o) {\n"
+ + " String formatted = \"unknown\";\n"
+ + " switch (Test2.a) {\n"
+ + " case String s -> System.out.println(s);\n"
+ + " case Integer i -> System.out.println(i);\n"
+ + " case Character c -> {\n"
+ + " return 1;\n"
+ + " }\n"
+ + " case default -> {\n"
+ + " return 1;\n"
+ + " }\n"
+ + " }\n"
+ + " return -1;\n"
+ + " }\n"
+ + "}\n"
+ + "class Test2{\n"
+ + " public static Object a;\n"
+ + "}");
+ }
+
+ @Test
+ public void testMultipleStatements() throws Exception {
+ try {
+ SourceVersion.valueOf("RELEASE_17");
+ } catch (IllegalArgumentException ex) {
+ //OK, skip test
+ return;
+ }
+ HintTest.create()
+ .input("package test;\n"
+ + "public class Test {\n"
+ + " private int formatter(Object o) {\n"
+ + " String formatted = \"unknown\";\n"
+ + " if (o instanceof String) { \n"
+ + " String s = (String) o;\n"
+ + " formatted = \"String\";\n"
+ + " System.out.println(s);\n"
+ + " } else if (o instanceof Integer) {\n"
+ + " Integer i = (Integer) o;\n"
+ + " formatted = \"Integer\";\n"
+ + " System.out.println(i);\n"
+ + " } else if (o instanceof Character) {\n"
+ + " Character c = (Character) o;\n"
+ + " formatted = \"Character\";\n"
+ + " return 1;\n"
+ + " } else {\n"
+ + " formatted = \"else\";\n"
+ + " return 1;\n"
+ + " }\n"
+ + " return -1;\n"
+ + " }"
+ + "}\n")
+ .sourceLevel(SourceVersion.latest().name())
+ .options("--enable-preview")
+ .run(ConvertToSwitchPatternInstanceOf.class)
+ .findWarning("4:8-4:10:verifier:" + Bundle.ERR_ConvertToSwitchPatternInstanceOf())
.applyFix()
.assertCompilable()
.assertOutput("package test;\n"
+ "public class Test {\n"
- + " private void test(Object o) {\n"
+ + " private int formatter(Object o) {\n"
+ + " String formatted = \"unknown\";\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"
+ + " case String s -> {\n"
+ + " formatted = \"String\";\n"
+ + " System.out.println(s);\n"
+ + " }\n"
+ + " case Integer i -> {\n"
+ + " formatted = \"Integer\";\n"
+ + " System.out.println(i);\n"
+ + " }\n"
+ + " case Character c -> {\n"
+ + " formatted = \"Character\";\n"
+ + " return 1;\n"
+ + " }\n"
+ + " case default -> {\n"
+ + " formatted = \"else\";\n"
+ + " return 1; \n"
+ + " }\n"
+ " }\n"
+ + " return -1;\n"
+ " }\n"
+ "}\n");
}
+
+ @Test
+ public void testEmptyStatementsMethodInvocation() throws Exception {
+ try {
+ SourceVersion.valueOf("RELEASE_17");
+ } catch (IllegalArgumentException ex) {
+ //OK, skip test
+ return;
+ }
+ HintTest.create()
+ .input("package test;\n"
+ + "public class Test {\n"
+ + " private int formatter(Object o) {\n"
+ + " String formatted = \"unknown\";\n"
+ + " if (Test2.m() instanceof String) { \n"
+ + " String s = (String) Test2.m();\n"
+ + " System.out.println(s);\n"
+ + " } else if (Test2.m() instanceof Integer) {\n"
+ + " Integer i = (Integer) Test2.m();\n"
+ + " System.out.println(i);\n"
+ + " } else if (Test2.m() instanceof Character) {\n"
+ + " Character c = (Character) Test2.m();\n"
+ + " } else {\n"
+ + " }\n"
+ + " return -1;\n"
+ + " }"
+ + "}\n"
+ + "class Test2{\n"
+ + " public static Object m(){\n"
+ + " return \"method invocation\";\n"
+ + " }"
+ + "}")
+ .sourceLevel(SourceVersion.latest().name())
+ .options("--enable-preview")
+ .run(ConvertToSwitchPatternInstanceOf.class)
+ .findWarning("4:8-4:10:verifier:" + Bundle.ERR_ConvertToSwitchPatternInstanceOf())
+ .applyFix()
+ .assertCompilable()
+ .assertOutput("package test;\n"
+ + "public class Test {\n"
+ + " private int formatter(Object o) {\n"
+ + " String formatted = \"unknown\";\n"
+ + " switch (Test2.m()) {\n"
+ + " case String s -> System.out.println(s);\n"
+ + " case Integer i -> System.out.println(i);\n"
+ + " case Character c -> {\n"
+ + " }\n"
+ + " case default -> {\n"
+ + " }\n"
+ + " }\n"
+ + " return -1;\n"
+ + " }\n"
+ + "}\n"
+ + "class Test2{\n"
+ + " public static Object m(){\n"
+ + " return \"method invocation\";\n"
+ + " }"
+ + "}");
+ }
}
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 fb9b24c..a27181e 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
@@ -372,6 +372,17 @@ public class TreeShims {
}
}
+ public static boolean isPatternMatch(Tree node) {
+ if (isJDKVersionRelease17_Or_Above()) {
+ try {
+ return node.getClass().getField("patternSwitch").getBoolean(node);
+ } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException ex) {
+ throw TreeShims.<RuntimeException>throwAny(ex);
+ }
+ }
+ return false;
+ }
+
public static boolean isJDKVersionSupportEnablePreview() {
return Integer.valueOf(SourceVersion.latest().name().split("_")[1]).compareTo(PATTERN_MATCHING_INSTANCEOF_PREVIEW_JDK_VERSION) <= 0;
}
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 94cd00c..0601b06 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
@@ -280,6 +280,7 @@ public class TreeFactory {
}
}
+
public CaseTree CaseMultiplePatterns(List<? extends Tree> expressions, List<? extends StatementTree> statements) {
ListBuffer<JCStatement> lb = new ListBuffer<JCStatement>();
for (StatementTree t : statements)
---------------------------------------------------------------------
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