diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/IfPatternMatchProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/IfPatternMatchProcessor.java index 0de5fd85f..456e772da 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/IfPatternMatchProcessor.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/IfPatternMatchProcessor.java @@ -127,13 +127,42 @@ private static boolean checkBranch(Exprent exprent, IfStatement statement, State Exprent left = first.getAllExprents().get(0); Exprent right = first.getAllExprents().get(1); - // Right side needs to be a cast function - // If it's not, we might be a record pattern match - if (!(right instanceof FunctionExprent)) { - return identifyRecordPatternMatch(statement, branch, iof, (AssignmentExprent) first); + boolean result = findPatternMatchingInstanceof(left, right, source, target, branch, iof, head); + + if (head.getExprents() != null && !head.getExprents().isEmpty() && head.getExprents().get(0) instanceof AssignmentExprent assignment) { + // If it's an assignement, get both sides + left = assignment.getAllExprents().get(0); + right = assignment.getAllExprents().get(1); + + // Right side needs to be a cast function + // If it's not, we might be a record pattern match + if (!(right instanceof FunctionExprent)) { + result |= identifyIfRecordPatternMatch(statement, branch, iof, assignment); + } } - if (((FunctionExprent) right).getFuncType() != FunctionType.CAST) { + statement.setPatternMatched(true); + + BasicBlockStatement before = statement.getBasichead(); + if (before.getExprents() != null && before.getExprents().size() > 0) { + Exprent last = before.getExprents().get(before.getExprents().size() - 1); + if (last instanceof AssignmentExprent && source instanceof VarExprent) { + Exprent stored = last.getAllExprents().get(0); + Exprent method = last.getAllExprents().get(1); + VarExprent checked = (VarExprent) source; + if ((!(method instanceof FunctionExprent) || ((FunctionExprent) method).getFuncType() != FunctionType.CAST) + && checked.equals(stored) && !checked.isVarReferenced(root, (VarExprent) stored)) { + iof.getLstOperands().set(0, last.getAllExprents().get(1)); + before.getExprents().remove(before.getExprents().size() - 1); + } + } + } + + return result; + } + + private static boolean findPatternMatchingInstanceof(Exprent left, Exprent right, Exprent source, Exprent target, Statement branch, FunctionExprent iof, Statement head) { + if (!(right instanceof FunctionExprent function) || function.getFuncType() != FunctionType.CAST) { return false; } @@ -173,24 +202,6 @@ private static boolean checkBranch(Exprent exprent, IfStatement statement, State if (storeType.isGeneric()) { iof.getLstOperands().set(1, new ConstExprent(storeType, null, iof.getLstOperands().get(1).bytecode)); } - - statement.setPatternMatched(true); - - BasicBlockStatement before = statement.getBasichead(); - if (before.getExprents() != null && before.getExprents().size() > 0) { - Exprent last = before.getExprents().get(before.getExprents().size() - 1); - if (last instanceof AssignmentExprent && source instanceof VarExprent) { - Exprent stored = last.getAllExprents().get(0); - Exprent method = last.getAllExprents().get(1); - VarExprent checked = (VarExprent) source; - if ((!(method instanceof FunctionExprent) || ((FunctionExprent) method).getFuncType() != FunctionType.CAST) - && checked.equals(stored) && !checked.isVarReferenced(root, (VarExprent) stored)) { - iof.getLstOperands().set(0, last.getAllExprents().get(1)); - before.getExprents().remove(before.getExprents().size() - 1); - } - } - } - return true; } @@ -236,7 +247,7 @@ private static void findVarsInPredecessors(List vvs, Statement r } } - private static boolean identifyRecordPatternMatch(IfStatement stat, Statement branch, FunctionExprent instOf, AssignmentExprent head) { + private static boolean identifyIfRecordPatternMatch(IfStatement stat, Statement branch, FunctionExprent instOf, AssignmentExprent head) { if (!stat.getTopParent().mt.getBytecodeVersion().hasRecordPatternMatching()) { return false; } @@ -249,19 +260,72 @@ private static boolean identifyRecordPatternMatch(IfStatement stat, Statement br // if (v instanceof MyType) { // var10000 = v; // ... - if (!instOf.getLstOperands().get(0).equals(headRight)) { + // or: + // + // if (v instanceof MyType var10000) { + // ... + + if (!(instOf.getLstOperands().size() > 2 ? instOf.getLstOperands().get(2) : instOf.getLstOperands().get(0)).equals(headRight)) { return false; } VarType type = instOf.getLstOperands().get(1).getExprType(); + PatternExprent exprent = identifyRecordPatternMatch(stat, branch, headRight, type, false); + if (exprent == null) { + return false; + } + + if (instOf.getLstOperands().size() > 2) { + instOf.getLstOperands().set(2, exprent); + } else { + instOf.getLstOperands().add(2, exprent); + } + + stat.setPatternMatched(true); + return true; + } + + public static PatternExprent identifyRecordPatternMatch(Statement parent, Statement branch, Exprent storeVariable, VarType type, boolean simulate) { + Statement original = branch; + StructClass cl = DecompilerContext.getStructContext().getClass(type.value); - if (cl == null || cl.getRecordComponents() == null) { - return false; // No idea what class, or not a record! + + if (cl == null || cl.getRecordComponents() == null || cl.getRecordComponents().isEmpty()) { + return null; } - List comp = cl.getRecordComponents(); + // Ending exprents we may want to remove + Map remove = new HashMap<>(); + // Statements that ought to be destroyed as a result of creating the pattern + List toDestroy = new ArrayList<>(); + + PatternData pattern = getChildPattern(cl, storeVariable, type, branch, 1, toDestroy, remove); + if (pattern == null) { + return null; + } + branch = pattern.stat; + + if (simulate) { + return pattern.exp; + } + if (original != branch) { + parent.replaceStatement(original, branch); + } + + for (Statement st : toDestroy) { + st.replaceWithEmpty(); + } + + for (Map.Entry e : remove.entrySet()) { + e.getKey().getExprents().remove(e.getValue()); + } + + return pattern.exp; + } + + private static PatternData getChildPattern(StructClass cl, Exprent storeVariable, VarType type, Statement branch, int stIdx, List toDestroy, Map remove) { // Iteratively go through the sequence to see if it extracts from the record // The general strategy is to identify an "extracting try" [1] for each record component. @@ -280,19 +344,20 @@ private static boolean identifyRecordPatternMatch(IfStatement stat, Statement br // realVar = exVar; // = ; - int stIdx = 1; - - // Map which variable refers to which part of the record - Map vars = new LinkedHashMap<>(); + if (cl == null || cl.getRecordComponents() == null) { + return null; // No idea what class, or not a record! + } - // Ending exprents we may want to remove - Map remove = new HashMap<>(); - // Statements that ought to be destroyed as a result of creating the pattern - List toDestroy = new ArrayList<>(); + record PatternStore(StructRecordComponent component, StructClass cl, VarType type, VarExprent store) { + } + List patternStores = new ArrayList<>(); + List comp = cl.getRecordComponents(); + // Map which variable refers to which part of the record + Map vars = new LinkedHashMap<>(); for (StructRecordComponent c : comp) { if (branch.getStats().size() <= stIdx) { - return false; + return null; } Statement next = branch.getStats().get(stIdx); @@ -317,7 +382,7 @@ private static boolean identifyRecordPatternMatch(IfStatement stat, Statement br } if (foundVar == null) { - return false; + return null; } toDestroy.add(next); @@ -340,7 +405,7 @@ private static boolean identifyRecordPatternMatch(IfStatement stat, Statement br // If that's the only other thing in the statement, then we can destroy it! boolean destroyed = false; if (next.getExprents().size() == 2) { - if (next.getExprents().get(1) instanceof AssignmentExprent nAssign && nAssign.getRight().equals(headRight)) { + if (next.getExprents().get(1) instanceof AssignmentExprent nAssign && nAssign.getRight().equals(storeVariable)) { toDestroy.add(next); destroyed = true; @@ -353,11 +418,21 @@ private static boolean identifyRecordPatternMatch(IfStatement stat, Statement br } } } - } else { + } else if (next instanceof IfStatement ifSt && ifSt.iftype == IfStatement.IFTYPE_IF && ifSt.getHeadexprent().getCondition() instanceof FunctionExprent func) { // 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) { + FunctionExprent function = null; + boolean found = false; + boolean inverted = false; + if (func.getFuncType() == FunctionType.INSTANCEOF) { + found = true; + function = func; + } else if (func.getFuncType() == FunctionType.BOOL_NOT && func.getLstOperands().get(0) instanceof FunctionExprent inner && inner.getFuncType() == FunctionType.INSTANCEOF) { + found = true; + inverted = true; + function = inner; + } + if (found) { // " = ;" idiom // Ensure this is the right idiom be fore we mark it for destruction. if (branch.getBasichead().getExprents().size() == 1) { @@ -367,8 +442,20 @@ private static boolean identifyRecordPatternMatch(IfStatement stat, Statement br } } - branch = ifSt.getIfstat(); - stIdx = 0; + Exprent store = function.getLstOperands().size() > 2 ? function.getLstOperands().get(2) : function.getLstOperands().get(0); + if (store instanceof VarExprent variable) { + patternStores.add(new PatternStore(c, DecompilerContext.getStructContext().getClass(variable.getExprType().value), variable.getExprType(), variable)); + vars.put(c, variable); + ok = true; + } + + if (inverted) { + stIdx++; + toDestroy.add(ifSt); + } else { + branch = ifSt.getIfstat(); + stIdx = 0; + } } } @@ -381,26 +468,30 @@ private static boolean identifyRecordPatternMatch(IfStatement stat, Statement br stIdx++; } } else { - return false; + return null; } } - PatternExprent pattern = new PatternExprent(PatternExprent.recordData(cl), type, new ArrayList<>(vars.values())); - - instOf.getLstOperands().add(2, pattern); - stat.setPatternMatched(true); - - for (Statement st : toDestroy) { - st.replaceWithEmpty(); - } - - for (Map.Entry e : remove.entrySet()) { - e.getKey().getExprents().remove(e.getValue()); + // Check for any nested record patterns + for (PatternStore patternStore : patternStores) { + List tmpToDestroy = new ArrayList<>(); + Map tmpRemove = new HashMap<>(); + PatternData patternData = getChildPattern(patternStore.cl, patternStore.store, patternStore.type, branch, stIdx, tmpToDestroy, tmpRemove); + if (patternData != null) { + vars.put(patternStore.component, patternData.exp); + branch = patternData.stat; + stIdx = patternData.index; + toDestroy.addAll(tmpToDestroy); + remove.putAll(tmpRemove); + } } - return true; + PatternExprent pattern = new PatternExprent(PatternExprent.recordData(cl), type, new ArrayList<>(vars.values())); + return new PatternData(pattern, branch, stIdx); } + private record PatternData(PatternExprent exp, Statement stat, int index) {} + public static boolean isStatementMatchThrow(Statement st) { if (st instanceof BasicBlockStatement && st.getExprents().size() == 1) { // throw ... diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/SwitchPatternMatchProcessor.java b/src/org/jetbrains/java/decompiler/modules/decompiler/SwitchPatternMatchProcessor.java index d429f63e6..0692ff61d 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/SwitchPatternMatchProcessor.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/SwitchPatternMatchProcessor.java @@ -159,31 +159,51 @@ private static boolean processStatement(SwitchStatement stat, Statement root) { oldStat.replaceWith(caseStat); } } - // make instanceof from assignment - BasicBlockStatement caseStatBlock = caseStat.getBasichead(); - if (caseStatBlock.getExprents().size() >= 1) { - Exprent expr = caseStatBlock.getExprents().get(0); - if (expr instanceof AssignmentExprent) { - AssignmentExprent assign = (AssignmentExprent) expr; - if (assign.getLeft() instanceof VarExprent) { - VarExprent var = (VarExprent) assign.getLeft(); + PatternExprent pattern; + if (stat.getCaseGuards().size() > i && stat.getCaseGuards().get(i) instanceof PatternExprent) { + pattern = (PatternExprent) stat.getCaseGuards().set(i, null); + } else { + pattern = identifySwitchRecordPatternMatch(stat, stat.getCaseStatements().get(i), false); + } - if (assign.getRight() instanceof FunctionExprent && ((FunctionExprent) assign.getRight()).getFuncType() == FunctionExprent.FunctionType.CAST) { - FunctionExprent cast = (FunctionExprent) assign.getRight(); + if (pattern != null) { + List operands = new ArrayList<>(); + operands.add(realSelector); + operands.add(new ConstExprent(pattern.getExprType(), null, null)); + operands.add(pattern); - List operands = new ArrayList<>(); - operands.add(cast.getLstOperands().get(0)); // checking var - operands.add(cast.getLstOperands().get(1)); // type - operands.add(var); // pattern match var + FunctionExprent function = new FunctionExprent(FunctionType.INSTANCEOF, operands, null); + allCases.set(0, function); + } else { + + // make instanceof from assignment + BasicBlockStatement caseStatBlock = caseStat.getBasichead(); + if (caseStatBlock.getExprents().size() >= 1) { + Exprent expr = caseStatBlock.getExprents().get(0); + if (expr instanceof AssignmentExprent) { + AssignmentExprent assign = (AssignmentExprent) expr; + + if (assign.getLeft() instanceof VarExprent) { + VarExprent var = (VarExprent) assign.getLeft(); + + if (assign.getRight() instanceof FunctionExprent && ((FunctionExprent) assign.getRight()).getFuncType() == FunctionExprent.FunctionType.CAST) { + FunctionExprent cast = (FunctionExprent) assign.getRight(); - FunctionExprent func = new FunctionExprent(FunctionExprent.FunctionType.INSTANCEOF, operands, null); + List operands = new ArrayList<>(); + operands.add(cast.getLstOperands().get(0)); // checking var + operands.add(cast.getLstOperands().get(1)); // type + operands.add(var); // pattern match var - caseStatBlock.getExprents().remove(0); + FunctionExprent func = new FunctionExprent(FunctionExprent.FunctionType.INSTANCEOF, operands, null); - // TODO: ssau representation - // any shared nulls will be at the end, and patterns & defaults can't be shared, so its safe to overwrite whatever's here - allCases.set(0, func); + caseStatBlock.getExprents().remove(0); + + // TODO: ssau representation + // any shared nulls will be at the end, and patterns & defaults can't be shared, + // so its safe to overwrite whatever's here + allCases.set(0, func); + } } } } @@ -345,6 +365,23 @@ private static boolean eliminateGuardRef(SwitchStatement stat, Map // alternatively, it can be inverted as `if (guardCond) { /* regular case code... */ break; } idx = __thisIdx + 1;` if (reference.b instanceof AssignmentExprent) { Statement assignStat = reference.a; + + // If a record pattern contains an `instanceof` check then a guard is used so + // attempt to eliminate it + for (int i = 0; i < stat.getCaseStatements().size(); i++) { + if (stat.getCaseStatements().get(i).containsStatement(assignStat)) { + Statement patternStat = stat.getCaseStatements().get(i); + PatternExprent pattern = identifySwitchRecordPatternMatch(stat, patternStat, simulate); + if (pattern != null) { + if (!simulate) { + guards.put(stat.getCaseValues().get(i), pattern); + } + return true; + } + break; + } + } + // Note: This can probably be checked earlier if (assignStat.getAllPredecessorEdges().size() > 1) { return false; @@ -463,6 +500,28 @@ private static boolean eliminateGuardRef(SwitchStatement stat, Map return false; } + private static PatternExprent identifySwitchRecordPatternMatch(SwitchStatement stat, Statement statement, boolean simulate) { + BasicBlockStatement head = statement.getBasichead(); + if (head.getExprents() == null || head.getExprents().isEmpty()) { + return null; + } + + Exprent first = head.getExprents().get(0); + + if (!(first instanceof AssignmentExprent assignment)) { + return null; + } + + if (!(assignment.getLeft() instanceof VarExprent assigned)) { + return null; + } + PatternExprent pattern = IfPatternMatchProcessor.identifyRecordPatternMatch(stat, statement, assigned, assigned.getExprType(), simulate); + if (pattern != null && !simulate) { + head.getExprents().remove(0); + } + return pattern; + } + private static boolean isSwitchPatternMatch(SwitchHeadExprent head) { Exprent value = head.getValue(); diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchExprent.java index 9cf79a2e2..6e24aedeb 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchExprent.java @@ -94,12 +94,13 @@ public TextBuffer toJava(int indent) { buf.appendField(field.getName(), false, field.getClassname(), field.getName(), field.getDescriptor()); } else if (value instanceof FunctionExprent && ((FunctionExprent) value).getFuncType() == FunctionExprent.FunctionType.INSTANCEOF) { // Pattern matching variables - List operands = ((FunctionExprent) value).getLstOperands(); - buf.append(operands.get(1).toJava(indent)); - buf.append(" "); - // We're pasting the var type, don't do it again - ((VarExprent)operands.get(2)).setDefinition(false); - buf.append(operands.get(2).toJava(indent)); + + Pattern pattern = (Pattern) value.getAllExprents().get(2); + for (VarExprent var : pattern.getPatternVars()) { + var.setWritingPattern(); + } + + buf.append(value.getAllExprents().get(2).toJava(indent)); } else { buf.append(value.toJava(indent)); } diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SwitchStatement.java b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SwitchStatement.java index 360fac57d..d4fb0f00b 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SwitchStatement.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SwitchStatement.java @@ -160,12 +160,13 @@ public TextBuffer toJava(int indent) { buf.appendField(field.getName(), false, field.getClassname(), field.getName(), field.getDescriptor()); } else if (value instanceof FunctionExprent && ((FunctionExprent) value).getFuncType() == FunctionType.INSTANCEOF) { // Pattern matching variables - List operands = ((FunctionExprent) value).getLstOperands(); - buf.append(operands.get(1).toJava(indent)); - buf.append(" "); - // We're pasting the var type, don't do it again - ((VarExprent)operands.get(2)).setDefinition(false); - buf.append(operands.get(2).toJava(indent)); + + Pattern pattern = (Pattern) value.getAllExprents().get(2); + for (VarExprent var : pattern.getPatternVars()) { + var.setWritingPattern(); + } + + buf.append(value.getAllExprents().get(2).toJava(indent)); } else { buf.append(value.toJava(indent)); } diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index f24c0ccd1..dca448cb9 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -689,6 +689,7 @@ private void registerDefault() { register(JAVA_21, "TestRecordPatterns4"); register(JAVA_21, "TestRecordPatterns5"); register(JAVA_21, "TestRecordPatterns6"); + register(JAVA_21, "TestRecordPatterns7"); 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 b46d1d95f..53ab8eea7 100644 --- a/testData/results/pkg/TestRecordPatterns1.dec +++ b/testData/results/pkg/TestRecordPatterns1.dec @@ -80,9 +80,6 @@ class 'pkg/TestRecordPatterns1' { e 11 f 12 10 12 - 1d 11 - 1e 11 - 1f 11 25 11 26 11 27 12 @@ -115,9 +112,6 @@ class 'pkg/TestRecordPatterns1' { e 18 f 19 10 19 - 1d 18 - 1e 18 - 1f 18 25 18 26 18 27 18 @@ -199,4 +193,4 @@ Lines mapping: 28 <-> 26 29 <-> 27 30 <-> 28 -32 <-> 30 \ No newline at end of file +32 <-> 30 diff --git a/testData/results/pkg/TestRecordPatterns4.dec b/testData/results/pkg/TestRecordPatterns4.dec index 806090dcb..99415298a 100644 --- a/testData/results/pkg/TestRecordPatterns4.dec +++ b/testData/results/pkg/TestRecordPatterns4.dec @@ -35,13 +35,7 @@ class 'pkg/TestRecordPatterns4' { 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 @@ -70,13 +64,7 @@ class 'pkg/TestRecordPatterns4' { 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 @@ -115,13 +103,7 @@ class 'pkg/TestRecordPatterns4' { 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 @@ -173,4 +155,4 @@ Lines mapping: 21 <-> 19 22 <-> 20 23 <-> 21 -25 <-> 23 \ No newline at end of file +25 <-> 23 diff --git a/testData/results/pkg/TestRecordPatterns5.dec b/testData/results/pkg/TestRecordPatterns5.dec index ad84fd699..3e3402e1c 100644 --- a/testData/results/pkg/TestRecordPatterns5.dec +++ b/testData/results/pkg/TestRecordPatterns5.dec @@ -41,9 +41,6 @@ class 'pkg/TestRecordPatterns5' { 4 4 5 4 6 4 - 14 4 - 15 4 - 16 4 1c 4 21 4 22 4 @@ -75,9 +72,6 @@ class 'pkg/TestRecordPatterns5' { 4 11 5 11 6 11 - 14 11 - 15 11 - 16 11 1c 11 21 12 22 12 @@ -119,9 +113,6 @@ class 'pkg/TestRecordPatterns5' { 4 21 5 21 6 21 - 14 21 - 15 21 - 16 21 1c 21 21 22 22 22 @@ -176,4 +167,4 @@ Lines mapping: 21 <-> 22 22 <-> 25 23 <-> 26 -25 <-> 29 \ No newline at end of file +25 <-> 29 diff --git a/testData/results/pkg/TestRecordPatterns6.dec b/testData/results/pkg/TestRecordPatterns6.dec index ceec98ceb..386e4e399 100644 --- a/testData/results/pkg/TestRecordPatterns6.dec +++ b/testData/results/pkg/TestRecordPatterns6.dec @@ -1,98 +1,26 @@ 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 Object test1(TestRecordPatterns6.I in) { + return switch (in) {// 11 + case TestRecordPatterns6.I.R1(Object var14) -> var14;// 12 + case TestRecordPatterns6.I.R2(int var15) -> var15;// 13 + case TestRecordPatterns6.I.R3(String var10) -> var10;// 14 + default -> throw new MatchException(null, null); + }; } - public String test(TestRecordPatterns6.I in) { + public String test2(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 + return (String)(switch (in) {// 19 + case TestRecordPatterns6.I.R1(String s) -> s;// 20 + case TestRecordPatterns6.I.R3(String var8) -> var8;// 21 + default -> throw new IllegalStateException();// 22 + }); } } @@ -109,198 +37,119 @@ public class TestRecordPatterns6 { } 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 'test1 (Lpkg/TestRecordPatterns6$I;)Ljava/lang/Object;' { + 0 6 + 9 6 + 10 6 + 11 6 + 12 6 + 13 6 + 14 6 + 15 6 + 16 6 + 17 6 + 18 6 + 19 6 + 1a 6 + 1b 6 + 1c 6 + 1d 6 + 1e 6 + 1f 6 + 20 6 + 21 6 + 22 6 + 23 6 + 24 6 + 25 6 + 26 6 + 27 6 + 28 6 + 29 6 + 2a 6 + 2b 6 + 30 10 + 31 10 + 35 10 + 41 7 + 42 7 + 43 7 + 44 7 + 47 7 + 48 7 + 57 8 + 58 8 + 59 8 + 5a 8 + 5d 8 + 5e 8 + 5f 8 + 60 8 + 61 8 + 70 9 + 71 9 + 72 9 + 73 9 + 76 9 + 77 9 + 78 6 } - 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 + method 'test2 (Lpkg/TestRecordPatterns6$I;)Ljava/lang/String;' { + 0 15 + 2 15 + 3 15 + 4 15 + 9 18 + 10 18 + 11 18 + 12 18 + 13 18 + 14 18 + 15 18 + 16 18 + 17 18 + 18 18 + 19 18 + 1a 18 + 1b 18 + 1c 18 + 1d 18 + 1e 18 + 1f 18 + 20 18 + 21 18 + 22 18 + 23 18 + 24 18 + 25 18 + 26 18 + 27 18 + 28 18 + 29 18 + 2a 18 + 2b 18 + 46 19 + 47 19 + 48 19 + 49 19 + 60 20 + 61 20 + 62 20 + 63 20 + 66 20 + 67 20 + 72 21 + 73 18 } } Lines mapping: -11 <-> 50 -12 <-> 10 -13 <-> 22 -14 <-> 15 -19 <-> 95 -20 <-> 62 -21 <-> 67 -22 <-> 92 \ No newline at end of file +11 <-> 7 +12 <-> 8 +13 <-> 9 +14 <-> 10 +19 <-> 19 +20 <-> 20 +21 <-> 21 +22 <-> 22 diff --git a/testData/results/pkg/TestRecordPatterns7.dec b/testData/results/pkg/TestRecordPatterns7.dec new file mode 100644 index 000000000..a6e5d53fe --- /dev/null +++ b/testData/results/pkg/TestRecordPatterns7.dec @@ -0,0 +1,179 @@ +package pkg; + +import java.util.Objects; + +public class TestRecordPatterns7 { + public void test(Object o) { + if (o instanceof TestRecordPatterns7.A(TestRecordPatterns7.C(TestRecordPatterns7.B(int var26, int var27), int var25), int var22, TestRecordPatterns7.B(int var28, int var29))// 5 + ) + { + System.out.println(var26 + var27 + var25 + var22 + var28 + var29);// 6 + } + }// 8 + + public void test2(Object o) { + Objects.requireNonNull(o); + + System.out + .println(// 11 + switch (o) { + case TestRecordPatterns7.A(TestRecordPatterns7.C(TestRecordPatterns7.B(int var28, int var29), int var27), int var24, TestRecordPatterns7.B(int var30, int var31)) -> var28// 12 + + var29 + + var27 + + var24 + + var30 + + var31; + default -> 0;// 13 + } + ); + } + + static record A(TestRecordPatterns7.C c, int i, TestRecordPatterns7.B b2) { + } + + static record B(int i1, int i2) { + } + + static record C(TestRecordPatterns7.B b, int i) { + } +} + +class 'pkg/TestRecordPatterns7' { + method 'test (Ljava/lang/Object;)V' { + 0 6 + 1 6 + 2 6 + 3 6 + 4 6 + 5 6 + 6 6 + 21 6 + 22 6 + 23 9 + 24 9 + 4f 6 + 50 6 + 51 9 + 52 9 + 5a 6 + 5b 6 + 5c 9 + 5d 9 + 65 6 + 66 6 + 67 9 + 68 9 + 70 6 + 71 6 + 72 9 + 73 9 + 7b 6 + 7c 6 + 7d 9 + 7e 9 + 81 9 + 82 9 + 83 9 + 84 9 + 85 9 + 86 9 + 87 9 + 88 9 + 89 9 + 8a 9 + 8b 9 + 8c 9 + 8d 9 + 8e 9 + 8f 9 + 90 9 + 91 9 + 92 9 + 93 9 + 94 9 + 95 9 + 96 9 + 97 9 + a9 11 + } + + method 'test2 (Ljava/lang/Object;)V' { + 0 16 + 1 16 + 2 16 + 3 14 + 5 14 + 6 14 + 7 14 + c 18 + 13 18 + 14 18 + 15 18 + 16 18 + 17 18 + 18 18 + 19 18 + 1a 18 + 1b 18 + 1c 18 + 1d 18 + 1e 18 + 1f 18 + 20 18 + 21 18 + 22 18 + 23 18 + 42 19 + 43 19 + 44 22 + 45 22 + 73 19 + 74 19 + 75 21 + 76 21 + 7e 19 + 7f 19 + 80 19 + 81 19 + 89 19 + 8a 19 + 8b 20 + 8c 20 + 94 19 + 95 19 + 96 23 + 97 23 + 9f 19 + a0 19 + a1 24 + a2 24 + a5 19 + a6 19 + ad 20 + ae 20 + af 19 + b1 21 + b2 19 + b4 22 + b5 19 + b7 23 + b8 19 + ba 24 + bb 19 + c1 25 + c5 17 + c6 17 + c7 17 + c8 28 + } +} + +Lines mapping: +5 <-> 7 +6 <-> 10 +8 <-> 12 +11 <-> 18 +12 <-> 20 +13 <-> 26 +Not mapped: +15 diff --git a/testData/results/pkg/TestUnnamedVar1.dec b/testData/results/pkg/TestUnnamedVar1.dec index d9a5d9628..5b8d3acb3 100644 --- a/testData/results/pkg/TestUnnamedVar1.dec +++ b/testData/results/pkg/TestUnnamedVar1.dec @@ -30,28 +30,8 @@ public class TestUnnamedVar1 { }// 15 public void test1(Object o) { - if (o instanceof TestUnnamedVar1.Point var2) { - TestUnnamedVar1.Point var10000 = var2; - - try { - var9 = var10000.x(); - } catch (Throwable var7) {// 18 - throw new MatchException(var7.toString(), var7); - } - - int var5 = var9; - var10000 = var2; - - try { - var11 = var10000.y(); - } catch (Throwable var6) { - throw new MatchException(var6.toString(), var6); - } - - Object var8 = var11; - if (var8 instanceof Integer) { - System.out.println(var5);// 19 - } + if (o instanceof TestUnnamedVar1.Point(int var5, Object var8)) {// 18 + System.out.println(var5);// 19 } }// 21 @@ -117,76 +97,52 @@ class 'pkg/TestUnnamedVar1' { 4 32 5 32 6 32 - b 32 - c 33 - d 36 - e 36 - f 36 - 10 41 - 11 41 - 12 52 - 13 52 - 15 42 - 16 45 - 17 45 - 18 45 - 19 50 - 1a 50 - 1b 51 - 1c 51 - 1d 51 - 1e 51 - 1f 51 - 20 51 - 21 51 - 22 51 - 23 52 - 24 52 - 25 52 - 26 52 - 27 52 - 28 52 - 29 52 - 2d 37 - 32 38 - 33 38 - 34 38 - 35 38 - 36 38 - 3a 38 - 3b 55 + 10 32 + 11 32 + 12 33 + 13 33 + 1b 32 + 1c 32 + 23 33 + 24 33 + 25 33 + 26 33 + 27 33 + 28 33 + 29 33 + 3b 35 } method 'stream (Ljava/util/List;)Ljava/util/List;' { - 0 58 - 1 58 - 2 58 - 3 58 - 4 58 - 5 58 - b 58 - c 58 - d 58 - e 58 - f 58 - 10 58 - 11 58 - 12 58 - 13 58 - 14 58 - 15 58 + 0 38 + 1 38 + 2 38 + 3 38 + 4 38 + 5 38 + b 38 + c 38 + d 38 + e 38 + f 38 + 10 38 + 11 38 + 12 38 + 13 38 + 14 38 + 15 38 } method 'lambda$stream$0 (Ljava/lang/String;)Ljava/lang/String;' { - 0 58 - 1 58 - 2 58 + 0 38 + 1 38 + 2 38 } method 'trycatch (Ljava/io/File;)V' { - 4 63 - c 64 - d 66 + 4 43 + c 44 + d 46 } } @@ -194,12 +150,12 @@ Lines mapping: 12 <-> 15 13 <-> 28 15 <-> 30 -18 <-> 38 -19 <-> 53 -21 <-> 56 -24 <-> 59 -29 <-> 64 -30 <-> 65 -33 <-> 67 +18 <-> 33 +19 <-> 34 +21 <-> 36 +24 <-> 39 +29 <-> 44 +30 <-> 45 +33 <-> 47 Not mapped: -32 \ No newline at end of file +32 diff --git a/testData/src/java21/pkg/TestRecordPatterns7.java b/testData/src/java21/pkg/TestRecordPatterns7.java new file mode 100644 index 000000000..1b3e50a35 --- /dev/null +++ b/testData/src/java21/pkg/TestRecordPatterns7.java @@ -0,0 +1,22 @@ +package pkg; + +public class TestRecordPatterns7 { + public void test(Object o) { + if (o instanceof A(C(B(int i1, int i2), int i3), int i4, B(int i5, int i6))) { + System.out.println(i1 + i2 + i3 + i4 + i5 + i6); + } + } + + public void test2(Object o) { + System.out.println(switch (o) { + case A(C(B(int i1, int i2), int i3), int i4, B(int i5, int i6)) -> i1 + i2 + i3 + i4 + i5 + i6; + default -> 0; + }); + } + + record A(C c, int i, B b2) {} + + record B(int i1, int i2) {} + + record C(B b, int i) {} +}