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 97fb4c9..177fa78 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 @@ -60,13 +60,26 @@ return null; } + /** + * Adds a require bundle proposal. Subclasses should implement the actual adding to the collection. + */ + public Object addRequireBundleModification(IProject project, ExportPackageDescription desc, int relevance) { + return JavaResolutionFactory.createRequireBundleProposal(project, desc, JavaResolutionFactory.TYPE_JAVA_COMPLETION, relevance); + } + + /** + * Adds a search repositories proposal. Subclasses should implement the actual adding to the collection. + */ + public Object addSearchRepositoriesModification(String packageName) { + return JavaResolutionFactory.createSearchRepositoriesProposal(packageName); + } + /* * Optimization for case where users is only interested in Import-Package and therefore can quit after first dependency is found */ public boolean isDone() { return false; } - } /** @@ -123,6 +136,12 @@ // if currentPackage will resolve class and is valid, pass it to collector fCollector.addResolutionModification(fProject, currentPackage); } + + // additinally add require bundle proposals + for (validPackagesIter = validPackages.iterator(); validPackagesIter.hasNext();) { + ExportPackageDescription currentPackage = validPackagesIter.next(); + fCollector.addRequireBundleModification(fProject, currentPackage, 16); + } } } 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 ca44068..59aa317 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 @@ -33,16 +33,21 @@ */ public IJavaCompletionProposal[] getCorrections(IInvocationContext context, IProblemLocation[] locations) throws CoreException { ArrayList results = new ArrayList(); + + AbstractClassResolutionCollector collector = createCollector(results); + for (int i = 0; i < locations.length; i++) { int id = locations[i].getProblemId(); switch (id) { case IProblem.ForbiddenReference : - handleAccessRestrictionProblem(context, locations[i], results); + handleAccessRestrictionProblem(context, locations[i], collector); case IProblem.ImportNotFound : // fall through case IProblem.UndefinedName : // fall through case IProblem.UndefinedType : // fall through - case IProblem.UnresolvedVariable : - handleImportNotFound(context, locations[i], results); + case IProblem.UnresolvedVariable : // fall through + case IProblem.MissingTypeInMethod : // fall through + case IProblem.MissingTypeInConstructor : + handleImportNotFound(context, locations[i], collector); } } @@ -52,7 +57,7 @@ /* * Adds IJavaCompletionProposals for a ForbiddenReference marker */ - private void handleAccessRestrictionProblem(IInvocationContext context, IProblemLocation location, Collection results) { + private void handleAccessRestrictionProblem(IInvocationContext context, IProblemLocation location, AbstractClassResolutionCollector collector) { IBinding referencedElement = null; ASTNode node = location.getCoveredNode(context.getASTRoot()); if (node instanceof Type) { @@ -91,19 +96,17 @@ 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); + handleAccessRestrictionByImportPackage(context.getCompilationUnit().getJavaProject().getProject(), exportPackages[i], collector); 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); + collector.addExportPackageResolutionModification(referencedPackage); } } } else { - handleAccessRestrictionByImportPackage(referencedPackage, results); + handleAccessRestrictionByImportPackage(referencedPackage, collector); } } } @@ -112,31 +115,35 @@ /* * Adds IJavaCompletionProposals for a Require-Bundle if user is using an Import-Package from the bundle */ - private void handleAccessRestrictionByImportPackage(IPackageFragment fragment, Collection results) { + private void handleAccessRestrictionByImportPackage(IPackageFragment fragment, AbstractClassResolutionCollector collector) { HashSet set = new HashSet(); IProject project = fragment.getJavaProject().getProject(); String pkgName = fragment.getElementName(); IPluginModelBase base = PluginRegistry.findModel(project); ExportPackageDescription[] descs = base.getBundleDescription().getResolvedImports(); + ExportPackageDescription foundExportPackage = null; 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); + foundExportPackage = exportedPkgs[j]; // any one is fine, so simply remember the last one + collector.addRequireBundleModification(project, exportedPkgs[j], 16); + break; } } } + } + if (foundExportPackage != null) { + collector.addResolutionModification(project, foundExportPackage); } } /* * 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) { + private void handleAccessRestrictionByImportPackage(IProject currentProject, ExportPackageDescription desc, AbstractClassResolutionCollector collector) { BundleDescription supplier = desc.getSupplier(); if (supplier != null) { String supplierId = supplier.getSymbolicName(); @@ -153,25 +160,21 @@ } if (!supplierImported) { // add import-package, if possible - boolean proposeRequireBundle = false; + boolean proposeImportPackage = true; 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; + proposeImportPackage = false; 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 (proposeImportPackage) { + collector.addResolutionModification(currentProject, desc); // relevance should actually be 16... } - if (proposal != null) - results.add(proposal); + collector.addRequireBundleModification(currentProject, desc, 16); } } } @@ -179,7 +182,7 @@ /* * Adds IJavaCompletionProposals for a ImportNotFound problem */ - private void handleImportNotFound(IInvocationContext context, IProblemLocation problemLocation, final Collection result) { + private void handleImportNotFound(IInvocationContext context, IProblemLocation problemLocation, final AbstractClassResolutionCollector collector) { CompilationUnit cu = context.getASTRoot(); ASTNode selectedNode = problemLocation.getCoveringNode(cu); if (selectedNode != null) { @@ -187,13 +190,13 @@ String className = null; String packageName = null; if (node == null) { - if (selectedNode instanceof SimpleName) { - ITypeBinding typeBinding = ((SimpleName) selectedNode).resolveTypeBinding(); + if (selectedNode instanceof Name) { + ITypeBinding typeBinding = ((Name) selectedNode).resolveTypeBinding(); if (typeBinding != null) { className = typeBinding.getBinaryName(); packageName = typeBinding.getPackage().getName(); } - if (className == null) { // fallback if the type cannot be resolved + if (className == null && selectedNode instanceof SimpleName) { // fallback if the type cannot be resolved className = ((SimpleName) selectedNode).getIdentifier(); } } @@ -204,7 +207,7 @@ // always add the search repositories proposal int lastPeriod = className.lastIndexOf('.'); // if there is no period assume we are importing a single name package packageName = className.substring(0, lastPeriod >= 0 ? lastPeriod : className.length()); - result.add(JavaResolutionFactory.createSearchRepositoriesProposal(packageName)); + collector.addSearchRepositoriesModification(packageName); } if (className != null) { @@ -213,8 +216,6 @@ if (!WorkspaceModelManager.isPluginProject(project)) return; - // 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()); @@ -231,11 +232,20 @@ private AbstractClassResolutionCollector createCollector(final Collection result) { return new AbstractClassResolutionCollector() { + // the list of package names for which an import package resolution has been created + private Set addedImportPackageResolutions = new HashSet(); + boolean isDone = false; public void addResolutionModification(IProject project, ExportPackageDescription desc) { + // guard against multiple import package resolutions for the same package + if (addedImportPackageResolutions.contains(desc.getName())) { + return; + } + Object proposal = JavaResolutionFactory.createImportPackageProposal(project, desc, JavaResolutionFactory.TYPE_JAVA_COMPLETION, 17); if (proposal != null) { + addedImportPackageResolutions.add(desc.getName()); result.add(proposal); isDone = true; } @@ -245,7 +255,24 @@ Object proposal = super.addExportPackageResolutionModification(aPackage); if (proposal != null) { result.add(proposal); - isDone = true; + } + return proposal; + } + + @Override + public Object addRequireBundleModification(IProject project, ExportPackageDescription desc, int relevance) { + Object proposal = super.addRequireBundleModification(project, desc, relevance); + if (proposal != null) { + result.add(proposal); + } + return proposal; + } + + @Override + public Object addSearchRepositoriesModification(String packageName) { + Object proposal = super.addSearchRepositoriesModification(packageName); + if (proposal != null) { + result.add(proposal); } return proposal; } @@ -275,8 +302,10 @@ case IProblem.ForbiddenReference : case IProblem.UndefinedName : // fall through case IProblem.ImportNotFound : // fall through - case IProblem.UndefinedType : - case IProblem.UnresolvedVariable : + case IProblem.UndefinedType : // fall through + case IProblem.UnresolvedVariable : // fall through + case IProblem.MissingTypeInMethod : // fall through + case IProblem.MissingTypeInConstructor : IJavaElement parent = unit.getParent(); if (parent != null) { IJavaProject project = parent.getJavaProject();