| /* |
| * Copyright 2000-2014 JetBrains s.r.o. |
| * |
| * Licensed 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.jetbrains.java.decompiler.modules.decompiler; |
| |
| import org.jetbrains.java.decompiler.modules.decompiler.stats.DoStatement; |
| import org.jetbrains.java.decompiler.modules.decompiler.stats.IfStatement; |
| import org.jetbrains.java.decompiler.modules.decompiler.stats.SequenceStatement; |
| import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Set; |
| |
| |
| public class LoopExtractHelper { |
| |
| |
| public static boolean extractLoops(Statement root) { |
| |
| boolean res = (extractLoopsRec(root) != 0); |
| |
| if (res) { |
| SequenceHelper.condenseSequences(root); |
| } |
| |
| return res; |
| } |
| |
| |
| private static int extractLoopsRec(Statement stat) { |
| |
| boolean res = false; |
| |
| while (true) { |
| |
| boolean updated = false; |
| |
| for (Statement st : stat.getStats()) { |
| int extr = extractLoopsRec(st); |
| res |= (extr != 0); |
| |
| if (extr == 2) { |
| updated = true; |
| break; |
| } |
| } |
| |
| if (!updated) { |
| break; |
| } |
| } |
| |
| if (stat.type == Statement.TYPE_DO) { |
| if (extractLoop((DoStatement)stat)) { |
| return 2; |
| } |
| } |
| |
| return res ? 1 : 0; |
| } |
| |
| |
| private static boolean extractLoop(DoStatement stat) { |
| |
| if (stat.getLooptype() != DoStatement.LOOP_DO) { |
| return false; |
| } |
| |
| for (StatEdge edge : stat.getLabelEdges()) { |
| if (edge.getType() != StatEdge.TYPE_CONTINUE && edge.getDestination().type != Statement.TYPE_DUMMYEXIT) { |
| return false; |
| } |
| } |
| |
| if (!extractLastIf(stat)) { |
| return extractFirstIf(stat); |
| } |
| else { |
| return true; |
| } |
| } |
| |
| private static boolean extractLastIf(DoStatement stat) { |
| |
| // search for an if condition at the end of the loop |
| Statement last = stat.getFirst(); |
| while (last.type == Statement.TYPE_SEQUENCE) { |
| last = last.getStats().getLast(); |
| } |
| |
| if (last.type == Statement.TYPE_IF) { |
| IfStatement lastif = (IfStatement)last; |
| if (lastif.iftype == IfStatement.IFTYPE_IF && lastif.getIfstat() != null) { |
| Statement ifstat = lastif.getIfstat(); |
| StatEdge elseedge = lastif.getAllSuccessorEdges().get(0); |
| |
| if (elseedge.getType() == StatEdge.TYPE_CONTINUE && elseedge.closure == stat) { |
| |
| Set<Statement> set = stat.getNeighboursSet(StatEdge.TYPE_CONTINUE, Statement.DIRECTION_BACKWARD); |
| set.remove(last); |
| |
| if (set.isEmpty()) { // no direct continues in a do{}while loop |
| if (isExternStatement(stat, ifstat, ifstat)) { |
| extractIfBlock(stat, lastif); |
| return true; |
| } |
| } |
| } |
| } |
| } |
| return false; |
| } |
| |
| private static boolean extractFirstIf(DoStatement stat) { |
| |
| // search for an if condition at the entrance of the loop |
| Statement first = stat.getFirst(); |
| while (first.type == Statement.TYPE_SEQUENCE) { |
| first = first.getFirst(); |
| } |
| |
| // found an if statement |
| if (first.type == Statement.TYPE_IF) { |
| IfStatement firstif = (IfStatement)first; |
| |
| if (firstif.getFirst().getExprents().isEmpty()) { |
| |
| if (firstif.iftype == IfStatement.IFTYPE_IF && firstif.getIfstat() != null) { |
| Statement ifstat = firstif.getIfstat(); |
| |
| if (isExternStatement(stat, ifstat, ifstat)) { |
| extractIfBlock(stat, firstif); |
| return true; |
| } |
| } |
| } |
| } |
| return false; |
| } |
| |
| |
| private static boolean isExternStatement(DoStatement loop, Statement block, Statement stat) { |
| |
| for (StatEdge edge : stat.getAllSuccessorEdges()) { |
| if (loop.containsStatement(edge.getDestination()) && |
| !block.containsStatement(edge.getDestination())) { |
| return false; |
| } |
| } |
| |
| for (Statement st : stat.getStats()) { |
| if (!isExternStatement(loop, block, st)) { |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| |
| private static void extractIfBlock(DoStatement loop, IfStatement ifstat) { |
| |
| Statement target = ifstat.getIfstat(); |
| StatEdge ifedge = ifstat.getIfEdge(); |
| |
| ifstat.setIfstat(null); |
| ifedge.getSource().changeEdgeType(Statement.DIRECTION_FORWARD, ifedge, StatEdge.TYPE_BREAK); |
| ifedge.closure = loop; |
| ifstat.getStats().removeWithKey(target.id); |
| |
| loop.addLabeledEdge(ifedge); |
| |
| SequenceStatement block = new SequenceStatement(Arrays.asList(loop, target)); |
| loop.getParent().replaceStatement(loop, block); |
| block.setAllParent(); |
| |
| loop.addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR, loop, target)); |
| |
| for (StatEdge edge : new ArrayList<StatEdge>(block.getLabelEdges())) { |
| if (edge.getType() == StatEdge.TYPE_CONTINUE || edge == ifedge) { |
| loop.addLabeledEdge(edge); |
| } |
| } |
| |
| for (StatEdge edge : block.getPredecessorEdges(StatEdge.TYPE_CONTINUE)) { |
| if (loop.containsStatementStrict(edge.getSource())) { |
| block.removePredecessor(edge); |
| edge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, edge, loop); |
| loop.addPredecessor(edge); |
| } |
| } |
| } |
| } |