diff --git a/codan/org.eclipse.cdt.codan.ui.cfgview/.classpath b/codan/org.eclipse.cdt.codan.ui.cfgview/.classpath new file mode 100644 index 00000000000..64c5e31b7a2 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.ui.cfgview/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/codan/org.eclipse.cdt.codan.ui.cfgview/.project b/codan/org.eclipse.cdt.codan.ui.cfgview/.project new file mode 100644 index 00000000000..3df8f20cc97 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.ui.cfgview/.project @@ -0,0 +1,34 @@ + + + org.eclipse.cdt.codan.ui.cfgview + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + org.eclipse.pde.api.tools.apiAnalysisBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + org.eclipse.pde.api.tools.apiAnalysisNature + + diff --git a/codan/org.eclipse.cdt.codan.ui.cfgview/.settings/org.eclipse.jdt.core.prefs b/codan/org.eclipse.cdt.codan.ui.cfgview/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000000..345c8c82184 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.ui.cfgview/.settings/org.eclipse.jdt.core.prefs @@ -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 diff --git a/codan/org.eclipse.cdt.codan.ui.cfgview/META-INF/MANIFEST.MF b/codan/org.eclipse.cdt.codan.ui.cfgview/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..eb3c510d920 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.ui.cfgview/META-INF/MANIFEST.MF @@ -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 diff --git a/codan/org.eclipse.cdt.codan.ui.cfgview/build.properties b/codan/org.eclipse.cdt.codan.ui.cfgview/build.properties new file mode 100644 index 00000000000..0d3d3a745d4 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.ui.cfgview/build.properties @@ -0,0 +1,6 @@ +source.. = src/ +output.. = bin/ +bin.includes = plugin.xml,\ + META-INF/,\ + .,\ + icons/ diff --git a/codan/org.eclipse.cdt.codan.ui.cfgview/icons/connector.png b/codan/org.eclipse.cdt.codan.ui.cfgview/icons/connector.png new file mode 100644 index 00000000000..f7e9831d347 Binary files /dev/null and b/codan/org.eclipse.cdt.codan.ui.cfgview/icons/connector.png differ diff --git a/codan/org.eclipse.cdt.codan.ui.cfgview/icons/decision.png b/codan/org.eclipse.cdt.codan.ui.cfgview/icons/decision.png new file mode 100644 index 00000000000..de3db627dee Binary files /dev/null and b/codan/org.eclipse.cdt.codan.ui.cfgview/icons/decision.png differ diff --git a/codan/org.eclipse.cdt.codan.ui.cfgview/icons/exit.png b/codan/org.eclipse.cdt.codan.ui.cfgview/icons/exit.png new file mode 100644 index 00000000000..c1c59a95330 Binary files /dev/null and b/codan/org.eclipse.cdt.codan.ui.cfgview/icons/exit.png differ diff --git a/codan/org.eclipse.cdt.codan.ui.cfgview/icons/jump.png b/codan/org.eclipse.cdt.codan.ui.cfgview/icons/jump.png new file mode 100644 index 00000000000..179cbd6f2be Binary files /dev/null and b/codan/org.eclipse.cdt.codan.ui.cfgview/icons/jump.png differ diff --git a/codan/org.eclipse.cdt.codan.ui.cfgview/icons/refresh_view.gif b/codan/org.eclipse.cdt.codan.ui.cfgview/icons/refresh_view.gif new file mode 100644 index 00000000000..a063c230aca Binary files /dev/null and b/codan/org.eclipse.cdt.codan.ui.cfgview/icons/refresh_view.gif differ diff --git a/codan/org.eclipse.cdt.codan.ui.cfgview/icons/start.png b/codan/org.eclipse.cdt.codan.ui.cfgview/icons/start.png new file mode 100644 index 00000000000..ce34b006b1c Binary files /dev/null and b/codan/org.eclipse.cdt.codan.ui.cfgview/icons/start.png differ diff --git a/codan/org.eclipse.cdt.codan.ui.cfgview/icons/task.png b/codan/org.eclipse.cdt.codan.ui.cfgview/icons/task.png new file mode 100644 index 00000000000..ba992a8ace8 Binary files /dev/null and b/codan/org.eclipse.cdt.codan.ui.cfgview/icons/task.png differ diff --git a/codan/org.eclipse.cdt.codan.ui.cfgview/plugin.xml b/codan/org.eclipse.cdt.codan.ui.cfgview/plugin.xml new file mode 100644 index 00000000000..40df7b700c2 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.ui.cfgview/plugin.xml @@ -0,0 +1,16 @@ + + + + + + + + + + diff --git a/codan/org.eclipse.cdt.codan.ui.cfgview/src/org/eclipse/cdt/codan/ui/cfgview/ControlFlowGraphPlugin.java b/codan/org.eclipse.cdt.codan.ui.cfgview/src/org/eclipse/cdt/codan/ui/cfgview/ControlFlowGraphPlugin.java new file mode 100644 index 00000000000..5c04087efa2 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.ui.cfgview/src/org/eclipse/cdt/codan/ui/cfgview/ControlFlowGraphPlugin.java @@ -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; + } + + +} diff --git a/codan/org.eclipse.cdt.codan.ui.cfgview/src/org/eclipse/cdt/codan/ui/cfgview/views/ControlFlowGraphView.java b/codan/org.eclipse.cdt.codan.ui.cfgview/src/org/eclipse/cdt/codan/ui/cfgview/views/ControlFlowGraphView.java new file mode 100644 index 00000000000..33066065296 --- /dev/null +++ b/codan/org.eclipse.cdt.codan.ui.cfgview/src/org/eclipse/cdt/codan/ui/cfgview/views/ControlFlowGraphView.java @@ -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. + *

+ * 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. + *

+ */ +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 blocks = getFlat( + ((IControlFlowGraph) parent).getStartNode(), + new ArrayList()); + return blocks.toArray(); + } else if (parent instanceof IDecisionNode) { + ArrayList blocks = new ArrayList(); + Iterator 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 blocks = getFlat( + ((IDecisionArc) parent).getOutgoing(), + new ArrayList()); + 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 getFlat(IBasicBlock node, + Collection 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 functions = new ArrayList(); + 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(); + } + }); + } +} \ No newline at end of file