diff --git a/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/model/cfg/ControlFlowGraphBuilder.java b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/model/cfg/ControlFlowGraphBuilder.java index 0e020a97e2f..632f8d531ea 100644 --- a/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/model/cfg/ControlFlowGraphBuilder.java +++ b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/model/cfg/ControlFlowGraphBuilder.java @@ -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); } /** diff --git a/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/cfg/ControlFlowGraphTest.java b/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/cfg/ControlFlowGraphTest.java index f2c91afd61d..231292c9d6e 100644 --- a/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/cfg/ControlFlowGraphTest.java +++ b/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/cfg/ControlFlowGraphTest.java @@ -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 nodes = graph.getNodes(); for (Iterator 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 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()); + } } diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/ControlFlowGraph.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/ControlFlowGraph.java index 8133e8c2877..8960d937fcf 100644 --- a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/ControlFlowGraph.java +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/ControlFlowGraph.java @@ -135,6 +135,8 @@ public class ControlFlowGraph implements IControlFlowGraph { * @param result */ private void getNodes(IBasicBlock start, Collection result) { + if (start == null) + return; // huh if (result.contains(start)) return; result.add(start); diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/PlainNode.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/PlainNode.java index d382fb4199b..6ffb7b612b9 100644 --- a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/PlainNode.java +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/PlainNode.java @@ -29,6 +29,8 @@ public class PlainNode extends AbstractSingleIncomingNode implements IPlainNode } public int getOutgoingSize() { + if (next == null) + return 0; return 1; }