| /* |
| * 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.stats; |
| |
| import org.jetbrains.java.decompiler.code.CodeConstants; |
| import org.jetbrains.java.decompiler.code.InstructionSequence; |
| import org.jetbrains.java.decompiler.main.DecompilerContext; |
| import org.jetbrains.java.decompiler.main.collectors.CounterContainer; |
| import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger; |
| import org.jetbrains.java.decompiler.modules.decompiler.StatEdge; |
| import org.jetbrains.java.decompiler.modules.decompiler.StrongConnectivityHelper; |
| import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent; |
| import org.jetbrains.java.decompiler.util.VBStyleCollection; |
| |
| import java.util.*; |
| |
| public class Statement { |
| |
| public static final int STATEDGE_ALL = 1 << 31; |
| public static final int STATEDGE_DIRECT_ALL = 1 << 30; |
| |
| public static final int DIRECTION_BACKWARD = 0; |
| public static final int DIRECTION_FORWARD = 1; |
| |
| public static final int TYPE_GENERAL = 0; |
| public static final int TYPE_IF = 2; |
| public static final int TYPE_DO = 5; |
| public static final int TYPE_SWITCH = 6; |
| public static final int TYPE_TRYCATCH = 7; |
| public static final int TYPE_BASICBLOCK = 8; |
| public static final int TYPE_FINALLY = 9; |
| public static final int TYPE_SYNCRONIZED = 10; |
| public static final int TYPE_PLACEHOLDER = 11; |
| public static final int TYPE_CATCHALL = 12; |
| public static final int TYPE_ROOT = 13; |
| public static final int TYPE_DUMMYEXIT = 14; |
| public static final int TYPE_SEQUENCE = 15; |
| |
| |
| public static final int LASTBASICTYPE_IF = 0; |
| public static final int LASTBASICTYPE_SWITCH = 1; |
| public static final int LASTBASICTYPE_GENERAL = 2; |
| |
| |
| // ***************************************************************************** |
| // public fields |
| // ***************************************************************************** |
| |
| public int type; |
| |
| public Integer id; |
| |
| // ***************************************************************************** |
| // private fields |
| // ***************************************************************************** |
| |
| private Map<Integer, List<StatEdge>> mapSuccEdges = new HashMap<Integer, List<StatEdge>>(); |
| private Map<Integer, List<StatEdge>> mapPredEdges = new HashMap<Integer, List<StatEdge>>(); |
| |
| private Map<Integer, List<Statement>> mapSuccStates = new HashMap<Integer, List<Statement>>(); |
| private Map<Integer, List<Statement>> mapPredStates = new HashMap<Integer, List<Statement>>(); |
| |
| // statement as graph |
| protected VBStyleCollection<Statement, Integer> stats = new VBStyleCollection<Statement, Integer>(); |
| |
| protected Statement parent; |
| |
| protected Statement first; |
| |
| protected List<Exprent> exprents; |
| |
| protected HashSet<StatEdge> labelEdges = new HashSet<StatEdge>(); |
| |
| protected List<Exprent> varDefinitions = new ArrayList<Exprent>(); |
| |
| // copied statement, s. deobfuscating of irreducible CFGs |
| private boolean copied = false; |
| |
| // relevant for the first stage of processing only |
| // set to null after initializing of the statement structure |
| |
| protected Statement post; |
| |
| protected int lastBasicType = LASTBASICTYPE_GENERAL; |
| |
| protected boolean isMonitorEnter; |
| |
| protected boolean containsMonitorExit; |
| |
| protected HashSet<Statement> continueSet = new HashSet<Statement>(); |
| |
| // ***************************************************************************** |
| // initializers |
| // ***************************************************************************** |
| |
| { |
| // set statement id |
| id = DecompilerContext.getCounterContainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER); |
| } |
| |
| // ***************************************************************************** |
| // public methods |
| // ***************************************************************************** |
| |
| public void clearTempInformation() { |
| |
| post = null; |
| continueSet = null; |
| |
| copied = false; |
| // FIXME: used in FlattenStatementsHelper.flattenStatement()! check and remove |
| //lastBasicType = LASTBASICTYPE_GENERAL; |
| isMonitorEnter = false; |
| containsMonitorExit = false; |
| |
| processMap(mapSuccEdges); |
| processMap(mapPredEdges); |
| processMap(mapSuccStates); |
| processMap(mapPredStates); |
| } |
| |
| private static <T> void processMap(Map<Integer, List<T>> map) { |
| map.remove(StatEdge.TYPE_EXCEPTION); |
| |
| List<T> lst = map.get(STATEDGE_DIRECT_ALL); |
| if (lst != null) { |
| map.put(STATEDGE_ALL, new ArrayList<T>(lst)); |
| } |
| else { |
| map.remove(STATEDGE_ALL); |
| } |
| } |
| |
| public void collapseNodesToStatement(Statement stat) { |
| |
| Statement head = stat.getFirst(); |
| Statement post = stat.getPost(); |
| |
| VBStyleCollection<Statement, Integer> setNodes = stat.getStats(); |
| |
| // post edges |
| if (post != null) { |
| for (StatEdge edge : post.getEdges(STATEDGE_DIRECT_ALL, DIRECTION_BACKWARD)) { |
| if (stat.containsStatementStrict(edge.getSource())) { |
| edge.getSource().changeEdgeType(DIRECTION_FORWARD, edge, StatEdge.TYPE_BREAK); |
| stat.addLabeledEdge(edge); |
| } |
| } |
| } |
| |
| // regular head edges |
| for (StatEdge prededge : head.getAllPredecessorEdges()) { |
| |
| if (prededge.getType() != StatEdge.TYPE_EXCEPTION && |
| stat.containsStatementStrict(prededge.getSource())) { |
| prededge.getSource().changeEdgeType(DIRECTION_FORWARD, prededge, StatEdge.TYPE_CONTINUE); |
| stat.addLabeledEdge(prededge); |
| } |
| |
| head.removePredecessor(prededge); |
| prededge.getSource().changeEdgeNode(DIRECTION_FORWARD, prededge, stat); |
| stat.addPredecessor(prededge); |
| } |
| |
| if (setNodes.containsKey(first.id)) { |
| first = stat; |
| } |
| |
| // exception edges |
| Set<Statement> setHandlers = new HashSet<Statement>(head.getNeighbours(StatEdge.TYPE_EXCEPTION, DIRECTION_FORWARD)); |
| for (Statement node : setNodes) { |
| setHandlers.retainAll(node.getNeighbours(StatEdge.TYPE_EXCEPTION, DIRECTION_FORWARD)); |
| } |
| |
| if (!setHandlers.isEmpty()) { |
| |
| for (StatEdge edge : head.getEdges(StatEdge.TYPE_EXCEPTION, DIRECTION_FORWARD)) { |
| Statement handler = edge.getDestination(); |
| |
| if (setHandlers.contains(handler)) { |
| if (!setNodes.containsKey(handler.id)) { |
| stat.addSuccessor(new StatEdge(stat, handler, edge.getExceptions())); |
| } |
| } |
| } |
| |
| for (Statement node : setNodes) { |
| for (StatEdge edge : node.getEdges(StatEdge.TYPE_EXCEPTION, DIRECTION_FORWARD)) { |
| if (setHandlers.contains(edge.getDestination())) { |
| node.removeSuccessor(edge); |
| } |
| } |
| } |
| } |
| |
| if (post != null && |
| !stat.getNeighbours(StatEdge.TYPE_EXCEPTION, DIRECTION_FORWARD).contains(post)) { // TODO: second condition redundant? |
| stat.addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR, stat, post)); |
| } |
| |
| |
| // adjust statement collection |
| for (Statement st : setNodes) { |
| stats.removeWithKey(st.id); |
| } |
| |
| stats.addWithKey(stat, stat.id); |
| |
| stat.setAllParent(); |
| stat.setParent(this); |
| |
| stat.buildContinueSet(); |
| // monitorenter and monitorexit |
| stat.buildMonitorFlags(); |
| |
| if (stat.type == TYPE_SWITCH) { |
| // special case switch, sorting leaf nodes |
| ((SwitchStatement)stat).sortEdgesAndNodes(); |
| } |
| } |
| |
| public void setAllParent() { |
| for (Statement st : stats) { |
| st.setParent(this); |
| } |
| } |
| |
| public void addLabeledEdge(StatEdge edge) { |
| |
| if (edge.closure != null) { |
| edge.closure.getLabelEdges().remove(edge); |
| } |
| edge.closure = this; |
| this.getLabelEdges().add(edge); |
| } |
| |
| private void addEdgeDirectInternal(int direction, StatEdge edge, int edgetype) { |
| |
| Map<Integer, List<StatEdge>> mapEdges = direction == DIRECTION_BACKWARD ? mapPredEdges : mapSuccEdges; |
| Map<Integer, List<Statement>> mapStates = direction == DIRECTION_BACKWARD ? mapPredStates : mapSuccStates; |
| |
| List<StatEdge> lst = mapEdges.get(edgetype); |
| if (lst == null) { |
| mapEdges.put(edgetype, lst = new ArrayList<StatEdge>()); |
| } |
| lst.add(edge); |
| |
| List<Statement> lstStates = mapStates.get(edgetype); |
| if (lstStates == null) { |
| mapStates.put(edgetype, lstStates = new ArrayList<Statement>()); |
| } |
| lstStates.add(direction == DIRECTION_BACKWARD ? edge.getSource() : edge.getDestination()); |
| } |
| |
| private void addEdgeInternal(int direction, StatEdge edge) { |
| |
| int type = edge.getType(); |
| |
| int[] arrtypes; |
| if (type == StatEdge.TYPE_EXCEPTION) { |
| arrtypes = new int[]{STATEDGE_ALL, StatEdge.TYPE_EXCEPTION}; |
| } |
| else { |
| arrtypes = new int[]{STATEDGE_ALL, STATEDGE_DIRECT_ALL, type}; |
| } |
| |
| for (int edgetype : arrtypes) { |
| addEdgeDirectInternal(direction, edge, edgetype); |
| } |
| } |
| |
| private void removeEdgeDirectInternal(int direction, StatEdge edge, int edgetype) { |
| |
| Map<Integer, List<StatEdge>> mapEdges = direction == DIRECTION_BACKWARD ? mapPredEdges : mapSuccEdges; |
| Map<Integer, List<Statement>> mapStates = direction == DIRECTION_BACKWARD ? mapPredStates : mapSuccStates; |
| |
| List<StatEdge> lst = mapEdges.get(edgetype); |
| if (lst != null) { |
| int index = lst.indexOf(edge); |
| if (index >= 0) { |
| lst.remove(index); |
| mapStates.get(edgetype).remove(index); |
| } |
| } |
| } |
| |
| private void removeEdgeInternal(int direction, StatEdge edge) { |
| |
| int type = edge.getType(); |
| |
| int[] arrtypes; |
| if (type == StatEdge.TYPE_EXCEPTION) { |
| arrtypes = new int[]{STATEDGE_ALL, StatEdge.TYPE_EXCEPTION}; |
| } |
| else { |
| arrtypes = new int[]{STATEDGE_ALL, STATEDGE_DIRECT_ALL, type}; |
| } |
| |
| for (int edgetype : arrtypes) { |
| removeEdgeDirectInternal(direction, edge, edgetype); |
| } |
| } |
| |
| public void addPredecessor(StatEdge edge) { |
| addEdgeInternal(DIRECTION_BACKWARD, edge); |
| } |
| |
| public void removePredecessor(StatEdge edge) { |
| |
| if (edge == null) { // FIXME: redundant? |
| return; |
| } |
| |
| removeEdgeInternal(DIRECTION_BACKWARD, edge); |
| } |
| |
| public void addSuccessor(StatEdge edge) { |
| addEdgeInternal(DIRECTION_FORWARD, edge); |
| |
| if (edge.closure != null) { |
| edge.closure.getLabelEdges().add(edge); |
| } |
| |
| edge.getDestination().addPredecessor(edge); |
| } |
| |
| public void removeSuccessor(StatEdge edge) { |
| |
| if (edge == null) { |
| return; |
| } |
| |
| removeEdgeInternal(DIRECTION_FORWARD, edge); |
| |
| if (edge.closure != null) { |
| edge.closure.getLabelEdges().remove(edge); |
| } |
| |
| if (edge.getDestination() != null) { // TODO: redundant? |
| edge.getDestination().removePredecessor(edge); |
| } |
| } |
| |
| // TODO: make obsolete and remove |
| public void removeAllSuccessors(Statement stat) { |
| |
| if (stat == null) { |
| return; |
| } |
| |
| for (StatEdge edge : getAllSuccessorEdges()) { |
| if (edge.getDestination() == stat) { |
| removeSuccessor(edge); |
| } |
| } |
| } |
| |
| public HashSet<Statement> buildContinueSet() { |
| continueSet.clear(); |
| |
| for (Statement st : stats) { |
| continueSet.addAll(st.buildContinueSet()); |
| if (st != first) { |
| continueSet.remove(st.getBasichead()); |
| } |
| } |
| |
| for (StatEdge edge : getEdges(StatEdge.TYPE_CONTINUE, DIRECTION_FORWARD)) { |
| continueSet.add(edge.getDestination().getBasichead()); |
| } |
| |
| if (type == TYPE_DO) { |
| continueSet.remove(first.getBasichead()); |
| } |
| |
| return continueSet; |
| } |
| |
| public void buildMonitorFlags() { |
| |
| for (Statement st : stats) { |
| st.buildMonitorFlags(); |
| } |
| |
| switch (type) { |
| case TYPE_BASICBLOCK: |
| BasicBlockStatement bblock = (BasicBlockStatement)this; |
| InstructionSequence seq = bblock.getBlock().getSeq(); |
| |
| if (seq != null && seq.length() > 0) { |
| for (int i = 0; i < seq.length(); i++) { |
| if (seq.getInstr(i).opcode == CodeConstants.opc_monitorexit) { |
| containsMonitorExit = true; |
| break; |
| } |
| } |
| isMonitorEnter = (seq.getLastInstr().opcode == CodeConstants.opc_monitorenter); |
| } |
| break; |
| case TYPE_SEQUENCE: |
| case TYPE_IF: |
| containsMonitorExit = false; |
| for (Statement st : stats) { |
| containsMonitorExit |= st.isContainsMonitorExit(); |
| } |
| |
| break; |
| case TYPE_SYNCRONIZED: |
| case TYPE_ROOT: |
| case TYPE_GENERAL: |
| break; |
| default: |
| containsMonitorExit = false; |
| for (Statement st : stats) { |
| containsMonitorExit |= st.isContainsMonitorExit(); |
| } |
| } |
| } |
| |
| |
| public List<Statement> getReversePostOrderList() { |
| return getReversePostOrderList(first); |
| } |
| |
| public List<Statement> getReversePostOrderList(Statement stat) { |
| List<Statement> res = new ArrayList<Statement>(); |
| |
| addToReversePostOrderListIterative(stat, res); |
| |
| return res; |
| } |
| |
| public List<Statement> getPostReversePostOrderList() { |
| return getPostReversePostOrderList(null); |
| } |
| |
| public List<Statement> getPostReversePostOrderList(List<Statement> lstexits) { |
| |
| List<Statement> res = new ArrayList<Statement>(); |
| |
| if (lstexits == null) { |
| StrongConnectivityHelper schelper = new StrongConnectivityHelper(this); |
| lstexits = StrongConnectivityHelper.getExitReps(schelper.getComponents()); |
| } |
| |
| HashSet<Statement> setVisited = new HashSet<Statement>(); |
| |
| for (Statement exit : lstexits) { |
| addToPostReversePostOrderList(exit, res, setVisited); |
| } |
| |
| if (res.size() != stats.size()) { |
| DecompilerContext.getLogger().writeMessage("computing post reverse post order failed!", IFernflowerLogger.Severity.ERROR); |
| |
| throw new RuntimeException("parsing failure!"); |
| } |
| |
| return res; |
| } |
| |
| public boolean containsStatement(Statement stat) { |
| return this == stat || containsStatementStrict(stat); |
| } |
| |
| public boolean containsStatementStrict(Statement stat) { |
| |
| if (stats.contains(stat)) { |
| return true; |
| } |
| |
| for (int i = 0; i < stats.size(); i++) { |
| if (stats.get(i).containsStatementStrict(stat)) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| // to be overwritten |
| public String toJava() { |
| return toJava(0); |
| } |
| |
| public String toJava(int indent) { |
| throw new RuntimeException("not implemented"); |
| } |
| |
| // TODO: make obsolete and remove |
| public List<Object> getSequentialObjects() { |
| return new ArrayList<Object>(stats); |
| } |
| |
| public void initExprents() { |
| // do nothing |
| } |
| |
| public void replaceExprent(Exprent oldexpr, Exprent newexpr) { |
| // do nothing |
| } |
| |
| public Statement getSimpleCopy() { |
| throw new RuntimeException("not implemented"); |
| } |
| |
| public void initSimpleCopy() { |
| if (!stats.isEmpty()) { |
| first = stats.get(0); |
| } |
| } |
| |
| public void replaceStatement(Statement oldstat, Statement newstat) { |
| |
| for (StatEdge edge : oldstat.getAllPredecessorEdges()) { |
| oldstat.removePredecessor(edge); |
| edge.getSource().changeEdgeNode(DIRECTION_FORWARD, edge, newstat); |
| newstat.addPredecessor(edge); |
| } |
| |
| for (StatEdge edge : oldstat.getAllSuccessorEdges()) { |
| oldstat.removeSuccessor(edge); |
| edge.setSource(newstat); |
| newstat.addSuccessor(edge); |
| } |
| |
| int statindex = stats.getIndexByKey(oldstat.id); |
| stats.removeWithKey(oldstat.id); |
| stats.addWithKeyAndIndex(statindex, newstat, newstat.id); |
| |
| newstat.setParent(this); |
| newstat.post = oldstat.post; |
| |
| if (first == oldstat) { |
| first = newstat; |
| } |
| |
| List<StatEdge> lst = new ArrayList<StatEdge>(oldstat.getLabelEdges()); |
| |
| for (int i = lst.size() - 1; i >= 0; i--) { |
| StatEdge edge = lst.get(i); |
| if (edge.getSource() != newstat) { |
| newstat.addLabeledEdge(edge); |
| } |
| else { |
| if (this == edge.getDestination() || this.containsStatementStrict(edge.getDestination())) { |
| edge.closure = null; |
| } |
| else { |
| this.addLabeledEdge(edge); |
| } |
| } |
| } |
| |
| oldstat.getLabelEdges().clear(); |
| } |
| |
| |
| // ***************************************************************************** |
| // private methods |
| // ***************************************************************************** |
| |
| private static void addToReversePostOrderListIterative(Statement root, List<Statement> lst) { |
| |
| LinkedList<Statement> stackNode = new LinkedList<Statement>(); |
| LinkedList<Integer> stackIndex = new LinkedList<Integer>(); |
| HashSet<Statement> setVisited = new HashSet<Statement>(); |
| |
| stackNode.add(root); |
| stackIndex.add(0); |
| |
| while (!stackNode.isEmpty()) { |
| |
| Statement node = stackNode.getLast(); |
| int index = stackIndex.removeLast(); |
| |
| setVisited.add(node); |
| |
| List<StatEdge> lstEdges = node.getAllSuccessorEdges(); |
| |
| for (; index < lstEdges.size(); index++) { |
| StatEdge edge = lstEdges.get(index); |
| Statement succ = edge.getDestination(); |
| |
| if (!setVisited.contains(succ) && |
| (edge.getType() == StatEdge.TYPE_REGULAR || edge.getType() == StatEdge.TYPE_EXCEPTION)) { // TODO: edge filter? |
| |
| stackIndex.add(index + 1); |
| |
| stackNode.add(succ); |
| stackIndex.add(0); |
| |
| break; |
| } |
| } |
| |
| if (index == lstEdges.size()) { |
| lst.add(0, node); |
| |
| stackNode.removeLast(); |
| } |
| } |
| } |
| |
| |
| private static void addToPostReversePostOrderList(Statement stat, List<Statement> lst, HashSet<Statement> setVisited) { |
| |
| if (setVisited.contains(stat)) { // because of not considered exception edges, s. isExitComponent. Should be rewritten, if possible. |
| return; |
| } |
| setVisited.add(stat); |
| |
| for (StatEdge prededge : stat.getEdges(StatEdge.TYPE_REGULAR | StatEdge.TYPE_EXCEPTION, DIRECTION_BACKWARD)) { |
| Statement pred = prededge.getSource(); |
| if (!setVisited.contains(pred)) { |
| addToPostReversePostOrderList(pred, lst, setVisited); |
| } |
| } |
| |
| lst.add(0, stat); |
| } |
| |
| // ***************************************************************************** |
| // getter and setter methods |
| // ***************************************************************************** |
| |
| public void changeEdgeNode(int direction, StatEdge edge, Statement value) { |
| |
| Map<Integer, List<StatEdge>> mapEdges = direction == DIRECTION_BACKWARD ? mapPredEdges : mapSuccEdges; |
| Map<Integer, List<Statement>> mapStates = direction == DIRECTION_BACKWARD ? mapPredStates : mapSuccStates; |
| |
| int type = edge.getType(); |
| |
| int[] arrtypes; |
| if (type == StatEdge.TYPE_EXCEPTION) { |
| arrtypes = new int[]{STATEDGE_ALL, StatEdge.TYPE_EXCEPTION}; |
| } |
| else { |
| arrtypes = new int[]{STATEDGE_ALL, STATEDGE_DIRECT_ALL, type}; |
| } |
| |
| for (int edgetype : arrtypes) { |
| List<StatEdge> lst = mapEdges.get(edgetype); |
| if (lst != null) { |
| int index = lst.indexOf(edge); |
| if (index >= 0) { |
| mapStates.get(edgetype).set(index, value); |
| } |
| } |
| } |
| |
| if (direction == DIRECTION_BACKWARD) { |
| edge.setSource(value); |
| } |
| else { |
| edge.setDestination(value); |
| } |
| } |
| |
| public void changeEdgeType(int direction, StatEdge edge, int newtype) { |
| |
| int oldtype = edge.getType(); |
| if (oldtype == newtype) { |
| return; |
| } |
| |
| if (oldtype == StatEdge.TYPE_EXCEPTION || newtype == StatEdge.TYPE_EXCEPTION) { |
| throw new RuntimeException("Invalid edge type!"); |
| } |
| |
| removeEdgeDirectInternal(direction, edge, oldtype); |
| addEdgeDirectInternal(direction, edge, newtype); |
| |
| if (direction == DIRECTION_FORWARD) { |
| edge.getDestination().changeEdgeType(DIRECTION_BACKWARD, edge, newtype); |
| } |
| |
| edge.setType(newtype); |
| } |
| |
| |
| private List<StatEdge> getEdges(int type, int direction) { |
| |
| Map<Integer, List<StatEdge>> map = direction == DIRECTION_BACKWARD ? mapPredEdges : mapSuccEdges; |
| |
| List<StatEdge> res; |
| if ((type & (type - 1)) == 0) { |
| res = map.get(type); |
| res = res == null ? new ArrayList<StatEdge>() : new ArrayList<StatEdge>(res); |
| } |
| else { |
| res = new ArrayList<StatEdge>(); |
| for (int edgetype : StatEdge.TYPES) { |
| if ((type & edgetype) != 0) { |
| List<StatEdge> lst = map.get(edgetype); |
| if (lst != null) { |
| res.addAll(lst); |
| } |
| } |
| } |
| } |
| |
| return res; |
| } |
| |
| public List<Statement> getNeighbours(int type, int direction) { |
| |
| Map<Integer, List<Statement>> map = direction == DIRECTION_BACKWARD ? mapPredStates : mapSuccStates; |
| |
| List<Statement> res; |
| if ((type & (type - 1)) == 0) { |
| res = map.get(type); |
| res = res == null ? new ArrayList<Statement>() : new ArrayList<Statement>(res); |
| } |
| else { |
| res = new ArrayList<Statement>(); |
| for (int edgetype : StatEdge.TYPES) { |
| if ((type & edgetype) != 0) { |
| List<Statement> lst = map.get(edgetype); |
| if (lst != null) { |
| res.addAll(lst); |
| } |
| } |
| } |
| } |
| |
| return res; |
| } |
| |
| public Set<Statement> getNeighboursSet(int type, int direction) { |
| return new HashSet<Statement>(getNeighbours(type, direction)); |
| } |
| |
| public List<StatEdge> getSuccessorEdges(int type) { |
| return getEdges(type, DIRECTION_FORWARD); |
| } |
| |
| public List<StatEdge> getPredecessorEdges(int type) { |
| return getEdges(type, DIRECTION_BACKWARD); |
| } |
| |
| public List<StatEdge> getAllSuccessorEdges() { |
| return getEdges(STATEDGE_ALL, DIRECTION_FORWARD); |
| } |
| |
| public List<StatEdge> getAllPredecessorEdges() { |
| return getEdges(STATEDGE_ALL, DIRECTION_BACKWARD); |
| } |
| |
| public Statement getFirst() { |
| return first; |
| } |
| |
| public void setFirst(Statement first) { |
| this.first = first; |
| } |
| |
| public Statement getPost() { |
| return post; |
| } |
| |
| public void setPost(Statement post) { |
| this.post = post; |
| } |
| |
| public VBStyleCollection<Statement, Integer> getStats() { |
| return stats; |
| } |
| |
| public int getLastBasicType() { |
| return lastBasicType; |
| } |
| |
| public HashSet<Statement> getContinueSet() { |
| return continueSet; |
| } |
| |
| public boolean isContainsMonitorExit() { |
| return containsMonitorExit; |
| } |
| |
| public boolean isMonitorEnter() { |
| return isMonitorEnter; |
| } |
| |
| public BasicBlockStatement getBasichead() { |
| if (type == TYPE_BASICBLOCK) { |
| return (BasicBlockStatement)this; |
| } |
| else { |
| return first.getBasichead(); |
| } |
| } |
| |
| public boolean isLabeled() { |
| |
| for (StatEdge edge : labelEdges) { |
| if (edge.labeled && edge.explicit) { // FIXME: consistent setting |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| public boolean hasBasicSuccEdge() { |
| |
| // FIXME: default switch |
| |
| return type == TYPE_BASICBLOCK || (type == TYPE_IF && |
| ((IfStatement)this).iftype == IfStatement.IFTYPE_IF) || |
| (type == TYPE_DO && ((DoStatement)this).getLooptype() != DoStatement.LOOP_DO); |
| } |
| |
| |
| public Statement getParent() { |
| return parent; |
| } |
| |
| public void setParent(Statement parent) { |
| this.parent = parent; |
| } |
| |
| public HashSet<StatEdge> getLabelEdges() { // FIXME: why HashSet? |
| return labelEdges; |
| } |
| |
| public List<Exprent> getVarDefinitions() { |
| return varDefinitions; |
| } |
| |
| public List<Exprent> getExprents() { |
| return exprents; |
| } |
| |
| public void setExprents(List<Exprent> exprents) { |
| this.exprents = exprents; |
| } |
| |
| public boolean isCopied() { |
| return copied; |
| } |
| |
| public void setCopied(boolean copied) { |
| this.copied = copied; |
| } |
| |
| // helper methods |
| public String toString() { |
| return id.toString(); |
| } |
| } |