WALA/com.ibm.wala.ide.jdt/source/com/ibm/wala/ide/AbstractJavaAnalysisAction....

220 lines
7.5 KiB
Java

/*******************************************************************************
* 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<>();
Job job = new Job("Compute project paths") {
@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
*/
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;
}
}