mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-07-23 00:45:28 +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.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
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.IBasicBlock;
|
||||||
import org.eclipse.cdt.codan.core.model.cfg.IBranchNode;
|
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.IExitNode;
|
||||||
import org.eclipse.cdt.codan.core.model.cfg.IJumpNode;
|
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.IPlainNode;
|
||||||
|
import org.eclipse.cdt.codan.core.model.cfg.ISingleOutgoing;
|
||||||
import org.eclipse.cdt.codan.core.model.cfg.IStartNode;
|
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.AbstractBasicBlock;
|
||||||
import org.eclipse.cdt.codan.internal.core.cfg.DecisionNode;
|
import org.eclipse.cdt.codan.internal.core.cfg.DecisionNode;
|
||||||
|
@ -80,12 +82,35 @@ public class ControlFlowGraphBuilder {
|
||||||
returnExit.setStartNode(start);
|
returnExit.setStartNode(start);
|
||||||
addOutgoing(last, returnExit);
|
addOutgoing(last, returnExit);
|
||||||
exits.add(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);
|
CxxControlFlowGraph graph = new CxxControlFlowGraph(start, exits);
|
||||||
graph.setUnconnectedNodes(dead);
|
graph.setUnconnectedNodes(dead);
|
||||||
return graph;
|
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 start2
|
||||||
* @param body
|
* @param body
|
||||||
|
@ -335,6 +360,7 @@ public class ControlFlowGraphBuilder {
|
||||||
IBasicBlock last = createSubGraph(prev, elem);
|
IBasicBlock last = createSubGraph(prev, elem);
|
||||||
prev = last;
|
prev = last;
|
||||||
}
|
}
|
||||||
|
addJump(prev, mergeNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -61,38 +61,58 @@ public class ControlFlowGraphTest extends CodanFastCxxAstTestCase {
|
||||||
ast.accept(visitor);
|
ast.accept(visitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkCfg() {
|
||||||
|
checkCfg(true);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
private void checkCfg() {
|
private void checkCfg(boolean decision) {
|
||||||
assertNotNull(graph);
|
assertNotNull(graph);
|
||||||
assertNotNull(graph.getStartNode());
|
assertNotNull(graph.getStartNode());
|
||||||
Collection<IBasicBlock> nodes = graph.getNodes();
|
Collection<IBasicBlock> nodes = graph.getNodes();
|
||||||
for (Iterator<IBasicBlock> iterator = nodes.iterator(); iterator
|
for (Iterator<IBasicBlock> iterator = nodes.iterator(); iterator
|
||||||
.hasNext();) {
|
.hasNext();) {
|
||||||
IBasicBlock node = iterator.next();
|
IBasicBlock node = iterator.next();
|
||||||
checkNode(node);
|
checkNode(node, decision);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param node
|
* @param node
|
||||||
*/
|
*/
|
||||||
private void checkNode(IBasicBlock node) {
|
private void checkNode(IBasicBlock node, boolean decision) {
|
||||||
IBasicBlock[] incomingNodes = node.getIncomingNodes();
|
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];
|
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);
|
fail("Block " + node + " inconsitent prev/next " + b);
|
||||||
}
|
}
|
||||||
IBasicBlock[] outgoingNodes = node.getOutgoingNodes();
|
IBasicBlock[] outgoingNodes = node.getOutgoingNodes();
|
||||||
for (int i = 0; i < outgoingNodes.length; i++) {
|
for (int i = 0; i < outgoingNodes.length; i++) {
|
||||||
IBasicBlock b = outgoingNodes[i];
|
IBasicBlock b = outgoingNodes[i];
|
||||||
|
if (b == null)
|
||||||
|
fail("Block " + node + " next is null");
|
||||||
if (!contains(node, b.getIncomingNodes()))
|
if (!contains(node, b.getIncomingNodes()))
|
||||||
fail("Block " + node + " inconsitent next/prev " + b);
|
fail("Block " + node + " inconsitent next/prev " + b);
|
||||||
}
|
}
|
||||||
if (node instanceof IDecisionNode) {
|
if (node instanceof IDecisionNode && decision) {
|
||||||
assertTrue("decision node outgping size",
|
assertTrue("decision node outgoing size " + node.getOutgoingSize(),
|
||||||
node.getOutgoingSize() > 1);
|
node.getOutgoingSize() > 1);
|
||||||
assertNotNull(((IDecisionNode) node).getMergeNode());
|
assertNotNull(((IDecisionNode) node).getMergeNode());
|
||||||
}
|
}
|
||||||
|
@ -360,4 +380,36 @@ public class ControlFlowGraphTest extends CodanFastCxxAstTestCase {
|
||||||
IBasicBlock m1 = jumpEnd(bElse);
|
IBasicBlock m1 = jumpEnd(bElse);
|
||||||
assertSame(m1, m2);
|
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
|
* @param result
|
||||||
*/
|
*/
|
||||||
private void getNodes(IBasicBlock start, Collection<IBasicBlock> result) {
|
private void getNodes(IBasicBlock start, Collection<IBasicBlock> result) {
|
||||||
|
if (start == null)
|
||||||
|
return; // huh
|
||||||
if (result.contains(start))
|
if (result.contains(start))
|
||||||
return;
|
return;
|
||||||
result.add(start);
|
result.add(start);
|
||||||
|
|
|
@ -29,6 +29,8 @@ public class PlainNode extends AbstractSingleIncomingNode implements IPlainNode
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getOutgoingSize() {
|
public int getOutgoingSize() {
|
||||||
|
if (next == null)
|
||||||
|
return 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue