mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-07-19 15:05:36 +02:00
Bug 335909 - adjusted cfg generation for switch and dead code
This commit is contained in:
parent
aadbf2a477
commit
53ecdbbc27
4 changed files with 89 additions and 7 deletions
|
@ -13,6 +13,7 @@ package org.eclipse.cdt.codan.core.cxx.internal.model.cfg;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.eclipse.cdt.codan.core.model.cfg.IBasicBlock;
|
||||
import org.eclipse.cdt.codan.core.model.cfg.IBranchNode;
|
||||
|
@ -22,6 +23,7 @@ import org.eclipse.cdt.codan.core.model.cfg.IDecisionNode;
|
|||
import org.eclipse.cdt.codan.core.model.cfg.IExitNode;
|
||||
import org.eclipse.cdt.codan.core.model.cfg.IJumpNode;
|
||||
import org.eclipse.cdt.codan.core.model.cfg.IPlainNode;
|
||||
import org.eclipse.cdt.codan.core.model.cfg.ISingleOutgoing;
|
||||
import org.eclipse.cdt.codan.core.model.cfg.IStartNode;
|
||||
import org.eclipse.cdt.codan.internal.core.cfg.AbstractBasicBlock;
|
||||
import org.eclipse.cdt.codan.internal.core.cfg.DecisionNode;
|
||||
|
@ -80,12 +82,35 @@ public class ControlFlowGraphBuilder {
|
|||
returnExit.setStartNode(start);
|
||||
addOutgoing(last, returnExit);
|
||||
exits.add(returnExit);
|
||||
if (dead.size() > 0) {
|
||||
for (Iterator iterator = dead.iterator(); iterator.hasNext();) {
|
||||
IBasicBlock ds = (IBasicBlock) iterator.next();
|
||||
IBasicBlock dl = findLast(ds);
|
||||
if (dl != null && dl.getOutgoingSize() == 0
|
||||
&& dl != returnExit) {
|
||||
((AbstractBasicBlock) dl).addOutgoing(returnExit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
CxxControlFlowGraph graph = new CxxControlFlowGraph(start, exits);
|
||||
graph.setUnconnectedNodes(dead);
|
||||
return graph;
|
||||
}
|
||||
|
||||
public IBasicBlock findLast(IBasicBlock node) {
|
||||
if (node instanceof IJumpNode)
|
||||
return null;
|
||||
if (node.getOutgoingSize() == 0)
|
||||
return node;
|
||||
if (node instanceof ISingleOutgoing) {
|
||||
return findLast(((ISingleOutgoing) node).getOutgoing());
|
||||
} else if (node instanceof IDecisionNode) {
|
||||
return findLast(((IDecisionNode) node).getMergeNode().getOutgoing());
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param start2
|
||||
* @param body
|
||||
|
@ -335,6 +360,7 @@ public class ControlFlowGraphBuilder {
|
|||
IBasicBlock last = createSubGraph(prev, elem);
|
||||
prev = last;
|
||||
}
|
||||
addJump(prev, mergeNode);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -61,38 +61,58 @@ public class ControlFlowGraphTest extends CodanFastCxxAstTestCase {
|
|||
ast.accept(visitor);
|
||||
}
|
||||
|
||||
private void checkCfg() {
|
||||
checkCfg(true);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private void checkCfg() {
|
||||
private void checkCfg(boolean decision) {
|
||||
assertNotNull(graph);
|
||||
assertNotNull(graph.getStartNode());
|
||||
Collection<IBasicBlock> nodes = graph.getNodes();
|
||||
for (Iterator<IBasicBlock> iterator = nodes.iterator(); iterator
|
||||
.hasNext();) {
|
||||
IBasicBlock node = iterator.next();
|
||||
checkNode(node);
|
||||
checkNode(node, decision);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param node
|
||||
*/
|
||||
private void checkNode(IBasicBlock node) {
|
||||
private void checkNode(IBasicBlock node, boolean decision) {
|
||||
IBasicBlock[] incomingNodes = node.getIncomingNodes();
|
||||
for (int i = 0; i < incomingNodes.length; i++) {
|
||||
nodes: for (int i = 0; i < incomingNodes.length; i++) {
|
||||
IBasicBlock b = incomingNodes[i];
|
||||
if (!contains(node, b.getOutgoingNodes()))
|
||||
if (b == null) {
|
||||
// check if dead node
|
||||
Iterator<IBasicBlock> iterator = graph
|
||||
.getUnconnectedNodeIterator();
|
||||
boolean dead = false;
|
||||
for (; iterator.hasNext();) {
|
||||
IBasicBlock d = iterator.next();
|
||||
if (node == d) {
|
||||
dead = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!dead)
|
||||
fail("Block " + node + " prev is null");
|
||||
} else if (!contains(node, b.getOutgoingNodes()))
|
||||
fail("Block " + node + " inconsitent prev/next " + b);
|
||||
}
|
||||
IBasicBlock[] outgoingNodes = node.getOutgoingNodes();
|
||||
for (int i = 0; i < outgoingNodes.length; i++) {
|
||||
IBasicBlock b = outgoingNodes[i];
|
||||
if (b == null)
|
||||
fail("Block " + node + " next is null");
|
||||
if (!contains(node, b.getIncomingNodes()))
|
||||
fail("Block " + node + " inconsitent next/prev " + b);
|
||||
}
|
||||
if (node instanceof IDecisionNode) {
|
||||
assertTrue("decision node outgping size",
|
||||
if (node instanceof IDecisionNode && decision) {
|
||||
assertTrue("decision node outgoing size " + node.getOutgoingSize(),
|
||||
node.getOutgoingSize() > 1);
|
||||
assertNotNull(((IDecisionNode) node).getMergeNode());
|
||||
}
|
||||
|
@ -360,4 +380,36 @@ public class ControlFlowGraphTest extends CodanFastCxxAstTestCase {
|
|||
IBasicBlock m1 = jumpEnd(bElse);
|
||||
assertSame(m1, m2);
|
||||
}
|
||||
|
||||
// foo() {
|
||||
// switch (0) {
|
||||
// case 1: ;
|
||||
// }
|
||||
// }
|
||||
public void test_switch1() {
|
||||
buildCfg(getAboveComment(), false);
|
||||
checkCfg(false);
|
||||
}
|
||||
|
||||
// foo() {
|
||||
// switch (0) {
|
||||
// case 1: break;
|
||||
// }
|
||||
// }
|
||||
public void test_switchbreak() {
|
||||
buildCfg(getAboveComment(), false);
|
||||
checkCfg(false);
|
||||
}
|
||||
|
||||
// foo() {
|
||||
// switch (0) {
|
||||
// a++;
|
||||
// }
|
||||
// }
|
||||
public void test_switchdead() {
|
||||
buildCfg(getAboveComment(), false);
|
||||
checkCfg(false);
|
||||
IStartNode startNode = graph.getStartNode();
|
||||
assertEquals(1, graph.getUnconnectedNodeSize());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -135,6 +135,8 @@ public class ControlFlowGraph implements IControlFlowGraph {
|
|||
* @param result
|
||||
*/
|
||||
private void getNodes(IBasicBlock start, Collection<IBasicBlock> result) {
|
||||
if (start == null)
|
||||
return; // huh
|
||||
if (result.contains(start))
|
||||
return;
|
||||
result.add(start);
|
||||
|
|
|
@ -29,6 +29,8 @@ public class PlainNode extends AbstractSingleIncomingNode implements IPlainNode
|
|||
}
|
||||
|
||||
public int getOutgoingSize() {
|
||||
if (next == null)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue