1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-16 21:45:22 +02:00

- added support for while loop in cfg

This commit is contained in:
Alena Laskavaia 2010-03-30 03:04:48 +00:00
parent 113c52b20c
commit 2edd020c84
11 changed files with 197 additions and 37 deletions

View file

@ -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.AbstractBasicBlock;
import org.eclipse.cdt.codan.internal.core.cfg.ConnectorNode; 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.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.IBasicBlock;
import org.eclipse.cdt.codan.provisional.core.model.cfg.IExitNode; import org.eclipse.cdt.codan.provisional.core.model.cfg.IExitNode;
import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement; 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.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTReturnStatement; import org.eclipse.cdt.core.dom.ast.IASTReturnStatement;
import org.eclipse.cdt.core.dom.ast.IASTStatement; import org.eclipse.cdt.core.dom.ast.IASTStatement;
import org.eclipse.cdt.core.dom.ast.IASTWhileStatement;
/** /**
* TODO: add description * TODO: add description
@ -41,7 +43,7 @@ public class ControlFlowGraphBuilder {
*/ */
public CxxControlFlowGraph build(IASTFunctionDefinition def) { public CxxControlFlowGraph build(IASTFunctionDefinition def) {
IASTStatement body = def.getBody(); IASTStatement body = def.getBody();
start = new CxxStartNode(null); start = new CxxStartNode();
exits = new ArrayList<IExitNode>(); exits = new ArrayList<IExitNode>();
dead = new ArrayList<IBasicBlock>(); dead = new ArrayList<IBasicBlock>();
IBasicBlock last = createSubGraph(start, body); IBasicBlock last = createSubGraph(start, body);
@ -71,7 +73,8 @@ public class ControlFlowGraphBuilder {
addOutgoing(prev, node); addOutgoing(prev, node);
return node; return node;
} else if (body instanceof IASTIfStatement) { } else if (body instanceof IASTIfStatement) {
DecisionNode node = new DecisionNode(prev); DecisionNode node = new CxxDecisionNode(prev,
((IASTIfStatement) body).getConditionExpression());
addOutgoing(prev, node); addOutgoing(prev, node);
ConnectorNode conn = new ConnectorNode(); ConnectorNode conn = new ConnectorNode();
node.setConnectorNode(conn); node.setConnectorNode(conn);
@ -84,6 +87,26 @@ public class ControlFlowGraphBuilder {
conn.addIncoming(then); conn.addIncoming(then);
addOutgoing(then, conn); addOutgoing(then, conn);
return 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) { } else if (body instanceof IASTReturnStatement) {
CxxExitNode node = new CxxExitNode(prev, start, body); CxxExitNode node = new CxxExitNode(prev, start, body);
addOutgoing(prev, node); addOutgoing(prev, node);

View file

@ -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();
}
}

View file

@ -12,7 +12,6 @@
package org.eclipse.cdt.codan.core.cxx.internal.model.cfg; package org.eclipse.cdt.codan.core.cxx.internal.model.cfg;
import org.eclipse.cdt.codan.internal.core.cfg.StartNode; import org.eclipse.cdt.codan.internal.core.cfg.StartNode;
import org.eclipse.cdt.codan.provisional.core.model.cfg.IBasicBlock;
/** /**
* TODO: add description * TODO: add description
@ -22,8 +21,8 @@ public class CxxStartNode extends StartNode {
/** /**
* @param next * @param next
*/ */
public CxxStartNode(IBasicBlock next) { public CxxStartNode() {
super(next); super();
} }
/* (non-Javadoc) /* (non-Javadoc)

View file

@ -81,6 +81,15 @@ public class ControlFlowGraphTest extends CodanTestCase {
fail(e.getMessage()); fail(e.getMessage());
} }
} }
/**
*
*/
private void checkCfg() {
assertNotNull(graph);
assertNotNull(graph.getStartNode());
}
/*- /*-
<code file="test1.c"> <code file="test1.c">
main() { main() {
@ -92,6 +101,9 @@ public class ControlFlowGraphTest extends CodanTestCase {
public void test1() { public void test1() {
load("test1.c"); load("test1.c");
buildCfg(); buildCfg();
graph.print(graph.getStartNode()); checkCfg();
} }
} }

View file

@ -1,7 +1,6 @@
package org.eclipse.cdt.codan.internal.core.cfg; package org.eclipse.cdt.codan.internal.core.cfg;
import java.util.Iterator; import java.util.Iterator;
import org.eclipse.cdt.codan.provisional.core.model.cfg.IBasicBlock; import org.eclipse.cdt.codan.provisional.core.model.cfg.IBasicBlock;
import org.eclipse.cdt.codan.provisional.core.model.cfg.ISingleOutgoing; import org.eclipse.cdt.codan.provisional.core.model.cfg.ISingleOutgoing;
@ -13,9 +12,8 @@ public abstract class AbstractSingleOutgoingNode extends AbstractBasicBlock
implements ISingleOutgoing { implements ISingleOutgoing {
private IBasicBlock next; private IBasicBlock next;
public AbstractSingleOutgoingNode(IBasicBlock next) { public AbstractSingleOutgoingNode() {
super(); super();
this.next = next;
} }
public Iterator<IBasicBlock> getOutgoingIterator() { public Iterator<IBasicBlock> getOutgoingIterator() {

View file

@ -12,21 +12,25 @@ package org.eclipse.cdt.codan.internal.core.cfg;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import org.eclipse.cdt.codan.provisional.core.model.cfg.IBasicBlock; 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.IConnectorNode;
import org.eclipse.cdt.codan.provisional.core.model.cfg.IJumpNode;
/** /**
* TODO: add description * TODO: add description
*/ */
public class ConnectorNode extends AbstractSingleOutgoingNode implements public class ConnectorNode extends AbstractSingleOutgoingNode implements
IConnectorNode { IConnectorNode {
ArrayList<IBasicBlock> incoming = new ArrayList<IBasicBlock>(2); protected ArrayList<IBasicBlock> incoming = new ArrayList<IBasicBlock>(2);
/**
* @param next
*/
public ConnectorNode() { public ConnectorNode() {
super(null); super();
}
public ConnectorNode(IBasicBlock prev) {
super();
addIncoming(prev);
} }
public void addIncoming(IBasicBlock node) { public void addIncoming(IBasicBlock node) {
@ -51,7 +55,22 @@ public class ConnectorNode extends AbstractSingleOutgoingNode implements
* () * ()
*/ */
public int getIncomingSize() { public int getIncomingSize() {
// TODO Auto-generated method stub
return incoming.size(); 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;
}
} }

View file

@ -1,6 +1,7 @@
package org.eclipse.cdt.codan.internal.core.cfg; package org.eclipse.cdt.codan.internal.core.cfg;
import java.util.Iterator; import java.util.Iterator;
import org.eclipse.cdt.codan.provisional.core.model.cfg.IBasicBlock; 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.IConnectorNode;
import org.eclipse.cdt.codan.provisional.core.model.cfg.IJumpNode; import org.eclipse.cdt.codan.provisional.core.model.cfg.IJumpNode;
@ -28,6 +29,16 @@ public class JumpNode extends AbstractSingleIncomingNode implements IJumpNode {
return 1; return 1;
} }
/*
* (non-Javadoc)
*
* @see
* org.eclipse.cdt.codan.provisional.core.model.cfg.IJumpNode#getJumpNode()
*/
public IConnectorNode getJumpNode() {
return jump;
}
public IBasicBlock getOutgoing() { public IBasicBlock getOutgoing() {
return jump; return jump;
} }

View file

@ -2,6 +2,7 @@ package org.eclipse.cdt.codan.internal.core.cfg;
import java.util.Collections; import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import org.eclipse.cdt.codan.provisional.core.model.cfg.IBasicBlock; import org.eclipse.cdt.codan.provisional.core.model.cfg.IBasicBlock;
import org.eclipse.cdt.codan.provisional.core.model.cfg.IStartNode; 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 class StartNode extends AbstractSingleOutgoingNode implements IStartNode {
public StartNode(IBasicBlock next) { public StartNode() {
super(next); super();
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")

View file

@ -1,5 +1,6 @@
package org.eclipse.cdt.codan.provisional.core.model.cfg; package org.eclipse.cdt.codan.provisional.core.model.cfg;
public interface IConnectorNode extends IBasicBlock, ISingleOutgoing { public interface IConnectorNode extends IBasicBlock, ISingleOutgoing {
/** Backward connector has incoming node which comes from backward arcs */
boolean hasBackwardIncoming();
} }

View file

@ -1,5 +1,7 @@
package org.eclipse.cdt.codan.provisional.core.model.cfg; package org.eclipse.cdt.codan.provisional.core.model.cfg;
public interface IJumpNode extends IBasicBlock { public interface IJumpNode extends IBasicBlock, ISingleOutgoing {
boolean isBackwardArc(); boolean isBackwardArc();
IConnectorNode getJumpNode();
} }

View file

@ -3,7 +3,6 @@ package org.eclipse.cdt.codan.ui.cfgview.views;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Iterator; 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.ControlFlowGraphBuilder;
import org.eclipse.cdt.codan.core.cxx.internal.model.cfg.CxxControlFlowGraph; import org.eclipse.cdt.codan.core.cxx.internal.model.cfg.CxxControlFlowGraph;
import org.eclipse.cdt.codan.internal.core.cfg.AbstractBasicBlock; import org.eclipse.cdt.codan.internal.core.cfg.AbstractBasicBlock;
@ -123,9 +122,14 @@ public class ControlFlowGraphView extends ViewPart {
ArrayList blocks = new ArrayList(); ArrayList blocks = new ArrayList();
Iterator<IDecisionArc> iter = ((IDecisionNode) parent) Iterator<IDecisionArc> iter = ((IDecisionNode) parent)
.getDecisionArcs(); .getDecisionArcs();
for (; iter.hasNext();) { if (iter.hasNext()) {
IDecisionArc arc = iter.next(); IDecisionArc arc0 = iter.next();
blocks.add(arc); 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()); blocks.add(((IDecisionNode) parent).getConnectionNode());
return blocks.toArray(); return blocks.toArray();
@ -151,9 +155,36 @@ public class ControlFlowGraphView extends ViewPart {
if (obj instanceof AbstractBasicBlock) { if (obj instanceof AbstractBasicBlock) {
strdata = ((AbstractBasicBlock) obj).toStringData(); 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; 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) { public Image getImage(Object obj) {
String imageKey = "task.png"; String imageKey = "task.png";
if (obj instanceof IDecisionNode if (obj instanceof IDecisionNode
@ -186,9 +217,12 @@ public class ControlFlowGraphView extends ViewPart {
public Collection<IBasicBlock> getFlat(IBasicBlock node, public Collection<IBasicBlock> getFlat(IBasicBlock node,
Collection<IBasicBlock> prev) { Collection<IBasicBlock> prev) {
prev.add(node); prev.add(node);
if (node instanceof IConnectorNode) { if (node instanceof IConnectorNode
&& !((IConnectorNode) node).hasBackwardIncoming()) {
return prev; return prev;
} }
if (node instanceof IJumpNode)
return prev;
if (node instanceof ISingleOutgoing) { if (node instanceof ISingleOutgoing) {
getFlat(((ISingleOutgoing) node).getOutgoing(), prev); getFlat(((ISingleOutgoing) node).getOutgoing(), prev);
} else if (node instanceof IDecisionNode) { } else if (node instanceof IDecisionNode) {
@ -273,7 +307,8 @@ public class ControlFlowGraphView extends ViewPart {
}; };
action1.setText("Synchronize"); action1.setText("Synchronize");
action1.setToolTipText("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() { doubleClickAction = new Action() {
public void run() { public void run() {
ISelection selection = viewer.getSelection(); ISelection selection = viewer.getSelection();
@ -365,7 +400,6 @@ public class ControlFlowGraphView extends ViewPart {
if (data instanceof IASTNode) { if (data instanceof IASTNode) {
IASTNode node = (IASTNode) data; IASTNode node = (IASTNode) data;
if (node instanceof IASTTranslationUnit) // don't if (node instanceof IASTTranslationUnit) // don't
return; return;
IASTFileLocation loc = node.getFileLocation(); IASTFileLocation loc = node.getFileLocation();
String filename = loc.getFileName(); String filename = loc.getFileName();
@ -381,19 +415,18 @@ public class ControlFlowGraphView extends ViewPart {
return; return;
} }
} else { } else {
// IPath path = new Path(filename); // IPath path = new Path(filename);
// if (tu != null) { // if (tu != null) {
// try { // try {
// aPart = EditorUtility.openInEditor(path, tu); // aPart = EditorUtility.openInEditor(path, tu);
// } catch (PartInitException e) { // } catch (PartInitException e) {
// return; // return;
// } // }
// } // }
} }
if (aPart instanceof AbstractTextEditor) { if (aPart instanceof AbstractTextEditor) {
((AbstractTextEditor) aPart).selectAndReveal( ((AbstractTextEditor) aPart).selectAndReveal(loc
loc.getNodeOffset(), .getNodeOffset(), loc.getNodeLength());
loc.getNodeLength());
} else } else
System.out.println(A_PART_INSTANCEOF System.out.println(A_PART_INSTANCEOF
+ aPart.getClass().getName()); + aPart.getClass().getName());