blob: 2df36c62fb7bf5cc0c3949888555a001e61c8c0d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2008 IBM Corporation and others.
* 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.pde.internal.ui.correction.java;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jdt.core.*;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.core.dom.*;
import org.eclipse.jdt.ui.text.java.*;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.osgi.service.resolver.*;
import org.eclipse.pde.core.plugin.IPluginModelBase;
import org.eclipse.pde.core.plugin.PluginRegistry;
import org.eclipse.pde.internal.core.WorkspaceModelManager;
import org.eclipse.pde.internal.ui.correction.java.FindClassResolutionsOperation.AbstractClassResolutionCollector;
public class QuickFixProcessor implements IQuickFixProcessor {
/* (non-Javadoc)
* @see org.eclipse.jdt.ui.text.java.IQuickFixProcessor#getCorrections(org.eclipse.jdt.ui.text.java.IInvocationContext, org.eclipse.jdt.ui.text.java.IProblemLocation[])
*/
public IJavaCompletionProposal[] getCorrections(IInvocationContext context, IProblemLocation[] locations) throws CoreException {
ArrayList results = new ArrayList();
for (int i = 0; i < locations.length; i++) {
int id = locations[i].getProblemId();
switch (id) {
case IProblem.ForbiddenReference :
handleAccessRestrictionProblem(context, locations[i], results);
case IProblem.ImportNotFound :
handleImportNotFound(context, locations[i], results);
}
}
return (IJavaCompletionProposal[]) results.toArray(new IJavaCompletionProposal[results.size()]);
}
/*
* Adds IJavaCompletionProposals for a ForbiddenReference marker
*/
private void handleAccessRestrictionProblem(IInvocationContext context, IProblemLocation location, Collection results) {
IBinding referencedElement = null;
ASTNode node = location.getCoveredNode(context.getASTRoot());
if (node instanceof Type) {
referencedElement = ((Type) node).resolveBinding();
} else if (node instanceof Name) {
referencedElement = ((Name) node).resolveBinding();
}
if (referencedElement != null) {
// get the project that contains the reference element
// ensure it exists in the workspace and is a plug-in project
IJavaProject referencedJavaProject = referencedElement.getJavaElement().getJavaProject();
if (referencedJavaProject != null && WorkspaceModelManager.isPluginProject(referencedJavaProject.getProject())) {
IPackageFragment referencedPackage = (IPackageFragment) referencedElement.getJavaElement().getAncestor(IJavaElement.PACKAGE_FRAGMENT);
IJavaProject currentProject = context.getCompilationUnit().getJavaProject();
// only find proposals for Plug-in projects
if (!WorkspaceModelManager.isPluginProject(currentProject.getProject()))
return;
// get the packages exported by the referenced plug-in project
if (!referencedJavaProject.equals(currentProject)) {
IPluginModelBase referencedModel = PluginRegistry.findModel(referencedJavaProject.getProject());
ExportPackageDescription[] exportPackages = referencedModel.getBundleDescription().getExportPackages();
// check if the required package is exported already
boolean packageExported = false;
if (referencedPackage != null) {
for (int i = 0; i < exportPackages.length; i++) {
if (exportPackages[i].getName().equals(referencedPackage.getElementName())) {
packageExported = true;
// check to see if access restriction is caused by Import-Package
handleAccessRestrictionByImportPackage(context.getCompilationUnit().getJavaProject().getProject(), exportPackages[i], results);
break;
}
}
// if the package is not exported, add the quickfix
if (!packageExported) {
Object proposal = JavaResolutionFactory.createExportPackageProposal(referencedJavaProject.getProject(), referencedPackage, JavaResolutionFactory.TYPE_JAVA_COMPLETION, 100);
if (proposal != null)
results.add(proposal);
}
}
} else {
handleAccessRestrictionByImportPackage(referencedPackage, results);
}
}
}
}
/*
* Adds IJavaCompletionProposals for a Require-Bundle if user is using an Import-Package from the bundle
*/
private void handleAccessRestrictionByImportPackage(IPackageFragment fragment, Collection results) {
HashSet set = new HashSet();
IProject project = fragment.getJavaProject().getProject();
String pkgName = fragment.getElementName();
IPluginModelBase base = PluginRegistry.findModel(project);
ExportPackageDescription[] descs = base.getBundleDescription().getResolvedImports();
for (int i = 0; i < descs.length; i++) {
BundleDescription exporter = descs[i].getExporter();
if (set.add(exporter.getSymbolicName())) {
ExportPackageDescription[] exportedPkgs = exporter.getExportPackages();
for (int j = 0; j < exportedPkgs.length; j++) {
if (exportedPkgs[j].getName().equals(pkgName)) {
Object proposal = JavaResolutionFactory.createRequireBundleProposal(project, exportedPkgs[j], JavaResolutionFactory.TYPE_JAVA_COMPLETION, 16);
if (proposal != null)
results.add(proposal);
}
}
}
}
}
/*
* Adds IJavaCompletionProposal for a Require-Bundle if user is using an Import-Package from the (workspace) bundle
*/
private void handleAccessRestrictionByImportPackage(IProject currentProject, ExportPackageDescription desc, Collection results) {
BundleDescription supplier = desc.getSupplier();
String supplierId = supplier.getSymbolicName();
if (supplier != null) {
IPluginModelBase base = PluginRegistry.findModel(currentProject);
BundleDescription bd = base.getBundleDescription();
BundleSpecification[] imports = bd.getRequiredBundles();
boolean supplierImported = false;
for (int j = 0; j < imports.length; j++) {
BundleDescription importSupplier = (BundleDescription) imports[j].getSupplier();
if (importSupplier != null && importSupplier.getSymbolicName().equals(supplierId)) {
supplierImported = true;
break;
}
}
if (!supplierImported) {
Object proposal = JavaResolutionFactory.createRequireBundleProposal(currentProject, desc, JavaResolutionFactory.TYPE_JAVA_COMPLETION, 16);
if (proposal != null)
results.add(proposal);
}
}
}
/*
* Adds IJavaCompletionProposals for a ImportNotFound problem
*/
private void handleImportNotFound(IInvocationContext context, IProblemLocation problemLocation, final Collection result) {
CompilationUnit cu = context.getASTRoot();
ASTNode selectedNode = problemLocation.getCoveringNode(cu);
if (selectedNode != null) {
ASTNode node = getParent(selectedNode);
// Find import declaration which is the problem
if (node instanceof ImportDeclaration) {
IProject project = cu.getJavaElement().getJavaProject().getProject();
// only try to find proposals on Plug-in Projects
if (!WorkspaceModelManager.isPluginProject(project))
return;
String className = ((ImportDeclaration) node).getName().getFullyQualifiedName();
// create a collector that will create IJavaCompletionProposals and load them into 'result'
AbstractClassResolutionCollector collector = createCollector(result);
IRunnableWithProgress findOperation = new FindClassResolutionsOperation(project, className, collector);
try {
findOperation.run(new NullProgressMonitor());
} catch (InvocationTargetException e) {
} catch (InterruptedException e) {
}
}
}
}
/*
* Custom AbstractClassResolutionCollector which will only add one IJavaCompletionProposal for adding an Import-Package entry
*/
private AbstractClassResolutionCollector createCollector(final Collection result) {
return new AbstractClassResolutionCollector() {
boolean isDone = false;
public void addResolutionModification(IProject project, ExportPackageDescription desc) {
Object proposal = JavaResolutionFactory.createImportPackageProposal(project, desc, JavaResolutionFactory.TYPE_JAVA_COMPLETION, 17);
if (proposal != null) {
result.add(proposal);
isDone = true;
}
}
// we want to finish after we add the first Import-Package Change
public boolean isDone() {
return isDone;
}
};
}
/*
* Copied from org.eclipse.jdt.internal.coreext.dom.ASTNoes.getParent. Simplified for IMPORT_DECLARATION
*/
private static ASTNode getParent(ASTNode node) {
do {
node = node.getParent();
} while (node != null && node.getNodeType() != ASTNode.IMPORT_DECLARATION);
return node;
}
/* (non-Javadoc)
* @see org.eclipse.jdt.ui.text.java.IQuickFixProcessor#hasCorrections(org.eclipse.jdt.core.ICompilationUnit, int)
*/
public boolean hasCorrections(ICompilationUnit unit, int problemId) {
switch (problemId) {
case IProblem.ForbiddenReference :
case IProblem.ImportNotFound :
IJavaElement parent = unit.getParent();
if (parent != null) {
IJavaProject project = parent.getJavaProject();
if (project != null)
return WorkspaceModelManager.isPluginProject(project.getProject());
}
}
return false;
}
}