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 9fb9923788a..b9c7608133e 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 @@ -12,6 +12,7 @@ package org.eclipse.cdt.codan.core.cxx.internal.model.cfg; import java.util.ArrayList; 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; @@ -21,8 +22,11 @@ import org.eclipse.cdt.codan.provisional.core.model.cfg.IConnectorNode; import org.eclipse.cdt.codan.provisional.core.model.cfg.IExitNode; import org.eclipse.cdt.codan.provisional.core.model.cfg.IPlainNode; import org.eclipse.cdt.codan.provisional.core.model.cfg.IStartNode; +import org.eclipse.cdt.core.dom.ast.IASTBreakStatement; +import org.eclipse.cdt.core.dom.ast.IASTCaseStatement; import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement; import org.eclipse.cdt.core.dom.ast.IASTDeclarationStatement; +import org.eclipse.cdt.core.dom.ast.IASTDefaultStatement; import org.eclipse.cdt.core.dom.ast.IASTExpressionStatement; import org.eclipse.cdt.core.dom.ast.IASTForStatement; import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition; @@ -30,6 +34,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.IASTSwitchStatement; import org.eclipse.cdt.core.dom.ast.IASTWhileStatement; /** @@ -79,79 +84,174 @@ public class ControlFlowGraphBuilder { addOutgoing(prev, node); return node; } else if (body instanceof IASTIfStatement) { - DecisionNode node = factory.createDecisionNode( - ((IASTIfStatement) body).getConditionExpression()); - addOutgoing(prev, node); - ConnectorNode conn = new ConnectorNode(); - node.setConnectorNode(conn); - IBasicBlock els = createSubGraph(node, ((IASTIfStatement) body) - .getElseClause()); - conn.addIncoming(els); - addOutgoing(els, conn); - IBasicBlock then = createSubGraph(node, ((IASTIfStatement) body) - .getThenClause()); - conn.addIncoming(then); - addOutgoing(then, conn); - return conn; + return createIf(prev, (IASTIfStatement) body); } else if (body instanceof IASTWhileStatement) { - // add continue connector - IConnectorNode nContinue = factory.createConnectorNode(); - addOutgoing(prev, nContinue); - // decision node - CxxDecisionNode decision = factory.createDecisionNode( - ((IASTWhileStatement) body).getCondition()); - addOutgoing(nContinue, decision); - // add break connector - IConnectorNode nBreak = factory.createConnectorNode(); - addOutgoing(decision, nBreak); - decision.setConnectorNode(nBreak); - // create body and jump to continue node - IBasicBlock nBody = createSubGraph(decision, - ((IASTWhileStatement) body).getBody()); - JumpNode jumpContinue = new JumpNode(); - addOutgoing(nBody, jumpContinue); - jumpContinue.setJump(nContinue, true); - // connect with backward link - addOutgoing(jumpContinue, nContinue); - - return nBreak; + return createWhile(prev, (IASTWhileStatement) body); } else if (body instanceof IASTForStatement) { - // add initializer - IPlainNode init = factory.createPlainNode(((IASTForStatement) body).getInitializerStatement()); - addOutgoing(prev, init); - prev = init; - // add continue connector - IConnectorNode nContinue2 = factory.createConnectorNode(); - addOutgoing(prev, nContinue2); - // decision node - CxxDecisionNode decision = factory.createDecisionNode( - ((IASTForStatement) body).getConditionExpression()); - addOutgoing(nContinue2, decision); - // add break connector - IConnectorNode nBreak = factory.createConnectorNode(); - addOutgoing(decision, nBreak); - decision.setConnectorNode(nBreak); - // create body and jump to continue node - IBasicBlock nBody = createSubGraph(decision, - ((IASTForStatement) body).getBody()); - // inc - IPlainNode inc = factory.createPlainNode(((IASTForStatement) body).getIterationExpression()); - addOutgoing(nBody, inc); - JumpNode jumpContinue = new JumpNode(); - addOutgoing(inc, jumpContinue); - jumpContinue.setJump(nContinue2, true); - // connect with backward link - addOutgoing(jumpContinue, nContinue2); - return nBreak; + return createFor(prev, (IASTForStatement) body); } else if (body instanceof IASTReturnStatement) { CxxExitNode node = factory.createExitNode(body); node.setStartNode(start); addOutgoing(prev, node); return node; + } else if (body instanceof IASTSwitchStatement) { + return createSwitch(prev, (IASTSwitchStatement) body); } return prev; } + /** + * @param prev + * @param body + * @return + */ + protected IBasicBlock createIf(IBasicBlock prev, IASTIfStatement body) { + DecisionNode node = factory.createDecisionNode(body + .getConditionExpression()); + addOutgoing(prev, node); + ConnectorNode conn = new ConnectorNode(); + node.setConnectorNode(conn); + IBasicBlock els = createSubGraph(node, body.getElseClause()); + conn.addIncoming(els); + addOutgoing(els, conn); + IBasicBlock then = createSubGraph(node, body.getThenClause()); + conn.addIncoming(then); + addOutgoing(then, conn); + return conn; + } + + /** + * @param prev + * @param body + * @return + */ + private IBasicBlock createSwitch(IBasicBlock prev, IASTSwitchStatement body) { + DecisionNode node = factory.createDecisionNode(body + .getControllerExpression()); + addOutgoing(prev, node); + ConnectorNode conn = new ConnectorNode(); + node.setConnectorNode(conn); + createSwitchBody(node, conn, body.getBody()); + return conn; + } + + /** + * @param switchNode + * @param conn + * @param def + * @param body + */ + private void createSwitchBody(DecisionNode switchNode, ConnectorNode conn, + IASTStatement body) { + if (!(body instanceof IASTCompoundStatement)) + return; // bad + IASTCompoundStatement comp = (IASTCompoundStatement) body; + IASTNode[] children = comp.getChildren(); + IBasicBlock prev = switchNode; + int labelNum = 1; + for (int i = 0; i < children.length; i++) { + IASTNode elem = children[i]; + if (elem instanceof IASTCaseStatement) { + IASTCaseStatement caseSt = (IASTCaseStatement) elem; + IPlainNode nextSt = factory + .createPlainNode(); + if (!(prev instanceof IExitNode) && prev != switchNode) + addOutgoing(prev, nextSt); + switchNode.addOutgoing(new CxxDecisionArc(switchNode, labelNum, + nextSt, caseSt)); + labelNum++; + ((AbstractBasicBlock)nextSt).addIncoming(switchNode); + prev = nextSt; + continue; + } + if (elem instanceof IASTBreakStatement) { + JumpNode nBreak = (JumpNode) factory.createJumpNode(); + addOutgoing(prev, nBreak); + nBreak.setJump(conn, false); + conn.addIncoming(nBreak); + prev = nBreak; + continue; + } + if (elem instanceof IASTDefaultStatement) { + IASTDefaultStatement caseSt = (IASTDefaultStatement) elem; + IPlainNode nextSt = factory + .createPlainNode(); + if (!(prev instanceof IExitNode) && prev != switchNode) + addOutgoing(prev, nextSt); + switchNode.addOutgoing(new CxxDecisionArc(switchNode, 0, + nextSt, caseSt)); + ((AbstractBasicBlock)nextSt).addIncoming(switchNode); + prev = nextSt; + continue; + } + IBasicBlock last = createSubGraph(prev, elem); + prev = last; + } + } + + /** + * @param prev + * @param forNode + * @return + */ + private IBasicBlock createFor(IBasicBlock prev, IASTForStatement forNode) { + // add initializer + IPlainNode init = factory.createPlainNode(forNode + .getInitializerStatement()); + addOutgoing(prev, init); + prev = init; + // add continue connector + IConnectorNode nContinue2 = factory.createConnectorNode(); + addOutgoing(prev, nContinue2); + // decision node + CxxDecisionNode decision = factory.createDecisionNode(forNode + .getConditionExpression()); + addOutgoing(nContinue2, decision); + // add break connector + IConnectorNode nBreak = factory.createConnectorNode(); + addOutgoing(decision, nBreak); + decision.setConnectorNode(nBreak); + // create body and jump to continue node + IBasicBlock nBody = createSubGraph(decision, forNode.getBody()); + // inc + IPlainNode inc = factory.createPlainNode(forNode + .getIterationExpression()); + addOutgoing(nBody, inc); + JumpNode jumpContinue = new JumpNode(); + addOutgoing(inc, jumpContinue); + jumpContinue.setJump(nContinue2, true); + // connect with backward link + addOutgoing(jumpContinue, nContinue2); + return nBreak; + } + + /** + * @param prev + * @param body + * @return + */ + protected IBasicBlock createWhile(IBasicBlock prev, IASTWhileStatement body) { + // add continue connector + IConnectorNode nContinue = factory.createConnectorNode(); + addOutgoing(prev, nContinue); + // decision node + CxxDecisionNode decision = factory.createDecisionNode(body + .getCondition()); + addOutgoing(nContinue, decision); + // add break connector + IConnectorNode nBreak = factory.createConnectorNode(); + addOutgoing(decision, nBreak); + decision.setConnectorNode(nBreak); + // create body and jump to continue node + IBasicBlock nBody = createSubGraph(decision, body.getBody()); + JumpNode jumpContinue = new JumpNode(); + addOutgoing(nBody, jumpContinue); + jumpContinue.setJump(nContinue, true); + // connect with backward link + addOutgoing(jumpContinue, nContinue); + return nBreak; + } + /** * @param prev * @param node diff --git a/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/model/cfg/CxxDecisionArc.java b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/model/cfg/CxxDecisionArc.java new file mode 100644 index 00000000000..d15a94e4dd3 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/model/cfg/CxxDecisionArc.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * 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.DecisionArc; +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 CxxDecisionArc extends DecisionArc { + private IASTNode label; + + /** + * @param decisionNode + * @param i + * @param node + */ + public CxxDecisionArc(DecisionNode decisionNode, int i, IBasicBlock node, + IASTNode label) { + super(decisionNode, i, node); + this.label = label; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.cdt.codan.internal.core.cfg.DecisionArc#toString() + */ + @Override + public String toString() { + return label.getRawSignature(); + } +} diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/DecisionArc.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/DecisionArc.java new file mode 100644 index 00000000000..ccd1dcc8621 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/DecisionArc.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * 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.internal.core.cfg; + +import org.eclipse.cdt.codan.provisional.core.model.cfg.IBasicBlock; +import org.eclipse.cdt.codan.provisional.core.model.cfg.IDecisionArc; +import org.eclipse.cdt.codan.provisional.core.model.cfg.IDecisionNode; + +public class DecisionArc implements IDecisionArc { + private final DecisionNode decisionNode; + protected int index; + protected IBasicBlock node; + + public DecisionArc(DecisionNode decisionNode, int i, IBasicBlock node) { + this.decisionNode = decisionNode; + this.index = i; + this.node = node; + } + + public int getIndex() { + return index; + } + + public IBasicBlock getOutgoing() { + return node; + } + + public IDecisionNode getDecisionNode() { + return this.decisionNode; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return index + ""; + } +} \ No newline at end of file diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/DecisionNode.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/DecisionNode.java index 2e8d5a3b800..0b3621c46b4 100644 --- a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/DecisionNode.java +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/DecisionNode.java @@ -29,38 +29,6 @@ public class DecisionNode extends AbstractSingleIncomingNode implements private List next = new ArrayList(2); private IConnectorNode conn; - class DecisionArc implements IDecisionArc { - int index; - IBasicBlock node; - - DecisionArc(int i, IBasicBlock node) { - this.index = i; - this.node = node; - } - - public int getIndex() { - return index; - } - - public IBasicBlock getOutgoing() { - return node; - } - - public IDecisionNode getDecisionNode() { - return DecisionNode.this; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#toString() - */ - @Override - public String toString() { - return index + ""; - } - } - /** * @param prev */ @@ -75,7 +43,11 @@ public class DecisionNode extends AbstractSingleIncomingNode implements @Override public void addOutgoing(IBasicBlock node) { - DecisionArc arc = new DecisionArc(getDecisionArcSize(), node); + DecisionArc arc = new DecisionArc(this, getDecisionArcSize(), node); + next.add(arc); + } + + public void addOutgoing(IDecisionArc arc) { next.add(arc); }