in src/org/jetbrains/java/decompiler/modules/decompiler/MergeHelper.java [519:665]
private static boolean tryConvertForEach(@Nullable AssignmentExprent @NotNull [] initExprents,
@NotNull DoStatement stat,
@NotNull AssignmentExprent firstDoExprent,
@Nullable Statement preData,
@Nullable Statement firstData,
@Nullable Statement lastData,
@Nullable Exprent lastExprent) {
if (initExprents[0]!=null && isIteratorCall(initExprents[0].getRight())) {
//Streams mimic Iterable but arnt.. so explicitly disallow their enhancements
//TODO: Check inheritance for Iterable instead of just names?
InvocationExprent invc = (InvocationExprent)getUncast((initExprents[0]).getRight());
if (invc.getClassName().startsWith("java/util/stream")) {
return false;
}
if (stat.getConditionExprent() != null && !isHasNextCall(drillNots(stat.getConditionExprent())) ||
firstDoExprent.type != Exprent.EXPRENT_ASSIGNMENT) {
return false;
}
if ((!isNextCall(firstDoExprent.getRight()) && !isNextUnboxing(firstDoExprent.getRight())) || firstDoExprent.getLeft().type != Exprent.EXPRENT_VAR) {
return false;
}
InvocationExprent next = (InvocationExprent)getUncast(firstDoExprent.getRight());
if (isNextUnboxing(next)){ next = (InvocationExprent)getUncast(next.getInstance());}
if (stat.getConditionExprent() == null) return false;
InvocationExprent hnext = (InvocationExprent)getUncast(drillNots(stat.getConditionExprent()));
if (next.getInstance().type != Exprent.EXPRENT_VAR ||
hnext.getInstance().type != Exprent.EXPRENT_VAR ||
((VarExprent)initExprents[0].getLeft()).isVarReferenced(stat, (VarExprent)next.getInstance(), (VarExprent)hnext.getInstance())) {
return false;
}
InvocationExprent holder = (InvocationExprent)(initExprents[0]).getRight();
initExprents[0].fillBytecodeRange(holder.getInstance().bytecode);
holder.fillBytecodeRange(holder.getInstance().bytecode);
firstDoExprent.fillBytecodeRange(firstDoExprent.getLeft().bytecode);
firstDoExprent.getRight().fillBytecodeRange(firstDoExprent.getLeft().bytecode);
if (stat.getIncExprent() != null) {
stat.getIncExprent().fillBytecodeRange(holder.getInstance().bytecode);
}
if (stat.getInitExprent() != null) {
stat.getInitExprent().fillBytecodeRange(firstDoExprent.getLeft().bytecode);
}
stat.setLoopType(DoStatement.LoopType.FOREACH);
stat.setInitExprent(firstDoExprent.getLeft());
stat.setIncExprent(holder.getInstance());
if (preData == null || preData.getExprents() == null || firstData == null || firstData.getExprents() == null) return false;
preData.getExprents().remove(initExprents[0]);
firstData.getExprents().remove(firstDoExprent);
if (initExprents[1] != null && initExprents[1].getLeft().type == Exprent.EXPRENT_VAR &&
holder.getInstance().type == Exprent.EXPRENT_VAR) {
VarExprent copy = (VarExprent)initExprents[1].getLeft();
VarExprent inc = (VarExprent)holder.getInstance();
if (copy.getIndex() == inc.getIndex() && copy.getVersion() == inc.getVersion() &&
!inc.isVarReferenced(stat.getTopParent(), copy) && !isNextCall(initExprents[1].getRight())) {
preData.getExprents().remove(initExprents[1]);
initExprents[1].fillBytecodeRange(initExprents[1].getRight().bytecode);
if (stat.getIncExprent() == null) return false;
stat.getIncExprent().fillBytecodeRange(initExprents[1].getRight().bytecode);
stat.setIncExprent(initExprents[1].getRight());
}
}
return true;
}
else if (initExprents[1] != null) {
if (firstDoExprent.getRight().type != Exprent.EXPRENT_ARRAY || firstDoExprent.getLeft().type != Exprent.EXPRENT_VAR) {
return false;
}
if (lastExprent == null || lastExprent.type != Exprent.EXPRENT_FUNCTION) {
return false;
}
if (initExprents[0] != null && initExprents[0].getRight().type != Exprent.EXPRENT_CONST ||
initExprents[1].getRight().type != Exprent.EXPRENT_FUNCTION ||
stat.getConditionExprent() != null && stat.getConditionExprent().type != Exprent.EXPRENT_FUNCTION) {
return false;
}
//FunctionExprent funcCond = (FunctionExprent)drillNots(stat.getConditionExprent()); //TODO: Verify this is counter < copy.length
FunctionExprent funcRight = (FunctionExprent)initExprents[1].getRight();
FunctionExprent funcInc = (FunctionExprent)lastExprent;
ArrayExprent arr = (ArrayExprent)firstDoExprent.getRight();
int incType = funcInc.getFuncType();
if (funcRight.getFuncType() != FunctionExprent.FUNCTION_ARRAY_LENGTH ||
(incType != FunctionExprent.FUNCTION_PPI && incType != FunctionExprent.FUNCTION_IPP) ||
arr.getIndex().type != Exprent.EXPRENT_VAR ||
arr.getArray().type != Exprent.EXPRENT_VAR) {
return false;
}
VarExprent index = (VarExprent)arr.getIndex();
VarExprent array = (VarExprent)arr.getArray();
VarExprent counter = (VarExprent)funcInc.getLstOperands().get(0);
if (counter.getIndex() != index.getIndex() ||
counter.getVersion() != index.getVersion()) {
return false;
}
if (counter.isVarReferenced(stat.getFirst(), index)) {
return false;
}
funcRight.getLstOperands().get(0).addBytecodeOffsets(initExprents[0].bytecode);
funcRight.getLstOperands().get(0).addBytecodeOffsets(initExprents[1].bytecode);
funcRight.getLstOperands().get(0).addBytecodeOffsets(lastExprent.bytecode);
firstDoExprent.getLeft().addBytecodeOffsets(firstDoExprent.bytecode);
firstDoExprent.getLeft().addBytecodeOffsets(initExprents[0].bytecode);
stat.setLoopType(DoStatement.LoopType.FOREACH);
stat.setInitExprent(firstDoExprent.getLeft());
stat.setIncExprent(funcRight.getLstOperands().get(0));
if (preData == null || preData.getExprents() == null ||
firstData == null || firstData.getExprents() == null ||
lastData == null || lastData.getExprents() == null) {
return false;
}
preData.getExprents().remove(initExprents[0]);
preData.getExprents().remove(initExprents[1]);
firstData.getExprents().remove(firstDoExprent);
lastData.getExprents().remove(lastExprent);
if (initExprents[2] != null && initExprents[2].getLeft().type == Exprent.EXPRENT_VAR) {
VarExprent copy = (VarExprent)initExprents[2].getLeft();
if (copy.getIndex() == array.getIndex() && copy.getVersion() == array.getVersion()) {
preData.getExprents().remove(initExprents[2]);
initExprents[2].getRight().addBytecodeOffsets(initExprents[2].bytecode);
Exprent exprent = stat.getIncExprent();
if (exprent == null) return false;
initExprents[2].getRight().addBytecodeOffsets(exprent.bytecode);
stat.setIncExprent(initExprents[2].getRight());
}
}
return true;
}
return false;
}