diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/IfPatternMatchProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/IfPatternMatchProcessor.java index 2639dced98..0de5fd85fa 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/IfPatternMatchProcessor.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/IfPatternMatchProcessor.java @@ -18,8 +18,12 @@ public static boolean matchInstanceof(RootStatement root) { if (res) { ValidationHelper.validateStatement(root); + SequenceHelper.condenseSequences(root); + // IfHelper already called SequenceHelper.condenseSequences if it returned true - if (!IfHelper.mergeAllIfs(root)) { + if (IfHelper.mergeAllIfs(root)) { + improvePatternTypes(root); + } else { SequenceHelper.condenseSequences(root); } } @@ -349,6 +353,23 @@ private static boolean identifyRecordPatternMatch(IfStatement stat, Statement br } } } + } else { + // Is the next statement an if with an instanceof inside? It might be a type-improving if. Search inside it too. + if (next instanceof IfStatement ifSt && ifSt.iftype == IfStatement.IFTYPE_IF + && ifSt.getHeadexprent().getCondition() instanceof FunctionExprent func && func.getFuncType() == FunctionType.INSTANCEOF) { + + // " = ;" idiom + // Ensure this is the right idiom be fore we mark it for destruction. + if (branch.getBasichead().getExprents().size() == 1) { + if (branch.getBasichead().getExprents().get(0) instanceof AssignmentExprent assign + && assign.getLeft() instanceof VarExprent && assign.getRight() instanceof VarExprent) { + toDestroy.add(branch.getBasichead()); + } + } + + branch = ifSt.getIfstat(); + stIdx = 0; + } } // If we found a "realVar = exVar;" then we can skip over this statement and move on. @@ -364,8 +385,6 @@ private static boolean identifyRecordPatternMatch(IfStatement stat, Statement br } } - toDestroy.add(branch.getBasichead()); - PatternExprent pattern = new PatternExprent(PatternExprent.recordData(cl), type, new ArrayList<>(vars.values())); instOf.getLstOperands().add(2, pattern); @@ -482,4 +501,104 @@ public static Exprent getLastExprentWhen(Exprent base, boolean ifTrue, boolean o // otherwise, return ourselves return base; } + + private static boolean improvePatternTypes(Statement stat) { + boolean res = false; + for (Statement st : stat.getStats()) { + res |= improvePatternTypes(st); + } + + if (stat instanceof IfStatement ifSt) { + Exprent cond = ifSt.getHeadexprent().getCondition(); + + if (improvePatternType(ifSt.getHeadexprent(), cond, ifSt.getIfstat())) { + res = true; + } + } + + return res; + } + + private static boolean improvePatternType(Exprent parent, Exprent ex, Statement st) { + boolean res = false; + for (Exprent e : ex.getAllExprents(false, true)) { + // don't recurse on self + if (e != ex) { + res |= improvePatternType(ex, e, st); + } + + if (e instanceof FunctionExprent fn && fn.getFuncType() == FunctionType.BOOLEAN_AND) { + Exprent base = fn.getLstOperands().get(0); + + // Check for record pattern instanceof + if (base instanceof FunctionExprent baseFn && baseFn.getFuncType() == FunctionType.INSTANCEOF + && baseFn.getLstOperands().size() > 2 && baseFn.getLstOperands().get(2) instanceof PatternExprent pattern + && pattern.getData() instanceof PatternExprent.PatternData.RecordPatternData) { + // Found one? now find type-enhancing instanceofs in the other arm + + // Map a list of vars 1:1 with the exprents in the pattern + List vars = new ArrayList<>(); + + for (Exprent patternEx : pattern.getExprents()) { + if (patternEx instanceof VarExprent var) { + vars.add(var); + } else { + vars.add(null); + } + + // TODO: recursively look? + } + + for (int j = 0; j < vars.size(); j++) { + VarExprent var = vars.get(j); + if (var == null) { + continue; + } + + // Now go through the following ordeal to improve pattern types. + // Look for cases that look like 'Rec(Object synth) && synth instanceof Type t' where 'synth' is a synthetic + // variable that is only used in the pattern. + + // Is the 'synth' variable used outside the pattern? All hope is lost. + if (var.isVarReferenced(st)) { + continue; + } + + // Go through all of the exprents one by one to see if we can find redundant instanceofs + // We need to start at the parent, as in the case where there is only one instanceof, such as + // 'o instanceof Rec(Object x) && x instanceof String s', we need to replace the whole expression with the + // left hand side. + out: + for (Exprent exp : parent.getAllExprents(true, true)) { + for (Exprent inst : exp.getAllExprents()) { + if (inst instanceof FunctionExprent instFun && instFun.getFuncType() == FunctionType.BOOLEAN_AND) { + // Search each arm of the boolean and + for (int i = 0; i < 2; i++) { + Exprent inner = instFun.getLstOperands().get(i); + if (inner instanceof FunctionExprent innerFun && innerFun.getFuncType() == FunctionType.INSTANCEOF && innerFun.getLstOperands().size() > 2) { + if (innerFun.getLstOperands().get(0).equals(var)) { + + // Replace the var + pattern.getExprents().set(j, innerFun.getLstOperands().get(2)); + pattern.getVarTypes().set(j, innerFun.getLstOperands().get(1).getExprType()); + + // replace 'A && B' where A is the redundant instanceof with simply 'B' + exp.replaceExprent(inst, instFun.getLstOperands().get(i ^ 1)); + + break out; + } + } + } + } + } + } + + // Iterate again, to try to replace all components + } + } + } + } + + return res; + } } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/PatternExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/PatternExprent.java index 2b0044cdb2..69802e2adb 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/PatternExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/PatternExprent.java @@ -1,6 +1,7 @@ package org.jetbrains.java.decompiler.modules.decompiler.exps; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.java.decompiler.modules.decompiler.DecHelper; import org.jetbrains.java.decompiler.modules.decompiler.ValidationHelper; import org.jetbrains.java.decompiler.modules.decompiler.vars.CheckTypesResult; @@ -17,17 +18,20 @@ public class PatternExprent extends Exprent implements Pattern { private final PatternData data; private final VarType varType; private final List exprents; + private final List<@Nullable VarType> varTypes; public PatternExprent(PatternData data, VarType type, List exprents) { super(Type.PATTERN); this.data = data; varType = type; this.exprents = exprents; + this.varTypes = new ArrayList<>(); for (Exprent exprent : exprents) { if (!(exprent instanceof Pattern)) { ValidationHelper.assertTrue(false, "Illegal input for PatternExprent"); } + varTypes.add(null); } } @@ -76,7 +80,12 @@ public CheckTypesResult checkExprTypeBounds() { // The type lower bound must be for (int i = 0; i < exprents.size(); i++) { - res.addMinTypeExprent(exprents.get(i), new VarType(record.cl.getRecordComponents().get(i).getDescriptor())); + VarType type = varTypes.get(i); + if (type != null) { + res.addMinTypeExprent(exprents.get(i), type); + } else { + res.addMinTypeExprent(exprents.get(i), new VarType(record.cl.getRecordComponents().get(i).getDescriptor())); + } } return res; @@ -107,6 +116,18 @@ public List getPatternVars() { return vars; } + public PatternData getData() { + return data; + } + + public List getExprents() { + return exprents; + } + + public List<@Nullable VarType> getVarTypes() { + return varTypes; + } + public static PatternData recordData(StructClass cl) { return new PatternData.RecordPatternData(cl); } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java index 14f6a0997a..2d358f0070 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java @@ -968,6 +968,10 @@ public void setPhantom(boolean phantom) { this.phantom = phantom; } + public String toDebug() { + return toJava().convertToStringAndAllowDataDiscard(); + } + // helper methods public String toString() { return "{" + type.prettyId + "}:" + id; diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index 9b9ca4703c..f24c0ccd10 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -685,6 +685,10 @@ private void registerDefault() { register(JAVA_8, "TestWhileForeach"); register(JAVA_21, "TestRecordPatterns1"); register(JAVA_21, "TestRecordPatterns2"); + register(JAVA_21, "TestRecordPatterns3"); + register(JAVA_21, "TestRecordPatterns4"); + register(JAVA_21, "TestRecordPatterns5"); + register(JAVA_21, "TestRecordPatterns6"); register(JAVA_21_PREVIEW, "TestStrProcessor"); register(JAVA_21_PREVIEW, "TestRawProcessor"); register(JAVA_21_PREVIEW, "TestFmtProcessor"); diff --git a/testData/results/pkg/TestRecordPatterns1.dec b/testData/results/pkg/TestRecordPatterns1.dec index d5c7e0df8f..b46d1d95fd 100644 --- a/testData/results/pkg/TestRecordPatterns1.dec +++ b/testData/results/pkg/TestRecordPatterns1.dec @@ -9,14 +9,14 @@ public class TestRecordPatterns1 { }// 11 public void test2(TestRecordPatterns1.R r) { - if (r instanceof TestRecordPatterns1.R(int var5, Object var11) && var11 instanceof String s) {// 14 + if (r instanceof TestRecordPatterns1.R(int var5, String s)) {// 14 System.out.println(var5);// 15 System.out.println(s);// 16 } }// 18 public void test3(TestRecordPatterns1.R r) { - if (r instanceof TestRecordPatterns1.R(int var5, Object var11) && var11 instanceof String s && s.length() > 10) {// 21 + if (r instanceof TestRecordPatterns1.R(int var5, String s) && s.length() > 10) {// 21 System.out.println(var5);// 22 System.out.println(s);// 23 } @@ -80,9 +80,6 @@ class 'pkg/TestRecordPatterns1' { e 11 f 12 10 12 - 1a 11 - 1b 11 - 1c 11 1d 11 1e 11 1f 11 @@ -118,9 +115,6 @@ class 'pkg/TestRecordPatterns1' { e 18 f 19 10 19 - 1a 18 - 1b 18 - 1c 18 1d 18 1e 18 1f 18 diff --git a/testData/results/pkg/TestRecordPatterns3.dec b/testData/results/pkg/TestRecordPatterns3.dec new file mode 100644 index 0000000000..8fc859114c --- /dev/null +++ b/testData/results/pkg/TestRecordPatterns3.dec @@ -0,0 +1,175 @@ +package pkg; + +public class TestRecordPatterns3 { + public void test1(TestRecordPatterns3.R r) { + if (r instanceof TestRecordPatterns3.R) {// 9 + System.out.println(r);// 10 + } + }// 12 + + public void test2(TestRecordPatterns3.R r) { + if (r instanceof TestRecordPatterns3.R) {// 15 + System.out.println(r);// 16 + } + }// 18 + + public void test3(TestRecordPatterns3.R r) { + if (r instanceof TestRecordPatterns3.R) {// 21 + System.out.println(r);// 22 + } + }// 24 + + public void test4(Object r) { + if (r instanceof TestRecordPatterns3.R var2) {// 27 + System.out.println(r);// 28 + } + }// 30 + + public void test5(Object r) { + if (r instanceof TestRecordPatterns3.R) {// 33 + System.out.println(r);// 34 + } + }// 36 + + public void test6(Object r) { + if (r instanceof TestRecordPatterns3.R x) {// 39 + System.out.println(x);// 40 + } + }// 42 + + static record R() { + } +} + +class 'pkg/TestRecordPatterns3' { + method 'test1 (Lpkg/TestRecordPatterns3$R;)V' { + 0 4 + 1 4 + 2 4 + 3 4 + 4 4 + 5 4 + 6 4 + 9 5 + a 5 + b 5 + c 5 + d 5 + e 5 + f 5 + 10 7 + } + + method 'test2 (Lpkg/TestRecordPatterns3$R;)V' { + 0 10 + 1 10 + 2 10 + 3 10 + 4 10 + 5 10 + 6 10 + 7 11 + 8 11 + 9 11 + a 11 + b 11 + c 11 + d 11 + e 13 + } + + method 'test3 (Lpkg/TestRecordPatterns3$R;)V' { + 0 16 + 1 16 + 2 16 + 3 16 + 4 16 + 5 16 + 6 16 + 7 17 + 9 17 + a 17 + b 17 + c 17 + d 17 + e 17 + f 17 + 10 19 + } + + method 'test4 (Ljava/lang/Object;)V' { + 0 22 + 1 22 + 2 22 + 3 22 + 4 22 + 5 22 + 6 22 + b 22 + c 23 + d 23 + e 23 + f 23 + 10 23 + 11 23 + 12 23 + 13 25 + } + + method 'test5 (Ljava/lang/Object;)V' { + 0 28 + 1 28 + 2 28 + 3 28 + 4 28 + 5 28 + 6 28 + 7 29 + 8 29 + 9 29 + a 29 + b 29 + c 29 + d 29 + e 31 + } + + method 'test6 (Ljava/lang/Object;)V' { + 0 34 + 1 34 + 2 34 + 3 34 + 4 34 + 5 34 + 6 34 + b 34 + c 35 + d 35 + e 35 + f 35 + 10 35 + 11 35 + 12 35 + 13 37 + } +} + +Lines mapping: +9 <-> 5 +10 <-> 6 +12 <-> 8 +15 <-> 11 +16 <-> 12 +18 <-> 14 +21 <-> 17 +22 <-> 18 +24 <-> 20 +27 <-> 23 +28 <-> 24 +30 <-> 26 +33 <-> 29 +34 <-> 30 +36 <-> 32 +39 <-> 35 +40 <-> 36 +42 <-> 38 diff --git a/testData/results/pkg/TestRecordPatterns4.dec b/testData/results/pkg/TestRecordPatterns4.dec new file mode 100644 index 0000000000..806090dcb5 --- /dev/null +++ b/testData/results/pkg/TestRecordPatterns4.dec @@ -0,0 +1,176 @@ +package pkg; + +public class TestRecordPatterns4 { + public void test1(TestRecordPatterns4.R r) { + if (r instanceof TestRecordPatterns4.R(Number x, String s)) {// 7 + System.out.println(x);// 8 + System.out.println(s);// 9 + } + }// 11 + + public void test2(TestRecordPatterns4.R r) { + if (r instanceof TestRecordPatterns4.R(Number x, String s) && s.length() > 10) {// 14 + System.out.println(x);// 15 + System.out.println(s);// 16 + } + }// 18 + + public void test3(TestRecordPatterns4.R r) { + if (r instanceof TestRecordPatterns4.R(Number x, String s) && s.length() > 10 && x.intValue() == 3) {// 21 + System.out.println(x);// 22 + System.out.println(s);// 23 + } + }// 25 + + static record R(Object a, Object b) { + } +} + +class 'pkg/TestRecordPatterns4' { + method 'test1 (Lpkg/TestRecordPatterns4$R;)V' { + 0 4 + 1 4 + 2 4 + 3 4 + 4 4 + 5 4 + 6 4 + 14 4 + 15 4 + 16 4 + 1c 4 + 28 4 + 29 4 + 2a 4 + 30 4 + 31 4 + 32 5 + 33 5 + 34 5 + 35 5 + 36 5 + 37 5 + 38 5 + 39 6 + 3a 6 + 3b 6 + 3c 6 + 3d 6 + 3e 6 + 3f 6 + 40 6 + 52 8 + } + + method 'test2 (Lpkg/TestRecordPatterns4$R;)V' { + 0 11 + 1 11 + 2 11 + 3 11 + 4 11 + 5 11 + 6 11 + 14 11 + 15 11 + 16 11 + 1c 11 + 28 11 + 29 11 + 2a 11 + 30 11 + 31 11 + 32 11 + 33 11 + 34 11 + 35 11 + 36 11 + 37 11 + 38 11 + 39 11 + 3a 11 + 3b 11 + 3c 12 + 3d 12 + 3e 12 + 3f 12 + 40 12 + 41 12 + 42 12 + 43 13 + 44 13 + 45 13 + 46 13 + 47 13 + 48 13 + 49 13 + 4a 13 + 5c 15 + } + + method 'test3 (Lpkg/TestRecordPatterns4$R;)V' { + 0 18 + 1 18 + 2 18 + 3 18 + 4 18 + 5 18 + 6 18 + 14 18 + 15 18 + 16 18 + 1c 18 + 28 18 + 29 18 + 2a 18 + 30 18 + 31 18 + 32 18 + 33 18 + 34 18 + 35 18 + 36 18 + 37 18 + 38 18 + 39 18 + 3a 18 + 3b 18 + 3c 18 + 3d 18 + 3e 18 + 3f 18 + 40 18 + 41 18 + 42 18 + 43 18 + 44 19 + 45 19 + 46 19 + 47 19 + 48 19 + 49 19 + 4a 19 + 4b 20 + 4c 20 + 4d 20 + 4e 20 + 4f 20 + 50 20 + 51 20 + 52 20 + 64 22 + } +} + +Lines mapping: +7 <-> 5 +8 <-> 6 +9 <-> 7 +11 <-> 9 +14 <-> 12 +15 <-> 13 +16 <-> 14 +18 <-> 16 +21 <-> 19 +22 <-> 20 +23 <-> 21 +25 <-> 23 \ No newline at end of file diff --git a/testData/results/pkg/TestRecordPatterns5.dec b/testData/results/pkg/TestRecordPatterns5.dec new file mode 100644 index 0000000000..ad84fd6991 --- /dev/null +++ b/testData/results/pkg/TestRecordPatterns5.dec @@ -0,0 +1,179 @@ +package pkg; + +public class TestRecordPatterns5 { + public void test1(TestRecordPatterns5.R r) { + if (r instanceof TestRecordPatterns5.R(Integer x, String var8)) {// 7 + System.out.println(x);// 8 + System.out.println(var8);// 9 + } + }// 11 + + public void test2(TestRecordPatterns5.R r) { + if (r instanceof TestRecordPatterns5.R(Integer x, String var11)) {// 14 + String var8 = var11; + if (var8.length() > 10) { + System.out.println(x);// 15 + System.out.println(var8);// 16 + } + } + }// 18 + + public void test3(TestRecordPatterns5.R r) { + if (r instanceof TestRecordPatterns5.R(Integer x, String var11)) {// 21 + String var8 = var11; + if (var8.length() > 10 && x == 3) { + System.out.println(x);// 22 + System.out.println(var8);// 23 + } + } + }// 25 + + static record R(Number a, String b) { + } +} + +class 'pkg/TestRecordPatterns5' { + method 'test1 (Lpkg/TestRecordPatterns5$R;)V' { + 0 4 + 1 4 + 2 4 + 3 4 + 4 4 + 5 4 + 6 4 + 14 4 + 15 4 + 16 4 + 1c 4 + 21 4 + 22 4 + 23 6 + 24 6 + 27 5 + 28 5 + 29 5 + 2a 5 + 2b 5 + 2c 5 + 2d 5 + 2e 6 + 2f 6 + 30 6 + 31 6 + 32 6 + 33 6 + 34 6 + 35 6 + 47 8 + } + + method 'test2 (Lpkg/TestRecordPatterns5$R;)V' { + 0 11 + 1 11 + 2 11 + 3 11 + 4 11 + 5 11 + 6 11 + 14 11 + 15 11 + 16 11 + 1c 11 + 21 12 + 22 12 + 23 13 + 24 13 + 27 13 + 28 13 + 29 13 + 2a 13 + 2b 13 + 2c 13 + 2d 13 + 2e 13 + 2f 13 + 30 13 + 31 14 + 32 14 + 33 14 + 34 14 + 35 14 + 36 14 + 37 14 + 38 15 + 39 15 + 3a 15 + 3b 15 + 3c 15 + 3d 15 + 3e 15 + 3f 15 + 51 18 + } + + method 'test3 (Lpkg/TestRecordPatterns5$R;)V' { + 0 21 + 1 21 + 2 21 + 3 21 + 4 21 + 5 21 + 6 21 + 14 21 + 15 21 + 16 21 + 1c 21 + 21 22 + 22 22 + 23 23 + 24 23 + 27 23 + 28 23 + 29 23 + 2a 23 + 2b 23 + 2c 23 + 2d 23 + 2e 23 + 2f 23 + 30 23 + 31 23 + 32 23 + 33 23 + 34 23 + 35 23 + 36 23 + 37 23 + 38 23 + 39 24 + 3a 24 + 3b 24 + 3c 24 + 3d 24 + 3e 24 + 3f 24 + 40 25 + 41 25 + 42 25 + 43 25 + 44 25 + 45 25 + 46 25 + 47 25 + 59 28 + } +} + +Lines mapping: +7 <-> 5 +8 <-> 6 +9 <-> 7 +11 <-> 9 +14 <-> 12 +15 <-> 15 +16 <-> 16 +18 <-> 19 +21 <-> 22 +22 <-> 25 +23 <-> 26 +25 <-> 29 \ No newline at end of file diff --git a/testData/results/pkg/TestRecordPatterns6.dec b/testData/results/pkg/TestRecordPatterns6.dec new file mode 100644 index 0000000000..ceec98ceba --- /dev/null +++ b/testData/results/pkg/TestRecordPatterns6.dec @@ -0,0 +1,306 @@ +package pkg; + +import java.lang.runtime.SwitchBootstraps; +import java.util.Objects; + +public class TestRecordPatterns6 { + public Object res(TestRecordPatterns6.I in) { + Object var17; + switch (in) { + case TestRecordPatterns6.I.R1 var4:// 12 + TestRecordPatterns6.I.R1 var20 = var4; + + try { + var17 = (TestRecordPatterns6.I.R3)var20.o(); + } catch (Throwable var13) {// 14 + throw new MatchException(var13.toString(), var13); + } + + Object var14 = var17; + var17 = (TestRecordPatterns6.I.R3)var14; + break; + case TestRecordPatterns6.I.R2 var6:// 13 + TestRecordPatterns6.I.R2 var18 = var6; + + try { + var19 = var18.i(); + } catch (Throwable var12) { + throw new MatchException(var12.toString(), var12); + } + + int var15 = var19; + var17 = var15; + break; + case TestRecordPatterns6.I.R3 var8: + var17 = var8; + + try { + var16 = var17.s(); + } catch (Throwable var11) { + throw new MatchException(var11.toString(), var11); + } + + String var10 = var16; + var17 = var10; + break; + default: + throw new MatchException(null, null); + } + + return var17;// 11 + } + + public String test(TestRecordPatterns6.I in) { + Objects.requireNonNull(in); + TestRecordPatterns6.I var2 = in; + byte var3 = 0; + + while (true) { + String var13; + switch (SwitchBootstraps.typeSwitch<"typeSwitch",TestRecordPatterns6.I.R1,TestRecordPatterns6.I.R3>(var2, var3)) { + case 0: + TestRecordPatterns6.I.R1 var4 = (TestRecordPatterns6.I.R1)var2;// 20 + TestRecordPatterns6.I.R1 var14 = var4; + + try { + var15 = var14.o(); + } catch (Throwable var10) {// 21 + throw new MatchException(var10.toString(), var10); + } + + if (!(var15 instanceof String s)) { + var3 = 1; + continue; + } + + var13 = s; + break; + case 1: + TestRecordPatterns6.I.R3 var6 = (TestRecordPatterns6.I.R3)var2; + TestRecordPatterns6.I.R3 var10000 = var6; + + try { + var13 = var10000.s(); + } catch (Throwable var9) { + throw new MatchException(var9.toString(), var9); + } + + String var8 = var13; + var13 = var8; + break; + default: + throw new IllegalStateException();// 22 + } + + return var13;// 19 + } + } + + sealed interface I permits TestRecordPatterns6.I.R1, TestRecordPatterns6.I.R2, TestRecordPatterns6.I.R3 { + public static record R1(Object o) implements TestRecordPatterns6.I { + } + + public static record R2(int i) implements TestRecordPatterns6.I { + } + + public static record R3(String s) implements TestRecordPatterns6.I { + } + } +} + +class 'pkg/TestRecordPatterns6' { + method 'res (Lpkg/TestRecordPatterns6$I;)Ljava/lang/Object;' { + 0 8 + 9 8 + 10 8 + 11 8 + 12 8 + 13 8 + 14 8 + 15 8 + 16 8 + 17 8 + 18 8 + 19 8 + 1a 8 + 1b 8 + 1c 8 + 1d 8 + 1e 8 + 1f 8 + 20 8 + 21 8 + 22 8 + 23 8 + 24 8 + 25 8 + 26 8 + 27 8 + 28 8 + 29 8 + 2a 8 + 2b 8 + 30 46 + 31 46 + 35 46 + 3a 9 + 3b 9 + 3c 10 + 3d 10 + 3e 13 + 3f 13 + 40 13 + 41 18 + 42 18 + 43 19 + 44 19 + 47 19 + 48 19 + 49 20 + 50 21 + 51 21 + 52 22 + 53 22 + 54 25 + 55 25 + 56 25 + 57 30 + 58 30 + 59 31 + 5a 31 + 5d 31 + 5e 31 + 5f 31 + 60 31 + 61 31 + 62 32 + 69 33 + 6a 33 + 6b 34 + 6c 34 + 6d 37 + 6e 37 + 6f 37 + 70 42 + 71 42 + 72 43 + 73 43 + 76 43 + 77 43 + 78 49 + 79 14 + 7e 15 + 7f 15 + 80 15 + 81 15 + 82 15 + 86 15 + } + + method 'test (Lpkg/TestRecordPatterns6$I;)Ljava/lang/String;' { + 0 53 + 2 53 + 3 53 + 4 53 + 6 54 + 7 55 + 8 55 + 9 59 + a 59 + b 59 + c 59 + d 59 + e 59 + f 59 + 10 59 + 11 59 + 12 59 + 13 59 + 14 59 + 15 59 + 16 59 + 17 59 + 18 59 + 19 59 + 1a 59 + 1b 59 + 1c 59 + 1d 59 + 1e 59 + 1f 59 + 20 59 + 21 59 + 22 59 + 23 59 + 24 59 + 25 59 + 26 59 + 27 59 + 28 59 + 29 59 + 2a 59 + 2b 59 + 2c 61 + 2d 61 + 2e 61 + 2f 61 + 30 61 + 31 61 + 32 62 + 33 62 + 34 65 + 35 65 + 36 65 + 3b 70 + 3c 70 + 3d 70 + 3e 70 + 3f 70 + 40 70 + 46 70 + 47 70 + 48 75 + 49 75 + 4b 71 + 4c 71 + 4d 72 + 52 76 + 55 78 + 56 78 + 57 78 + 58 78 + 59 78 + 5a 78 + 5b 79 + 5c 79 + 5d 82 + 5e 82 + 5f 82 + 60 87 + 61 87 + 62 88 + 63 88 + 66 88 + 67 88 + 68 89 + 72 91 + 73 94 + 74 66 + 79 67 + 7a 67 + 7b 67 + 7c 67 + 7d 67 + 81 67 + } +} + +Lines mapping: +11 <-> 50 +12 <-> 10 +13 <-> 22 +14 <-> 15 +19 <-> 95 +20 <-> 62 +21 <-> 67 +22 <-> 92 \ No newline at end of file diff --git a/testData/src/java21/pkg/TestRecordPatterns3.java b/testData/src/java21/pkg/TestRecordPatterns3.java new file mode 100644 index 0000000000..7698a8f280 --- /dev/null +++ b/testData/src/java21/pkg/TestRecordPatterns3.java @@ -0,0 +1,43 @@ +package pkg; + +public class TestRecordPatterns3 { + record R() { + + } + + public void test1(R r) { + if (r instanceof R()) { + System.out.println(r); + } + } + + public void test2(R r) { + if (r instanceof R) { + System.out.println(r); + } + } + + public void test3(R r) { + if (r instanceof R x) { + System.out.println(x); + } + } + + public void test4(Object r) { + if (r instanceof R()) { + System.out.println(r); + } + } + + public void test5(Object r) { + if (r instanceof R) { + System.out.println(r); + } + } + + public void test6(Object r) { + if (r instanceof R x) { + System.out.println(x); + } + } +} diff --git a/testData/src/java21/pkg/TestRecordPatterns4.java b/testData/src/java21/pkg/TestRecordPatterns4.java new file mode 100644 index 0000000000..ed7c4c52b8 --- /dev/null +++ b/testData/src/java21/pkg/TestRecordPatterns4.java @@ -0,0 +1,26 @@ +package pkg; + +public class TestRecordPatterns4 { + record R(Object a, Object b) {} + + public void test1(R r) { + if (r instanceof R(Number x, String s)) { + System.out.println(x); + System.out.println(s); + } + } + + public void test2(R r) { + if (r instanceof R(Number x, String s) && s.length() > 10) { + System.out.println(x); + System.out.println(s); + } + } + + public void test3(R r) { + if (r instanceof R(Number x, String s) && s.length() > 10 && x.intValue() == 3) { + System.out.println(x); + System.out.println(s); + } + } +} diff --git a/testData/src/java21/pkg/TestRecordPatterns5.java b/testData/src/java21/pkg/TestRecordPatterns5.java new file mode 100644 index 0000000000..e5ff6bf316 --- /dev/null +++ b/testData/src/java21/pkg/TestRecordPatterns5.java @@ -0,0 +1,26 @@ +package pkg; + +public class TestRecordPatterns5 { + record R(Number a, String b) {} + + public void test1(R r) { + if (r instanceof R(Integer x, String s)) { + System.out.println(x); + System.out.println(s); + } + } + + public void test2(R r) { + if (r instanceof R(Integer x, String s) && s.length() > 10) { + System.out.println(x); + System.out.println(s); + } + } + + public void test3(R r) { + if (r instanceof R(Integer x, String s) && s.length() > 10 && x.intValue() == 3) { + System.out.println(x); + System.out.println(s); + } + } +} diff --git a/testData/src/java21/pkg/TestRecordPatterns6.java b/testData/src/java21/pkg/TestRecordPatterns6.java new file mode 100644 index 0000000000..5cdcd31506 --- /dev/null +++ b/testData/src/java21/pkg/TestRecordPatterns6.java @@ -0,0 +1,25 @@ +package pkg; + +public class TestRecordPatterns6 { + sealed interface I { + record R1(Object o) implements I {}; + record R2(int i) implements I {}; + record R3(String s) implements I {}; + } + + public Object test1(I in) { + return switch (in) { + case I.R1(Object o) -> o; + case I.R2(int i) -> i; + case I.R3(String s) -> s; + }; + } + + public String test2(I in) { + return switch (in) { + case I.R1(String s) -> s; + case I.R3(String s) -> s; + default -> throw new IllegalStateException(); + }; + } +}