summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCarsten Pfeiffer2012-06-28 15:46:27 (EDT)
committer Curtis Windatt2012-07-10 16:10:53 (EDT)
commitbea2564e1384b0efccb9674977384b8e522e11a6 (patch)
treecd3f68523fd2227852cb7bda1b81b6f8697716ac
parente59ae8e70c8ecb2fc8a144c87cbfd6b75b7a86de (diff)
downloadeclipse.pde.ui-bea2564e1384b0efccb9674977384b8e522e11a6.zip
eclipse.pde.ui-bea2564e1384b0efccb9674977384b8e522e11a6.tar.gz
eclipse.pde.ui-bea2564e1384b0efccb9674977384b8e522e11a6.tar.bz2
Improved Import-Package QuickFix
Made the quickfix work not only for import-statements, but also for method-invocatoins, field access and type references.
-rw-r--r--ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/correction/java/FindClassResolutionsOperation.java172
-rw-r--r--ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/correction/java/QuickFixProcessor.java63
2 files changed, 207 insertions, 28 deletions
diff --git a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/correction/java/FindClassResolutionsOperation.java b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/correction/java/FindClassResolutionsOperation.java
index 5460f49..8d91862 100644
--- a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/correction/java/FindClassResolutionsOperation.java
+++ b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/correction/java/FindClassResolutionsOperation.java
@@ -12,8 +12,10 @@ package org.eclipse.pde.internal.ui.correction.java;
import java.util.*;
import org.eclipse.core.resources.IProject;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.*;
+import org.eclipse.jdt.core.*;
+import org.eclipse.jdt.core.search.*;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.osgi.service.resolver.*;
import org.eclipse.pde.core.plugin.IPluginModelBase;
@@ -48,6 +50,16 @@ public class FindClassResolutionsOperation implements IRunnableWithProgress {
*/
abstract public void addResolutionModification(IProject project, ExportPackageDescription desc);
+ /**
+ * Adds an export package proposal. Subclasses should implement the actual adding to the collection.
+ */
+ public Object addExportPackageResolutionModification(IPackageFragment aPackage) {
+ if (aPackage.exists()) {
+ return JavaResolutionFactory.createExportPackageProposal(aPackage.getResource().getProject(), aPackage, JavaResolutionFactory.TYPE_JAVA_COMPLETION, 100);
+ }
+ return null;
+ }
+
/*
* Optimization for case where users is only interested in Import-Package and therefore can quit after first dependency is found
*/
@@ -83,12 +95,22 @@ public class FindClassResolutionsOperation implements IRunnableWithProgress {
typeName = null;
}
- if (packageName != null && !isImportedPackage(packageName)) {
- Set validPackages = getValidPackages(packageName);
+ Set packagesToExport = new HashSet();
+ Collection validPackages = getValidPackages(typeName, packageName, packagesToExport, monitor);
+ if (validPackages != null) {
+
+ if (validPackages.isEmpty()) {
+ for (Iterator it = packagesToExport.iterator(); it.hasNext();) {
+ IPackageFragment packageFragment = (IPackageFragment) it.next();
+ fCollector.addExportPackageResolutionModification(packageFragment);
+ }
+ return;
+ }
+
Iterator validPackagesIter = validPackages.iterator();
Set visiblePkgs = null;
-
- while (validPackagesIter.hasNext() && !fCollector.isDone()) {
+ boolean allowMultipleFixes = packageName == null;
+ while (validPackagesIter.hasNext() && (allowMultipleFixes || !fCollector.isDone())) {
// since getting visible packages is not very efficient, only do it once and cache result
if (visiblePkgs == null) {
visiblePkgs = getVisiblePackages();
@@ -104,37 +126,147 @@ public class FindClassResolutionsOperation implements IRunnableWithProgress {
}
}
- private boolean isImportedPackage(String packageName) {
- IPluginModelBase model = PluginRegistry.findModel(fProject.getProject());
+ private Collection getValidPackages(String typeName, String packageName, Set packagesToExport, IProgressMonitor monitor) {
+ SubMonitor subMonitor = SubMonitor.convert(monitor, 3);
+
+ Collection validPackages = null;
+ ImportPackageSpecification[] importPkgs = null;
+ IPluginModelBase model = PluginRegistry.findModel(fProject);
if (model != null && model.getBundleDescription() != null) {
- ImportPackageSpecification[] importPkgs = model.getBundleDescription().getImportPackages();
- for (int i = 0; i < importPkgs.length; i++) {
- if (importPkgs[i].getName().equals(packageName)) {
- return true;
+ importPkgs = model.getBundleDescription().getImportPackages();
+ }
+ subMonitor.worked(1);
+
+ if (importPkgs != null) {
+ if (packageName != null) {
+ if (!isImportedPackage(packageName, importPkgs)) {
+ validPackages = getValidPackages(packageName);
+ }
+ subMonitor.worked(1);
+ } else {
+ // find possible types in the global packages
+ validPackages = findValidPackagesContainingSimpleType(typeName, importPkgs, packagesToExport, subMonitor.newChild(1));
+ }
+ }
+ return validPackages;
+ }
+
+ /**
+ * Finds all exported packages containing the simple type aTypeName. The packages
+ * will be filtered from the given packages which are already imported, and all
+ * system packages.
+ *
+ * If no exported package is left, packagesToExport will be filled with those
+ * packages that would have been returned, if they were exported.
+ * @param aTypeName the simple type to search for
+ * @param importPkgs the packages which are already imported
+ * @param packagesToExport return parameter that will be filled with packages to export
+ * if no valid package to import was found
+ * @param monitor
+ * @return the set of packages to import
+ */
+ private Collection findValidPackagesContainingSimpleType(String aTypeName, ImportPackageSpecification[] importPkgs, Set packagesToExport, IProgressMonitor monitor) {
+ SubMonitor subMonitor = SubMonitor.convert(monitor);
+
+ IPluginModelBase[] activeModels = PluginRegistry.getActiveModels();
+ Set javaProjects = new HashSet(activeModels.length * 2);
+
+ for (int i = 0; i < activeModels.length; i++) {
+ IResource resource = activeModels[i].getUnderlyingResource();
+ if (resource != null && resource.isAccessible()) {
+ IJavaProject javaProject = JavaCore.create(resource.getProject());
+ if (javaProject.exists()) {
+ javaProjects.add(javaProject);
}
}
- return false;
}
- // if no BundleDescription, we return true so we don't create any proposals. This is the safe way out if no BundleDescription is available.
- return true;
+ final IJavaProject currentJavaProject = JavaCore.create(fProject);
+ javaProjects.remove(currentJavaProject); // no need to search in current project itself
+
+ try {
+ IJavaSearchScope searchScope = SearchEngine.createJavaSearchScope((IJavaElement[]) javaProjects.toArray(new IJavaElement[javaProjects.size()]));
+
+ final Map packages = new HashMap();
+ SearchRequestor requestor = new SearchRequestor() {
+
+ public void acceptSearchMatch(SearchMatch aMatch) throws CoreException {
+ Object element = aMatch.getElement();
+ if (element instanceof IType) {
+ IType type = (IType) element;
+ if (!currentJavaProject.equals(type.getJavaProject())) {
+ IPackageFragment packageFragment = type.getPackageFragment();
+ if (packageFragment.exists()) {
+ packages.put(packageFragment.getElementName(), packageFragment);
+ }
+ }
+ }
+ }
+ };
+
+ SearchPattern typePattern = SearchPattern.createPattern(aTypeName, IJavaSearchConstants.TYPE, IJavaSearchConstants.DECLARATIONS, SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE);
+ new SearchEngine().search(typePattern, new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()}, searchScope, requestor, subMonitor.newChild(1));
+
+ if (!packages.isEmpty()) {
+ // transform to ExportPackageDescriptions
+ Map exportDescriptions = new HashMap(packages.size());
+
+ // remove system packages if they happen to be included. Adding a system package won't resolve anything, since package package already comes from JRE
+ ExportPackageDescription[] systemPackages = PDECore.getDefault().getModelManager().getState().getState().getSystemPackages();
+ for (int i = 0; i < systemPackages.length; i++) {
+ packages.remove(systemPackages[i].getName());
+ }
+ // also remove packages that are already imported
+ for (int i = 0; i < importPkgs.length; i++) {
+ packages.remove(importPkgs[i].getName());
+ }
+
+ // finally create the list of ExportPackageDescriptions
+ ExportPackageDescription[] knownPackages = PDECore.getDefault().getModelManager().getState().getState().getExportedPackages();
+ for (int i = 0; i < knownPackages.length; i++) {
+ if (packages.containsKey(knownPackages[i].getName())) {
+ exportDescriptions.put(knownPackages[i].getName(), knownPackages[i]);
+ }
+ }
+ if (exportDescriptions.isEmpty()) {
+ // no packages to import found, maybe there are packages to export
+ packagesToExport.addAll(packages.values());
+ }
+
+ return exportDescriptions.values();
+ }
+
+ return Collections.EMPTY_SET;
+ } catch (CoreException ex) {
+ // ignore, return an empty set
+ return Collections.EMPTY_SET;
+ }
}
- private static Set getValidPackages(String pkgName) {
+ private boolean isImportedPackage(String packageName, ImportPackageSpecification[] importPkgs) {
+ for (int i = 0; i < importPkgs.length; i++) {
+ if (importPkgs[i].getName().equals(packageName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static Collection getValidPackages(String pkgName) {
ExportPackageDescription[] knownPackages = PDECore.getDefault().getModelManager().getState().getState().getExportedPackages();
- Set validPackages = new HashSet();
+ Map validPackages = new HashMap();
for (int i = 0; i < knownPackages.length; i++) {
if (knownPackages[i].getName().equals(pkgName)) {
- validPackages.add(knownPackages[i]);
+ validPackages.put(knownPackages[i].getName(), knownPackages[i]);
}
}
// remove system packages if they happen to be included. Adding a system package won't resolve anything, since package package already comes from JRE
if (!validPackages.isEmpty()) {
knownPackages = PDECore.getDefault().getModelManager().getState().getState().getSystemPackages();
for (int i = 0; i < knownPackages.length; i++) {
- validPackages.remove(knownPackages[i]);
+ validPackages.remove(knownPackages[i].getName());
}
}
- return validPackages;
+ return validPackages.values();
}
private Set getVisiblePackages() {
diff --git a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/correction/java/QuickFixProcessor.java b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/correction/java/QuickFixProcessor.java
index 6cd111d..5582f1f 100644
--- a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/correction/java/QuickFixProcessor.java
+++ b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/correction/java/QuickFixProcessor.java
@@ -38,7 +38,10 @@ public class QuickFixProcessor implements IQuickFixProcessor {
switch (id) {
case IProblem.ForbiddenReference :
handleAccessRestrictionProblem(context, locations[i], results);
- case IProblem.ImportNotFound :
+ case IProblem.ImportNotFound : // fall through
+ case IProblem.UndefinedName : // fall through
+ case IProblem.UndefinedType : // fall through
+ case IProblem.UnresolvedVariable :
handleImportNotFound(context, locations[i], results);
}
@@ -56,6 +59,16 @@ public class QuickFixProcessor implements IQuickFixProcessor {
referencedElement = ((Type) node).resolveBinding();
} else if (node instanceof Name) {
referencedElement = ((Name) node).resolveBinding();
+ } else if (node instanceof MethodInvocation) {
+ IMethodBinding tempMethod = ((MethodInvocation) node).resolveMethodBinding();
+ if (tempMethod != null) {
+ referencedElement = tempMethod.getDeclaringClass();
+ }
+ } else if (node instanceof FieldAccess) {
+ IVariableBinding tempVariable = ((FieldAccess) node).resolveFieldBinding();
+ if (tempVariable != null) {
+ referencedElement = tempVariable.getDeclaringClass();
+ }
}
if (referencedElement != null) {
// get the project that contains the reference element
@@ -139,7 +152,24 @@ public class QuickFixProcessor implements IQuickFixProcessor {
}
}
if (!supplierImported) {
- Object proposal = JavaResolutionFactory.createRequireBundleProposal(currentProject, desc, JavaResolutionFactory.TYPE_JAVA_COMPLETION, 16);
+ // add import-package, if possible
+ boolean proposeRequireBundle = false;
+
+ ImportPackageSpecification[] importPackages = bd.getImportPackages();
+ for (int i = 0; i < importPackages.length; i++) {
+ if (desc.getName().equals(importPackages[i].getName())) {
+ // already imported, try require-bundle
+ proposeRequireBundle = true;
+ break;
+ }
+ }
+
+ Object proposal = null;
+ if (proposeRequireBundle) {
+ proposal = JavaResolutionFactory.createRequireBundleProposal(currentProject, desc, JavaResolutionFactory.TYPE_JAVA_COMPLETION, 16);
+ } else {
+ proposal = JavaResolutionFactory.createImportPackageProposal(currentProject, desc, JavaResolutionFactory.TYPE_JAVA_COMPLETION, 16);
+ }
if (proposal != null)
results.add(proposal);
}
@@ -159,8 +189,13 @@ public class QuickFixProcessor implements IQuickFixProcessor {
if (node == null) {
if (selectedNode instanceof SimpleName) {
ITypeBinding typeBinding = ((SimpleName) selectedNode).resolveTypeBinding();
- className = typeBinding.getBinaryName();
- packageName = typeBinding.getPackage().getName();
+ if (typeBinding != null) {
+ className = typeBinding.getBinaryName();
+ packageName = typeBinding.getPackage().getName();
+ }
+ if (className == null) { // fallback if the type cannot be resolved
+ className = ((SimpleName) selectedNode).getIdentifier();
+ }
}
} else if (node instanceof ImportDeclaration) {
// Find import declaration which is the problem
@@ -172,7 +207,7 @@ public class QuickFixProcessor implements IQuickFixProcessor {
result.add(JavaResolutionFactory.createSearchRepositoriesProposal(packageName));
}
- if (className != null && packageName != null) {
+ if (className != null) {
IProject project = cu.getJavaElement().getJavaProject().getProject();
// only try to find proposals on Plug-in Projects
if (!WorkspaceModelManager.isPluginProject(project))
@@ -191,7 +226,7 @@ public class QuickFixProcessor implements IQuickFixProcessor {
}
/*
- * Custom AbstractClassResolutionCollector which will only add one IJavaCompletionProposal for adding an Import-Package entry
+ * Custom AbstractClassResolutionCollector which will only add one IJavaCompletionProposal for adding an Import-Package or Export-Package entry
*/
private AbstractClassResolutionCollector createCollector(final Collection result) {
return new AbstractClassResolutionCollector() {
@@ -206,7 +241,16 @@ public class QuickFixProcessor implements IQuickFixProcessor {
}
}
- // we want to finish after we add the first Import-Package Change
+ public Object addExportPackageResolutionModification(IPackageFragment aPackage) {
+ Object proposal = super.addExportPackageResolutionModification(aPackage);
+ if (proposal != null) {
+ result.add(proposal);
+ isDone = true;
+ }
+ return proposal;
+ }
+
+ // we want to finish after we add the first Import- or Export-Package Change
public boolean isDone() {
return isDone;
}
@@ -229,7 +273,10 @@ public class QuickFixProcessor implements IQuickFixProcessor {
public boolean hasCorrections(ICompilationUnit unit, int problemId) {
switch (problemId) {
case IProblem.ForbiddenReference :
- case IProblem.ImportNotFound :
+ case IProblem.UndefinedName : // fall through
+ case IProblem.ImportNotFound : // fall through
+ case IProblem.UndefinedType :
+ case IProblem.UnresolvedVariable :
IJavaElement parent = unit.getParent();
if (parent != null) {
IJavaProject project = parent.getJavaProject();