summaryrefslogtreecommitdiff
path: root/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/LoopExtractHelper.java
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/LoopExtractHelper.java')
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/LoopExtractHelper.java206
1 files changed, 206 insertions, 0 deletions
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/LoopExtractHelper.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/LoopExtractHelper.java
new file mode 100644
index 000000000000..d5c9e8f20aee
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/LoopExtractHelper.java
@@ -0,0 +1,206 @@
+/*
+ * 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);
+ }
+ }
+ }
+}