blob: 1da923e9332691c4b897ff76740b1c9152981b5e [file] [log] [blame]
/**********************************************************************
* Copyright (c) 2008 IBM Corporation.
* 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.ptp.pldt.mpi.analysis.cdt.graphs;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.ptp.pldt.mpi.analysis.cdt.graphs.impl.CallGraph;
import org.eclipse.ptp.pldt.mpi.analysis.cdt.graphs.impl.ResourceCollector;
/**
* Convenience class for constructing various graphs from C source files
*
* @author Beth Tibbitts
*
*/
public class GraphCreator {
/**
* Convenience method for initializing and computing the call graph in one place.
* <br>This is done in two steps:
* <br>(1) initCallGraph(): initialize call graph with function information
* <br>(2) computeCallGraph(): compute caller/callee/recursive etc. info on the graph
* @param resource
* @return
*/
public ICallGraph createCallGraph(IResource resource) {
ICallGraph cg = initCallGraph(resource);
computeCallGraph(cg);
return cg;
}
/**
* Create call graph structure from resources (C source files) but caller/callee
* calculations are not done yet; will descend to children of a container if
* called with a folder or project argument.
* @param resource
* @return call graph initialized with basic function information
*/
public ICallGraph initCallGraph(IResource resource) {
ICallGraph callGraph = new CallGraph();
callGraph = initCallGraph(resource, callGraph);
return callGraph;
}
/**
* Add information to an existing call graph.
* <br>Will descend to children if this is a container (folder or project)
*
* @param resource contains source file(s) whose functions will be found and added to the call graph.
* @param callGraph
* @return
*/
public ICallGraph initCallGraph(IResource resource, ICallGraph callGraph) {
boolean foundError = resourceCollector(resource, callGraph);
if(foundError) {
System.out.println("Error occurred during call graph creation.");
}
return callGraph;
}
/**
* Create an empty call graph, ready to fill with function information
* later with subsequent calls to initCallGraph(resource, callGraph)
* @return
*/
public ICallGraph initCallGraph() {
return new CallGraph();
}
/**
* Calculate the caller/callee and recursive properties of the call graph
* @return
*/
public ICallGraph computeCallGraph(ICallGraph callGraph) {
callGraph.buildCG();
return callGraph;
}
/**
* Run analysis ("Resource collector") on a resource (e.g. File or Folder)
* and add the function information found in/under the given resource (file or container)
* to the given call graph
* <br>Will descend to members of folder
*
* @param resource
* the resource selected by the user
* @param callGraph the call graph to which the information will be appended
* @return
*/
public boolean resourceCollector(IResource resource, ICallGraph callGraph) {
boolean foundError = false;
// if it's a C file, collect info in the call graph for this file
if (resource instanceof IFile) {
IFile file = (IFile) resource;
String filename = file.getName();
if (filename.endsWith(".c")) {
ResourceCollector rc = new ResourceCollector(callGraph, file);
rc.run();
}
// if it's a container, run resourceCollector on each of its members
} else if (resource instanceof IContainer) {
IContainer container = (IContainer) resource;
try {
IResource[] mems = container.members();
for (int i = 0; i < mems.length; i++) {
boolean err = resourceCollector(mems[i], callGraph);
foundError = foundError || err;
}
} catch (CoreException e) {
e.printStackTrace();
foundError=true;
}
} else {
// ?????
String name = "";
if (resource instanceof IResource) {
IResource res = (IResource) resource;
// name=res.getName(); // simple filename only, no path info
IPath path = res.getProjectRelativePath();
name = path.toString();
}
System.out.println("Cancelled by User, aborting analysis on subsequent files... "
+ name);
}
return foundError;
}
/**
* Print a call graph structure
* @param cg the call graph to print
*/
public void showCallGraph(ICallGraph cg) {
System.out.println("Show call graph");
List<ICallGraphNode> nodes = cg.getAllNodes();
for (Iterator<ICallGraphNode> iterator = nodes.iterator(); iterator.hasNext();) {
ICallGraphNode cgNode = iterator.next();
printCGNode(cgNode, "");
//System.out.println(" callers: ==>");
for (Iterator<ICallGraphNode> iterator2 = cgNode.getCallers().iterator(); iterator2.hasNext();) {
ICallGraphNode caller = iterator2.next();
printCGNode(caller," caller: ");
}
//System.out.println(" <== callees:");
for (Iterator<ICallGraphNode> iterator3 = cgNode.getCallees().iterator(); iterator3.hasNext();) {
ICallGraphNode callee = iterator3.next();
printCGNode(callee," callee: ");
}
System.out.println(" ");
}
List<List<ICallGraphNode>>cycles = cg.getCycles();
System.out.println("Recursive cycles:");
for (List<ICallGraphNode> cycle : cycles) {
System.out.println("Cycle: ");
for (Iterator<ICallGraphNode> iterator = cycle.iterator(); iterator.hasNext();) {
ICallGraphNode fn = iterator.next();
System.out.print(" "+fn.getFuncName());
}
System.out.println(" \n");
}
List<String> vars= cg.getEnv();
System.out.println("Global variables:");
for (Iterator<String> varit= vars.iterator(); varit.hasNext();) {
String var = varit.next();
System.out.println("Global var: "+var);
}
}
public void printCGNode(ICallGraphNode cgNode, String prefix) {
System.out.println(prefix+" "+cgNode.getFuncName()+" in "+cgNode.getFileName());
cgNode.getCFG();
}
}