1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-22 14:12:10 +02:00

- test view to inspect control flow graph

This commit is contained in:
Alena Laskavaia 2010-03-29 02:31:04 +00:00
parent 9993dae7a5
commit 6b922df8c2
15 changed files with 586 additions and 0 deletions

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View file

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>org.eclipse.cdt.codan.ui.cfgview</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.ManifestBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.SchemaBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.api.tools.apiAnalysisBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.pde.api.tools.apiAnalysisNature</nature>
</natures>
</projectDescription>

View file

@ -0,0 +1,8 @@
#Sat Mar 27 20:39:28 EDT 2010
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
org.eclipse.jdt.core.compiler.compliance=1.5
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.5

View file

@ -0,0 +1,17 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Control Flow Graph
Bundle-SymbolicName: org.eclipse.cdt.codan.ui.cfgview;singleton:=true
Bundle-Version: 1.0.0.qualifier
Bundle-Activator: org.eclipse.cdt.codan.ui.cfgview.ControlFlowGraphPlugin
Bundle-Vendor: Eclipse CDT
Require-Bundle: org.eclipse.ui,
org.eclipse.core.runtime,
org.eclipse.cdt.codan.core;bundle-version="1.0.0",
org.eclipse.cdt.codan.core.cxx;bundle-version="1.0.0",
org.eclipse.cdt.core;bundle-version="5.2.0",
org.eclipse.cdt.ui;bundle-version="5.2.0",
org.eclipse.core.resources;bundle-version="3.6.0",
org.eclipse.ui.editors;bundle-version="3.6.0"
Bundle-RequiredExecutionEnvironment: J2SE-1.5
Bundle-ActivationPolicy: lazy

View file

@ -0,0 +1,6 @@
source.. = src/
output.. = bin/
bin.includes = plugin.xml,\
META-INF/,\
.,\
icons/

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 996 B

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
<extension
point="org.eclipse.ui.views">
<view
category="org.eclipse.cdt.ui.views"
class="org.eclipse.cdt.codan.ui.cfgview.views.ControlFlowGraphView"
icon="icons/decision.png"
id="oeg.eclipse.cdt.codan.ui.cfgview.views.ControlFlowGraphView"
name="Control Flow Graph">
</view>
</extension>
</plugin>

View file

@ -0,0 +1,82 @@
package org.eclipse.cdt.codan.ui.cfgview;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.ImageRegistry;
import org.eclipse.swt.graphics.Image;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;
/**
* The activator class controls the plug-in life cycle
*/
public class ControlFlowGraphPlugin extends AbstractUIPlugin {
// The plug-in ID
public static final String PLUGIN_ID = "org.eclipse.cdt.codan.ui.cfgview"; //$NON-NLS-1$
// The shared instance
private static ControlFlowGraphPlugin plugin;
/**
* The constructor
*/
public ControlFlowGraphPlugin() {
}
/*
* (non-Javadoc)
* @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
*/
public void start(BundleContext context) throws Exception {
super.start(context);
plugin = this;
}
/*
* (non-Javadoc)
* @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
*/
public void stop(BundleContext context) throws Exception {
plugin = null;
super.stop(context);
}
/**
* Returns the shared instance
*
* @return the shared instance
*/
public static ControlFlowGraphPlugin getDefault() {
return plugin;
}
/**
* Returns an image descriptor for the image file at the given
* plug-in relative path
*
* @param path the path
* @return the image descriptor
*/
public ImageDescriptor getImageDescriptor(String key) {
ImageRegistry registry = getImageRegistry();
ImageDescriptor descriptor = registry.getDescriptor(key);
if (descriptor == null) {
descriptor = imageDescriptorFromPlugin(PLUGIN_ID,key);
registry.put(key, descriptor);
}
return descriptor;
}
public Image getImage(String key) {
ImageRegistry registry = getImageRegistry();
Image image = registry.get(key);
if (image == null) {
ImageDescriptor descriptor = imageDescriptorFromPlugin(PLUGIN_ID,key);
registry.put(key, descriptor);
image = registry.get(key);
}
return image;
}
}

View file

