1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-08-03 14:25:37 +02:00

- added more tests and support for goto/label statements

This commit is contained in:
Alena Laskavaia 2010-04-17 01:58:12 +00:00
parent 0f78d0c5fd
commit 5a5d22c50d
8 changed files with 268 additions and 56 deletions

View file

@ -12,6 +12,7 @@ package org.eclipse.cdt.codan.core.cxx.internal.model.cfg;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import org.eclipse.cdt.codan.internal.core.cfg.AbstractBasicBlock;
import org.eclipse.cdt.codan.internal.core.cfg.ConnectorNode;
@ -34,7 +35,9 @@ import org.eclipse.cdt.core.dom.ast.IASTDoStatement;
import org.eclipse.cdt.core.dom.ast.IASTExpressionStatement;
import org.eclipse.cdt.core.dom.ast.IASTForStatement;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.IASTGotoStatement;
import org.eclipse.cdt.core.dom.ast.IASTIfStatement;
import org.eclipse.cdt.core.dom.ast.IASTLabelStatement;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTReturnStatement;
import org.eclipse.cdt.core.dom.ast.IASTStatement;
@ -52,6 +55,7 @@ public class ControlFlowGraphBuilder {
CxxNodeFactory factory = new CxxNodeFactory();
IConnectorNode outerBreak;
IConnectorNode outerContinue;
HashMap<String, IBasicBlock> labels = new HashMap<String, IBasicBlock>(0);
/**
* @param def
@ -68,7 +72,9 @@ public class ControlFlowGraphBuilder {
returnExit.setStartNode(start);
addOutgoing(last, returnExit);
}
return new CxxControlFlowGraph(start, exits);
CxxControlFlowGraph graph = new CxxControlFlowGraph(start, exits);
graph.setUnconnectedNodes(dead);
return graph;
}
/**
@ -112,10 +118,53 @@ public class ControlFlowGraphBuilder {
return prev;
} else if (body instanceof IASTSwitchStatement) {
return createSwitch(prev, (IASTSwitchStatement) body);
} else if (body instanceof IASTLabelStatement) {
IASTLabelStatement ast = (IASTLabelStatement) body;
String labelName = ast.getName().toString();
IBranchNode labNode = (IBranchNode) labels.get(labelName);
IConnectorNode conn;
if (labNode != null) {
conn = (IConnectorNode) labNode.getOutgoing();
addOutgoing(prev, labNode);
} else {
// labeled statement contains of connector for jumps, branch for
// label
// and nested statement
conn = createLabelNodes(prev, labelName);
}
return createSubGraph(conn, ast.getNestedStatement());
} else if (body instanceof IASTGotoStatement) {
IASTGotoStatement ast = (IASTGotoStatement)body;
String labelName = ast.getName().toString();
IConnectorNode conn;
IBranchNode labNode = (IBranchNode) labels.get(labelName);
if (labNode!=null) {
conn = (IConnectorNode) labNode.getOutgoing();
} else {
conn = createLabelNodes(null, labelName);
}
IJumpNode gotoNode = factory.createJumpNode();
((JumpNode) gotoNode).setJump(conn, labNode!=null);
addOutgoing(prev, gotoNode);
return gotoNode;
}
return prev;
}
/**
* @param prev
* @param labelName
* @return
*/
protected IConnectorNode createLabelNodes(IBasicBlock prev, String labelName) {
IBranchNode branch = factory.createBranchNode(labelName);
if (prev!=null) addOutgoing(prev, branch);
labels.put(labelName, branch);
IConnectorNode conn = factory.createConnectorNode();
addOutgoing(branch, conn);
return conn;
}
/**
* @param prev
* @param body
@ -127,11 +176,11 @@ public class ControlFlowGraphBuilder {
addOutgoing(prev, ifNode);
IConnectorNode mergeNode = factory.createConnectorNode();
ifNode.setMergeNode(mergeNode);
IBranchNode thenNode = factory.createLabeledNode(IBranchNode.THEN);
IBranchNode thenNode = factory.createBranchNode(IBranchNode.THEN);
addOutgoing(ifNode, thenNode);
IBasicBlock then = createSubGraph(thenNode, body.getThenClause());
addJump(then, mergeNode);
IBranchNode elseNode = factory.createLabeledNode(IBranchNode.ELSE);
IBranchNode elseNode = factory.createBranchNode(IBranchNode.ELSE);
addOutgoing(ifNode, elseNode);
IBasicBlock els = createSubGraph(elseNode, body.getElseClause());
addJump(els, mergeNode);
@ -173,7 +222,7 @@ public class ControlFlowGraphBuilder {
}
if (elem instanceof IASTDefaultStatement) {
IBranchNode lbl = factory
.createLabeledNode(IBranchNode.DEFAULT);
.createBranchNode(IBranchNode.DEFAULT);
if (!(prev instanceof IExitNode) && prev != switchNode)
addOutgoing(prev, lbl);
addOutgoing(switchNode, lbl);
@ -185,9 +234,9 @@ public class ControlFlowGraphBuilder {
IBranchNode lbl = null;
if (elem instanceof IASTCaseStatement) {
IASTCaseStatement caseSt = (IASTCaseStatement) elem;
lbl = factory.createLabeledNode(caseSt);
lbl = factory.createBranchNode(caseSt);
} else if (elem instanceof IASTDefaultStatement) {
lbl = factory.createLabeledNode(IBranchNode.DEFAULT);
lbl = factory.createBranchNode(IBranchNode.DEFAULT);
}
if (!(prev instanceof IExitNode) && prev != switchNode) {
IConnectorNode here = factory.createConnectorNode();
@ -231,7 +280,7 @@ public class ControlFlowGraphBuilder {
IConnectorNode nBreak = factory.createConnectorNode();
decision.setMergeNode(nBreak);
// create body and jump to continue node
IBranchNode loopStart = factory.createLabeledNode(IBranchNode.THEN);
IBranchNode loopStart = factory.createBranchNode(IBranchNode.THEN);
addOutgoing(decision, loopStart);
// set break/continue
IConnectorNode nContinue = factory.createConnectorNode();
@ -250,7 +299,7 @@ public class ControlFlowGraphBuilder {
// connect with backward link
addJump(inc, beforeCheck, true);
// add "else" branch
IBranchNode loopEnd = factory.createLabeledNode(IBranchNode.ELSE);
IBranchNode loopEnd = factory.createBranchNode(IBranchNode.ELSE);
addOutgoing(decision, loopEnd);
addJump(loopEnd, nBreak);
return nBreak;
@ -273,7 +322,7 @@ public class ControlFlowGraphBuilder {
IConnectorNode nBreak = factory.createConnectorNode();
decision.setMergeNode(nBreak);
// create body and jump to continue node
IBranchNode loopStart = factory.createLabeledNode(IBranchNode.THEN);
IBranchNode loopStart = factory.createBranchNode(IBranchNode.THEN);
addOutgoing(decision, loopStart);
// set break/continue
IConnectorNode savedContinue = outerContinue;
@ -287,7 +336,7 @@ public class ControlFlowGraphBuilder {
// backward jump
addJump(endBody, nContinue, true);
// connect with else branch
IBranchNode loopEnd = factory.createLabeledNode(IBranchNode.ELSE);
IBranchNode loopEnd = factory.createBranchNode(IBranchNode.ELSE);
addOutgoing(decision, loopEnd);
addJump(loopEnd, nBreak);
return nBreak;
@ -315,7 +364,7 @@ public class ControlFlowGraphBuilder {
.getCondition());
addOutgoing(nContinue, decision);
// then branch
IBranchNode thenNode = factory.createLabeledNode(IBranchNode.THEN);
IBranchNode thenNode = factory.createBranchNode(IBranchNode.THEN);
addOutgoing(decision, thenNode);
IJumpNode jumpToStart = factory.createJumpNode();
addOutgoing(thenNode, jumpToStart);
@ -323,7 +372,7 @@ public class ControlFlowGraphBuilder {
// connect with backward link
addOutgoing(jumpToStart, loopStart);
// connect with else branch
IBranchNode loopEnd = factory.createLabeledNode(IBranchNode.ELSE);
IBranchNode loopEnd = factory.createBranchNode(IBranchNode.ELSE);
addOutgoing(decision, loopEnd);
// add break connector
decision.setMergeNode(nBreak);
@ -339,6 +388,8 @@ public class ControlFlowGraphBuilder {
boolean backward) {
if (prev instanceof IJumpNode)
return (IJumpNode) prev;
if (prev instanceof IExitNode)
return null;
IJumpNode jump = factory.createJumpNode();
addOutgoing(prev, jump);
addOutgoing(jump, conn);
@ -351,12 +402,13 @@ public class ControlFlowGraphBuilder {
* @param node
*/
private void addOutgoing(IBasicBlock prev, IBasicBlock node) {
if (!(node instanceof IStartNode))
((AbstractBasicBlock) node).addIncoming(prev);
if (prev instanceof IExitNode) {
if (prev instanceof IExitNode || prev == null) {
dead.add(node);
return;
} else if (prev instanceof AbstractBasicBlock) {
((AbstractBasicBlock) prev).addOutgoing(node);
}
if (!(node instanceof IStartNode))
((AbstractBasicBlock) node).addIncoming(prev);
}
}

View file

@ -61,8 +61,8 @@ public class CxxNodeFactory extends NodeFactory implements INodeFactory {
* @param caseSt
* @return
*/
public IBranchNode createLabeledNode(IASTNode caseSt) {
IBranchNode node = createLabeledNode(caseSt.getRawSignature());
public IBranchNode createBranchNode(IASTNode caseSt) {
IBranchNode node = createBranchNode(caseSt.getRawSignature());
((AbstractBasicBlock) node).setData(caseSt);
return node;
}

View file

@ -15,9 +15,17 @@ import java.util.Iterator;
import org.eclipse.cdt.codan.core.cxx.internal.model.cfg.ControlFlowGraphBuilder;
import org.eclipse.cdt.codan.core.test.CodanTestCase;
import org.eclipse.cdt.codan.internal.core.cfg.AbstractBasicBlock;
import org.eclipse.cdt.codan.internal.core.cfg.ControlFlowGraph;
import org.eclipse.cdt.codan.provisional.core.model.cfg.IBasicBlock;
import org.eclipse.cdt.codan.provisional.core.model.cfg.IBranchNode;
import org.eclipse.cdt.codan.provisional.core.model.cfg.IConnectorNode;
import org.eclipse.cdt.codan.provisional.core.model.cfg.IDecisionNode;
import org.eclipse.cdt.codan.provisional.core.model.cfg.IExitNode;
import org.eclipse.cdt.codan.provisional.core.model.cfg.IJumpNode;
import org.eclipse.cdt.codan.provisional.core.model.cfg.IPlainNode;
import org.eclipse.cdt.codan.provisional.core.model.cfg.ISingleOutgoing;
import org.eclipse.cdt.codan.provisional.core.model.cfg.IStartNode;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
@ -36,6 +44,7 @@ import org.eclipse.core.runtime.CoreException;
*/
public class ControlFlowGraphTest extends CodanTestCase {
ControlFlowGraph graph;
void processFile(IFile file) throws CoreException, InterruptedException {
// create translation unit and access index
ICElement model = CoreModel.getDefault().create(file);
@ -64,28 +73,30 @@ public class ControlFlowGraphTest extends CodanTestCase {
{
shouldVisitDeclarations = true;
}
public int visit(IASTDeclaration decl) {
if (decl instanceof IASTFunctionDefinition) {
graph = new ControlFlowGraphBuilder().build((IASTFunctionDefinition) decl);
graph = new ControlFlowGraphBuilder()
.build((IASTFunctionDefinition) decl);
return PROCESS_ABORT;
}
return PROCESS_CONTINUE;
}
};
ast.accept(visitor);
}
void buildCfg() {
try {
IResource el = cproject.getProject().findMember(currentFile.getName());
IResource el = cproject.getProject().findMember(
currentFile.getName());
processFile((IFile) el);
} catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
/**
*
*/
@ -93,28 +104,32 @@ public class ControlFlowGraphTest extends CodanTestCase {
assertNotNull(graph);
assertNotNull(graph.getStartNode());
Collection<IBasicBlock> nodes = graph.getNodes();
for (Iterator<IBasicBlock> iterator = nodes.iterator(); iterator.hasNext();) {
IBasicBlock node = iterator.next();
for (Iterator<IBasicBlock> iterator = nodes.iterator(); iterator
.hasNext();) {
IBasicBlock node = iterator.next();
checkNode(node);
}
}
/**
* @param node
*/
private void checkNode(IBasicBlock node) {
for (Iterator<IBasicBlock> iterator = node.getIncomingIterator(); iterator.hasNext();) {
for (Iterator<IBasicBlock> iterator = node.getIncomingIterator(); iterator
.hasNext();) {
IBasicBlock b = iterator.next();
if (!contains(node, b.getOutgoingIterator()))
fail("Block "+node+" inconsitent prev/next "+b);
fail("Block " + node + " inconsitent prev/next " + b);
}
for (Iterator<IBasicBlock> iterator = node.getOutgoingIterator(); iterator.hasNext();) {
for (Iterator<IBasicBlock> iterator = node.getOutgoingIterator(); iterator
.hasNext();) {
IBasicBlock b = iterator.next();
if (!contains(node, b.getIncomingIterator()))
fail("Block "+node+" inconsitent next/prev "+b);
fail("Block " + node + " inconsitent next/prev " + b);
}
if (node instanceof IDecisionNode) {
assertTrue("decision node outgping size",node.getOutgoingSize()>1);
assertTrue("decision node outgping size",
node.getOutgoingSize() > 1);
assertNotNull(((IDecisionNode) node).getMergeNode());
}
}
@ -124,15 +139,62 @@ public class ControlFlowGraphTest extends CodanTestCase {
* @param outgoingIterator
* @return
*/
private boolean contains(IBasicBlock node,
Iterator<IBasicBlock> iterator) {
private boolean contains(IBasicBlock node, Iterator<IBasicBlock> iterator) {
for (; iterator.hasNext();) {
IBasicBlock b = iterator.next();
if (b.equals(node)) return true;
if (b.equals(node))
return true;
}
return false;
}
/**
* @param file
*/
protected void buildAndCheck(String file) {
load(file);
buildCfg();
checkCfg();
}
/**
* @param des
* @return
*/
private String data(IBasicBlock des) {
return ((AbstractBasicBlock) des).toStringData();
}
/**
* Return first node after the branch
*
* @param des
* @return
*/
private IBasicBlock branchEnd(IDecisionNode des, String label) {
for (Iterator<IBasicBlock> iterator = des.getOutgoingIterator(); iterator
.hasNext();) {
IBranchNode bn = (IBranchNode) iterator.next();
if (label.equals(bn.getLabel()))
return bn.getOutgoing();
}
return null;
}
/**
* Return node where control jumps, following the chain until jump is hit
*
* @param a
* @return
*/
private IBasicBlock jumpEnd(IBasicBlock a) {
if (a instanceof IJumpNode)
return ((IJumpNode) a).getOutgoing();
if (a instanceof ISingleOutgoing)
return jumpEnd(((ISingleOutgoing) a).getOutgoing());
return null;
}
/*-
<code file="test1.c">
main() {
@ -141,11 +203,8 @@ public class ControlFlowGraphTest extends CodanTestCase {
}
</code>
*/
public void test1() {
load("test1.c");
buildCfg();
checkCfg();
public void test_basic() {
buildAndCheck("test1.c");
}
/*-
@ -159,10 +218,110 @@ public class ControlFlowGraphTest extends CodanTestCase {
</code>
*/
public void test_while() {
load("test2.c");
buildCfg();
checkCfg();
buildAndCheck("test2.c");
IStartNode startNode = graph.getStartNode();
IPlainNode decl = (IPlainNode) startNode.getOutgoing();
IConnectorNode conn = (IConnectorNode) decl.getOutgoing();
IDecisionNode des = (IDecisionNode) conn.getOutgoing();
assertEquals("a--", data(des));
IPlainNode bThen = (IPlainNode) branchEnd(des, IBranchNode.THEN);
assertEquals("a=a-2;", data(bThen));
IBasicBlock bElse = branchEnd(des, IBranchNode.ELSE);
IBasicBlock m2 = jumpEnd(bThen);
IBasicBlock m1 = jumpEnd(bElse);
assertSame(conn, m2);
IExitNode ret = (IExitNode) ((IConnectorNode) m1).getOutgoing();
}
/*-
<code file="test3.c">
main() {
int a=10;
if (a--) {
a=a-2;
}
}
</code>
*/
public void test_if() {
buildAndCheck("test3.c");
IStartNode startNode = graph.getStartNode();
IPlainNode decl = (IPlainNode) startNode.getOutgoing();
IDecisionNode des = (IDecisionNode) decl.getOutgoing();
assertEquals("a--", data(des));
IPlainNode bThen = (IPlainNode) branchEnd(des, IBranchNode.THEN);
assertEquals("a=a-2;", data(bThen));
IBasicBlock bElse = branchEnd(des, IBranchNode.ELSE);
IBasicBlock m2 = jumpEnd(bThen);
IBasicBlock m1 = jumpEnd(bElse);
assertSame(m1, m2);
}
/*-
<code file="test4.c">
main() {
int a=10;
if (a--) {
return;
}
}
</code>
*/
public void test_if_ret() {
buildAndCheck("test4.c");
IStartNode startNode = graph.getStartNode();
IPlainNode decl = (IPlainNode) startNode.getOutgoing();
IDecisionNode des = (IDecisionNode) decl.getOutgoing();
assertEquals("a--", data(des));
IExitNode bThen = (IExitNode) branchEnd(des, IBranchNode.THEN);
IBasicBlock bElse = branchEnd(des, IBranchNode.ELSE);
IBasicBlock m1 = jumpEnd(bElse);
}
/*-
<code file="test5.c">
main() {
int a=10;
if (a--) {
return;
a++;
}
}
</code>
*/
public void test_if_dead() {
buildAndCheck("test5.c");
IStartNode startNode = graph.getStartNode();
IPlainNode decl = (IPlainNode) startNode.getOutgoing();
IDecisionNode des = (IDecisionNode) decl.getOutgoing();
assertEquals("a--", data(des));
IExitNode bThen = (IExitNode) branchEnd(des, IBranchNode.THEN);
IBasicBlock bElse = branchEnd(des, IBranchNode.ELSE);
IBasicBlock m1 = jumpEnd(bElse);
assertEquals(1,graph.getUnconnectedNodeSize());
}
/*-
<code file="test_ifif.c">
foo() {
int a=10, x=5;
if (a--) {
if (x<0)
a++;
}
}
</code>
*/
public void test_ifif() {
buildAndCheck("test_ifif.c");
IStartNode startNode = graph.getStartNode();
IPlainNode decl = (IPlainNode) startNode.getOutgoing();
IDecisionNode des = (IDecisionNode) decl.getOutgoing();
assertEquals("a--", data(des));
IDecisionNode bThen = (IDecisionNode) branchEnd(des, IBranchNode.THEN);
assertEquals("x<0", data(bThen));
IBasicBlock bElse = branchEnd(des, IBranchNode.ELSE);
IBasicBlock m2 = jumpEnd(branchEnd(bThen,IBranchNode.THEN));
IBasicBlock m1 = jumpEnd(bElse);
IBasicBlock m3 = jumpEnd(m2);
assertSame(m1, m3);
}
}

View file

@ -44,7 +44,7 @@ public abstract class AbstractBasicBlock implements IBasicBlock {
*/
public String toStringData() {
if (getData() == null)
return "";
return "0x" + Integer.toHexString(System.identityHashCode(this));
return getData().toString();
}

View file

@ -18,11 +18,11 @@ import java.util.LinkedHashSet;
import java.util.List;
import org.eclipse.cdt.codan.provisional.core.model.cfg.IBasicBlock;
import org.eclipse.cdt.codan.provisional.core.model.cfg.IBranchNode;
import org.eclipse.cdt.codan.provisional.core.model.cfg.IConnectorNode;
import org.eclipse.cdt.codan.provisional.core.model.cfg.IControlFlowGraph;
import org.eclipse.cdt.codan.provisional.core.model.cfg.IDecisionNode;
import org.eclipse.cdt.codan.provisional.core.model.cfg.IExitNode;
import org.eclipse.cdt.codan.provisional.core.model.cfg.IBranchNode;
import org.eclipse.cdt.codan.provisional.core.model.cfg.ISingleOutgoing;
import org.eclipse.cdt.codan.provisional.core.model.cfg.IStartNode;
@ -55,6 +55,11 @@ public class ControlFlowGraph implements IControlFlowGraph {
exitNodes));
}
public void setUnconnectedNodes(Collection<IBasicBlock> nodes) {
this.deadNodes = Collections
.unmodifiableList(new ArrayList<IBasicBlock>(nodes));
}
/*
* (non-Javadoc)
*
@ -97,8 +102,7 @@ public class ControlFlowGraph implements IControlFlowGraph {
* getUnconnectedNodeIterator()
*/
public Iterator<IBasicBlock> getUnconnectedNodeIterator() {
// TODO Auto-generated method stub
return null;
return deadNodes.iterator();
}
/*
@ -108,8 +112,7 @@ public class ControlFlowGraph implements IControlFlowGraph {
* getUnconnectedNodeSize()
*/
public int getUnconnectedNodeSize() {
// TODO Auto-generated method stub
return 0;
return deadNodes.size();
}
/*

View file

@ -22,7 +22,7 @@ public interface INodeFactory {
IConnectorNode createConnectorNode();
IBranchNode createLabeledNode(String label);
IBranchNode createBranchNode(String label);
IStartNode createStartNode();

View file

@ -101,7 +101,7 @@ public class NodeFactory implements INodeFactory {
return new ExitNode();
}
public IBranchNode createLabeledNode(String label) {
public IBranchNode createBranchNode(String label) {
return new BranchNode(label);
}
}

View file

@ -171,12 +171,10 @@ 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());
}
if (obj instanceof IConnectorNode) {
strdata = blockHexLabel(obj) ;
} else if (obj instanceof IJumpNode) {
strdata = "jump to "+blockHexLabel(((IJumpNode) obj).getJumpNode());
}
return obj.getClass().getSimpleName() + ": " + strdata;
}