in src/org/jetbrains/java/decompiler/modules/decompiler/sforms/FlattenStatementsHelper.java [60:389]
private void flattenStatement() {
class StatementStackEntry {
public final Statement statement;
public final LinkedList<StackEntry> stackFinally;
public final List<Exprent> tailExprents;
public int statementIndex;
public int edgeIndex;
public List<StatEdge> succEdges;
StatementStackEntry(Statement statement, LinkedList<StackEntry> stackFinally, List<Exprent> tailExprents) {
this.statement = statement;
this.stackFinally = stackFinally;
this.tailExprents = tailExprents;
}
}
LinkedList<StatementStackEntry> lstStackStatements = new LinkedList<>();
lstStackStatements.add(new StatementStackEntry(root, new LinkedList<>(), null));
mainloop:
while (!lstStackStatements.isEmpty()) {
StatementStackEntry statEntry = lstStackStatements.removeFirst();
Statement stat = statEntry.statement;
LinkedList<StackEntry> stackFinally = statEntry.stackFinally;
int statementBreakIndex = statEntry.statementIndex;
DirectNode node, nd;
List<StatEdge> lstSuccEdges = new ArrayList<>();
DirectNode sourcenode = null;
if (statEntry.succEdges == null) {
switch (stat.type) {
case BASIC_BLOCK -> {
node = new DirectNode(DirectNodeType.DIRECT, stat, (BasicBlockStatement)stat);
if (stat.getExprents() != null) {
node.exprents = stat.getExprents();
}
graph.nodes.putWithKey(node, node.id);
mapDestinationNodes.put(stat.id, new String[]{node.id, null});
lstSuccEdges.addAll(stat.getSuccessorEdges(EdgeType.DIRECT_ALL));
sourcenode = node;
List<Exprent> tailExprentList = statEntry.tailExprents;
if (tailExprentList != null) {
DirectNode tail = new DirectNode(DirectNodeType.TAIL, stat, stat.id + "_tail");
tail.exprents = tailExprentList;
graph.nodes.putWithKey(tail, tail.id);
mapDestinationNodes.put(-stat.id, new String[]{tail.id, null});
listEdges.add(new Edge(node.id, -stat.id, EdgeType.REGULAR));
sourcenode = tail;
}
// 'if' statement: record positive branch
if (stat.getLastBasicType() == StatementType.IF) {
mapPosIfBranch.put(sourcenode.id, lstSuccEdges.get(0).getDestination().id);
}
}
case CATCH_ALL, TRY_CATCH -> {
DirectNode firstnd = new DirectNode(DirectNodeType.TRY, stat, stat.id + "_try");
if (stat.type == Statement.StatementType.TRY_CATCH) {
CatchStatement catchStat = (CatchStatement)stat;
if (catchStat.getTryType() == CatchStatement.CatchStatementType.RESOURCES) {
firstnd.exprents = catchStat.getResources();
}
}
mapDestinationNodes.put(stat.id, new String[]{firstnd.id, null});
graph.nodes.putWithKey(firstnd, firstnd.id);
LinkedList<StatementStackEntry> lst = new LinkedList<>();
for (Statement st : stat.getStats()) {
listEdges.add(new Edge(firstnd.id, st.id, EdgeType.REGULAR));
LinkedList<StackEntry> stack = stackFinally;
if (stat.type == StatementType.CATCH_ALL && ((CatchAllStatement)stat).isFinally()) {
stack = new LinkedList<>(stackFinally);
if (st == stat.getFirst()) { // catch head
stack.add(new StackEntry((CatchAllStatement)stat, Boolean.FALSE));
}
else { // handler
stack.add(new StackEntry((CatchAllStatement)stat, Boolean.TRUE, EdgeType.BREAK,
root.getDummyExit(), st, st, firstnd, firstnd, true));
}
}
lst.add(new StatementStackEntry(st, stack, null));
}
lstStackStatements.addAll(0, lst);
}
case DO -> {
if (statementBreakIndex == 0) {
statEntry.statementIndex = 1;
lstStackStatements.addFirst(statEntry);
lstStackStatements.addFirst(new StatementStackEntry(stat.getFirst(), stackFinally, null));
continue mainloop;
}
nd = graph.nodes.getWithKey(mapDestinationNodes.get(stat.getFirst().id)[0]);
DoStatement dostat = (DoStatement)stat;
LoopType loopType = dostat.getLoopType();
if (loopType == LoopType.DO) {
mapDestinationNodes.put(stat.id, new String[]{nd.id, nd.id});
break;
}
lstSuccEdges.add(stat.getSuccessorEdges(EdgeType.DIRECT_ALL).get(0)); // exactly one edge
switch (loopType) {
case WHILE, DO_WHILE -> {
node = new DirectNode(DirectNodeType.CONDITION, stat, stat.id + "_cond");
node.exprents = dostat.getConditionExprentList();
graph.nodes.putWithKey(node, node.id);
listEdges.add(new Edge(node.id, stat.getFirst().id, EdgeType.REGULAR));
if (loopType == LoopType.WHILE) {
mapDestinationNodes.put(stat.id, new String[]{node.id, node.id});
}
else {
mapDestinationNodes.put(stat.id, new String[]{nd.id, node.id});
boolean found = false;
for (Edge edge : listEdges) {
if (edge.statid.equals(stat.id) && edge.edgetype == EdgeType.CONTINUE) {
found = true;
break;
}
}
if (!found) {
listEdges.add(new Edge(nd.id, stat.id, EdgeType.CONTINUE));
}
}
sourcenode = node;
}
case FOR, FOREACH -> {
DirectNode nodeinit = new DirectNode(DirectNodeType.INIT, stat, stat.id + "_init");
if (dostat.getInitExprent() != null) {
nodeinit.exprents = dostat.getInitExprentList();
}
graph.nodes.putWithKey(nodeinit, nodeinit.id);
DirectNode nodecond = new DirectNode(DirectNodeType.CONDITION, stat, stat.id + "_cond");
if (loopType != DoStatement.LoopType.FOREACH) {
nodecond.exprents = dostat.getConditionExprentList();
}
graph.nodes.putWithKey(nodecond, nodecond.id);
DirectNode nodeinc = new DirectNode(DirectNodeType.INCREMENT, stat, stat.id + "_inc");
nodeinc.exprents = dostat.getIncExprentList();
graph.nodes.putWithKey(nodeinc, nodeinc.id);
mapDestinationNodes.put(stat.id, new String[]{nodeinit.id, nodeinc.id});
mapDestinationNodes.put(-stat.id, new String[]{nodecond.id, null});
listEdges.add(new Edge(nodecond.id, stat.getFirst().id, EdgeType.REGULAR));
listEdges.add(new Edge(nodeinit.id, -stat.id, EdgeType.REGULAR));
listEdges.add(new Edge(nodeinc.id, -stat.id, EdgeType.REGULAR));
boolean found = false;
for (Edge edge : listEdges) {
if (edge.statid.equals(stat.id) && edge.edgetype == EdgeType.CONTINUE) {
found = true;
break;
}
}
if (!found) {
listEdges.add(new Edge(nd.id, stat.id, EdgeType.CONTINUE));
}
sourcenode = nodecond;
}
}
}
case SYNCHRONIZED, SWITCH, IF, SEQUENCE, ROOT -> {
int statsize = stat.getStats().size();
if (stat.type == StatementType.SYNCHRONIZED) {
statsize = 2; // exclude the handler if synchronized
}
if (statementBreakIndex <= statsize) {
List<Exprent> tailexprlst = switch (stat.type) {
case SYNCHRONIZED -> ((SynchronizedStatement)stat).getHeadexprentList();
case SWITCH -> ((SwitchStatement)stat).getHeadExprentList();
case IF -> ((IfStatement)stat).getHeadexprentList();
default -> null;
};
for (int i = statementBreakIndex; i < statsize; i++) {
statEntry.statementIndex = i + 1;
lstStackStatements.addFirst(statEntry);
lstStackStatements.addFirst(
new StatementStackEntry(stat.getStats().get(i), stackFinally,
(i == 0 && tailexprlst != null && tailexprlst.get(0) != null) ? tailexprlst : null));
continue mainloop;
}
node = graph.nodes.getWithKey(mapDestinationNodes.get(stat.getFirst().id)[0]);
mapDestinationNodes.put(stat.id, new String[]{node.id, null});
if (stat.type == StatementType.IF && stat instanceof IfStatement && ((IfStatement)stat).iftype == IfStatement.IFTYPE_IF) {
lstSuccEdges.add(stat.getSuccessorEdges(EdgeType.DIRECT_ALL).get(0)); // exactly one edge
sourcenode = tailexprlst != null && !tailexprlst.isEmpty() && tailexprlst.get(0) == null
? node
: graph.nodes.getWithKey(node.id + "_tail");
}
}
}
}
}
// no successor edges
if (sourcenode != null) {
if (statEntry.succEdges != null) {
lstSuccEdges = statEntry.succEdges;
}
for (int edgeindex = statEntry.edgeIndex; edgeindex < lstSuccEdges.size(); edgeindex++) {
StatEdge edge = lstSuccEdges.get(edgeindex);
LinkedList<StackEntry> stack = new LinkedList<>(stackFinally);
EdgeType edgetype = edge.getType();
Statement destination = edge.getDestination();
DirectNode finallyShortRangeSource = sourcenode;
DirectNode finallyLongRangeSource = sourcenode;
Statement finallyShortRangeEntry = null;
Statement finallyLongRangeEntry = null;
boolean isFinallyMonitorExceptionPath = false;
boolean isFinallyExit = false;
while (true) {
StackEntry entry = null;
if (!stack.isEmpty()) {
entry = stack.getLast();
}
boolean created = true;
if (entry == null) {
saveEdge(sourcenode, destination, edgetype, isFinallyExit ? finallyShortRangeSource : null, finallyLongRangeSource,
finallyShortRangeEntry, finallyLongRangeEntry, isFinallyMonitorExceptionPath);
}
else {
CatchAllStatement catchall = entry.catchstatement;
if (entry.state) { // finally handler statement
if (edgetype == EdgeType.FINALLY_EXIT) {
stack.removeLast();
destination = entry.destination;
edgetype = entry.edgetype;
finallyShortRangeSource = entry.finallyShortRangeSource;
finallyLongRangeSource = entry.finallyLongRangeSource;
finallyShortRangeEntry = entry.finallyShortRangeEntry;
finallyLongRangeEntry = entry.finallyLongRangeEntry;
isFinallyExit = true;
isFinallyMonitorExceptionPath = (catchall.getMonitor() != null) & entry.isFinallyExceptionPath;
created = false;
}
else {
if (!catchall.containsStatementStrict(destination)) {
stack.removeLast();
created = false;
}
else {
saveEdge(sourcenode, destination, edgetype, isFinallyExit ? finallyShortRangeSource : null, finallyLongRangeSource,
finallyShortRangeEntry, finallyLongRangeEntry, isFinallyMonitorExceptionPath);
}
}
}
else { // finally protected try statement
if (!catchall.containsStatementStrict(destination)) {
saveEdge(sourcenode, catchall.getHandler(), EdgeType.REGULAR, isFinallyExit ? finallyShortRangeSource : null,
finallyLongRangeSource, finallyShortRangeEntry, finallyLongRangeEntry, isFinallyMonitorExceptionPath);
stack.removeLast();
stack.add(new StackEntry(catchall, Boolean.TRUE, edgetype, destination, catchall.getHandler(),
finallyLongRangeEntry == null ? catchall.getHandler() : finallyLongRangeEntry,
sourcenode, finallyLongRangeSource, false));
statEntry.edgeIndex = edgeindex + 1;
statEntry.succEdges = lstSuccEdges;
lstStackStatements.addFirst(statEntry);
lstStackStatements.addFirst(new StatementStackEntry(catchall.getHandler(), stack, null));
continue mainloop;
}
else {
saveEdge(sourcenode, destination, edgetype, isFinallyExit ? finallyShortRangeSource : null, finallyLongRangeSource,
finallyShortRangeEntry, finallyLongRangeEntry, isFinallyMonitorExceptionPath);
}
}
}
if (created) {
break;
}
}
}
}
}
}