LoopConversionQuickAssistProcessor.java
/*******************************************************************************
* Copyright (c) 2026 Carsten Hammer and others.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* https://www.eclipse.org/legal/epl-2.0/
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.sandbox.jdt.internal.ui.fix;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.internal.ui.text.correction.proposals.FixCorrectionProposal;
import org.eclipse.jdt.ui.cleanup.CleanUpOptions;
import org.eclipse.jdt.ui.text.java.IInvocationContext;
import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal;
import org.eclipse.jdt.ui.text.java.IProblemLocation;
import org.eclipse.jdt.ui.text.java.IQuickAssistProcessor;
import org.sandbox.jdt.internal.corext.fix.helper.LoopConversionService;
import org.sandbox.jdt.internal.corext.fix.helper.LoopTargetFormat;
import org.sandbox.jdt.internal.corext.fix2.MYCleanUpConstants;
import org.sandbox.jdt.internal.ui.preferences.cleanup.CleanUpMessages;
/** Native JDT proposals, including its change preview, undo and cleanup support. */
public final class LoopConversionQuickAssistProcessor implements IQuickAssistProcessor {
@Override
public boolean hasAssists(IInvocationContext context) {
if (context.getASTRoot() == null) {
return false;
}
for (LoopTargetFormat target : LoopTargetFormat.values()) {
if (!analyze(context, target, context.getSelectionOffset(), context.getSelectionLength()).operations().isEmpty()) {
return true;
}
}
return false;
}
@Override
public IJavaCompletionProposal[] getAssists(IInvocationContext context, IProblemLocation[] locations) throws CoreException {
if (context.getASTRoot() == null) {
return new IJavaCompletionProposal[0];
}
var proposals = new ArrayList<IJavaCompletionProposal>();
for (LoopTargetFormat target : LoopTargetFormat.values()) {
var proposal = proposal(context, target, context.getSelectionOffset(), context.getSelectionLength());
if (proposal != null) {
proposals.add(proposal);
}
}
return proposals.toArray(IJavaCompletionProposal[]::new);
}
static LoopConversionService.Analysis analyze(IInvocationContext context, LoopTargetFormat target, int offset, int length) {
return LoopConversionService.analyzeSelection(context.getASTRoot(), LoopConversionService.handlers(target), offset, length);
}
static FixCorrectionProposal proposal(IInvocationContext context, LoopTargetFormat target, int offset, int length) {
var fix = analyze(context, target, offset, length).createFix(label(target));
return fix == null ? null : new FixCorrectionProposal(fix,
new UseFunctionalCallCleanUp(options(target)), 50, null, context);
}
public static String label(LoopTargetFormat target) {
return switch (target) {
case STREAM -> CleanUpMessages.LoopConversion_Assist_Stream;
case FOR_LOOP -> CleanUpMessages.LoopConversion_Assist_EnhancedFor;
case WHILE_LOOP -> CleanUpMessages.LoopConversion_Assist_IteratorWhile;
};
}
public static Map<String, String> options(LoopTargetFormat target) {
Map<String, String> options = new HashMap<>();
options.put(MYCleanUpConstants.LOOP_CONVERSION_ENABLED, CleanUpOptions.TRUE);
options.put(MYCleanUpConstants.LOOP_CONVERSION_TARGET_FORMAT, target.getId());
LoopConversionService.handlers(target).forEach(handler ->
options.put(UseFunctionalCallCleanUpCore.sourceOption(handler), CleanUpOptions.TRUE));
return options;
}
}