diff options
Diffstat (limited to 'plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/LowBreakHelper.java')
-rw-r--r-- | plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/LowBreakHelper.java | 208 |
1 files changed, 208 insertions, 0 deletions
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/LowBreakHelper.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/LowBreakHelper.java new file mode 100644 index 000000000000..67e9248d0f83 --- /dev/null +++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/LowBreakHelper.java @@ -0,0 +1,208 @@ +/* + * 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.IfStatement; +import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement; +import org.jetbrains.java.decompiler.modules.decompiler.stats.SynchronizedStatement; + +import java.util.List; + +public class LowBreakHelper { + + public static void lowBreakLabels(Statement root) { + + lowBreakLabelsRec(root); + + liftBreakLabels(root); + } + + private static void lowBreakLabelsRec(Statement stat) { + + while (true) { + + boolean found = false; + + for (StatEdge edge : stat.getLabelEdges()) { + if (edge.getType() == StatEdge.TYPE_BREAK) { + Statement minclosure = getMinClosure(stat, edge.getSource()); + if (minclosure != stat) { + minclosure.addLabeledEdge(edge); + edge.labeled = isBreakEdgeLabeled(edge.getSource(), minclosure); + found = true; + break; + } + } + } + + if (!found) { + break; + } + } + + for (Statement st : stat.getStats()) { + lowBreakLabelsRec(st); + } + } + + public static boolean isBreakEdgeLabeled(Statement source, Statement closure) { + + if (closure.type == Statement.TYPE_DO || closure.type == Statement.TYPE_SWITCH) { + + Statement parent = source.getParent(); + + if (parent == closure) { + return false; + } + else { + return isBreakEdgeLabeled(parent, closure) || + (parent.type == Statement.TYPE_DO || parent.type == Statement.TYPE_SWITCH); + } + } + else { + return true; + } + } + + public static Statement getMinClosure(Statement closure, Statement source) { + + while (true) { + + Statement newclosure = null; + + switch (closure.type) { + case Statement.TYPE_SEQUENCE: + Statement last = closure.getStats().getLast(); + + if (isOkClosure(closure, source, last)) { + newclosure = last; + } + break; + case Statement.TYPE_IF: + IfStatement ifclosure = (IfStatement)closure; + if (isOkClosure(closure, source, ifclosure.getIfstat())) { + newclosure = ifclosure.getIfstat(); + } + else if (isOkClosure(closure, source, ifclosure.getElsestat())) { + newclosure = ifclosure.getElsestat(); + } + break; + case Statement.TYPE_TRYCATCH: + for (Statement st : closure.getStats()) { + if (isOkClosure(closure, source, st)) { + newclosure = st; + break; + } + } + break; + case Statement.TYPE_SYNCRONIZED: + Statement body = ((SynchronizedStatement)closure).getBody(); + + if (isOkClosure(closure, source, body)) { + newclosure = body; + } + } + + if (newclosure == null) { + break; + } + + closure = newclosure; + } + + return closure; + } + + private static boolean isOkClosure(Statement closure, Statement source, Statement stat) { + + boolean ok = false; + + if (stat != null && stat.containsStatementStrict(source)) { + + List<StatEdge> lst = stat.getAllSuccessorEdges(); + + ok = lst.isEmpty(); + if (!ok) { + StatEdge edge = lst.get(0); + ok = (edge.closure == closure && edge.getType() == StatEdge.TYPE_BREAK); + } + } + + return ok; + } + + + private static void liftBreakLabels(Statement stat) { + + for (Statement st : stat.getStats()) { + liftBreakLabels(st); + } + + + while (true) { + + boolean found = false; + + for (StatEdge edge : stat.getLabelEdges()) { + if (edge.explicit && edge.labeled && edge.getType() == StatEdge.TYPE_BREAK) { + + Statement newclosure = getMaxBreakLift(stat, edge); + + if (newclosure != null) { + newclosure.addLabeledEdge(edge); + edge.labeled = isBreakEdgeLabeled(edge.getSource(), newclosure); + + found = true; + break; + } + } + } + + if (!found) { + break; + } + } + } + + private static Statement getMaxBreakLift(Statement stat, StatEdge edge) { + + Statement closure = null; + Statement newclosure = stat; + + while ((newclosure = getNextBreakLift(newclosure, edge)) != null) { + closure = newclosure; + } + + return closure; + } + + private static Statement getNextBreakLift(Statement stat, StatEdge edge) { + + Statement closure = stat.getParent(); + + while (closure != null && !closure.containsStatementStrict(edge.getDestination())) { + + boolean labeled = isBreakEdgeLabeled(edge.getSource(), closure); + if (closure.isLabeled() || !labeled) { + return closure; + } + + closure = closure.getParent(); + } + + return null; + } +} |