/******************************************************************************* * Copyright (c) 2002 - 2006 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 com.ibm.wala.ide; import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.Collection; import java.util.Iterator; import java.util.LinkedList; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jface.action.IAction; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.ui.IObjectActionDelegate; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.progress.IProgressService; import com.ibm.wala.classLoader.Module; import com.ibm.wala.ide.util.EclipseProjectPath; import com.ibm.wala.ide.util.JavaEclipseProjectPath; import com.ibm.wala.ipa.callgraph.AnalysisScope; import com.ibm.wala.types.ClassLoaderReference; import com.ibm.wala.util.collections.HashSetFactory; import com.ibm.wala.util.debug.Assertions; /** * An Eclipse action that analyzes a Java selection */ public abstract class AbstractJavaAnalysisAction implements IObjectActionDelegate, IRunnableWithProgress { /** * The current {@link ISelection} highlighted in the Eclipse workspace */ private ISelection currentSelection; public AbstractJavaAnalysisAction() { super(); } /* * @see IObjectActionDelegate#setActivePart(IAction, IWorkbenchPart) */ @Override public void setActivePart(IAction action, IWorkbenchPart targetPart) { } /** * Compute an analysis scope for the current selection */ public static AnalysisScope computeScope(IStructuredSelection selection) throws IOException { return computeScope(selection, EclipseProjectPath.AnalysisScopeType.NO_SOURCE); } /** * Compute an analysis scope for the current selection * * @param scopeType should analysis use the source files in the Eclipse projects rather than the class files. */ public static AnalysisScope computeScope(final IStructuredSelection selection, final EclipseProjectPath.AnalysisScopeType scopeType) throws IOException { if (selection == null) { throw new IllegalArgumentException("null selection"); } final Collection<EclipseProjectPath> projectPaths = new LinkedList<EclipseProjectPath>(); Job job = new Job("Compute project paths") { @SuppressWarnings("unchecked") @Override protected IStatus run(IProgressMonitor monitor) { for (Iterator it = selection.iterator(); it.hasNext();) { Object object = it.next(); if (object instanceof IJavaElement) { IJavaElement e = (IJavaElement) object; IJavaProject jp = e.getJavaProject(); try { projectPaths.add(JavaEclipseProjectPath.make(jp, scopeType)); } catch (CoreException e1) { e1.printStackTrace(); // skip and continue } catch (IOException e2) { e2.printStackTrace(); return new Status(IStatus.ERROR, "", 0, "", e2); } } else { Assertions.UNREACHABLE(object.getClass()); } } return Status.OK_STATUS; } }; // lock the whole workspace job.setRule(ResourcesPlugin.getWorkspace().getRoot()); job.schedule(); try { job.join(); IStatus result = job.getResult(); if (result.getSeverity() == IStatus.ERROR) { Throwable exception = result.getException(); if (exception instanceof IOException) { throw (IOException) exception; } else if (exception instanceof RuntimeException) { throw (RuntimeException) exception; } } } catch (InterruptedException e) { e.printStackTrace(); assert false; } AnalysisScope scope = mergeProjectPaths(projectPaths); return scope; } /** * compute the java projects represented by the current selection */ @SuppressWarnings("unchecked") protected Collection<IJavaProject> computeJavaProjects() { IStructuredSelection selection = (IStructuredSelection) currentSelection; Collection<IJavaProject> projects = HashSetFactory.make(); for (Iterator it = selection.iterator(); it.hasNext();) { Object object = it.next(); if (object instanceof IJavaElement) { IJavaElement e = (IJavaElement) object; IJavaProject jp = e.getJavaProject(); projects.add(jp); } else { Assertions.UNREACHABLE(object.getClass()); } } return projects; } /** * create an analysis scope as the union of a bunch of EclipseProjectPath */ private static AnalysisScope mergeProjectPaths(Collection<EclipseProjectPath> projectPaths) throws IOException { AnalysisScope scope = AnalysisScope.createJavaAnalysisScope(); Collection<Module> seen = HashSetFactory.make(); // to avoid duplicates, we first add all application modules, then // extension // modules, then primordial buildScope(ClassLoaderReference.Application, projectPaths, scope, seen); buildScope(ClassLoaderReference.Extension, projectPaths, scope, seen); buildScope(ClassLoaderReference.Primordial, projectPaths, scope, seen); return scope; } /** * Enhance an {@link AnalysisScope} to include in a particular loader, elements from a set of Eclipse projects * * @param loader the class loader in which new {@link Module}s will live * @param projectPaths Eclipse project paths to add to the analysis scope * @param scope the {@link AnalysisScope} under construction. This will be mutated. * @param seen set of {@link Module}s which have already been seen, and should not be added to the analysis scope */ private static void buildScope(ClassLoaderReference loader, Collection<EclipseProjectPath> projectPaths, AnalysisScope scope, Collection<Module> seen) throws IOException { for (EclipseProjectPath path : projectPaths) { AnalysisScope pScope = path.toAnalysisScope((File) null); for (Module m : pScope.getModules(loader)) { if (!seen.contains(m)) { seen.add(m); scope.addToScope(loader, m); } } } } /* * @see IActionDelegate#run(IAction) */ @Override public void run(IAction action) { IProgressService progressService = PlatformUI.getWorkbench().getProgressService(); try { progressService.busyCursorWhile(this); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } /* * @see IActionDelegate#selectionChanged(IAction, ISelection) */ @Override public void selectionChanged(IAction action, ISelection selection) { currentSelection = selection; } /** * @return The current {@link ISelection} highlighted in the Eclipse workspace */ public ISelection getCurrentSelection() { return currentSelection; } }