diff options
Diffstat (limited to 'src/org/jetbrains/java/decompiler/modules/decompiler/LabelHelper.java')
-rw-r--r-- | src/org/jetbrains/java/decompiler/modules/decompiler/LabelHelper.java | 1008 |
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; + } } |