mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-08-06 15:55:47 +02:00
- added more tests and support for goto/label statements
This commit is contained in:
parent
0f78d0c5fd
commit
5a5d22c50d
8 changed files with 268 additions and 56 deletions
|
@ -12,6 +12,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 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;
|
||||||
|
@ -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.IASTExpressionStatement;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTForStatement;
|
import org.eclipse.cdt.core.dom.ast.IASTForStatement;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
|
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.IASTIfStatement;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTLabelStatement;
|
||||||
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;
|
||||||
|
@ -52,6 +55,7 @@ public class ControlFlowGraphBuilder {
|
||||||
CxxNodeFactory factory = new CxxNodeFactory();
|
CxxNodeFactory factory = new CxxNodeFactory();
|
||||||
IConnectorNode outerBreak;
|
IConnectorNode outerBreak;
|
||||||
IConnectorNode outerContinue;
|
IConnectorNode outerContinue;
|
||||||
|
HashMap<String, IBasicBlock> labels = new HashMap<String, IBasicBlock>(0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param def
|
* @param def
|
||||||
|
@ -68,7 +72,9 @@ public class ControlFlowGraphBuilder {
|
||||||
returnExit.setStartNode(start);
|
returnExit.setStartNode(start);
|
||||||
addOutgoing(last, returnExit);
|
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;
|
return prev;
|
||||||
} else if (body instanceof IASTSwitchStatement) {
|
} else if (body instanceof IASTSwitchStatement) {
|
||||||
return createSwitch(prev, (IASTSwitchStatement) body);
|
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;
|
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 prev
|
||||||
* @param body
|
* @param body
|
||||||
|
@ -127,11 +176,11 @@ public class ControlFlowGraphBuilder {
|
||||||
addOutgoing(prev, ifNode);
|
addOutgoing(prev, ifNode);
|
||||||
IConnectorNode mergeNode = factory.createConnectorNode();
|
IConnectorNode mergeNode = factory.createConnectorNode();
|
||||||
ifNode.setMergeNode(mergeNode);
|
ifNode.setMergeNode(mergeNode);
|
||||||
IBranchNode thenNode = factory.createLabeledNode(IBranchNode.THEN);
|
IBranchNode thenNode = factory.createBranchNode(IBranchNode.THEN);
|
||||||
addOutgoing(ifNode, thenNode);
|
addOutgoing(ifNode, thenNode);
|
||||||
IBasicBlock then = createSubGraph(thenNode, body.getThenClause());
|
IBasicBlock then = createSubGraph(thenNode, body.getThenClause());
|
||||||
addJump(then, mergeNode);
|
addJump(then, mergeNode);
|
||||||
IBranchNode elseNode = factory.createLabeledNode(IBranchNode.ELSE);
|
IBranchNode elseNode = factory.createBranchNode(IBranchNode.ELSE);
|
||||||
addOutgoing(ifNode, elseNode);
|
addOutgoing(ifNode, elseNode);
|
||||||
IBasicBlock els = createSubGraph(elseNode, body.getElseClause());
|
IBasicBlock els = createSubGraph(elseNode, body.getElseClause());
|
||||||
addJump(els, mergeNode);
|
addJump(els, mergeNode);
|
||||||
|
@ -173,7 +222,7 @@ public class ControlFlowGraphBuilder {
|
||||||
}
|
}
|
||||||
if (elem instanceof IASTDefaultStatement) {
|
if (elem instanceof IASTDefaultStatement) {
|
||||||
IBranchNode lbl = factory
|
IBranchNode lbl = factory
|
||||||
.createLabeledNode(IBranchNode.DEFAULT);
|
.createBranchNode(IBranchNode.DEFAULT);
|
||||||
if (!(prev instanceof IExitNode) && prev != switchNode)
|
if (!(prev instanceof IExitNode) && prev != switchNode)
|
||||||
addOutgoing(prev, lbl);
|
addOutgoing(prev, lbl);
|
||||||
addOutgoing(switchNode, lbl);
|
addOutgoing(switchNode, lbl);
|
||||||
|
@ -185,9 +234,9 @@ public class ControlFlowGraphBuilder {
|
||||||
IBranchNode lbl = null;
|
IBranchNode lbl = null;
|
||||||
if (elem instanceof IASTCaseStatement) {
|
if (elem instanceof IASTCaseStatement) {
|
||||||
IASTCaseStatement caseSt = (IASTCaseStatement) elem;
|
IASTCaseStatement caseSt = (IASTCaseStatement) elem;
|
||||||
lbl = factory.createLabeledNode(caseSt);
|
lbl = factory.createBranchNode(caseSt);
|
||||||
} else if (elem instanceof IASTDefaultStatement) {
|
} else if (elem instanceof IASTDefaultStatement) {
|
||||||
lbl = factory.createLabeledNode(IBranchNode.DEFAULT);
|
lbl = factory.createBranchNode(IBranchNode.DEFAULT);
|
||||||
}
|
}
|
||||||
if (!(prev instanceof IExitNode) && prev != switchNode) {
|
if (!(prev instanceof IExitNode) && prev != switchNode) {
|
||||||
IConnectorNode here = factory.createConnectorNode();
|
IConnectorNode here = factory.createConnectorNode();
|
||||||
|
@ -231,7 +280,7 @@ public class ControlFlowGraphBuilder {
|
||||||
IConnectorNode nBreak = factory.createConnectorNode();
|
IConnectorNode nBreak = factory.createConnectorNode();
|
||||||
decision.setMergeNode(nBreak);
|
decision.setMergeNode(nBreak);
|
||||||
// create body and jump to continue node
|
// create body and jump to continue node
|
||||||
IBranchNode loopStart = factory.createLabeledNode(IBranchNode.THEN);
|
IBranchNode loopStart = factory.createBranchNode(IBranchNode.THEN);
|
||||||
addOutgoing(decision, loopStart);
|
addOutgoing(decision, loopStart);
|
||||||
// set break/continue
|
// set break/continue
|
||||||
IConnectorNode nContinue = factory.createConnectorNode();
|
IConnectorNode nContinue = factory.createConnectorNode();
|
||||||
|
@ -250,7 +299,7 @@ public class ControlFlowGraphBuilder {
|
||||||
// connect with backward link
|
// connect with backward link
|
||||||
addJump(inc, beforeCheck, true);
|
addJump(inc, beforeCheck, true);
|
||||||
// add "else" branch
|
// add "else" branch
|
||||||
IBranchNode loopEnd = factory.createLabeledNode(IBranchNode.ELSE);
|
IBranchNode loopEnd = factory.createBranchNode(IBranchNode.ELSE);
|
||||||
addOutgoing(decision, loopEnd);
|
addOutgoing(decision, loopEnd);
|
||||||
addJump(loopEnd, nBreak);
|
addJump(loopEnd, nBreak);
|
||||||
return nBreak;
|
return nBreak;
|
||||||
|
@ -273,7 +322,7 @@ public class ControlFlowGraphBuilder {
|
||||||
IConnectorNode nBreak = factory.createConnectorNode();
|
IConnectorNode nBreak = factory.createConnectorNode();
|
||||||
decision.setMergeNode(nBreak);
|
decision.setMergeNode(nBreak);
|
||||||
// create body and jump to continue node
|
// create body and jump to continue node
|
||||||
IBranchNode loopStart = factory.createLabeledNode(IBranchNode.THEN);
|
IBranchNode loopStart = factory.createBranchNode(IBranchNode.THEN);
|
||||||
addOutgoing(decision, loopStart);
|
addOutgoing(decision, loopStart);
|
||||||
// set break/continue
|
// set break/continue
|
||||||
IConnectorNode savedContinue = outerContinue;
|
IConnectorNode savedContinue = outerContinue;
|
||||||
|
@ -287,7 +336,7 @@ public class ControlFlowGraphBuilder {
|
||||||
// backward jump
|
// backward jump
|
||||||
addJump(endBody, nContinue, true);
|
addJump(endBody, nContinue, true);
|
||||||
// connect with else branch
|
// connect with else branch
|
||||||
IBranchNode loopEnd = factory.createLabeledNode(IBranchNode.ELSE);
|
IBranchNode loopEnd = factory.createBranchNode(IBranchNode.ELSE);
|
||||||
addOutgoing(decision, loopEnd);
|
addOutgoing(decision, loopEnd);
|
||||||
addJump(loopEnd, nBreak);
|
addJump(loopEnd, nBreak);
|
||||||
return nBreak;
|
return nBreak;
|
||||||
|
@ -315,7 +364,7 @@ public class ControlFlowGraphBuilder {
|
||||||
.getCondition());
|
.getCondition());
|
||||||
addOutgoing(nContinue, decision);
|
addOutgoing(nContinue, decision);
|
||||||
// then branch
|
// then branch
|
||||||
IBranchNode thenNode = factory.createLabeledNode(IBranchNode.THEN);
|
IBranchNode thenNode = factory.createBranchNode(IBranchNode.THEN);
|
||||||
addOutgoing(decision, thenNode);
|
addOutgoing(decision, thenNode);
|
||||||
IJumpNode jumpToStart = factory.createJumpNode();
|
IJumpNode jumpToStart = factory.createJumpNode();
|
||||||
addOutgoing(thenNode, jumpToStart);
|
addOutgoing(thenNode, jumpToStart);
|
||||||
|
@ -323,7 +372,7 @@ public class ControlFlowGraphBuilder {
|
||||||
// connect with backward link
|
// connect with backward link
|
||||||
addOutgoing(jumpToStart, loopStart);
|
addOutgoing(jumpToStart, loopStart);
|
||||||
// connect with else branch
|
// connect with else branch
|
||||||
IBranchNode loopEnd = factory.createLabeledNode(IBranchNode.ELSE);
|
IBranchNode loopEnd = factory.createBranchNode(IBranchNode.ELSE);
|
||||||
addOutgoing(decision, loopEnd);
|
addOutgoing(decision, loopEnd);
|
||||||
// add break connector
|
// add break connector
|
||||||
decision.setMergeNode(nBreak);
|
decision.setMergeNode(nBreak);
|
||||||
|
@ -339,6 +388,8 @@ public class ControlFlowGraphBuilder {
|
||||||
boolean backward) {
|
boolean backward) {
|
||||||
if (prev instanceof IJumpNode)
|
if (prev instanceof IJumpNode)
|
||||||
return (IJumpNode) prev;
|
return (IJumpNode) prev;
|
||||||
|
if (prev instanceof IExitNode)
|
||||||
|
return null;
|
||||||
IJumpNode jump = factory.createJumpNode();
|
IJumpNode jump = factory.createJumpNode();
|
||||||
addOutgoing(prev, jump);
|
addOutgoing(prev, jump);
|
||||||
addOutgoing(jump, conn);
|
addOutgoing(jump, conn);
|
||||||
|
@ -351,12 +402,13 @@ public class ControlFlowGraphBuilder {
|
||||||
* @param node
|
* @param node
|
||||||
*/
|
*/
|
||||||
private void addOutgoing(IBasicBlock prev, IBasicBlock node) {
|
private void addOutgoing(IBasicBlock prev, IBasicBlock node) {
|
||||||
if (!(node instanceof IStartNode))
|
if (prev instanceof IExitNode || prev == null) {
|
||||||
((AbstractBasicBlock) node).addIncoming(prev);
|
|
||||||
if (prev instanceof IExitNode) {
|
|
||||||
dead.add(node);
|
dead.add(node);
|
||||||
|
return;
|
||||||
} else if (prev instanceof AbstractBasicBlock) {
|
} else if (prev instanceof AbstractBasicBlock) {
|
||||||
((AbstractBasicBlock) prev).addOutgoing(node);
|
((AbstractBasicBlock) prev).addOutgoing(node);
|
||||||
}
|
}
|
||||||
|
if (!(node instanceof IStartNode))
|
||||||
|
((AbstractBasicBlock) node).addIncoming(prev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,8 +61,8 @@ public class CxxNodeFactory extends NodeFactory implements INodeFactory {
|
||||||
* @param caseSt
|
* @param caseSt
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public IBranchNode createLabeledNode(IASTNode caseSt) {
|
public IBranchNode createBranchNode(IASTNode caseSt) {
|
||||||
IBranchNode node = createLabeledNode(caseSt.getRawSignature());
|
IBranchNode node = createBranchNode(caseSt.getRawSignature());
|
||||||
((AbstractBasicBlock) node).setData(caseSt);
|
((AbstractBasicBlock) node).setData(caseSt);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.cxx.internal.model.cfg.ControlFlowGraphBuilder;
|
||||||
import org.eclipse.cdt.codan.core.test.CodanTestCase;
|
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.internal.core.cfg.ControlFlowGraph;
|
||||||
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.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.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.CCorePlugin;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
|
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
|
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
|
||||||
|
@ -36,6 +44,7 @@ import org.eclipse.core.runtime.CoreException;
|
||||||
*/
|
*/
|
||||||
public class ControlFlowGraphTest extends CodanTestCase {
|
public class ControlFlowGraphTest extends CodanTestCase {
|
||||||
ControlFlowGraph graph;
|
ControlFlowGraph graph;
|
||||||
|
|
||||||
void processFile(IFile file) throws CoreException, InterruptedException {
|
void processFile(IFile file) throws CoreException, InterruptedException {
|
||||||
// create translation unit and access index
|
// create translation unit and access index
|
||||||
ICElement model = CoreModel.getDefault().create(file);
|
ICElement model = CoreModel.getDefault().create(file);
|
||||||
|
@ -64,28 +73,30 @@ public class ControlFlowGraphTest extends CodanTestCase {
|
||||||
{
|
{
|
||||||
shouldVisitDeclarations = true;
|
shouldVisitDeclarations = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int visit(IASTDeclaration decl) {
|
public int visit(IASTDeclaration decl) {
|
||||||
if (decl instanceof IASTFunctionDefinition) {
|
if (decl instanceof IASTFunctionDefinition) {
|
||||||
graph = new ControlFlowGraphBuilder().build((IASTFunctionDefinition) decl);
|
graph = new ControlFlowGraphBuilder()
|
||||||
|
.build((IASTFunctionDefinition) decl);
|
||||||
return PROCESS_ABORT;
|
return PROCESS_ABORT;
|
||||||
}
|
}
|
||||||
return PROCESS_CONTINUE;
|
return PROCESS_CONTINUE;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
ast.accept(visitor);
|
ast.accept(visitor);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void buildCfg() {
|
void buildCfg() {
|
||||||
try {
|
try {
|
||||||
|
IResource el = cproject.getProject().findMember(
|
||||||
IResource el = cproject.getProject().findMember(currentFile.getName());
|
currentFile.getName());
|
||||||
processFile((IFile) el);
|
processFile((IFile) el);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
fail(e.getMessage());
|
fail(e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@ -93,28 +104,32 @@ public class ControlFlowGraphTest extends CodanTestCase {
|
||||||
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.hasNext();) {
|
for (Iterator<IBasicBlock> iterator = nodes.iterator(); iterator
|
||||||
IBasicBlock node = iterator.next();
|
.hasNext();) {
|
||||||
|
IBasicBlock node = iterator.next();
|
||||||
checkNode(node);
|
checkNode(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param node
|
* @param node
|
||||||
*/
|
*/
|
||||||
private void checkNode(IBasicBlock 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();
|
IBasicBlock b = iterator.next();
|
||||||
if (!contains(node, b.getOutgoingIterator()))
|
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();
|
IBasicBlock b = iterator.next();
|
||||||
if (!contains(node, b.getIncomingIterator()))
|
if (!contains(node, b.getIncomingIterator()))
|
||||||
fail("Block "+node+" inconsitent next/prev "+b);
|
fail("Block " + node + " inconsitent next/prev " + b);
|
||||||
}
|
}
|
||||||
if (node instanceof IDecisionNode) {
|
if (node instanceof IDecisionNode) {
|
||||||
assertTrue("decision node outgping size",node.getOutgoingSize()>1);
|
assertTrue("decision node outgping size",
|
||||||
|
node.getOutgoingSize() > 1);
|
||||||
assertNotNull(((IDecisionNode) node).getMergeNode());
|
assertNotNull(((IDecisionNode) node).getMergeNode());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -124,15 +139,62 @@ public class ControlFlowGraphTest extends CodanTestCase {
|
||||||
* @param outgoingIterator
|
* @param outgoingIterator
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private boolean contains(IBasicBlock node,
|
private boolean contains(IBasicBlock node, Iterator<IBasicBlock> iterator) {
|
||||||
Iterator<IBasicBlock> iterator) {
|
|
||||||
for (; iterator.hasNext();) {
|
for (; iterator.hasNext();) {
|
||||||
IBasicBlock b = iterator.next();
|
IBasicBlock b = iterator.next();
|
||||||
if (b.equals(node)) return true;
|
if (b.equals(node))
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
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">
|
<code file="test1.c">
|
||||||
main() {
|
main() {
|
||||||
|
@ -141,11 +203,8 @@ public class ControlFlowGraphTest extends CodanTestCase {
|
||||||
}
|
}
|
||||||
</code>
|
</code>
|
||||||
*/
|
*/
|
||||||
public void test1() {
|
public void test_basic() {
|
||||||
load("test1.c");
|
buildAndCheck("test1.c");
|
||||||
buildCfg();
|
|
||||||
checkCfg();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
|
@ -159,10 +218,110 @@ public class ControlFlowGraphTest extends CodanTestCase {
|
||||||
</code>
|
</code>
|
||||||
*/
|
*/
|
||||||
public void test_while() {
|
public void test_while() {
|
||||||
load("test2.c");
|
buildAndCheck("test2.c");
|
||||||
buildCfg();
|
IStartNode startNode = graph.getStartNode();
|
||||||
checkCfg();
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,7 @@ public abstract class AbstractBasicBlock implements IBasicBlock {
|
||||||
*/
|
*/
|
||||||
public String toStringData() {
|
public String toStringData() {
|
||||||
if (getData() == null)
|
if (getData() == null)
|
||||||
return "";
|
return "0x" + Integer.toHexString(System.identityHashCode(this));
|
||||||
return getData().toString();
|
return getData().toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,11 +18,11 @@ import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
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.IBranchNode;
|
||||||
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.IControlFlowGraph;
|
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.IDecisionNode;
|
||||||
import org.eclipse.cdt.codan.provisional.core.model.cfg.IExitNode;
|
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.ISingleOutgoing;
|
||||||
import org.eclipse.cdt.codan.provisional.core.model.cfg.IStartNode;
|
import org.eclipse.cdt.codan.provisional.core.model.cfg.IStartNode;
|
||||||
|
|
||||||
|
@ -55,6 +55,11 @@ public class ControlFlowGraph implements IControlFlowGraph {
|
||||||
exitNodes));
|
exitNodes));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setUnconnectedNodes(Collection<IBasicBlock> nodes) {
|
||||||
|
this.deadNodes = Collections
|
||||||
|
.unmodifiableList(new ArrayList<IBasicBlock>(nodes));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
*
|
*
|
||||||
|
@ -97,8 +102,7 @@ public class ControlFlowGraph implements IControlFlowGraph {
|
||||||
* getUnconnectedNodeIterator()
|
* getUnconnectedNodeIterator()
|
||||||
*/
|
*/
|
||||||
public Iterator<IBasicBlock> getUnconnectedNodeIterator() {
|
public Iterator<IBasicBlock> getUnconnectedNodeIterator() {
|
||||||
// TODO Auto-generated method stub
|
return deadNodes.iterator();
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -108,8 +112,7 @@ public class ControlFlowGraph implements IControlFlowGraph {
|
||||||
* getUnconnectedNodeSize()
|
* getUnconnectedNodeSize()
|
||||||
*/
|
*/
|
||||||
public int getUnconnectedNodeSize() {
|
public int getUnconnectedNodeSize() {
|
||||||
// TODO Auto-generated method stub
|
return deadNodes.size();
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -22,7 +22,7 @@ public interface INodeFactory {
|
||||||
|
|
||||||
IConnectorNode createConnectorNode();
|
IConnectorNode createConnectorNode();
|
||||||
|
|
||||||
IBranchNode createLabeledNode(String label);
|
IBranchNode createBranchNode(String label);
|
||||||
|
|
||||||
IStartNode createStartNode();
|
IStartNode createStartNode();
|
||||||
|
|
||||||
|
|
|
@ -101,7 +101,7 @@ public class NodeFactory implements INodeFactory {
|
||||||
return new ExitNode();
|
return new ExitNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IBranchNode createLabeledNode(String label) {
|
public IBranchNode createBranchNode(String label) {
|
||||||
return new BranchNode(label);
|
return new BranchNode(label);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -171,12 +171,10 @@ 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) {
|
||||||
if (obj instanceof IConnectorNode) {
|
strdata = blockHexLabel(obj) ;
|
||||||
strdata = blockHexLabel(obj);
|
} else if (obj instanceof IJumpNode) {
|
||||||
} else if (obj instanceof IJumpNode) {
|
strdata = "jump to "+blockHexLabel(((IJumpNode) obj).getJumpNode());
|
||||||
strdata = blockHexLabel(((IJumpNode) obj).getJumpNode());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return obj.getClass().getSimpleName() + ": " + strdata;
|
return obj.getClass().getSimpleName() + ": " + strdata;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue