/*******************************************************************************
* Copyright (c) 2000, 2012 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.jdt.internal.ui.text.correction;
import org.eclipse.che.ide.ext.java.shared.dto.Problem;
import org.eclipse.che.jface.text.contentassist.ICompletionProposal;
import org.eclipse.che.jface.text.quickassist.IQuickAssistInvocationContext;
import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.internal.ui.JavaPlugin;
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.eclipse.jdt.ui.text.java.IQuickFixProcessor;
import org.eclipse.jface.text.source.Annotation;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class JavaCorrectionProcessor implements org.eclipse.che.jface.text.quickassist.IQuickAssistProcessor {
private static final String QUICKFIX_PROCESSOR_CONTRIBUTION_ID= "quickFixProcessors"; //$NON-NLS-1$
private static final String QUICKASSIST_PROCESSOR_CONTRIBUTION_ID= "quickAssistProcessors"; //$NON-NLS-1$
private static ContributedProcessorDescriptor[] fgContributedAssistProcessors= null;
private static ContributedProcessorDescriptor[] fgContributedCorrectionProcessors= null;
private static ContributedProcessorDescriptor[] getProcessorDescriptors(String contributionId, boolean testMarkerTypes) {
// IConfigurationElement[] elements= Platform.getExtensionRegistry().getConfigurationElementsFor(JavaPlugin.ID_PLUGIN, contributionId);
ArrayList<ContributedProcessorDescriptor> res= new ArrayList<>();
//
// for (int i= 0; i < elements.length; i++) {
// ContributedProcessorDescriptor desc= new ContributedProcessorDescriptor(elements[i], testMarkerTypes);
// IStatus status= desc.checkSyntax();
// if (status.isOK()) {
// res.add(desc);
// } else {
// JavaPlugin.log(status);
// }
// }
if(contributionId == QUICKFIX_PROCESSOR_CONTRIBUTION_ID) {
res.add(new ContributedProcessorDescriptor(new QuickFixProcessor(), testMarkerTypes));
} else {
res.add(new ContributedProcessorDescriptor(new QuickAssistProcessor(), testMarkerTypes));
res.add(new ContributedProcessorDescriptor(new AdvancedQuickAssistProcessor(), testMarkerTypes));
}
return res.toArray(new ContributedProcessorDescriptor[res.size()]);
}
private static ContributedProcessorDescriptor[] getCorrectionProcessors() {
if (fgContributedCorrectionProcessors == null) {
fgContributedCorrectionProcessors= getProcessorDescriptors(QUICKFIX_PROCESSOR_CONTRIBUTION_ID, true);
}
return fgContributedCorrectionProcessors;
}
private static ContributedProcessorDescriptor[] getAssistProcessors() {
if (fgContributedAssistProcessors == null) {
fgContributedAssistProcessors= getProcessorDescriptors(QUICKASSIST_PROCESSOR_CONTRIBUTION_ID, false);
}
return fgContributedAssistProcessors;
}
public static boolean hasCorrections(ICompilationUnit cu, int problemId, String markerType) {
ContributedProcessorDescriptor[] processors= getCorrectionProcessors();
SafeHasCorrections collector= new SafeHasCorrections(cu, problemId);
for (int i= 0; i < processors.length; i++) {
if (processors[i].canHandleMarkerType(markerType)) {
collector.process(processors[i]);
if (collector.hasCorrections()) {
return true;
}
}
}
return false;
}
// public static boolean isQuickFixableType(Annotation annotation) {
// return (annotation instanceof IJavaAnnotation || annotation instanceof SimpleMarkerAnnotation) && !annotation.isMarkedDeleted();
// }
public static boolean hasCorrections(Annotation annotation) {
// if (annotation instanceof IJavaAnnotation) {
// IJavaAnnotation javaAnnotation= (IJavaAnnotation) annotation;
// int problemId= javaAnnotation.getId();
// if (problemId != -1) {
// ICompilationUnit cu= javaAnnotation.getCompilationUnit();
// if (cu != null) {
// return hasCorrections(cu, problemId, javaAnnotation.getMarkerType());
// }
// }
// }
// if (annotation instanceof SimpleMarkerAnnotation) {
// return hasCorrections(((SimpleMarkerAnnotation) annotation).getMarker());
// }
// return false;
throw new UnsupportedOperationException("hasCorrections");
}
// private static boolean hasCorrections(IMarker marker) {
// if (marker == null || !marker.exists())
// return false;
//
// IMarkerHelpRegistry registry= IDE.getMarkerHelpRegistry();
// return registry != null && registry.hasResolutions(marker);
// }
public static boolean hasAssists(IInvocationContext context) {
ContributedProcessorDescriptor[] processors= getAssistProcessors();
SafeHasAssist collector= new SafeHasAssist(context);
for (int i= 0; i < processors.length; i++) {
collector.process(processors[i]);
if (collector.hasAssists()) {
return true;
}
}
return false;
}
// private JavaCorrectionAssistant fAssistant;
private String fErrorMessage;
/*
* Constructor for JavaCorrectionProcessor.
*/
public JavaCorrectionProcessor(/*JavaCorrectionAssistant assistant*/) {
// fAssistant= assistant;
// fAssistant.addCompletionListener(new ICompletionListener() {
//
// public void assistSessionEnded(ContentAssistEvent event) {
// fAssistant.setStatusLineVisible(false);
// }
//
// public void assistSessionStarted(ContentAssistEvent event) {
// fAssistant.setStatusLineVisible(true);
// fAssistant.setStatusMessage(getJumpHintStatusLineMessage());
// }
//
// public void selectionChanged(ICompletionProposal proposal, boolean smartToggle) {
// if (proposal instanceof IStatusLineProposal) {
// IStatusLineProposal statusLineProposal= (IStatusLineProposal)proposal;
// String message= statusLineProposal.getStatusMessage();
// if (message != null) {
// fAssistant.setStatusMessage(message);
// return;
// }
// }
// fAssistant.setStatusMessage(getJumpHintStatusLineMessage());
// }
//
// private String getJumpHintStatusLineMessage() {
// if (fAssistant.isUpdatedOffset()) {
// String key= getQuickAssistBinding();
// if (key == null)
// return CorrectionMessages.JavaCorrectionProcessor_go_to_original_using_menu;
// else
// return Messages.format(CorrectionMessages.JavaCorrectionProcessor_go_to_original_using_key, key);
// } else if (fAssistant.isProblemLocationAvailable()) {
// String key= getQuickAssistBinding();
// if (key == null)
// return CorrectionMessages.JavaCorrectionProcessor_go_to_closest_using_menu;
// else
// return Messages.format(CorrectionMessages.JavaCorrectionProcessor_go_to_closest_using_key, key);
// } else
// return ""; //$NON-NLS-1$
// }
//
// private String getQuickAssistBinding() {
// final IBindingService bindingSvc= (IBindingService) PlatformUI.getWorkbench().getAdapter(IBindingService.class);
// return bindingSvc.getBestActiveBindingFormattedFor(ITextEditorActionDefinitionIds.QUICK_ASSIST);
// }
// });
}
/*
* @see IContentAssistProcessor#computeCompletionProposals(ITextViewer, int)
*/
public ICompletionProposal[] computeQuickAssistProposals(IQuickAssistInvocationContext quickAssistContext) {
// ISourceViewer viewer= quickAssistContext.getSourceViewer();
// int documentOffset= quickAssistContext.getOffset();
//
//// IEditorPart part= fAssistant.getEditor();
//
// ICompilationUnit cu= JavaUI.getWorkingCopyManager().getWorkingCopy(part.getEditorInput());
// IAnnotationModel model= JavaUI.getDocumentProvider().getAnnotationModel(part.getEditorInput());
//
// AssistContext context= null;
// if (cu != null) {
// int length= viewer != null ? viewer.getSelectedRange().y : 0;
// context= new AssistContext(cu, viewer, /*part, */documentOffset, length);
// }
//
// Annotation[] annotations= fAssistant.getAnnotationsAtOffset();
//
// fErrorMessage= null;
//
// ICompletionProposal[] res= null;
// if (model != null && context != null && annotations != null) {
// ArrayList<IJavaCompletionProposal> proposals= new ArrayList<IJavaCompletionProposal>(10);
// IStatus status= collectProposals(context, model, annotations, true, !fAssistant.isUpdatedOffset(), proposals);
// res= proposals.toArray(new ICompletionProposal[proposals.size()]);
// if (!status.isOK()) {
// fErrorMessage= status.getMessage();
// JavaPlugin.log(status);
// }
// }
//
// if (res == null || res.length == 0) {
// return new ICompletionProposal[] { new ChangeCorrectionProposal(CorrectionMessages.NoCorrectionProposal_description, new
// NullChange(""), IProposalRelevance.NO_SUGGESSTIONS_AVAILABLE, null) }; //$NON-NLS-1$
// }
// if (res.length > 1) {
// Arrays.sort(res, new CompletionProposalComparator());
// }
// return res;
throw new UnsupportedOperationException("computeQuickAssistProposals");
}
public static IStatus collectProposals(IInvocationContext context, /*IAnnotationModel model, */List<Problem> annotations, boolean addQuickFixes, boolean addQuickAssists, Collection<IJavaCompletionProposal> proposals) {
ArrayList<ProblemLocation> problems= new ArrayList<>();
// collect problem locations and corrections from marker annotations
for (Problem curr : annotations) {
problems.add(new ProblemLocation(curr));
}
// for (int i= 0; i < annotations.length; i++) {
// Annotation curr= annotations[i];
// ProblemLocation problemLocation= null;
// if (curr instanceof IJavaAnnotation) {
// problemLocation= getProblemLocation((IJavaAnnotation) curr, model);
// if (problemLocation != null) {
// problems.add(problemLocation);
// }
// }
//// if (problemLocation == null && addQuickFixes && curr instanceof SimpleMarkerAnnotation) {
//// collectMarkerProposals((SimpleMarkerAnnotation) curr, proposals);
//// }
// }
MultiStatus resStatus= null;
IProblemLocation[] problemLocations= problems.toArray(new IProblemLocation[problems.size()]);
if (addQuickFixes) {
IStatus status= collectCorrections(context, problemLocations, proposals);
if (!status.isOK()) {
resStatus= new MultiStatus(JavaPlugin.ID_PLUGIN, IStatus.ERROR, CorrectionMessages.JavaCorrectionProcessor_error_quickfix_message, null);
resStatus.add(status);
}
}
if (addQuickAssists) {
IStatus status= collectAssists(context, problemLocations, proposals);
if (!status.isOK()) {
if (resStatus == null) {
resStatus= new MultiStatus(JavaPlugin.ID_PLUGIN, IStatus.ERROR, CorrectionMessages.JavaCorrectionProcessor_error_quickassist_message, null);
}
resStatus.add(status);
}
}
if (resStatus != null) {
return resStatus;
}
return Status.OK_STATUS;
}
// private static ProblemLocation getProblemLocation(IJavaAnnotation javaAnnotation, IAnnotationModel model) {
// int problemId= javaAnnotation.getId();
// if (problemId != -1) {
// Position pos= model.getPosition((Annotation) javaAnnotation);
// if (pos != null) {
// return new ProblemLocation(pos.getOffset(), pos.getLength(), javaAnnotation); // java problems all handled by the quick assist processors
// }
// }
// return null;
// }
// private static void collectMarkerProposals(SimpleMarkerAnnotation annotation, Collection<IJavaCompletionProposal> proposals) {
// IMarker marker= annotation.getMarker();
// IMarkerResolution[] res= IDE.getMarkerHelpRegistry().getResolutions(marker);
// if (res.length > 0) {
// for (int i= 0; i < res.length; i++) {
// proposals.add(new MarkerResolutionProposal(res[i], marker));
// }
// }
// }
private static abstract class SafeCorrectionProcessorAccess implements ISafeRunnable {
private MultiStatus fMulti = null;
private ContributedProcessorDescriptor fDescriptor;
public void process(ContributedProcessorDescriptor[] desc) {
for (int i = 0; i < desc.length; i++) {
fDescriptor = desc[i];
SafeRunner.run(this);
}
}
public void process(ContributedProcessorDescriptor desc) {
fDescriptor = desc;
SafeRunner.run(this);
}
public void run() throws Exception {
safeRun(fDescriptor);
}
protected abstract void safeRun(ContributedProcessorDescriptor processor) throws Exception;
public void handleException(Throwable exception) {
if (fMulti == null) {
fMulti = new MultiStatus(JavaPlugin.ID_PLUGIN, IStatus.OK, CorrectionMessages.JavaCorrectionProcessor_error_status, null);
}
fMulti.merge(new Status(IStatus.ERROR, JavaPlugin.ID_PLUGIN, IStatus.ERROR, CorrectionMessages
.JavaCorrectionProcessor_error_status,
exception));
}
public IStatus getStatus() {
if (fMulti == null) {
return Status.OK_STATUS;
}
return fMulti;
}
}
private static class SafeCorrectionCollector extends SafeCorrectionProcessorAccess {
private final IInvocationContext fContext;
private final Collection<IJavaCompletionProposal> fProposals;
private IProblemLocation[] fLocations;
public SafeCorrectionCollector(IInvocationContext context, Collection<IJavaCompletionProposal> proposals) {
fContext = context;
fProposals = proposals;
}
public void setProblemLocations(IProblemLocation[] locations) {
fLocations = locations;
}
@Override
public void safeRun(ContributedProcessorDescriptor desc) throws Exception {
IQuickFixProcessor curr = (IQuickFixProcessor)desc.getProcessor(fContext.getCompilationUnit(), IQuickFixProcessor.class);
if (curr != null) {
IJavaCompletionProposal[] res = curr.getCorrections(fContext, fLocations);
if (res != null) {
for (int k = 0; k < res.length; k++) {
fProposals.add(res[k]);
}
}
}
}
}
private static class SafeAssistCollector extends SafeCorrectionProcessorAccess {
private final IInvocationContext fContext;
private final IProblemLocation[] fLocations;
private final Collection<IJavaCompletionProposal> fProposals;
public SafeAssistCollector(IInvocationContext context, IProblemLocation[] locations,
Collection<IJavaCompletionProposal> proposals) {
fContext = context;
fLocations = locations;
fProposals = proposals;
}
@Override
public void safeRun(ContributedProcessorDescriptor desc) throws Exception {
IQuickAssistProcessor curr =
(IQuickAssistProcessor)desc.getProcessor(fContext.getCompilationUnit(), IQuickAssistProcessor.class);
if (curr != null) {
IJavaCompletionProposal[] res = curr.getAssists(fContext, fLocations);
if (res != null) {
for (int k = 0; k < res.length; k++) {
fProposals.add(res[k]);
}
}
}
}
}
private static class SafeHasAssist extends SafeCorrectionProcessorAccess {
private final IInvocationContext fContext;
private boolean fHasAssists;
public SafeHasAssist(IInvocationContext context) {
fContext = context;
fHasAssists = false;
}
public boolean hasAssists() {
return fHasAssists;
}
@Override
public void safeRun(ContributedProcessorDescriptor desc) throws Exception {
IQuickAssistProcessor processor =
(IQuickAssistProcessor)desc.getProcessor(fContext.getCompilationUnit(), IQuickAssistProcessor.class);
if (processor != null && processor.hasAssists(fContext)) {
fHasAssists = true;
}
}
}
private static class SafeHasCorrections extends SafeCorrectionProcessorAccess {
private final ICompilationUnit fCu;
private final int fProblemId;
private boolean fHasCorrections;
public SafeHasCorrections(ICompilationUnit cu, int problemId) {
fCu = cu;
fProblemId = problemId;
fHasCorrections = false;
}
public boolean hasCorrections() {
return fHasCorrections;
}
@Override
public void safeRun(ContributedProcessorDescriptor desc) throws Exception {
IQuickFixProcessor processor = (IQuickFixProcessor)desc.getProcessor(fCu, IQuickFixProcessor.class);
if (processor != null && processor.hasCorrections(fCu, fProblemId)) {
fHasCorrections = true;
}
}
}
public static IStatus collectCorrections(IInvocationContext context, IProblemLocation[] locations,
Collection<IJavaCompletionProposal> proposals) {
ContributedProcessorDescriptor[] processors = getCorrectionProcessors();
SafeCorrectionCollector collector = new SafeCorrectionCollector(context, proposals);
for (int i = 0; i < processors.length; i++) {
ContributedProcessorDescriptor curr = processors[i];
IProblemLocation[] handled = getHandledProblems(locations, curr);
if (handled != null) {
collector.setProblemLocations(handled);
collector.process(curr);
}
}
return collector.getStatus();
}
private static IProblemLocation[] getHandledProblems(IProblemLocation[] locations, ContributedProcessorDescriptor processor) {
// implementation tries to avoid creating a new array
boolean allHandled = true;
ArrayList<IProblemLocation> res = null;
for (int i = 0; i < locations.length; i++) {
IProblemLocation curr = locations[i];
if (processor.canHandleMarkerType(curr.getMarkerType())) {
if (!allHandled) { // first handled problem
if (res == null) {
res = new ArrayList<IProblemLocation>(locations.length - i);
}
res.add(curr);
}
} else if (allHandled) {
if (i > 0) { // first non handled problem
res = new ArrayList<IProblemLocation>(locations.length - i);
for (int k = 0; k < i; k++) {
res.add(locations[k]);
}
}
allHandled = false;
}
}
if (allHandled) {
return locations;
}
if (res == null) {
return null;
}
return res.toArray(new IProblemLocation[res.size()]);
}
public static IStatus collectAssists(IInvocationContext context, IProblemLocation[] locations,
Collection<IJavaCompletionProposal> proposals) {
ContributedProcessorDescriptor[] processors = getAssistProcessors();
SafeAssistCollector collector = new SafeAssistCollector(context, locations, proposals);
collector.process(processors);
return collector.getStatus();
}
/*
* @see IContentAssistProcessor#getErrorMessage()
*/
public String getErrorMessage() {
return fErrorMessage;
}
/*
* @see org.eclipse.jface.text.quickassist.IQuickAssistProcessor#canFix(org.eclipse.jface.text.source.Annotation)
* @since 3.2
*/
public boolean canFix(Annotation annotation) {
return hasCorrections(annotation);
}
/*
* @see org.eclipse.jface.text.quickassist.IQuickAssistProcessor#canAssist(org.eclipse.jface.text.quickassist
* .IQuickAssistInvocationContext)
* @since 3.2
*/
public boolean canAssist(IQuickAssistInvocationContext invocationContext) {
if (invocationContext instanceof IInvocationContext)
return hasAssists((IInvocationContext)invocationContext);
return false;
}
}