summaryrefslogtreecommitdiffstats
path: root/src/org/jetbrains/java/decompiler/modules/decompiler/LabelHelper.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/org/jetbrains/java/decompiler/modules/decompiler/LabelHelper.java')
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/LabelHelper.java1008
1 files changed, 500 insertions, 508 deletions
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/LabelHelper.java b/src/org/jetbrains/java/decompiler/modules/decompiler/LabelHelper.java
index 6d7a897..2e00d5b 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/LabelHelper.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/LabelHelper.java
@@ -1,521 +1,513 @@
/*
- * Fernflower - The Analytical Java Decompiler
- * http://www.reversed-java.com
+ * Copyright 2000-2014 JetBrains s.r.o.
*
- * (C) 2008 - 2010, Stiver
+ * 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
*
- * This software is NEITHER public domain NOR free software
- * as per GNU License. See license.txt for more details.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * This software is distributed WITHOUT ANY WARRANTY; without
- * even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE.
+ * 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 java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map.Entry;
-
import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
-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.RootStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.SequenceStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.SwitchStatement;
-import org.jetbrains.java.decompiler.modules.decompiler.stats.SynchronizedStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.*;
+
+import java.util.*;
+import java.util.Map.Entry;
public class LabelHelper {
-
- public static void cleanUpEdges(RootStatement root) {
-
- resetAllEdges(root);
-
- removeNonImmediateEdges(root);
-
- liftClosures(root);
-
- lowContinueLabels(root, new HashSet<StatEdge>());
-
- lowClosures(root);
-
- }
-
- public static void identifyLabels(RootStatement root) {
-
- setExplicitEdges(root);
-
- hideDefaultSwitchEdges(root);
-
- processStatementLabel(root);
-
- setRetEdgesUnlabeled(root);
- }
-
- private static void liftClosures(Statement stat) {
-
- for(StatEdge edge : stat.getAllSuccessorEdges()) {
- switch(edge.getType()) {
- case StatEdge.TYPE_CONTINUE:
- if(edge.getDestination() != edge.closure) {
- edge.getDestination().addLabeledEdge(edge);
- }
- break;
- case StatEdge.TYPE_BREAK:
- Statement dest = edge.getDestination();
- if(dest.type != Statement.TYPE_DUMMYEXIT) {
- Statement parent = dest.getParent();
-
- List<Statement> lst = new ArrayList<Statement>();
- if(parent.type == Statement.TYPE_SEQUENCE) {
- lst.addAll(((SequenceStatement)parent).getStats());
- } else if(parent.type == Statement.TYPE_SWITCH) {
- lst.addAll(((SwitchStatement)parent).getCaseStatements());
- }
-
- for(int i=0;i<lst.size();i++) {
- if(lst.get(i) == dest) {
- lst.get(i-1).addLabeledEdge(edge);
- break;
- }
- }
- }
- }
- }
-
- for(Statement st : stat.getStats()) {
- liftClosures(st);
- }
-
- }
-
- private static void removeNonImmediateEdges(Statement stat) {
-
- for(Statement st : stat.getStats()) {
- removeNonImmediateEdges(st);
- }
-
- if(!stat.hasBasicSuccEdge()) {
- for(StatEdge edge : stat.getSuccessorEdges(StatEdge.TYPE_CONTINUE | StatEdge.TYPE_BREAK)) {
- stat.removeSuccessor(edge);
- }
- }
- }
-
- public static void lowContinueLabels(Statement stat, HashSet<StatEdge> edges) {
-
- boolean ok = (stat.type != Statement.TYPE_DO);
- if(!ok) {
- DoStatement dostat = (DoStatement)stat;
- ok = dostat.getLooptype() == DoStatement.LOOP_DO ||
- dostat.getLooptype() == DoStatement.LOOP_WHILE ||
- (dostat.getLooptype() == DoStatement.LOOP_FOR && dostat.getIncExprent() == null);
- }
-
- if(ok) {
- edges.addAll(stat.getPredecessorEdges(StatEdge.TYPE_CONTINUE));
- }
-
- if(ok && stat.type == Statement.TYPE_DO) {
- for(StatEdge edge: edges) {
- if(stat.containsStatementStrict(edge.getSource())) {
-
- edge.getDestination().removePredecessor(edge);
- edge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, edge, stat);
- stat.addPredecessor(edge);
-
- stat.addLabeledEdge(edge);
- }
- }
- }
-
- for(Statement st: stat.getStats()) {
- if(st == stat.getFirst()) {
- lowContinueLabels(st, edges);
- } else {
- lowContinueLabels(st, new HashSet<StatEdge>());
- }
- }
- }
-
- public static void lowClosures(Statement stat) {
-
- for(StatEdge edge : new ArrayList<StatEdge>(stat.getLabelEdges())) {
-
- if(edge.getType() == StatEdge.TYPE_BREAK) { // FIXME: ?
- for(Statement st : stat.getStats()) {
- if(st.containsStatementStrict(edge.getSource())) {
- if(MergeHelper.isDirectPath(st, edge.getDestination())) {
- st.addLabeledEdge(edge);
- }
- }
- }
- }
- }
-
- for(Statement st: stat.getStats()) {
- lowClosures(st);
- }
-
- }
-
- private static void resetAllEdges(Statement stat) {
-
- for(Statement st: stat.getStats()) {
- resetAllEdges(st);
- }
-
- for(StatEdge edge: stat.getAllSuccessorEdges()) {
- edge.explicit = true;
- edge.labeled = true;
- }
- }
-
- private static void setRetEdgesUnlabeled(RootStatement root) {
- Statement exit = root.getDummyExit();
- for(StatEdge edge: exit.getAllPredecessorEdges()) {
- List<Exprent> lst = edge.getSource().getExprents();
- if(edge.getType() == StatEdge.TYPE_FINALLYEXIT || (lst != null && !lst.isEmpty() &&
- lst.get(lst.size()-1).type == Exprent.EXPRENT_EXIT)) {
- edge.labeled = false;
- }
- }
- }
-
- private static HashMap<Statement, List<StatEdge>> setExplicitEdges(Statement stat) {
-
- HashMap<Statement, List<StatEdge>> mapEdges = new HashMap<Statement, List<StatEdge>>();
-
- if(stat.getExprents() != null) {
- return mapEdges;
- }
-
-
- switch(stat.type) {
- case Statement.TYPE_TRYCATCH:
- case Statement.TYPE_CATCHALL:
-
- for(Statement st : stat.getStats()) {
- HashMap<Statement, List<StatEdge>> mapEdges1 = setExplicitEdges(st);
- processEdgesWithNext(st, mapEdges1, null);
-
- if(stat.type == Statement.TYPE_TRYCATCH || st == stat.getFirst()) { // edges leaving a finally catch block are always explicit
- // merge the maps
- if(mapEdges1 != null) {
- for(Entry<Statement, List<StatEdge>> entr : mapEdges1.entrySet()) {
- if(mapEdges.containsKey(entr.getKey())) {
- mapEdges.get(entr.getKey()).addAll(entr.getValue());
- } else {
- mapEdges.put(entr.getKey(), entr.getValue());
- }
- }
- }
- }
- }
-
- break;
- case Statement.TYPE_DO:
- mapEdges = setExplicitEdges(stat.getFirst());
- processEdgesWithNext(stat.getFirst(), mapEdges, stat);
- break;
- case Statement.TYPE_IF:
- IfStatement ifstat = (IfStatement)stat;
- // head statement is a basic block
- if(ifstat.getIfstat() == null) { // empty if
- processEdgesWithNext(ifstat.getFirst(), mapEdges, null);
- } else {
- if(ifstat.getIfstat() != null) {
- mapEdges = setExplicitEdges(ifstat.getIfstat());
- processEdgesWithNext(ifstat.getIfstat(), mapEdges, null);
- }
-
- HashMap<Statement, List<StatEdge>> mapEdges1 = null;
- if(ifstat.getElsestat() != null) {
- mapEdges1 = setExplicitEdges(ifstat.getElsestat());
- processEdgesWithNext(ifstat.getElsestat(), mapEdges1, null);
- }
-
- // merge the maps
- if(mapEdges1 != null) {
- for(Entry<Statement, List<StatEdge>> entr : mapEdges1.entrySet()) {
- if(mapEdges.containsKey(entr.getKey())) {
- mapEdges.get(entr.getKey()).addAll(entr.getValue());
- } else {
- mapEdges.put(entr.getKey(), entr.getValue());
- }
- }
- }
- }
- break;
- case Statement.TYPE_ROOT:
- mapEdges = setExplicitEdges(stat.getFirst());
- processEdgesWithNext(stat.getFirst(), mapEdges, ((RootStatement)stat).getDummyExit());
- break;
- case Statement.TYPE_SEQUENCE:
- int index = 0;
- while(index < stat.getStats().size()-1) {
- Statement st = stat.getStats().get(index);
- processEdgesWithNext(st, setExplicitEdges(st), stat.getStats().get(index+1));
- index++;
- }
-
- Statement st = stat.getStats().get(index);
- mapEdges = setExplicitEdges(st);
- processEdgesWithNext(st, mapEdges, null);
- break;
- case Statement.TYPE_SWITCH:
- SwitchStatement swst = (SwitchStatement)stat;
-
- for(int i=0;i<swst.getCaseStatements().size()-1;i++) {
- Statement stt = swst.getCaseStatements().get(i);
- Statement stnext = swst.getCaseStatements().get(i+1);
-
- if(stnext.getExprents() != null && stnext.getExprents().isEmpty()) {
- stnext = stnext.getAllSuccessorEdges().get(0).getDestination();
- }
- processEdgesWithNext(stt, setExplicitEdges(stt), stnext);
- }
-
- int last = swst.getCaseStatements().size()-1;
- if(last >= 0) { // empty switch possible
- Statement stlast = swst.getCaseStatements().get(last);
- if(stlast.getExprents() != null && stlast.getExprents().isEmpty()) {
- StatEdge edge = stlast.getAllSuccessorEdges().get(0);
- mapEdges.put(edge.getDestination(), new ArrayList<StatEdge>(Arrays.asList(new StatEdge[] {edge})));
- } else {
- mapEdges = setExplicitEdges(stlast);
- processEdgesWithNext(stlast, mapEdges, null);
- }
- }
-
- break;
- case Statement.TYPE_SYNCRONIZED:
- SynchronizedStatement synstat = (SynchronizedStatement)stat;
-
- processEdgesWithNext(synstat.getFirst(), setExplicitEdges(stat.getFirst()), synstat.getBody()); // FIXME: basic block?
- mapEdges = setExplicitEdges(synstat.getBody());
- processEdgesWithNext(synstat.getBody(), mapEdges, null);
- }
-
-
- return mapEdges;
- }
-
- private static void processEdgesWithNext(Statement stat, HashMap<Statement, List<StatEdge>> mapEdges, Statement next) {
-
- StatEdge statedge = null;
-
- List<StatEdge> lstSuccs = stat.getAllSuccessorEdges();
- if(!lstSuccs.isEmpty()) {
- statedge = lstSuccs.get(0);
-
- if(statedge.getDestination() == next) {
- statedge.explicit = false;
- statedge = null;
- } else {
- next = statedge.getDestination();
- }
- }
-
- // no next for a do statement
- if(stat.type == Statement.TYPE_DO && ((DoStatement)stat).getLooptype() == DoStatement.LOOP_DO) {
- next = null;
- }
-
- if(next == null) {
- if(mapEdges.size() == 1) {
- List<StatEdge> lstEdges = mapEdges.values().iterator().next();
- if(lstEdges.size() > 1 && mapEdges.keySet().iterator().next().type != Statement.TYPE_DUMMYEXIT) {
- StatEdge edge_example = lstEdges.get(0);
-
- Statement closure = stat.getParent();
- if(!closure.containsStatementStrict(edge_example.closure)) {
- closure = edge_example.closure;
- }
-
- StatEdge newedge = new StatEdge(edge_example.getType(), stat, edge_example.getDestination(), closure);
- stat.addSuccessor(newedge);
-
- for(StatEdge edge : lstEdges) {
- edge.explicit = false;
- }
-
- mapEdges.put(newedge.getDestination(), new ArrayList<StatEdge>(Arrays.asList(new StatEdge[] {newedge})));
- }
- }
- } else {
-
- boolean implfound = false;
-
- for(Entry<Statement, List<StatEdge>> entr : mapEdges.entrySet()) {
- if(entr.getKey() == next) {
- for(StatEdge edge : entr.getValue()) {
- edge.explicit = false;
- }
- implfound = true;
- break;
- }
- }
-
- if(stat.getAllSuccessorEdges().isEmpty() && !implfound) {
- List<StatEdge> lstEdges = null;
- for(Entry<Statement, List<StatEdge>> entr : mapEdges.entrySet()) {
- if(entr.getKey().type != Statement.TYPE_DUMMYEXIT &&
- (lstEdges == null || entr.getValue().size() > lstEdges.size())) {
- lstEdges = entr.getValue();
- }
- }
-
- if(lstEdges != null && lstEdges.size() > 1) {
- StatEdge edge_example = lstEdges.get(0);
-
- Statement closure = stat.getParent();
- if(!closure.containsStatementStrict(edge_example.closure)) {
- closure = edge_example.closure;
- }
-
- StatEdge newedge = new StatEdge(edge_example.getType(), stat, edge_example.getDestination(), closure);
- stat.addSuccessor(newedge);
-
- for(StatEdge edge : lstEdges) {
- edge.explicit = false;
- }
- }
- }
-
- mapEdges.clear();
- }
-
- if(statedge != null) {
- mapEdges.put(statedge.getDestination(), new ArrayList<StatEdge>(Arrays.asList(new StatEdge[] {statedge})));
- }
-
- }
-
- private static void hideDefaultSwitchEdges(Statement stat) {
-
- if(stat.type == Statement.TYPE_SWITCH) {
- SwitchStatement swst = (SwitchStatement)stat;
-
- int last = swst.getCaseStatements().size()-1;
- if(last >= 0) { // empty switch possible
- Statement stlast = swst.getCaseStatements().get(last);
-
- if(stlast.getExprents() != null && stlast.getExprents().isEmpty()) {
- if(!stlast.getAllSuccessorEdges().get(0).explicit) {
- List<StatEdge> lstEdges = swst.getCaseEdges().get(last);
- lstEdges.remove(swst.getDefault_edge());
-
- if(lstEdges.isEmpty()) {
- swst.getCaseStatements().remove(last);
- swst.getCaseEdges().remove(last);
- }
- }
- }
- }
- }
-
- for(Statement st : stat.getStats()) {
- hideDefaultSwitchEdges(st);
- }
-
- }
-
- private static HashSet<Statement>[] processStatementLabel(Statement stat) {
-
- HashSet<Statement> setBreak = new HashSet<Statement>();
- HashSet<Statement> setContinue = new HashSet<Statement>();
-
- if(stat.getExprents() == null) {
- for(Statement st: stat.getStats()) {
- HashSet<Statement>[] arr = processStatementLabel(st);
-
- setBreak.addAll(arr[0]);
- setContinue.addAll(arr[1]);
- }
-
- boolean shieldtype = (stat.type == Statement.TYPE_DO || stat.type == Statement.TYPE_SWITCH);
-
- for(StatEdge edge: stat.getLabelEdges()) {
- if(edge.explicit) {
- if(shieldtype && ((edge.getType() == StatEdge.TYPE_BREAK && setBreak.contains(edge.getSource())) ||
- (edge.getType() == StatEdge.TYPE_CONTINUE && setContinue.contains(edge.getSource())))) {
- edge.labeled = false;
- }
- }
- }
-
- switch(stat.type) {
- case Statement.TYPE_DO:
- setContinue.clear();
- case Statement.TYPE_SWITCH:
- setBreak.clear();
- }
- }
-
- setBreak.add(stat);
- setContinue.add(stat);
-
- return new HashSet[] {setBreak, setContinue};
- }
-
- public static void replaceContinueWithBreak(Statement stat) {
-
- if(stat.type == Statement.TYPE_DO) {
-
- List<StatEdge> lst = stat.getPredecessorEdges(StatEdge.TYPE_CONTINUE);
-
- for(StatEdge edge : lst) {
-
- if(edge.explicit) {
- Statement minclosure = getMinContinueClosure(edge);
-
- if(minclosure != edge.closure &&
- !InlineSingleBlockHelper.isBreakEdgeLabeled(edge.getSource(), minclosure)) {
- edge.getSource().changeEdgeType(Statement.DIRECTION_FORWARD, edge, StatEdge.TYPE_BREAK);
- edge.labeled = false;
- minclosure.addLabeledEdge(edge);
- }
- }
- }
- }
-
- for(Statement st : stat.getStats()) {
- replaceContinueWithBreak(st);
- }
-
- }
-
- private static Statement getMinContinueClosure(StatEdge edge) {
-
- Statement closure = edge.closure;
- for(;;) {
-
- boolean found = false;
-
- for(Statement st : closure.getStats()) {
- if(st.containsStatementStrict(edge.getSource())) {
- if(MergeHelper.isDirectPath(st, edge.getDestination())) {
- closure = st;
- found = true;
- break;
- }
- }
- }
-
- if(!found) {
- break;
- }
- }
-
- return closure;
- }
-
+
+ public static void cleanUpEdges(RootStatement root) {
+
+ resetAllEdges(root);
+
+ removeNonImmediateEdges(root);
+
+ liftClosures(root);
+
+ lowContinueLabels(root, new HashSet<StatEdge>());
+
+ lowClosures(root);
+ }
+
+ public static void identifyLabels(RootStatement root) {
+
+ setExplicitEdges(root);
+
+ hideDefaultSwitchEdges(root);
+
+ processStatementLabel(root);
+
+ setRetEdgesUnlabeled(root);
+ }
+
+ private static void liftClosures(Statement stat) {
+
+ for (StatEdge edge : stat.getAllSuccessorEdges()) {
+ switch (edge.getType()) {
+ case StatEdge.TYPE_CONTINUE:
+ if (edge.getDestination() != edge.closure) {
+ edge.getDestination().addLabeledEdge(edge);
+ }
+ break;
+ case StatEdge.TYPE_BREAK:
+ Statement dest = edge.getDestination();
+ if (dest.type != Statement.TYPE_DUMMYEXIT) {
+ Statement parent = dest.getParent();
+
+ List<Statement> lst = new ArrayList<Statement>();
+ if (parent.type == Statement.TYPE_SEQUENCE) {
+ lst.addAll(((SequenceStatement)parent).getStats());
+ }
+ else if (parent.type == Statement.TYPE_SWITCH) {
+ lst.addAll(((SwitchStatement)parent).getCaseStatements());
+ }
+
+ for (int i = 0; i < lst.size(); i++) {
+ if (lst.get(i) == dest) {
+ lst.get(i - 1).addLabeledEdge(edge);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ for (Statement st : stat.getStats()) {
+ liftClosures(st);
+ }
+ }
+
+ private static void removeNonImmediateEdges(Statement stat) {
+
+ for (Statement st : stat.getStats()) {
+ removeNonImmediateEdges(st);
+ }
+
+ if (!stat.hasBasicSuccEdge()) {
+ for (StatEdge edge : stat.getSuccessorEdges(StatEdge.TYPE_CONTINUE | StatEdge.TYPE_BREAK)) {
+ stat.removeSuccessor(edge);
+ }
+ }
+ }
+
+ public static void lowContinueLabels(Statement stat, HashSet<StatEdge> edges) {
+
+ boolean ok = (stat.type != Statement.TYPE_DO);
+ if (!ok) {
+ DoStatement dostat = (DoStatement)stat;
+ ok = dostat.getLooptype() == DoStatement.LOOP_DO ||
+ dostat.getLooptype() == DoStatement.LOOP_WHILE ||
+ (dostat.getLooptype() == DoStatement.LOOP_FOR && dostat.getIncExprent() == null);
+ }
+
+ if (ok) {
+ edges.addAll(stat.getPredecessorEdges(StatEdge.TYPE_CONTINUE));
+ }
+
+ if (ok && stat.type == Statement.TYPE_DO) {
+ for (StatEdge edge : edges) {
+ if (stat.containsStatementStrict(edge.getSource())) {
+
+ edge.getDestination().removePredecessor(edge);
+ edge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, edge, stat);
+ stat.addPredecessor(edge);
+
+ stat.addLabeledEdge(edge);
+ }
+ }
+ }
+
+ for (Statement st : stat.getStats()) {
+ if (st == stat.getFirst()) {
+ lowContinueLabels(st, edges);
+ }
+ else {
+ lowContinueLabels(st, new HashSet<StatEdge>());
+ }
+ }
+ }
+
+ public static void lowClosures(Statement stat) {
+
+ for (StatEdge edge : new ArrayList<StatEdge>(stat.getLabelEdges())) {
+
+ if (edge.getType() == StatEdge.TYPE_BREAK) { // FIXME: ?
+ for (Statement st : stat.getStats()) {
+ if (st.containsStatementStrict(edge.getSource())) {
+ if (MergeHelper.isDirectPath(st, edge.getDestination())) {
+ st.addLabeledEdge(edge);
+ }
+ }
+ }
+ }
+ }
+
+ for (Statement st : stat.getStats()) {
+ lowClosures(st);
+ }
+ }
+
+ private static void resetAllEdges(Statement stat) {
+
+ for (Statement st : stat.getStats()) {
+ resetAllEdges(st);
+ }
+
+ for (StatEdge edge : stat.getAllSuccessorEdges()) {
+ edge.explicit = true;
+ edge.labeled = true;
+ }
+ }
+
+ private static void setRetEdgesUnlabeled(RootStatement root) {
+ Statement exit = root.getDummyExit();
+ for (StatEdge edge : exit.getAllPredecessorEdges()) {
+ List<Exprent> lst = edge.getSource().getExprents();
+ if (edge.getType() == StatEdge.TYPE_FINALLYEXIT || (lst != null && !lst.isEmpty() &&
+ lst.get(lst.size() - 1).type == Exprent.EXPRENT_EXIT)) {
+ edge.labeled = false;
+ }
+ }
+ }
+
+ private static HashMap<Statement, List<StatEdge>> setExplicitEdges(Statement stat) {
+
+ HashMap<Statement, List<StatEdge>> mapEdges = new HashMap<Statement, List<StatEdge>>();
+
+ if (stat.getExprents() != null) {
+ return mapEdges;
+ }
+
+
+ switch (stat.type) {
+ case Statement.TYPE_TRYCATCH:
+ case Statement.TYPE_CATCHALL:
+
+ for (Statement st : stat.getStats()) {
+ HashMap<Statement, List<StatEdge>> mapEdges1 = setExplicitEdges(st);
+ processEdgesWithNext(st, mapEdges1, null);
+
+ if (stat.type == Statement.TYPE_TRYCATCH || st == stat.getFirst()) { // edges leaving a finally catch block are always explicit
+ // merge the maps
+ if (mapEdges1 != null) {
+ for (Entry<Statement, List<StatEdge>> entr : mapEdges1.entrySet()) {
+ if (mapEdges.containsKey(entr.getKey())) {
+ mapEdges.get(entr.getKey()).addAll(entr.getValue());
+ }
+ else {
+ mapEdges.put(entr.getKey(), entr.getValue());
+ }
+ }
+ }
+ }
+ }
+
+ break;
+ case Statement.TYPE_DO:
+ mapEdges = setExplicitEdges(stat.getFirst());
+ processEdgesWithNext(stat.getFirst(), mapEdges, stat);
+ break;
+ case Statement.TYPE_IF:
+ IfStatement ifstat = (IfStatement)stat;
+ // head statement is a basic block
+ if (ifstat.getIfstat() == null) { // empty if
+ processEdgesWithNext(ifstat.getFirst(), mapEdges, null);
+ }
+ else {
+ if (ifstat.getIfstat() != null) {
+ mapEdges = setExplicitEdges(ifstat.getIfstat());
+ processEdgesWithNext(ifstat.getIfstat(), mapEdges, null);
+ }
+
+ HashMap<Statement, List<StatEdge>> mapEdges1 = null;
+ if (ifstat.getElsestat() != null) {
+ mapEdges1 = setExplicitEdges(ifstat.getElsestat());
+ processEdgesWithNext(ifstat.getElsestat(), mapEdges1, null);
+ }
+
+ // merge the maps
+ if (mapEdges1 != null) {
+ for (Entry<Statement, List<StatEdge>> entr : mapEdges1.entrySet()) {
+ if (mapEdges.containsKey(entr.getKey())) {
+ mapEdges.get(entr.getKey()).addAll(entr.getValue());
+ }
+ else {
+ mapEdges.put(entr.getKey(), entr.getValue());
+ }
+ }
+ }
+ }
+ break;
+ case Statement.TYPE_ROOT:
+ mapEdges = setExplicitEdges(stat.getFirst());
+ processEdgesWithNext(stat.getFirst(), mapEdges, ((RootStatement)stat).getDummyExit());
+ break;
+ case Statement.TYPE_SEQUENCE:
+ int index = 0;
+ while (index < stat.getStats().size() - 1) {
+ Statement st = stat.getStats().get(index);
+ processEdgesWithNext(st, setExplicitEdges(st), stat.getStats().get(index + 1));
+ index++;
+ }
+
+ Statement st = stat.getStats().get(index);
+ mapEdges = setExplicitEdges(st);
+ processEdgesWithNext(st, mapEdges, null);
+ break;
+ case Statement.TYPE_SWITCH:
+ SwitchStatement swst = (SwitchStatement)stat;
+
+ for (int i = 0; i < swst.getCaseStatements().size() - 1; i++) {
+ Statement stt = swst.getCaseStatements().get(i);
+ Statement stnext = swst.getCaseStatements().get(i + 1);
+
+ if (stnext.getExprents() != null && stnext.getExprents().isEmpty()) {
+ stnext = stnext.getAllSuccessorEdges().get(0).getDestination();
+ }
+ processEdgesWithNext(stt, setExplicitEdges(stt), stnext);
+ }
+
+ int last = swst.getCaseStatements().size() - 1;
+ if (last >= 0) { // empty switch possible
+ Statement stlast = swst.getCaseStatements().get(last);
+ if (stlast.getExprents() != null && stlast.getExprents().isEmpty()) {
+ StatEdge edge = stlast.getAllSuccessorEdges().get(0);
+ mapEdges.put(edge.getDestination(), new ArrayList<StatEdge>(Arrays.asList(new StatEdge[]{edge})));
+ }
+ else {
+ mapEdges = setExplicitEdges(stlast);
+ processEdgesWithNext(stlast, mapEdges, null);
+ }
+ }
+
+ break;
+ case Statement.TYPE_SYNCRONIZED:
+ SynchronizedStatement synstat = (SynchronizedStatement)stat;
+
+ processEdgesWithNext(synstat.getFirst(), setExplicitEdges(stat.getFirst()), synstat.getBody()); // FIXME: basic block?
+ mapEdges = setExplicitEdges(synstat.getBody());
+ processEdgesWithNext(synstat.getBody(), mapEdges, null);
+ }
+
+
+ return mapEdges;
+ }
+
+ private static void processEdgesWithNext(Statement stat, HashMap<Statement, List<StatEdge>> mapEdges, Statement next) {
+
+ StatEdge statedge = null;
+
+ List<StatEdge> lstSuccs = stat.getAllSuccessorEdges();
+ if (!lstSuccs.isEmpty()) {
+ statedge = lstSuccs.get(0);
+
+ if (statedge.getDestination() == next) {
+ statedge.explicit = false;
+ statedge = null;
+ }
+ else {
+ next = statedge.getDestination();
+ }
+ }
+
+ // no next for a do statement
+ if (stat.type == Statement.TYPE_DO && ((DoStatement)stat).getLooptype() == DoStatement.LOOP_DO) {
+ next = null;
+ }
+
+ if (next == null) {
+ if (mapEdges.size() == 1) {
+ List<StatEdge> lstEdges = mapEdges.values().iterator().next();
+ if (lstEdges.size() > 1 && mapEdges.keySet().iterator().next().type != Statement.TYPE_DUMMYEXIT) {
+ StatEdge edge_example = lstEdges.get(0);
+
+ Statement closure = stat.getParent();
+ if (!closure.containsStatementStrict(edge_example.closure)) {
+ closure = edge_example.closure;
+ }
+
+ StatEdge newedge = new StatEdge(edge_example.getType(), stat, edge_example.getDestination(), closure);
+ stat.addSuccessor(newedge);
+
+ for (StatEdge edge : lstEdges) {
+ edge.explicit = false;
+ }
+
+ mapEdges.put(newedge.getDestination(), new ArrayList<StatEdge>(Arrays.asList(new StatEdge[]{newedge})));
+ }
+ }
+ }
+ else {
+
+ boolean implfound = false;
+
+ for (Entry<Statement, List<StatEdge>> entr : mapEdges.entrySet()) {
+ if (entr.getKey() == next) {
+ for (StatEdge edge : entr.getValue()) {
+ edge.explicit = false;
+ }
+ implfound = true;
+ break;
+ }
+ }
+
+ if (stat.getAllSuccessorEdges().isEmpty() && !implfound) {
+ List<StatEdge> lstEdges = null;
+ for (Entry<Statement, List<StatEdge>> entr : mapEdges.entrySet()) {
+ if (entr.getKey().type != Statement.TYPE_DUMMYEXIT &&
+ (lstEdges == null || entr.getValue().size() > lstEdges.size())) {
+ lstEdges = entr.getValue();
+ }
+ }
+
+ if (lstEdges != null && lstEdges.size() > 1) {
+ StatEdge edge_example = lstEdges.get(0);
+
+ Statement closure = stat.getParent();
+ if (!closure.containsStatementStrict(edge_example.closure)) {
+ closure = edge_example.closure;
+ }
+
+ StatEdge newedge = new StatEdge(edge_example.getType(), stat, edge_example.getDestination(), closure);
+ stat.addSuccessor(newedge);
+
+ for (StatEdge edge : lstEdges) {
+ edge.explicit = false;
+ }
+ }
+ }
+
+ mapEdges.clear();
+ }
+
+ if (statedge != null) {
+ mapEdges.put(statedge.getDestination(), new ArrayList<StatEdge>(Arrays.asList(new StatEdge[]{statedge})));
+ }
+ }
+
+ private static void hideDefaultSwitchEdges(Statement stat) {
+
+ if (stat.type == Statement.TYPE_SWITCH) {
+ SwitchStatement swst = (SwitchStatement)stat;
+
+ int last = swst.getCaseStatements().size() - 1;
+ if (last >= 0) { // empty switch possible
+ Statement stlast = swst.getCaseStatements().get(last);
+
+ if (stlast.getExprents() != null && stlast.getExprents().isEmpty()) {
+ if (!stlast.getAllSuccessorEdges().get(0).explicit) {
+ List<StatEdge> lstEdges = swst.getCaseEdges().get(last);
+ lstEdges.remove(swst.getDefault_edge());
+
+ if (lstEdges.isEmpty()) {
+ swst.getCaseStatements().remove(last);
+ swst.getCaseEdges().remove(last);
+ }
+ }
+ }
+ }
+ }
+
+ for (Statement st : stat.getStats()) {
+ hideDefaultSwitchEdges(st);
+ }
+ }
+
+ private static HashSet<Statement>[] processStatementLabel(Statement stat) {
+
+ HashSet<Statement> setBreak = new HashSet<Statement>();
+ HashSet<Statement> setContinue = new HashSet<Statement>();
+
+ if (stat.getExprents() == null) {
+ for (Statement st : stat.getStats()) {
+ HashSet<Statement>[] arr = processStatementLabel(st);
+
+ setBreak.addAll(arr[0]);
+ setContinue.addAll(arr[1]);
+ }
+
+ boolean shieldtype = (stat.type == Statement.TYPE_DO || stat.type == Statement.TYPE_SWITCH);
+
+ for (StatEdge edge : stat.getLabelEdges()) {
+ if (edge.explicit) {
+ if (shieldtype && ((edge.getType() == StatEdge.TYPE_BREAK && setBreak.contains(edge.getSource())) ||
+ (edge.getType() == StatEdge.TYPE_CONTINUE && setContinue.contains(edge.getSource())))) {
+ edge.labeled = false;
+ }
+ }
+ }
+
+ switch (stat.type) {
+ case Statement.TYPE_DO:
+ setContinue.clear();
+ case Statement.TYPE_SWITCH:
+ setBreak.clear();
+ }
+ }
+
+ setBreak.add(stat);
+ setContinue.add(stat);
+
+ return new HashSet[]{setBreak, setContinue};
+ }
+
+ public static void replaceContinueWithBreak(Statement stat) {
+
+ if (stat.type == Statement.TYPE_DO) {
+
+ List<StatEdge> lst = stat.getPredecessorEdges(StatEdge.TYPE_CONTINUE);
+
+ for (StatEdge edge : lst) {
+
+ if (edge.explicit) {
+ Statement minclosure = getMinContinueClosure(edge);
+
+ if (minclosure != edge.closure &&
+ !InlineSingleBlockHelper.isBreakEdgeLabeled(edge.getSource(), minclosure)) {
+ edge.getSource().changeEdgeType(Statement.DIRECTION_FORWARD, edge, StatEdge.TYPE_BREAK);
+ edge.labeled = false;
+ minclosure.addLabeledEdge(edge);
+ }
+ }
+ }
+ }
+
+ for (Statement st : stat.getStats()) {
+ replaceContinueWithBreak(st);
+ }
+ }
+
+ private static Statement getMinContinueClosure(StatEdge edge) {
+
+ Statement closure = edge.closure;
+ for (; ; ) {
+
+ boolean found = false;
+
+ for (Statement st : closure.getStats()) {
+ if (st.containsStatementStrict(edge.getSource())) {
+ if (MergeHelper.isDirectPath(st, edge.getDestination())) {
+ closure = st;
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (!found) {
+ break;
+ }
+ }
+
+ return closure;
+ }
}