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 dbd1306a1cc..884c1a9a7cb 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 @@ -15,6 +15,7 @@ import java.util.Collection; import org.eclipse.cdt.codan.internal.core.cfg.AbstractBasicBlock; import org.eclipse.cdt.codan.internal.core.cfg.ConnectorNode; import org.eclipse.cdt.codan.internal.core.cfg.DecisionNode; +import org.eclipse.cdt.codan.internal.core.cfg.JumpNode; import org.eclipse.cdt.codan.provisional.core.model.cfg.IBasicBlock; import org.eclipse.cdt.codan.provisional.core.model.cfg.IExitNode; import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement; @@ -25,6 +26,7 @@ import org.eclipse.cdt.core.dom.ast.IASTIfStatement; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTReturnStatement; import org.eclipse.cdt.core.dom.ast.IASTStatement; +import org.eclipse.cdt.core.dom.ast.IASTWhileStatement; /** * TODO: add description @@ -41,7 +43,7 @@ public class ControlFlowGraphBuilder { */ public CxxControlFlowGraph build(IASTFunctionDefinition def) { IASTStatement body = def.getBody(); - start = new CxxStartNode(null); + start = new CxxStartNode(); exits = new ArrayList(); dead = new ArrayList(); IBasicBlock last = createSubGraph(start, body); @@ -71,7 +73,8 @@ public class ControlFlowGraphBuilder { addOutgoing(prev, node); return node; } else if (body instanceof IASTIfStatement) { - DecisionNode node = new DecisionNode(prev); + DecisionNode node = new CxxDecisionNode(prev, + ((IASTIfStatement) body).getConditionExpression()); addOutgoing(prev, node); ConnectorNode conn = new ConnectorNode(); node.setConnectorNode(conn); @@ -84,6 +87,26 @@ public class ControlFlowGraphBuilder { conn.addIncoming(then); addOutgoing(then, conn); return conn; + } else if (body instanceof IASTWhileStatement) { + // add continue connector + ConnectorNode nContinue = new ConnectorNode(prev); + addOutgoing(prev, nContinue); + // decision node + CxxDecisionNode decision = new CxxDecisionNode(nContinue, + ((IASTWhileStatement) body).getCondition()); + addOutgoing(nContinue, decision); + // add break connector + ConnectorNode nBreak = new ConnectorNode(decision); + addOutgoing(decision, nBreak); + decision.setConnectorNode(nBreak); + // create body and jump to continue node + IBasicBlock nBody = createSubGraph(decision, + ((IASTWhileStatement) body).getBody()); + JumpNode jumpContinue = new JumpNode(nBody, nContinue, true); + addOutgoing(nBody, jumpContinue); + // connect with backward link + nContinue.addIncoming(jumpContinue); + return nBreak; } else if (body instanceof IASTReturnStatement) { CxxExitNode node = new CxxExitNode(prev, start, body); addOutgoing(prev, node); diff --git a/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/model/cfg/CxxDecisionNode.java b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/model/cfg/CxxDecisionNode.java new file mode 100644 index 00000000000..d6aafa304e0 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/model/cfg/CxxDecisionNode.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (c) 2009 Alena Laskavaia + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alena Laskavaia - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.codan.core.cxx.internal.model.cfg; + +import org.eclipse.cdt.codan.internal.core.cfg.DecisionNode; +import org.eclipse.cdt.codan.provisional.core.model.cfg.IBasicBlock; +import org.eclipse.cdt.core.dom.ast.IASTNode; + +/** + * TODO: add description + */ +public class CxxDecisionNode extends DecisionNode { + + + /** + * @param prev + * @param expression + */ + public CxxDecisionNode(IBasicBlock prev, IASTNode expression) { + super(prev); + this.setNode(expression); + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return getNode().getRawSignature(); + } + + /** + * @param node the node to set + */ + public void setNode(IASTNode node) { + setData(node); + } + + /** + * @return the node + */ + public IASTNode getNode() { + return (IASTNode) getData(); + } + /** + * @return + */ + public String toStringData() { + if (getNode() == null) + return ""; + return getNode().getRawSignature(); + } +} diff --git a/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/model/cfg/CxxStartNode.java b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/model/cfg/CxxStartNode.java index 012fc825008..29b01b4ea7b 100644 --- a/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/model/cfg/CxxStartNode.java +++ b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/model/cfg/CxxStartNode.java @@ -12,7 +12,6 @@ package org.eclipse.cdt.codan.core.cxx.internal.model.cfg; import org.eclipse.cdt.codan.internal.core.cfg.StartNode; -import org.eclipse.cdt.codan.provisional.core.model.cfg.IBasicBlock; /** * TODO: add description @@ -22,8 +21,8 @@ public class CxxStartNode extends StartNode { /** * @param next */ - public CxxStartNode(IBasicBlock next) { - super(next); + public CxxStartNode() { + super(); } /* (non-Javadoc) 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 a7d08892ab4..1da3f8f693b 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 @@ -81,6 +81,15 @@ public class ControlFlowGraphTest extends CodanTestCase { fail(e.getMessage()); } } + + /** + * + */ + private void checkCfg() { + assertNotNull(graph); + assertNotNull(graph.getStartNode()); + + } /*- main() { @@ -92,6 +101,9 @@ public class ControlFlowGraphTest extends CodanTestCase { public void test1() { load("test1.c"); buildCfg(); - graph.print(graph.getStartNode()); + checkCfg(); + } + + } diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/AbstractSingleOutgoingNode.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/AbstractSingleOutgoingNode.java index 675d93cdcec..a243be850ed 100644 --- a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/AbstractSingleOutgoingNode.java +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/AbstractSingleOutgoingNode.java @@ -1,7 +1,6 @@ package org.eclipse.cdt.codan.internal.core.cfg; import java.util.Iterator; - import org.eclipse.cdt.codan.provisional.core.model.cfg.IBasicBlock; import org.eclipse.cdt.codan.provisional.core.model.cfg.ISingleOutgoing; @@ -13,9 +12,8 @@ public abstract class AbstractSingleOutgoingNode extends AbstractBasicBlock implements ISingleOutgoing { private IBasicBlock next; - public AbstractSingleOutgoingNode(IBasicBlock next) { + public AbstractSingleOutgoingNode() { super(); - this.next = next; } public Iterator getOutgoingIterator() { diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/ConnectorNode.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/ConnectorNode.java index 9307dc35346..e60dd1c8ed7 100644 --- a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/ConnectorNode.java +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/ConnectorNode.java @@ -12,21 +12,25 @@ package org.eclipse.cdt.codan.internal.core.cfg; import java.util.ArrayList; import java.util.Iterator; + import org.eclipse.cdt.codan.provisional.core.model.cfg.IBasicBlock; import org.eclipse.cdt.codan.provisional.core.model.cfg.IConnectorNode; +import org.eclipse.cdt.codan.provisional.core.model.cfg.IJumpNode; /** * TODO: add description */ public class ConnectorNode extends AbstractSingleOutgoingNode implements IConnectorNode { - ArrayList incoming = new ArrayList(2); + protected ArrayList incoming = new ArrayList(2); - /** - * @param next - */ public ConnectorNode() { - super(null); + super(); + } + + public ConnectorNode(IBasicBlock prev) { + super(); + addIncoming(prev); } public void addIncoming(IBasicBlock node) { @@ -51,7 +55,22 @@ public class ConnectorNode extends AbstractSingleOutgoingNode implements * () */ public int getIncomingSize() { - // TODO Auto-generated method stub return incoming.size(); } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.cdt.codan.provisional.core.model.cfg.IConnectorNode# + * hasBackwardIncoming() + */ + public boolean hasBackwardIncoming() { + for (IBasicBlock node : incoming) { + if (node instanceof IJumpNode) { + if (((IJumpNode) node).isBackwardArc()) + return true; + } + } + return false; + } } diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/JumpNode.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/JumpNode.java index d9ee6bf9203..a88ec7d3f48 100644 --- a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/JumpNode.java +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/JumpNode.java @@ -1,6 +1,7 @@ package org.eclipse.cdt.codan.internal.core.cfg; import java.util.Iterator; + import org.eclipse.cdt.codan.provisional.core.model.cfg.IBasicBlock; import org.eclipse.cdt.codan.provisional.core.model.cfg.IConnectorNode; import org.eclipse.cdt.codan.provisional.core.model.cfg.IJumpNode; @@ -28,6 +29,16 @@ public class JumpNode extends AbstractSingleIncomingNode implements IJumpNode { return 1; } + /* + * (non-Javadoc) + * + * @see + * org.eclipse.cdt.codan.provisional.core.model.cfg.IJumpNode#getJumpNode() + */ + public IConnectorNode getJumpNode() { + return jump; + } + public IBasicBlock getOutgoing() { return jump; } diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/StartNode.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/StartNode.java index 1c4c2c2692c..3fad0f08841 100644 --- a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/StartNode.java +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/StartNode.java @@ -2,6 +2,7 @@ package org.eclipse.cdt.codan.internal.core.cfg; import java.util.Collections; import java.util.Iterator; + import org.eclipse.cdt.codan.provisional.core.model.cfg.IBasicBlock; import org.eclipse.cdt.codan.provisional.core.model.cfg.IStartNode; @@ -10,8 +11,8 @@ import org.eclipse.cdt.codan.provisional.core.model.cfg.IStartNode; * */ public class StartNode extends AbstractSingleOutgoingNode implements IStartNode { - public StartNode(IBasicBlock next) { - super(next); + public StartNode() { + super(); } @SuppressWarnings("unchecked") diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/provisional/core/model/cfg/IConnectorNode.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/provisional/core/model/cfg/IConnectorNode.java index 7504ea1dc3b..72f032d8a07 100644 --- a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/provisional/core/model/cfg/IConnectorNode.java +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/provisional/core/model/cfg/IConnectorNode.java @@ -1,5 +1,6 @@ package org.eclipse.cdt.codan.provisional.core.model.cfg; - public interface IConnectorNode extends IBasicBlock, ISingleOutgoing { + /** Backward connector has incoming node which comes from backward arcs */ + boolean hasBackwardIncoming(); } diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/provisional/core/model/cfg/IJumpNode.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/provisional/core/model/cfg/IJumpNode.java index b4516521ff0..8bde8bb073f 100644 --- a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/provisional/core/model/cfg/IJumpNode.java +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/provisional/core/model/cfg/IJumpNode.java @@ -1,5 +1,7 @@ package org.eclipse.cdt.codan.provisional.core.model.cfg; -public interface IJumpNode extends IBasicBlock { +public interface IJumpNode extends IBasicBlock, ISingleOutgoing { boolean isBackwardArc(); + + IConnectorNode getJumpNode(); } diff --git a/codan/org.eclipse.cdt.codan.ui.cfgview/src/org/eclipse/cdt/codan/ui/cfgview/views/ControlFlowGraphView.java b/codan/org.eclipse.cdt.codan.ui.cfgview/src/org/eclipse/cdt/codan/ui/cfgview/views/ControlFlowGraphView.java index 386943fe878..76930c1e2b7 100644 --- a/codan/org.eclipse.cdt.codan.ui.cfgview/src/org/eclipse/cdt/codan/ui/cfgview/views/ControlFlowGraphView.java +++ b/codan/org.eclipse.cdt.codan.ui.cfgview/src/org/eclipse/cdt/codan/ui/cfgview/views/ControlFlowGraphView.java @@ -3,7 +3,6 @@ package org.eclipse.cdt.codan.ui.cfgview.views; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; - import org.eclipse.cdt.codan.core.cxx.internal.model.cfg.ControlFlowGraphBuilder; import org.eclipse.cdt.codan.core.cxx.internal.model.cfg.CxxControlFlowGraph; import org.eclipse.cdt.codan.internal.core.cfg.AbstractBasicBlock; @@ -123,9 +122,14 @@ public class ControlFlowGraphView extends ViewPart { ArrayList blocks = new ArrayList(); Iterator iter = ((IDecisionNode) parent) .getDecisionArcs(); - for (; iter.hasNext();) { - IDecisionArc arc = iter.next(); - blocks.add(arc); + if (iter.hasNext()) { + IDecisionArc arc0 = iter.next(); + for (; iter.hasNext();) { + IDecisionArc arc = iter.next(); + blocks.add(arc); + } + blocks.add(arc0);// people naturally expect false branch + // after true } blocks.add(((IDecisionNode) parent).getConnectionNode()); return blocks.toArray(); @@ -151,9 +155,36 @@ public class ControlFlowGraphView extends ViewPart { if (obj instanceof AbstractBasicBlock) { strdata = ((AbstractBasicBlock) obj).toStringData(); } + if (strdata == null || strdata.length() == 0) { + if (obj instanceof IConnectorNode) { + strdata = blockHexLabel(obj); + } else if (obj instanceof IJumpNode) { + strdata = blockHexLabel(((IJumpNode) obj).getJumpNode()); + } else if (obj instanceof IDecisionArc) { + IDecisionArc arc = (IDecisionArc) obj; + int index = arc.getIndex(); + if (arc.getDecisionNode().getDecisionArcSize() == 2) { + if (index == 0) + strdata = "false"; + else + strdata = "true"; + } else if (index == 0) + strdata = "default"; + else + strdata = "" + index; + } + } return obj.getClass().getSimpleName() + ": " + strdata; } + /** + * @param obj + * @return + */ + protected String blockHexLabel(Object obj) { + return "0x" + Integer.toHexString(System.identityHashCode(obj)); + } + public Image getImage(Object obj) { String imageKey = "task.png"; if (obj instanceof IDecisionNode @@ -186,9 +217,12 @@ public class ControlFlowGraphView extends ViewPart { public Collection getFlat(IBasicBlock node, Collection prev) { prev.add(node); - if (node instanceof IConnectorNode) { + if (node instanceof IConnectorNode + && !((IConnectorNode) node).hasBackwardIncoming()) { return prev; } + if (node instanceof IJumpNode) + return prev; if (node instanceof ISingleOutgoing) { getFlat(((ISingleOutgoing) node).getOutgoing(), prev); } else if (node instanceof IDecisionNode) { @@ -273,7 +307,8 @@ public class ControlFlowGraphView extends ViewPart { }; action1.setText("Synchronize"); action1.setToolTipText("Synchronize"); - action1.setImageDescriptor(ControlFlowGraphPlugin.getDefault().getImageDescriptor("icons/refresh_view.gif")); + action1.setImageDescriptor(ControlFlowGraphPlugin.getDefault() + .getImageDescriptor("icons/refresh_view.gif")); doubleClickAction = new Action() { public void run() { ISelection selection = viewer.getSelection(); @@ -365,7 +400,6 @@ public class ControlFlowGraphView extends ViewPart { if (data instanceof IASTNode) { IASTNode node = (IASTNode) data; if (node instanceof IASTTranslationUnit) // don't - return; IASTFileLocation loc = node.getFileLocation(); String filename = loc.getFileName(); @@ -381,19 +415,18 @@ public class ControlFlowGraphView extends ViewPart { return; } } else { -// IPath path = new Path(filename); -// if (tu != null) { -// try { -// aPart = EditorUtility.openInEditor(path, tu); -// } catch (PartInitException e) { -// return; -// } -// } + // IPath path = new Path(filename); + // if (tu != null) { + // try { + // aPart = EditorUtility.openInEditor(path, tu); + // } catch (PartInitException e) { + // return; + // } + // } } if (aPart instanceof AbstractTextEditor) { - ((AbstractTextEditor) aPart).selectAndReveal( - loc.getNodeOffset(), - loc.getNodeLength()); + ((AbstractTextEditor) aPart).selectAndReveal(loc + .getNodeOffset(), loc.getNodeLength()); } else System.out.println(A_PART_INSTANCEOF + aPart.getClass().getName());