diff --git a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/core/manipulation/CleanUpContextCore.java b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/core/manipulation/CleanUpContextCore.java index 5d49faa50a0..73d00894882 100644 --- a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/core/manipulation/CleanUpContextCore.java +++ b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/core/manipulation/CleanUpContextCore.java @@ -19,6 +19,8 @@ import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.internal.corext.refactoring.structure.ImportRemover; + /** * The context that contains all information required by a clean up to create a fix. @@ -33,6 +35,8 @@ public class CleanUpContextCore { private final CompilationUnit fAst; + private ImportRemover fSharedImportRemover; + /** * Creates a new clean up context. * @@ -75,4 +79,25 @@ public ICompilationUnit getCompilationUnit() { public CompilationUnit getAST() { return fAst; } + + /** + * Sets the shared ImportRemover for this cleanup context. + * This allows multiple cleanups to share a single ImportRemover instance. + * + * @param remover the ImportRemover to share across cleanups + * @since 1.13 + */ + public void setSharedImportRemover(ImportRemover remover) { + fSharedImportRemover = remover; + } + + /** + * Gets the shared ImportRemover for this cleanup context. + * + * @return the shared ImportRemover, or null if none has been set + * @since 1.13 + */ + public ImportRemover getSharedImportRemover() { + return fSharedImportRemover; + } } diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/CompilationUnitRewriteOperationsFixCore.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/CompilationUnitRewriteOperationsFixCore.java index dfe519736a6..4cece8f566d 100644 --- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/CompilationUnitRewriteOperationsFixCore.java +++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/CompilationUnitRewriteOperationsFixCore.java @@ -39,6 +39,7 @@ import org.eclipse.jdt.internal.corext.codemanipulation.ContextSensitiveImportRewriteContext; import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite; +import org.eclipse.jdt.internal.corext.refactoring.structure.ImportRemover; public class CompilationUnitRewriteOperationsFixCore extends AbstractFixCore { @@ -87,6 +88,7 @@ public String getAdditionalInfo() { private final CompilationUnitRewriteOperation[] fOperations; private final CompilationUnit fCompilationUnit; protected LinkedProposalModelCore fLinkedProposalModel; + private ImportRemover fSharedImportRemover; public CompilationUnitRewriteOperationsFixCore(String name, CompilationUnit compilationUnit, CompilationUnitRewriteOperation operation) { this(name, compilationUnit, new CompilationUnitRewriteOperation[] { operation }); @@ -114,10 +116,26 @@ public LinkedProposalModelCore getLinkedPositions() { return fLinkedProposalModel; } + /** + * Sets the shared ImportRemover to be used by this fix. + * This allows multiple fixes to share a single ImportRemover instance. + * + * @param remover the ImportRemover to share + * @since 1.13 + */ + public void setSharedImportRemover(ImportRemover remover) { + fSharedImportRemover = remover; + } + @Override public CompilationUnitChange createChange(IProgressMonitor progressMonitor) throws CoreException { CompilationUnitRewrite cuRewrite= new CompilationUnitRewrite((ICompilationUnit)fCompilationUnit.getJavaElement(), fCompilationUnit); + // Use shared ImportRemover if available + if (fSharedImportRemover != null) { + cuRewrite.setImportRemover(fSharedImportRemover); + } + fLinkedProposalModel.clear(); for (CompilationUnitRewriteOperation operation : fOperations) { operation.rewriteAST(cuRewrite, fLinkedProposalModel); diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/helper/WhileToForEach.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/helper/WhileToForEach.java index 662f0f93e44..5c0f38e0227 100644 --- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/helper/WhileToForEach.java +++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/helper/WhileToForEach.java @@ -564,7 +564,6 @@ public void rewrite(UseIteratorToForLoopFixCore upp, final WhileLoopToChangeHit newEnhancedForStatement.setBody(ASTNodes.createMoveTarget(rewrite, hit.whileStatement.getBody())); ASTNodes.replaceButKeepComment(rewrite, hit.whileStatement, newEnhancedForStatement, group); remover.registerRemovedNode(hit.whileStatement.getExpression()); - remover.applyRemoves(importRewrite); } private boolean isLocalOrMemberType(ITypeBinding binding, WhileStatement whileStatement) { diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/structure/CompilationUnitRewrite.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/structure/CompilationUnitRewrite.java index 576c8a6fc24..ed084670617 100644 --- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/structure/CompilationUnitRewrite.java +++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/structure/CompilationUnitRewrite.java @@ -392,6 +392,17 @@ public ImportRemover getImportRemover() { return fImportRemover; } + /** + * Sets an external ImportRemover to be used by this CompilationUnitRewrite. + * This allows multiple CompilationUnitRewrite instances to share the same ImportRemover. + * + * @param remover the ImportRemover to use + * @since 1.13 + */ + public void setImportRemover(ImportRemover remover) { + fImportRemover = remover; + } + private void clearGroupDescriptionEdits() { for (TextEditGroup group : fTextEditGroups) { group.clearTextEdits(); diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest1d8.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest1d8.java index 127987b1ce0..c679c6b2bd5 100644 --- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest1d8.java +++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest1d8.java @@ -5607,7 +5607,6 @@ private static void dumpIMethod(String next) { String expected= """ package test; import java.io.File; - import java.util.Iterator; import java.util.List; public class Test { @@ -7367,6 +7366,61 @@ void test1() { } + /** + * https://github.com/eclipse-jdt/eclipse.jdt.ui/issues/121 + * Test that unused Iterator import is removed when both for-loop and while-loop are converted + * + * @throws CoreException on failure + */ + @Test + public void testIssue121_CombinedForAndWhileLoopIteratorImportRemoval() throws CoreException { + IPackageFragment pack= fSourceFolder.createPackageFragment("test", false, null); + String sample= """ + package test; + + import java.util.Date; + import java.util.Iterator; + import java.util.List; + import java.util.Map; + + public class Test { + private void method(List list, Map> map) { + Iterator removed = list.iterator(); + while (removed.hasNext()) { + System.out.println(removed.next()); + } + for (Iterator> value = map.values().iterator(); value.hasNext();) { + System.out.println(value.next()); + } + } + } + """; + ICompilationUnit cu= pack.createCompilationUnit("Test.java", sample, false, null); + + enable(CleanUpConstants.CONTROL_STATEMENTS_CONVERT_FOR_LOOP_TO_ENHANCED); + + String expected= """ + package test; + + import java.util.Date; + import java.util.List; + import java.util.Map; + + public class Test { + private void method(List list, Map> map) { + for (String element : list) { + System.out.println(element); + } + for (List list2 : map.values()) { + System.out.println(list2); + } + } + } + """; + assertRefactoringResultAsExpected(new ICompilationUnit[] { cu }, new String[] { expected }, + new HashSet<>(Arrays.asList(FixMessages.Java50Fix_ConvertToEnhancedForLoop_description))); + } + @Test public void testRemoveSuppressWarnings() throws Exception { IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null); diff --git a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpRefactoring.java b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpRefactoring.java index cb455f73641..4f1b1a83b85 100644 --- a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpRefactoring.java +++ b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpRefactoring.java @@ -75,6 +75,7 @@ import org.eclipse.jdt.internal.corext.refactoring.Checks; import org.eclipse.jdt.internal.corext.refactoring.changes.DynamicValidationStateChange; import org.eclipse.jdt.internal.corext.refactoring.changes.MultiStateCompilationUnitChange; +import org.eclipse.jdt.internal.corext.refactoring.structure.ImportRemover; import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser; import org.eclipse.jdt.internal.corext.refactoring.util.TextEditUtil; import org.eclipse.jdt.internal.corext.util.Messages; @@ -782,6 +783,14 @@ public static CleanUpChange calculateChange(CleanUpContext context, ICleanUp[] c if (cleanUps.length == 0) return null; + // Create shared ImportRemover for all cleanups on this compilation unit + CompilationUnit ast = context.getAST(); + if (ast != null) { + IJavaProject project = context.getCompilationUnit().getJavaProject(); + ImportRemover sharedRemover = new ImportRemover(project, ast); + context.setSharedImportRemover(sharedRemover); + } + CleanUpChange solution= null; int i= 0; do { @@ -796,6 +805,10 @@ public static CleanUpChange calculateChange(CleanUpContext context, ICleanUp[] c fix= cleanUp.createFix(context); } if (fix != null) { + // Pass shared ImportRemover to fix if it supports it + if (fix instanceof CompilationUnitRewriteOperationsFixCore && context.getSharedImportRemover() != null) { + ((CompilationUnitRewriteOperationsFixCore) fix).setSharedImportRemover(context.getSharedImportRemover()); + } CompilationUnitChange current= fix.createChange(null); TextEdit currentEdit= current.getEdit();