@ -0,0 +1,416 @@
package org.eclipse.cdt.codan.ui.cfgview.views;
import java.util.ArrayList;
import java.util.Collection;
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.CxxControlFlowGraph;
import org.eclipse.cdt.codan.internal.core.cfg.AbstractBasicBlock;
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.IJumpNode;
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.ui.cfgview.ControlFlowGraphPlugin;
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.c.CASTVisitor;
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.ILanguage;
import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.cdt.core.parser.ParserUtil;
import org.eclipse.cdt.core.resources.FileStorage;
import org.eclipse.cdt.internal.ui.util.EditorUtility;
import org.eclipse.cdt.ui.CDTUITools;
import org.eclipse.cdt.ui.text.SharedASTJob;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.DrillDownAdapter;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.texteditor.AbstractTextEditor;
/**
* This sample class demonstrates how to plug-in a new workbench view. The view
* shows data obtained from the model. The sample creates a dummy model on the
* fly, but a real implementation would connect to the model available either in
* this or another plug-in (e.g. the workspace). The view is connected to the
* model using a content provider.
* <p>
* The view uses a label provider to define how model objects should be
* presented in the view. Each view can present the same model objects using
* different labels and icons, if needed. Alternatively, a single label provider
* can be shared between views in order to ensure that objects of the same type
* are presented in the same way everywhere.
* <p>
*/
public class ControlFlowGraphView extends ViewPart {
/**
* The ID of the view as specified by the extension.
*/
public static final String ID = "org.eclipse.cdt.codan.ui.cfgview.views.ControlFlowGraphView";
private TreeViewer viewer;
private DrillDownAdapter drillDownAdapter;
private Action action1;
private Action doubleClickAction;
class ViewContentProvider implements IStructuredContentProvider,
ITreeContentProvider {
public void inputChanged(Viewer v, Object oldInput, Object newInput) {
}
public void dispose() {
}
public Object[] getElements(Object parent) {
return getChildren(parent);
}
public Object getParent(Object child) {
return null;
}
public Object[] getChildren(Object parent) {
if (parent instanceof Collection) {
return ((Collection) parent).toArray();
} else if (parent instanceof IControlFlowGraph) {
Collection<IBasicBlock> blocks = getFlat(
((IControlFlowGraph) parent).getStartNode(),
new ArrayList<IBasicBlock>());
return blocks.toArray();
} else if (parent instanceof IDecisionNode) {
ArrayList blocks = new ArrayList();
Iterator<IDecisionArc> iter = ((IDecisionNode) parent)
.getDecisionArcs();
for (; iter.hasNext();) {
IDecisionArc arc = iter.next();
blocks.add(arc);
}
blocks.add(((IDecisionNode) parent).getConnectionNode());
return blocks.toArray();
} else if (parent instanceof IDecisionArc) {
Collection<IBasicBlock> blocks = getFlat(
((IDecisionArc) parent).getOutgoing(),
new ArrayList<IBasicBlock>());
return blocks.toArray();
}
return new Object[0];
}
public boolean hasChildren(Object parent) {
return getChildren(parent).length > 0;
}
}
class ViewLabelProvider extends LabelProvider {
public String getText(Object obj) {
if (obj == null)
return null;
String strdata = "";
if (obj instanceof AbstractBasicBlock) {
strdata = ((AbstractBasicBlock) obj).toStringData();
}
return obj.getClass().getSimpleName() + ": " + strdata;
}
public Image getImage(Object obj) {
String imageKey = "task.png";
if (obj instanceof IDecisionNode
|| obj instanceof IControlFlowGraph)
imageKey = "decision.png";
else if (obj instanceof IExitNode)
imageKey = "exit.png";
else if (obj instanceof IStartNode)
imageKey = "start.png";
else if (obj instanceof IJumpNode)
imageKey = "jump.png";
else if (obj instanceof IConnectorNode)
imageKey = "connector.png";
return ControlFlowGraphPlugin.getDefault().getImage(
"icons/" + imageKey);
}
}
/**
* The constructor.
*/
public ControlFlowGraphView() {
}
/**
* @param prev
* @param startNode
* @return
*/
public Collection<IBasicBlock> getFlat(IBasicBlock node,
Collection<IBasicBlock> prev) {
prev.add(node);
if (node instanceof IConnectorNode) {
return prev;
}
if (node instanceof ISingleOutgoing) {
getFlat(((ISingleOutgoing) node).getOutgoing(), prev);
} else if (node instanceof IDecisionNode) {
getFlat(((IDecisionNode) node).getConnectionNode().getOutgoing(),
prev);
}
return prev;
}
/**
* This is a callback that will allow us to create the viewer and initialize
* it.
*/
public void createPartControl(Composite parent) {
viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
drillDownAdapter = new DrillDownAdapter(viewer);
viewer.setContentProvider(new ViewContentProvider());
viewer.setLabelProvider(new ViewLabelProvider());
viewer.setInput(getViewSite());
makeActions();
hookContextMenu();
hookSingleClickAction();
contributeToActionBars();
}
private void hookContextMenu() {
MenuManager menuMgr = new MenuManager("#PopupMenu");
menuMgr.setRemoveAllWhenShown(true);
menuMgr.addMenuListener(new IMenuListener() {
public void menuAboutToShow(IMenuManager manager) {
ControlFlowGraphView.this.fillContextMenu(manager);
}
});
Menu menu = menuMgr.createContextMenu(viewer.getControl());
viewer.getControl().setMenu(menu);
getSite().registerContextMenu(menuMgr, viewer);
}
private void contributeToActionBars() {
IActionBars bars = getViewSite().getActionBars();
fillLocalPullDown(bars.getMenuManager());
fillLocalToolBar(bars.getToolBarManager());
}
private void fillLocalPullDown(IMenuManager manager) {
manager.add(action1);
manager.add(new Separator());
}
private void fillContextMenu(IMenuManager manager) {
manager.add(action1);
manager.add(new Separator());
drillDownAdapter.addNavigationActions(manager);
// Other plug-ins can contribute there actions here
manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
}
private void fillLocalToolBar(IToolBarManager manager) {
manager.add(action1);
manager.add(new Separator());
drillDownAdapter.addNavigationActions(manager);
}
private void makeActions() {
action1 = new Action() {
public void run() {
IEditorPart e = PlatformUI.getWorkbench()
.getActiveWorkbenchWindow().getActivePage()
.getActiveEditor();
ITranslationUnit tu = (ITranslationUnit) CDTUITools
.getEditorInputCElement(e.getEditorInput());
Job job = new SharedASTJob("Job Name", tu) {
@Override
public IStatus runOnAST(ILanguage lang,
IASTTranslationUnit ast) throws CoreException {
processAst(ast);
return Status.OK_STATUS;
}
};
job.schedule();
}
};
action1.setText("Synchronize");
action1.setToolTipText("Action 1 tooltip");
action1.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages()
.getImageDescriptor(ISharedImages.IMG_OBJS_INFO_TSK));
doubleClickAction = new Action() {
public void run() {
ISelection selection = viewer.getSelection();
Object obj = ((IStructuredSelection) selection)
.getFirstElement();
showMessage("Double-click detected on " + obj.toString());
}
};
}
private void hookDoubleClickAction() {
viewer.addDoubleClickListener(new IDoubleClickListener() {
public void doubleClick(DoubleClickEvent event) {
doubleClickAction.run();
}
});
}
private void showMessage(String message) {
MessageDialog.openInformation(viewer.getControl().getShell(),
"Control Flow Graph", message);
}
protected void processAst(IASTTranslationUnit ast) {
final ArrayList<IControlFlowGraph> functions = new ArrayList<IControlFlowGraph>();
CASTVisitor visitor = new CASTVisitor() {
{
shouldVisitDeclarations = true;
}
public int visit(IASTDeclaration decl) {
if (decl instanceof IASTFunctionDefinition) {
CxxControlFlowGraph graph = new ControlFlowGraphBuilder()
.build((IASTFunctionDefinition) decl);
functions.add(graph);
return PROCESS_SKIP;
}
return PROCESS_CONTINUE;
}
};
ast.accept(visitor);
viewer.getControl().getDisplay().asyncExec(new Runnable() {
public void run() {
// TODO Auto-generated method stub
viewer.setInput(functions);
}
});
}
/**
* Passing the focus request to the viewer's control.
*/
public void setFocus() {
viewer.getControl().setFocus();
}
private class ASTHighlighterAction extends Action {
private static final String A_PART_INSTANCEOF = "aPart instanceof "; //$NON-NLS-1$
IEditorPart aPart = null;
public ASTHighlighterAction(IEditorPart part) {
this.aPart = part;
}
public void setPart(IEditorPart part) {
this.aPart = part;
}
protected boolean open(String filename) throws PartInitException,
CModelException {
IPath path = new Path(filename);
IFile f = ResourcesPlugin.getWorkspace().getRoot()
.getFileForLocation(path);
if (f != null) {
EditorUtility.openInEditor(f);
return true;
}
FileStorage storage = new FileStorage(null, path);
EditorUtility.openInEditor(storage);
return true;
}
@Override
public void run() {
ISelection selection = viewer.getSelection();
Object obj = ((IStructuredSelection) selection).getFirstElement();
if (obj instanceof AbstractBasicBlock) {
Object data = ((AbstractBasicBlock) obj).getData();
if (data instanceof IASTNode) {
IASTNode node = (IASTNode) data;
if (node instanceof IASTTranslationUnit) // don't
return;
IASTFileLocation loc = node.getFileLocation();
String filename = loc.getFileName();
if (filename.equals(""))
return;
IResource r = ParserUtil.getResourceForFilename(filename);
if (r != null) {
try {
aPart = EditorUtility.openInEditor(r);
} catch (PartInitException pie) {
return;
} catch (CModelException e) {
return;
}
} else {
// IPath path = new Path(filename);
// if (tu != null) {
// try {
// aPart = EditorUtility.openInEditor(path, tu);
// } catch (PartInitException e) {
// return;
// }
// }
}
if (aPart instanceof AbstractTextEditor) {
((AbstractTextEditor) aPart).selectAndReveal(
loc.getNodeOffset(),
loc.getNodeLength());
} else
System.out.println(A_PART_INSTANCEOF
+ aPart.getClass().getName());
aPart.getSite().getPage().activate(
aPart.getSite().getPage().findView(ID));
}
}
}
}
private void hookSingleClickAction() {
viewer.addSelectionChangedListener(new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
new ASTHighlighterAction(null).run();
}
});
}
}