diff --git a/codan/org.eclipse.cdt.codan.core.cxx/META-INF/MANIFEST.MF b/codan/org.eclipse.cdt.codan.core.cxx/META-INF/MANIFEST.MF index a0c33d23824..61e4337d87d 100644 --- a/codan/org.eclipse.cdt.codan.core.cxx/META-INF/MANIFEST.MF +++ b/codan/org.eclipse.cdt.codan.core.cxx/META-INF/MANIFEST.MF @@ -11,6 +11,7 @@ Require-Bundle: org.eclipse.core.runtime, Bundle-ActivationPolicy: lazy Export-Package: org.eclipse.cdt.codan.core.cxx, org.eclipse.cdt.codan.core.cxx.internal.model;x-friends:="org.eclipse.cdt.codan.checkers.ui,org.eclipse.cdt.codan.ui,org.eclipse.cdt.codan.ui.cxx", + org.eclipse.cdt.codan.core.cxx.internal.model.cfg;x-friends:="org.eclipse.cdt.codan.core.test", org.eclipse.cdt.codan.core.cxx.model Bundle-RequiredExecutionEnvironment: J2SE-1.5 Bundle-Vendor: Eclipse CDT 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 new file mode 100644 index 00000000000..dbd1306a1cc --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/model/cfg/ControlFlowGraphBuilder.java @@ -0,0 +1,106 @@ +/******************************************************************************* + * 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 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; +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; +import org.eclipse.cdt.core.dom.ast.IASTDeclarationStatement; +import org.eclipse.cdt.core.dom.ast.IASTExpressionStatement; +import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition; +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; + +/** + * TODO: add description + */ +public class ControlFlowGraphBuilder { + CxxStartNode start; + Collection exits; + Collection dead; + CxxExitNode returnExit; + + /** + * @param def + * @return + */ + public CxxControlFlowGraph build(IASTFunctionDefinition def) { + IASTStatement body = def.getBody(); + start = new CxxStartNode(null); + exits = new ArrayList(); + dead = new ArrayList(); + IBasicBlock last = createSubGraph(start, body); + if (!(last instanceof IExitNode)) { + returnExit = new CxxExitNode(last, start, null); + addOutgoing(last, returnExit); + } + return new CxxControlFlowGraph(start, exits); + } + + /** + * @param start2 + * @param body + */ + private IBasicBlock createSubGraph(IBasicBlock prev, IASTNode body) { + if (body instanceof IASTCompoundStatement) { + IASTCompoundStatement comp = (IASTCompoundStatement) body; + IASTNode[] children = comp.getChildren(); + for (int i = 0; i < children.length; i++) { + IASTNode node = children[i]; + IBasicBlock last = createSubGraph(prev, node); + prev = last; + } + } else if (body instanceof IASTExpressionStatement + || body instanceof IASTDeclarationStatement) { + CxxPlainNode node = new CxxPlainNode(prev, body); + addOutgoing(prev, node); + return node; + } else if (body instanceof IASTIfStatement) { + DecisionNode node = new DecisionNode(prev); + 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; + } else if (body instanceof IASTReturnStatement) { + CxxExitNode node = new CxxExitNode(prev, start, body); + addOutgoing(prev, node); + return node; + } + return prev; + } + + /** + * @param prev + * @param node + */ + private void addOutgoing(IBasicBlock prev, IBasicBlock node) { + if (prev instanceof IExitNode) { + dead.add(node); + } else if (prev instanceof AbstractBasicBlock) { + ((AbstractBasicBlock) prev).addOutgoing(node); + } + } +} diff --git a/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/model/cfg/CxxControlFlowGraph.java b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/model/cfg/CxxControlFlowGraph.java new file mode 100644 index 00000000000..f9386e20704 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/model/cfg/CxxControlFlowGraph.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * 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 java.util.Collection; + +import org.eclipse.cdt.codan.internal.core.cfg.ControlFlowGraph; +import org.eclipse.cdt.codan.provisional.core.model.cfg.IExitNode; +import org.eclipse.cdt.codan.provisional.core.model.cfg.IStartNode; +import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition; + +/** + * TODO: add description + */ +public class CxxControlFlowGraph extends ControlFlowGraph { + /** + * @param start + * @param exitNodes + */ + public CxxControlFlowGraph(IStartNode start, Collection exitNodes) { + super(start, exitNodes); + } + + public static CxxControlFlowGraph build(IASTFunctionDefinition def) { + return new ControlFlowGraphBuilder().build(def); + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + // TODO Auto-generated method stub + return super.toString(); + } + +} diff --git a/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/model/cfg/CxxExitNode.java b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/model/cfg/CxxExitNode.java new file mode 100644 index 00000000000..5a4c5562d64 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/model/cfg/CxxExitNode.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * 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.ExitNode; +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.IStartNode; +import org.eclipse.cdt.core.dom.ast.IASTNode; + +/** + * TODO: add description + */ +public class CxxExitNode extends ExitNode implements IExitNode { + /** + * @param prev + * @param start + */ + public CxxExitNode(IBasicBlock prev, IStartNode start, IASTNode node) { + super(prev, start); + setNode(node); + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + if (getNode()!=null) + return getNode().getRawSignature(); + return "return; // fake"; + } + + /** + * @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/CxxPlainNode.java b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/model/cfg/CxxPlainNode.java new file mode 100644 index 00000000000..8cef5c65c3b --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/model/cfg/CxxPlainNode.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.PlainNode; +import org.eclipse.cdt.codan.provisional.core.model.cfg.IBasicBlock; +import org.eclipse.cdt.core.dom.ast.IASTNode; + +/** + * TODO: add description + */ +public class CxxPlainNode extends PlainNode { + + + /** + * @param prev + * @param body + */ + public CxxPlainNode(IBasicBlock prev, IASTNode body) { + super(prev, null); + this.setNode(body); + } + + /* (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 new file mode 100644 index 00000000000..012fc825008 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/internal/model/cfg/CxxStartNode.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * 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.StartNode; +import org.eclipse.cdt.codan.provisional.core.model.cfg.IBasicBlock; + +/** + * TODO: add description + */ +public class CxxStartNode extends StartNode { + + /** + * @param next + */ + public CxxStartNode(IBasicBlock next) { + super(next); + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return "start"; + } +} diff --git a/codan/org.eclipse.cdt.codan.core.test/META-INF/MANIFEST.MF b/codan/org.eclipse.cdt.codan.core.test/META-INF/MANIFEST.MF index 4c105898c91..55aeda2fc8e 100644 --- a/codan/org.eclipse.cdt.codan.core.test/META-INF/MANIFEST.MF +++ b/codan/org.eclipse.cdt.codan.core.test/META-INF/MANIFEST.MF @@ -10,7 +10,8 @@ Require-Bundle: org.eclipse.core.runtime, org.eclipse.core.resources;bundle-version="3.5.0", org.eclipse.cdt.core.tests, org.junit;bundle-version="3.8.2", - org.eclipse.cdt.codan.core;bundle-version="1.0.0" + org.eclipse.cdt.codan.core;bundle-version="1.0.0", + org.eclipse.cdt.codan.core.cxx;bundle-version="1.0.0" Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: J2SE-1.5 Bundle-Vendor: Eclipse CDT 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 new file mode 100644 index 00000000000..a7d08892ab4 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/cfg/ControlFlowGraphTest.java @@ -0,0 +1,97 @@ +/******************************************************************************* + * 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.cfg; + +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.ControlFlowGraph; +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.dom.ast.IASTDeclaration; +import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition; +import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; +import org.eclipse.cdt.core.dom.ast.c.CASTVisitor; +import org.eclipse.cdt.core.index.IIndex; +import org.eclipse.cdt.core.model.CoreModel; +import org.eclipse.cdt.core.model.ICElement; +import org.eclipse.cdt.core.model.ITranslationUnit; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.Path; + +/** + * TODO: add description + */ +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); + if (!(model instanceof ITranslationUnit)) + return; // not a C/C++ file + ITranslationUnit tu = (ITranslationUnit) model; + IIndex index = CCorePlugin.getIndexManager().getIndex(tu.getCProject()); + // lock the index for read access + index.acquireReadLock(); + try { + // create index based ast + IASTTranslationUnit ast = tu.getAST(index, + ITranslationUnit.AST_SKIP_INDEXED_HEADERS); + // traverse the ast using the visitor pattern. + processAst(ast); + } finally { + index.releaseReadLock(); + } + } + + /** + * @param ast + */ + private void processAst(IASTTranslationUnit ast) { + CASTVisitor visitor = new CASTVisitor() { + { + shouldVisitDeclarations = true; + } + public int visit(IASTDeclaration decl) { + if (decl instanceof IASTFunctionDefinition) { + graph = new ControlFlowGraphBuilder().build((IASTFunctionDefinition) decl); + return PROCESS_ABORT; + } + return PROCESS_CONTINUE; + } + }; + ast.accept(visitor); + + } + void buildCfg() { + try { + Path path = new Path(currentFile.toString()); + IResource el = cproject.getProject().findMember(currentFile.getName()); + processFile((IFile) el); + } catch (Exception e) { + e.printStackTrace(); + fail(e.getMessage()); + } + } + /*- + + main() { + int a; + a=1; + } + + */ + public void test1() { + load("test1.c"); + buildCfg(); + graph.print(graph.getStartNode()); + } +} diff --git a/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/test/CheckerTestCase.java b/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/test/CheckerTestCase.java index 24a7c3f6117..c878a97eb6c 100644 --- a/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/test/CheckerTestCase.java +++ b/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/test/CheckerTestCase.java @@ -10,208 +10,20 @@ *******************************************************************************/ package org.eclipse.cdt.codan.core.test; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.PrintStream; -import java.net.URL; -import java.util.ArrayList; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import org.eclipse.cdt.codan.core.CodanRuntime; import org.eclipse.cdt.codan.core.model.IProblemReporter; -import org.eclipse.cdt.core.CCorePlugin; -import org.eclipse.cdt.core.dom.IPDOMManager; -import org.eclipse.cdt.core.model.ICProject; -import org.eclipse.cdt.core.testplugin.CProjectHelper; -import org.eclipse.cdt.core.testplugin.util.BaseTestCase; import org.eclipse.core.resources.IMarker; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IWorkspace; -import org.eclipse.core.resources.IWorkspaceRunnable; -import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.NullProgressMonitor; /** * @author Alena * */ -public class CheckerTestCase extends BaseTestCase { - ArrayList tempFiles = new ArrayList(); - protected File tmpDir; - private ICProject cproject; +public class CheckerTestCase extends CodanTestCase { private IMarker[] markers; - private File currentFile; - /** - * Override for c++ - * - * @return is c++ tests - */ - public boolean isCpp() { - return false; - } - - public void setUp() throws Exception { - super.setUp(); - removeLeftOverProjects(); - cproject = createProject(isCpp()); - tmpDir = cproject.getProject().getLocation().makeAbsolute().toFile(); - } - - public File load(String file) { - CodanCoreTestActivator plugin = CodanCoreTestActivator.getDefault(); - String name = getClass().getName(); - String classFile = name.replaceAll("\\.", "/"); - classFile += ".java"; - InputStream st = null; - File f = null; - try { - if (plugin != null) { - URL resource = plugin.getBundle().getResource( - "src/" + classFile); - st = resource.openStream(); - } else { - st = getClass().getResourceAsStream(classFile); - } - } catch (IOException e) { - fail("Cannot find java file: " + classFile); - } - try { - f = saveFile(st, file); - st.close(); - currentFile = f; - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return f; - } - static final Pattern filePattern = Pattern.compile("file=\"(.*)\""); - - /** - * @param st - * @param file - * @return - * @throws IOException - */ - private File saveFile(InputStream st, String file) throws IOException { - BufferedReader r = new BufferedReader(new InputStreamReader(st)); - String line; - File testFile = new File(tmpDir, file); - tempFiles.add(testFile); - PrintStream wr = new PrintStream(testFile); - try { - boolean print = false; - while ((line = r.readLine()) != null) { - if (line.contains("")) { - print = false; - } else if (print) { - wr.println(line); - } - } - } finally { - wr.close(); - } - return testFile; - } - - public void tearDown() throws CoreException { - if (cproject != null) { - try { - cproject.getProject().delete( - IResource.FORCE - | IResource.ALWAYS_DELETE_PROJECT_CONTENT, - new NullProgressMonitor()); - } catch (CoreException e) { - throw e; - } - } - } - - /** - * @throws CoreException - */ - private void removeLeftOverProjects() throws CoreException { - final IWorkspace workspace = ResourcesPlugin.getWorkspace(); - IProject[] projects = workspace.getRoot().getProjects(); - for (int i = 0; i < projects.length; i++) { - IProject p = projects[i]; - if (p.getName().startsWith("Codan")) { - p.delete(IResource.FORCE - | IResource.ALWAYS_DELETE_PROJECT_CONTENT, - new NullProgressMonitor()); - } - } - } - - protected ICProject createProject(final boolean cpp) throws CoreException { - final ICProject cprojects[] = new ICProject[1]; - ModelJoiner mj = new ModelJoiner(); - try { - // Create the cproject - final String projectName = "CodanProjTest_" - + System.currentTimeMillis(); - final IWorkspace workspace = ResourcesPlugin.getWorkspace(); - workspace.run(new IWorkspaceRunnable() { - public void run(IProgressMonitor monitor) throws CoreException { - // Create the cproject - ICProject cproject = cpp ? CProjectHelper.createCCProject( - projectName, null, IPDOMManager.ID_NO_INDEXER) - : CProjectHelper.createCProject(projectName, null, - IPDOMManager.ID_NO_INDEXER); - cprojects[0] = cproject; - } - }, null); - mj.join(); - // Index the cproject - CCorePlugin.getIndexManager().setIndexerId(cprojects[0], - IPDOMManager.ID_FAST_INDEXER); - // wait until the indexer is done - assertTrue(CCorePlugin.getIndexManager().joinIndexer(360000, - new NullProgressMonitor())); - } finally { - mj.dispose(); - } - return cprojects[0]; - } - - protected void loadFiles() throws CoreException { - ModelJoiner mj = new ModelJoiner(); - try { - final IWorkspace workspace = ResourcesPlugin.getWorkspace(); - workspace.run(new IWorkspaceRunnable() { - public void run(IProgressMonitor monitor) throws CoreException { - cproject.getProject().refreshLocal(1, monitor); - } - }, null); - mj.join(); - // Index the cproject - CCorePlugin.getIndexManager().setIndexerId(cproject, - IPDOMManager.ID_FAST_INDEXER); - // wait until the indexer is done - assertTrue(CCorePlugin.getIndexManager().joinIndexer(360000, - new NullProgressMonitor())); - } finally { - mj.dispose(); - } - return; - } /** * @param i @@ -243,31 +55,6 @@ public class CheckerTestCase extends BaseTestCase { assertTrue("Error on line " + i + " not found ", found); } - /** - * @param pos - * @return - * @throws IOException - */ - private int pos2line(int pos) throws IOException { - FileInputStream st = new FileInputStream(currentFile); - try { - int c; - int line = 1; - int cur = 0; - while ((c = st.read()) != -1) { - if (c == '\n') - line++; - if (cur >= pos) - return line; - cur++; - } - ; - } finally { - st.close(); - } - return 0; - } - public void checkNoErrors() { assertTrue("Found errors but should not", markers == null || markers.length == 0); diff --git a/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/test/CodanTestCase.java b/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/test/CodanTestCase.java new file mode 100644 index 00000000000..b88c6fd1d9d --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/test/CodanTestCase.java @@ -0,0 +1,205 @@ +/******************************************************************************* + * 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.test; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; + +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.dom.IPDOMManager; +import org.eclipse.cdt.core.model.ICProject; +import org.eclipse.cdt.core.testplugin.CProjectHelper; +import org.eclipse.cdt.core.testplugin.util.BaseTestCase; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspace; +import org.eclipse.core.resources.IWorkspaceRunnable; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; + +/** + * TODO: add description + */ +public class CodanTestCase extends BaseTestCase { + ArrayList tempFiles = new ArrayList(); + protected File tmpDir; + protected ICProject cproject; + protected File currentFile; + + /** + * + */ + public CodanTestCase() { + super(); + } + + /** + * @param name + */ + public CodanTestCase(String name) { + super(name); + } + + /** + * Override for c++ + * + * @return is c++ tests + */ + public boolean isCpp() { + return false; + } + + public void setUp() throws Exception { + super.setUp(); + removeLeftOverProjects(); + cproject = createProject(isCpp()); + tmpDir = cproject.getProject().getLocation().makeAbsolute().toFile(); + } + + public File load(String file) { + Class clazz = getClass(); + InputStream st = null; + try { + st = TestUtils.getJavaFileText(clazz); + } catch (IOException e) { + fail("Cannot find java file: " + clazz + ": " + e.getMessage()); + } + + try { + File testFile = new File(tmpDir, file); + tempFiles.add(testFile); + TestUtils.saveFile(st, testFile); + st.close(); + currentFile = testFile; + try { + cproject.getProject().refreshLocal(1, null); + } catch (CoreException e) { + // hmm + } + return testFile; + } catch (IOException e) { + fail("Cannot save test: " + file + ": " + e.getMessage()); + return null; + } + } + + public void tearDown() throws CoreException { + if (cproject != null) { + try { + cproject.getProject().delete( + IResource.FORCE + | IResource.ALWAYS_DELETE_PROJECT_CONTENT, + new NullProgressMonitor()); + } catch (CoreException e) { + throw e; + } + } + } + + /** + * @throws CoreException + */ + private void removeLeftOverProjects() throws CoreException { + final IWorkspace workspace = ResourcesPlugin.getWorkspace(); + IProject[] projects = workspace.getRoot().getProjects(); + for (int i = 0; i < projects.length; i++) { + IProject p = projects[i]; + if (p.getName().startsWith("Codan")) { + p.delete(IResource.FORCE + | IResource.ALWAYS_DELETE_PROJECT_CONTENT, + new NullProgressMonitor()); + } + } + } + + protected ICProject createProject(final boolean cpp) throws CoreException { + final ICProject cprojects[] = new ICProject[1]; + ModelJoiner mj = new ModelJoiner(); + try { + // Create the cproject + final String projectName = "CodanProjTest_" + + System.currentTimeMillis(); + final IWorkspace workspace = ResourcesPlugin.getWorkspace(); + workspace.run(new IWorkspaceRunnable() { + public void run(IProgressMonitor monitor) throws CoreException { + // Create the cproject + ICProject cproject = cpp ? CProjectHelper.createCCProject( + projectName, null, IPDOMManager.ID_NO_INDEXER) + : CProjectHelper.createCProject(projectName, null, + IPDOMManager.ID_NO_INDEXER); + cprojects[0] = cproject; + } + }, null); + mj.join(); + // Index the cproject + CCorePlugin.getIndexManager().setIndexerId(cprojects[0], + IPDOMManager.ID_FAST_INDEXER); + // wait until the indexer is done + assertTrue(CCorePlugin.getIndexManager().joinIndexer(360000, + new NullProgressMonitor())); + } finally { + mj.dispose(); + } + return cprojects[0]; + } + + protected void loadFiles() throws CoreException { + ModelJoiner mj = new ModelJoiner(); + try { + final IWorkspace workspace = ResourcesPlugin.getWorkspace(); + workspace.run(new IWorkspaceRunnable() { + public void run(IProgressMonitor monitor) throws CoreException { + cproject.getProject().refreshLocal(1, monitor); + } + }, null); + mj.join(); + // Index the cproject + CCorePlugin.getIndexManager().setIndexerId(cproject, + IPDOMManager.ID_FAST_INDEXER); + // wait until the indexer is done + assertTrue(CCorePlugin.getIndexManager().joinIndexer(360000, + new NullProgressMonitor())); + } finally { + mj.dispose(); + } + return; + } + + /** + * @param pos + * @return + * @throws IOException + */ + protected int pos2line(int pos) throws IOException { + FileInputStream st = new FileInputStream(currentFile); + try { + int c; + int line = 1; + int cur = 0; + while ((c = st.read()) != -1) { + if (c == '\n') + line++; + if (cur >= pos) + return line; + cur++; + } + ; + } finally { + st.close(); + } + return 0; + } +} \ No newline at end of file diff --git a/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/test/TestUtils.java b/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/test/TestUtils.java new file mode 100644 index 00000000000..98560820f5d --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core.test/src/org/eclipse/cdt/codan/core/test/TestUtils.java @@ -0,0 +1,86 @@ +/******************************************************************************* + * 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.test; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.PrintStream; +import java.net.URL; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * TODO: add description + */ +public class TestUtils { + static final Pattern filePattern = Pattern.compile("file=\"(.*)\""); + /** + * @param st + * @param testFile + * @return + * @throws FileNotFoundException + * @throws IOException + */ + public static File saveFile(InputStream st, File testFile) + throws FileNotFoundException, IOException { + BufferedReader r = new BufferedReader(new InputStreamReader(st)); + String line; + PrintStream wr = new PrintStream(testFile); + try { + boolean print = false; + while ((line = r.readLine()) != null) { + if (line.contains("")) { + print = false; + } else if (print) { + wr.println(line); + } + } + } finally { + wr.close(); + } + return testFile; + } + + /** + * @param clazz + * @return + * @throws IOException + */ + public static InputStream getJavaFileText(Class clazz) throws IOException { + CodanCoreTestActivator plugin = CodanCoreTestActivator.getDefault(); + String classFile = clazz.getName().replaceAll("\\.", "/"); + classFile += ".java"; + InputStream st = null; + + if (plugin != null) { + URL resource = plugin.getBundle().getResource( + "src/" + classFile); + st = resource.openStream(); + } else { + st = clazz.getResourceAsStream(classFile); + } + + return st; + } +} diff --git a/codan/org.eclipse.cdt.codan.core/META-INF/MANIFEST.MF b/codan/org.eclipse.cdt.codan.core/META-INF/MANIFEST.MF index e46fcd86489..bd5608920dc 100644 --- a/codan/org.eclipse.cdt.codan.core/META-INF/MANIFEST.MF +++ b/codan/org.eclipse.cdt.codan.core/META-INF/MANIFEST.MF @@ -16,4 +16,6 @@ Export-Package: org.eclipse.cdt.codan.core, org.eclipse.cdt.codan.core.cxx, org.eclipse.cdt.codan.core.test, org.eclipse.cdt.codan.ui", - org.eclipse.cdt.codan.internal.core.model;x-friends:="org.eclipse.cdt.codan.core.cxx,org.eclipse.cdt.codan.core.test,org.eclipse.cdt.codan.ui" + org.eclipse.cdt.codan.internal.core.cfg;x-friends:="org.eclipse.cdt.codan.core.cxx", + org.eclipse.cdt.codan.internal.core.model;x-friends:="org.eclipse.cdt.codan.core.cxx,org.eclipse.cdt.codan.core.test,org.eclipse.cdt.codan.ui", + org.eclipse.cdt.codan.provisional.core.model.cfg diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/AbstarctBasicBlock.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/AbstarctBasicBlock.java deleted file mode 100644 index 1318698a431..00000000000 --- a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/AbstarctBasicBlock.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.eclipse.cdt.codan.internal.core.cfg; - -import java.util.Iterator; - -import org.eclipse.cdt.codan.provisional.core.model.cfg.IBasicBlock; - -public abstract class AbstarctBasicBlock implements IBasicBlock { - static class OneElementIterator implements Iterator { - private T o; - - public OneElementIterator(T o) { - this.o = o; - } - - public boolean hasNext() { - return o != null; - } - - public T next() { - T x = o; - o = null; - return x; - } - - public void remove() { - throw new UnsupportedOperationException(); - } - } -} diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/AbstractBasicBlock.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/AbstractBasicBlock.java new file mode 100644 index 00000000000..4ffa7a97fc6 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/AbstractBasicBlock.java @@ -0,0 +1,49 @@ +package org.eclipse.cdt.codan.internal.core.cfg; + +import java.util.Iterator; +import org.eclipse.cdt.codan.provisional.core.model.cfg.IBasicBlock; + +public abstract class AbstractBasicBlock implements IBasicBlock { + private Object data; + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } + + static class OneElementIterator implements Iterator { + private V o; + + public OneElementIterator(V o) { + this.o = o; + } + + public boolean hasNext() { + return o != null; + } + + public V next() { + V x = o; + o = null; + return x; + } + + public void remove() { + throw new UnsupportedOperationException(); + } + } + + public abstract void addOutgoing(IBasicBlock node); + + /** + * @return + */ + public String toStringData() { + if (getData() == null) + return ""; + return getData().toString(); + } +} diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/AbstractSingleIncomingNode.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/AbstractSingleIncomingNode.java new file mode 100644 index 00000000000..a11d8bb20d2 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/AbstractSingleIncomingNode.java @@ -0,0 +1,31 @@ +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.ISingleIncoming; + +/** + * Abstrat node with one incoming arc + * + */ +public abstract class AbstractSingleIncomingNode extends AbstractBasicBlock + implements ISingleIncoming { + final IBasicBlock prev; + + public AbstractSingleIncomingNode(IBasicBlock prev) { + super(); + this.prev = prev; + } + + public Iterator getIncomingIterator() { + return new OneElementIterator(prev); + } + + public int getIncomingSize() { + return 1; + } + + public IBasicBlock getIncoming() { + return prev; + } +} 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 new file mode 100644 index 00000000000..675d93cdcec --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/AbstractSingleOutgoingNode.java @@ -0,0 +1,51 @@ +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; + +/** + * Abstract impl of basic block with single outgoing arc + * + */ +public abstract class AbstractSingleOutgoingNode extends AbstractBasicBlock + implements ISingleOutgoing { + private IBasicBlock next; + + public AbstractSingleOutgoingNode(IBasicBlock next) { + super(); + this.next = next; + } + + public Iterator getOutgoingIterator() { + return new OneElementIterator(next); + } + + public int getOutgoingSize() { + return 1; + } + + public IBasicBlock getOutgoing() { + return next; + } + + public void setOutgoing(IBasicBlock exit) { + if (this.next != null) + throw new IllegalArgumentException( + "Cannot modify already exiting connector"); //$NON-NLS-1$ + this.next = exit; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.cdt.codan.internal.core.cfg.AbstractBasicBlock#addOutgoing + * (org.eclipse.cdt.codan.provisional.core.model.cfg.IBasicBlock) + */ + @Override + public void addOutgoing(IBasicBlock node) { + setOutgoing(node); + } +} 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 new file mode 100644 index 00000000000..9307dc35346 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/ConnectorNode.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * 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 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; + +/** + * TODO: add description + */ +public class ConnectorNode extends AbstractSingleOutgoingNode implements + IConnectorNode { + ArrayList incoming = new ArrayList(2); + + /** + * @param next + */ + public ConnectorNode() { + super(null); + } + + public void addIncoming(IBasicBlock node) { + incoming.add(node); + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.cdt.codan.provisional.core.model.cfg.IBasicBlock# + * getIncomingIterator() + */ + public Iterator getIncomingIterator() { + return incoming.iterator(); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.cdt.codan.provisional.core.model.cfg.IBasicBlock#getIncomingSize + * () + */ + public int getIncomingSize() { + // TODO Auto-generated method stub + return incoming.size(); + } +} diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/ControlFlowGraph.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/ControlFlowGraph.java new file mode 100644 index 00000000000..73e4375d35a --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/ControlFlowGraph.java @@ -0,0 +1,99 @@ +/******************************************************************************* + * 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 java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +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.IControlFlowGraph; +import org.eclipse.cdt.codan.provisional.core.model.cfg.IDecisionArc; +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.ISingleOutgoing; +import org.eclipse.cdt.codan.provisional.core.model.cfg.IStartNode; + +/** + * TODO: add description + */ +public class ControlFlowGraph implements IControlFlowGraph { + private List exitNodes; + private IStartNode start; + + public ControlFlowGraph(IStartNode start, Collection exitNodes) { + setExitNodes(exitNodes); + this.start = start; + } + + public Iterator getExitNodeIterator() { + return exitNodes.iterator(); + } + + public int getExitNodeSize() { + return exitNodes.size(); + } + + public void setExitNodes(Collection exitNodes) { + if (this.exitNodes != null) + throw new IllegalArgumentException( + "Cannot modify already exiting connector"); //$NON-NLS-1$ + this.exitNodes = Collections.unmodifiableList(new ArrayList( + exitNodes)); + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.cdt.codan.provisional.core.model.cfg.IControlFlowGraph# + * getStartNode() + */ + public IStartNode getStartNode() { + return start; + } + + void setStartNode(IStartNode start) { + this.start = start; + } + + public void print(IBasicBlock node) { + System.out.println(node.toString()); + if (node instanceof IConnectorNode) + return; + if (node instanceof IDecisionNode) { + // todo + Iterator decisionArcs = ((IDecisionNode) node) + .getDecisionArcs(); + for (; decisionArcs.hasNext();) { + IDecisionArc arc = decisionArcs.next(); + System.out.println("{" + arc.getIndex() + ":"); + print(arc.getOutgoing()); + System.out.println("}"); + } + print(((IDecisionNode) node).getConnectionNode()); + } else if (node instanceof ISingleOutgoing) { + print(((ISingleOutgoing) node).getOutgoing()); + } + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.cdt.codan.provisional.core.model.cfg.IControlFlowGraph# + * getUnconnectedNodeIterator() + */ + public Iterator getUnconnectedNodeIterator() { + // TODO Auto-generated method stub + return null; + } +} 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 new file mode 100644 index 00000000000..cf315cab2bf --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/DecisionNode.java @@ -0,0 +1,153 @@ +/******************************************************************************* + * 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 java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +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.IDecisionArc; +import org.eclipse.cdt.codan.provisional.core.model.cfg.IDecisionNode; + +/** + * @see {@link IDecisionNode} + */ +public class DecisionNode extends AbstractSingleIncomingNode implements + IDecisionNode { + 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 + */ + public DecisionNode(IBasicBlock prev) { + super(prev); + } + + public void setDecisionArcs(Collection next) { + this.next = Collections.unmodifiableList(new ArrayList( + next)); + } + + @Override + public void addOutgoing(IBasicBlock node) { + DecisionArc arc = new DecisionArc(getDecisionArcSize(), node); + next.add(arc); + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.cdt.codan.provisional.core.model.cfg.IDecisionNode# + * getDecisionArcs() + */ + public Iterator getDecisionArcs() { + return next.iterator(); + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.cdt.codan.provisional.core.model.cfg.IDecisionNode# + * getDecisionArcSize() + */ + public int getDecisionArcSize() { + return next.size(); + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.cdt.codan.provisional.core.model.cfg.IBasicBlock# + * getOutgoingIterator() + */ + public Iterator getOutgoingIterator() { + return new Iterator() { + private Iterator it; + { + it = next.iterator(); + } + + public boolean hasNext() { + return it.hasNext(); + } + + public IBasicBlock next() { + IDecisionArc arc = it.next(); + return arc.getOutgoing(); + } + + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.cdt.codan.provisional.core.model.cfg.IBasicBlock#getOutgoingSize + * () + */ + public int getOutgoingSize() { + return next.size(); + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.cdt.codan.provisional.core.model.cfg.IDecisionNode# + * getConnectionNode() + */ + public IConnectorNode getConnectionNode() { + return conn; + } + + public void setConnectorNode(IConnectorNode conn) { + this.conn = conn; + } +} diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/ExitNode.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/ExitNode.java new file mode 100644 index 00000000000..76ed3247104 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/ExitNode.java @@ -0,0 +1,60 @@ +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.IExitNode; +import org.eclipse.cdt.codan.provisional.core.model.cfg.IStartNode; + +/** + * Plain node has one prev one jump + * + */ +public class ExitNode extends AbstractBasicBlock implements IExitNode { + private IBasicBlock prev; + private IStartNode start; + + public ExitNode(IBasicBlock prev, IStartNode start) { + super(); + this.prev = prev; + this.start = start; + } + + public Iterator getIncomingIterator() { + return new OneElementIterator(prev); + } + + @SuppressWarnings("unchecked") + public Iterator getOutgoingIterator() { + return Collections.EMPTY_LIST.iterator(); + } + + public int getIncomingSize() { + return 1; + } + + public int getOutgoingSize() { + return 0; + } + + public IBasicBlock getIncoming() { + return prev; + } + + public IStartNode getStartNode() { + return start; + } + + public void setIncoming(IBasicBlock prev) { + this.prev = prev; + } + + public void setStartNode(IStartNode start) { + this.start = start; + } + + @Override + public void addOutgoing(IBasicBlock node) { + throw new UnsupportedOperationException(); + } +} 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 5cc008b0dee..d9ee6bf9203 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,47 +1,33 @@ 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; /** - * Plain node has one prev one jump - * + * Jump node is node that connects unusual control pass, such as goto, break and + * continue + * */ -public class JumpNode extends AbstarctBasicBlock implements IJumpNode { - final private IBasicBlock entry; - private IBasicBlock jump; +public class JumpNode extends AbstractSingleIncomingNode implements IJumpNode { + private IConnectorNode jump; private boolean backward; - public JumpNode(IBasicBlock entry, IBasicBlock jump, boolean backward) { - super(); - this.entry = entry; + public JumpNode(IBasicBlock entry, IConnectorNode jump, boolean backward) { + super(entry); this.jump = jump; this.backward = backward; } - public Iterator getIncomingIterator() { - return new OneElementIterator(entry); - } - public Iterator getOutgoingIterator() { return new OneElementIterator(jump); } - public int getIncomingSize() { - return 1; - } - public int getOutgoingSize() { return 1; } - public IBasicBlock getIncoming() { - return entry; - } - public IBasicBlock getOutgoing() { return jump; } @@ -50,9 +36,10 @@ public class JumpNode extends AbstarctBasicBlock implements IJumpNode { return backward; } - public void setJump(IBasicBlock jump) { - if (!(jump instanceof IConnectorNode)) - throw new IllegalArgumentException("Jump target must be a connection node"); //$NON-NLS-1$ + public void setJump(IConnectorNode jump) { + if (this.jump != null) + throw new IllegalArgumentException( + "Cannot modify exiting connector"); //$NON-NLS-1$ this.jump = jump; } @@ -60,4 +47,8 @@ public class JumpNode extends AbstarctBasicBlock implements IJumpNode { this.backward = backward; } + @Override + public void addOutgoing(IBasicBlock node) { + throw new UnsupportedOperationException(); + } } diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/PlainNode.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/PlainNode.java index 4f407e45ad6..89f56f558c3 100644 --- a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/PlainNode.java +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/cfg/PlainNode.java @@ -6,45 +6,45 @@ import org.eclipse.cdt.codan.provisional.core.model.cfg.IBasicBlock; import org.eclipse.cdt.codan.provisional.core.model.cfg.IPlainNode; /** - * Plain node has one prev one jump - * + * Plain node has one incoming arc and one outgoing arc + * */ -public class PlainNode extends AbstarctBasicBlock implements IPlainNode { - final IBasicBlock prev; +public class PlainNode extends AbstractSingleIncomingNode implements IPlainNode { IBasicBlock next; - public PlainNode(IBasicBlock entry, IBasicBlock exit) { - super(); - this.prev = entry; - this.next = exit; - } - - public Iterator getIncomingIterator() { - return new OneElementIterator(prev); + public PlainNode(IBasicBlock prev, IBasicBlock next) { + super(prev); + this.next = next; } public Iterator getOutgoingIterator() { return new OneElementIterator(next); } - public int getIncomingSize() { - return 1; - } - public int getOutgoingSize() { return 1; } - public IBasicBlock getIncoming() { - return prev; - } - public IBasicBlock getOutgoing() { return next; } public void setOutgoing(IBasicBlock exit) { - if (this.next != null) throw new IllegalArgumentException("Cannot modify already exiting connector"); //$NON-NLS-1$ + if (this.next != null) + throw new IllegalArgumentException( + "Cannot modify already exiting connector"); //$NON-NLS-1$ this.next = exit; } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.cdt.codan.internal.core.cfg.AbstractBasicBlock#addOutgoing + * (org.eclipse.cdt.codan.provisional.core.model.cfg.IBasicBlock) + */ + @Override + public void addOutgoing(IBasicBlock node) { + setOutgoing(node); + } } 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 34d037fc09a..1c4c2c2692c 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 @@ -1,27 +1,17 @@ package org.eclipse.cdt.codan.internal.core.cfg; -import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.Iterator; -import java.util.List; - import org.eclipse.cdt.codan.provisional.core.model.cfg.IBasicBlock; import org.eclipse.cdt.codan.provisional.core.model.cfg.IStartNode; /** - * Start node has no prev, one jump and it is connect to function exits - * + * Start node has no incoming, one outgoing and it is connect to function exits + * */ -public class StartNode extends AbstarctBasicBlock implements IStartNode { - private IBasicBlock next; - private List exitNodes; - - public StartNode(IBasicBlock next, Collection exitNodes) { - super(); - this.next = next; - if (exitNodes != null) this.exitNodes = Collections.unmodifiableList(new ArrayList(exitNodes)); - else this.exitNodes = null; // incomplete node +public class StartNode extends AbstractSingleOutgoingNode implements IStartNode { + public StartNode(IBasicBlock next) { + super(next); } @SuppressWarnings("unchecked") @@ -29,37 +19,12 @@ public class StartNode extends AbstarctBasicBlock implements IStartNode { return Collections.EMPTY_LIST.iterator(); } - public Iterator getOutgoingIterator() { - return new OneElementIterator(next); - } - public int getIncomingSize() { return 0; } - public int getOutgoingSize() { - return 1; - } - - public IBasicBlock getOutgoing() { - return next; - } - - public Iterator getExitNodeIterator() { - return exitNodes.iterator(); - } - - public int getExitNodeSize() { - return exitNodes.size(); - } - - public void setOutgoing(IBasicBlock next) { - if (this.next != null) throw new IllegalArgumentException("Cannot modify already exiting connector"); //$NON-NLS-1$ - this.next = next; - } - - public void setExitNodes(Collection exitNodes) { - if (this.exitNodes != null) throw new IllegalArgumentException("Cannot modify already exiting connector"); //$NON-NLS-1$ - this.exitNodes = Collections.unmodifiableList(new ArrayList(exitNodes)); + @Override + public void addOutgoing(IBasicBlock node) { + setOutgoing(node); } } diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/provisional/core/model/cfg/IBasicBlock.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/provisional/core/model/cfg/IBasicBlock.java index 616caf06613..6f9dbfbecdc 100644 --- a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/provisional/core/model/cfg/IBasicBlock.java +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/provisional/core/model/cfg/IBasicBlock.java @@ -2,6 +2,15 @@ package org.eclipse.cdt.codan.provisional.core.model.cfg; import java.util.Iterator; +/** + * + * Control flow graph basic block node - superinterface of all nodes. Each node + * has iterator and size over incoming and outgoing arc + *

+ * The following are speciazed versions of the nodes: + *

  • {@link IStartNode} - start node of the graph + *
  • {@link I} + */ public interface IBasicBlock { Iterator getIncomingIterator(); @@ -10,5 +19,4 @@ public interface IBasicBlock { int getIncomingSize(); int getOutgoingSize(); - } 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 7a2b9ce55ef..7504ea1dc3b 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,5 @@ package org.eclipse.cdt.codan.provisional.core.model.cfg; -public interface IConnectorNode extends IBasicBlock { +public interface IConnectorNode extends IBasicBlock, ISingleOutgoing { } diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/provisional/core/model/cfg/IControlFlowGraph.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/provisional/core/model/cfg/IControlFlowGraph.java new file mode 100644 index 00000000000..a5fc8a488cc --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/provisional/core/model/cfg/IControlFlowGraph.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * 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.provisional.core.model.cfg; + +import java.util.Iterator; + +/** + * TODO: add description + */ +public interface IControlFlowGraph { + IStartNode getStartNode(); + + /** + * + * @return + */ + Iterator getExitNodeIterator(); + + int getExitNodeSize(); + + Iterator getUnconnectedNodeIterator(); +} diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/provisional/core/model/cfg/IDecisionArc.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/provisional/core/model/cfg/IDecisionArc.java index 0c167576cd2..ed72b37c9d1 100644 --- a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/provisional/core/model/cfg/IDecisionArc.java +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/provisional/core/model/cfg/IDecisionArc.java @@ -1,5 +1,31 @@ package org.eclipse.cdt.codan.provisional.core.model.cfg; -public interface IDecisionArc { +/** + * Arc that has a condition upon it, for example if branches have true/false + * condition, and switch branches have case condition + */ +public interface IDecisionArc extends ISingleOutgoing { + /** + * Index represent branch index in decision node, as well semantics:
    + * 0 - always a false (else) branch of if, and default branch for switch, + * even if no code exists
    + * 1 - is true (then) branch for if + * + * @return + */ + int getIndex(); + /** + * Basic block that is at the end of the arc + * + * @return + */ + IBasicBlock getOutgoing(); + + /** + * Return parent node (decision node) or the decision arc + * + * @return + */ + IDecisionNode getDecisionNode(); } diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/provisional/core/model/cfg/IDecisionNode.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/provisional/core/model/cfg/IDecisionNode.java index f7bb6c2bfe7..7329c528232 100644 --- a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/provisional/core/model/cfg/IDecisionNode.java +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/provisional/core/model/cfg/IDecisionNode.java @@ -1,5 +1,17 @@ package org.eclipse.cdt.codan.provisional.core.model.cfg; -public interface IDecisionNode extends IBasicBlock { +import java.util.Iterator; +/** + * + * Interface for decision node. This node represent condition node in the graph, + * it has one incoming arc and many outgoing, each of them has a value of + * condition associated with it. + */ +public interface IDecisionNode extends IBasicBlock, ISingleIncoming { + Iterator getDecisionArcs(); + + int getDecisionArcSize(); + + IConnectorNode getConnectionNode(); } diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/provisional/core/model/cfg/IExitNode.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/provisional/core/model/cfg/IExitNode.java new file mode 100644 index 00000000000..5e0b7d9bce0 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/provisional/core/model/cfg/IExitNode.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * 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.provisional.core.model.cfg; + +/** + * Exit node of the graph. Usually return from the function, can also be throw + * or abort, such at exit(0) call. + * + */ +public interface IExitNode extends IBasicBlock, ISingleIncoming { + IStartNode getStartNode(); +} diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/provisional/core/model/cfg/IPlainNode.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/provisional/core/model/cfg/IPlainNode.java index 296a6b4f197..c845e9c6795 100644 --- a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/provisional/core/model/cfg/IPlainNode.java +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/provisional/core/model/cfg/IPlainNode.java @@ -1,5 +1,5 @@ package org.eclipse.cdt.codan.provisional.core.model.cfg; -public interface IPlainNode extends IBasicBlock, ISingleOutgoing, ISingleIncoming { - +public interface IPlainNode extends IBasicBlock, ISingleOutgoing, + ISingleIncoming { } diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/provisional/core/model/cfg/IStartNode.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/provisional/core/model/cfg/IStartNode.java index 47e3ec7e3b9..dc75d2540d4 100644 --- a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/provisional/core/model/cfg/IStartNode.java +++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/provisional/core/model/cfg/IStartNode.java @@ -1,9 +1,10 @@ package org.eclipse.cdt.codan.provisional.core.model.cfg; -import java.util.Iterator; +/** + * Start node of the control flow graph. Each graph has only one start node. It + * has no incoming arcs and one outgoing arc. It also contains iterator for + * function exit nodes. + */ public interface IStartNode extends IBasicBlock, ISingleOutgoing { - Iterator getExitNodeIterator(); - - int getExitNodeSize(); }