1 11 12 package org.eclipse.jdt.internal.ui.text.correction; 13 14 import java.util.ArrayList ; 15 import java.util.Arrays ; 16 import java.util.Collection ; 17 18 import org.eclipse.core.runtime.IConfigurationElement; 19 import org.eclipse.core.runtime.ISafeRunnable; 20 import org.eclipse.core.runtime.IStatus; 21 import org.eclipse.core.runtime.MultiStatus; 22 import org.eclipse.core.runtime.Platform; 23 import org.eclipse.core.runtime.SafeRunner; 24 import org.eclipse.core.runtime.Status; 25 26 import org.eclipse.core.resources.IMarker; 27 28 import org.eclipse.jface.text.ITextViewer; 29 import org.eclipse.jface.text.Position; 30 import org.eclipse.jface.text.contentassist.ContentAssistEvent; 31 import org.eclipse.jface.text.contentassist.ICompletionListener; 32 import org.eclipse.jface.text.contentassist.ICompletionProposal; 33 import org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext; 34 import org.eclipse.jface.text.source.Annotation; 35 import org.eclipse.jface.text.source.IAnnotationModel; 36 37 import org.eclipse.ui.IEditorPart; 38 import org.eclipse.ui.IMarkerHelpRegistry; 39 import org.eclipse.ui.IMarkerResolution; 40 import org.eclipse.ui.texteditor.SimpleMarkerAnnotation; 41 42 import org.eclipse.ui.ide.IDE; 43 44 import org.eclipse.ltk.core.refactoring.NullChange; 45 46 import org.eclipse.jdt.core.ICompilationUnit; 47 48 import org.eclipse.jdt.ui.JavaUI; 49 import org.eclipse.jdt.ui.text.java.CompletionProposalComparator; 50 import org.eclipse.jdt.ui.text.java.IInvocationContext; 51 import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal; 52 import org.eclipse.jdt.ui.text.java.IProblemLocation; 53 import org.eclipse.jdt.ui.text.java.IQuickAssistProcessor; 54 import org.eclipse.jdt.ui.text.java.IQuickFixProcessor; 55 56 import org.eclipse.jdt.internal.ui.JavaPlugin; 57 import org.eclipse.jdt.internal.ui.javaeditor.IJavaAnnotation; 58 59 60 public class JavaCorrectionProcessor implements org.eclipse.jface.text.quickassist.IQuickAssistProcessor { 61 62 private static final String QUICKFIX_PROCESSOR_CONTRIBUTION_ID= "quickFixProcessors"; private static final String QUICKASSIST_PROCESSOR_CONTRIBUTION_ID= "quickAssistProcessors"; 65 private static ContributedProcessorDescriptor[] fgContributedAssistProcessors= null; 66 private static ContributedProcessorDescriptor[] fgContributedCorrectionProcessors= null; 67 68 private static ContributedProcessorDescriptor[] getProcessorDescriptors(String contributionId, boolean testMarkerTypes) { 69 IConfigurationElement[] elements= Platform.getExtensionRegistry().getConfigurationElementsFor(JavaUI.ID_PLUGIN, contributionId); 70 ArrayList res= new ArrayList (elements.length); 71 72 for (int i= 0; i < elements.length; i++) { 73 ContributedProcessorDescriptor desc= new ContributedProcessorDescriptor(elements[i], testMarkerTypes); 74 IStatus status= desc.checkSyntax(); 75 if (status.isOK()) { 76 res.add(desc); 77 } else { 78 JavaPlugin.log(status); 79 } 80 } 81 return (ContributedProcessorDescriptor[]) res.toArray(new ContributedProcessorDescriptor[res.size()]); 82 } 83 84 private static ContributedProcessorDescriptor[] getCorrectionProcessors() { 85 if (fgContributedCorrectionProcessors == null) { 86 fgContributedCorrectionProcessors= getProcessorDescriptors(QUICKFIX_PROCESSOR_CONTRIBUTION_ID, true); 87 } 88 return fgContributedCorrectionProcessors; 89 } 90 91 private static ContributedProcessorDescriptor[] getAssistProcessors() { 92 if (fgContributedAssistProcessors == null) { 93 fgContributedAssistProcessors= getProcessorDescriptors(QUICKASSIST_PROCESSOR_CONTRIBUTION_ID, false); 94 } 95 return fgContributedAssistProcessors; 96 } 97 98 public static boolean hasCorrections(ICompilationUnit cu, int problemId, String markerType) { 99 ContributedProcessorDescriptor[] processors= getCorrectionProcessors(); 100 SafeHasCorrections collector= new SafeHasCorrections(cu, problemId); 101 for (int i= 0; i < processors.length; i++) { 102 if (processors[i].canHandleMarkerType(markerType)) { 103 collector.process(processors[i]); 104 if (collector.hasCorrections()) { 105 return true; 106 } 107 } 108 } 109 return false; 110 } 111 112 public static boolean isQuickFixableType(Annotation annotation) { 113 return (annotation instanceof IJavaAnnotation || annotation instanceof SimpleMarkerAnnotation) && !annotation.isMarkedDeleted(); 114 } 115 116 117 public static boolean hasCorrections(Annotation annotation) { 118 if (annotation instanceof IJavaAnnotation) { 119 IJavaAnnotation javaAnnotation= (IJavaAnnotation) annotation; 120 int problemId= javaAnnotation.getId(); 121 if (problemId != -1) { 122 ICompilationUnit cu= javaAnnotation.getCompilationUnit(); 123 if (cu != null) { 124 return hasCorrections(cu, problemId, javaAnnotation.getMarkerType()); 125 } 126 } 127 } 128 if (annotation instanceof SimpleMarkerAnnotation) { 129 return hasCorrections(((SimpleMarkerAnnotation) annotation).getMarker()); 130 } 131 return false; 132 } 133 134 private static boolean hasCorrections(IMarker marker) { 135 if (marker == null || !marker.exists()) 136 return false; 137 138 IMarkerHelpRegistry registry= IDE.getMarkerHelpRegistry(); 139 return registry != null && registry.hasResolutions(marker); 140 } 141 142 public static boolean hasAssists(IInvocationContext context) { 143 ContributedProcessorDescriptor[] processors= getAssistProcessors(); 144 SafeHasAssist collector= new SafeHasAssist(context); 145 146 for (int i= 0; i < processors.length; i++) { 147 collector.process(processors[i]); 148 if (collector.hasAssists()) { 149 return true; 150 } 151 } 152 return false; 153 } 154 155 private JavaCorrectionAssistant fAssistant; 156 private String fErrorMessage; 157 158 161 public JavaCorrectionProcessor(JavaCorrectionAssistant assistant) { 162 fAssistant= assistant; 163 fAssistant.addCompletionListener(new ICompletionListener() { 164 165 public void assistSessionEnded(ContentAssistEvent event) { 166 fAssistant.setStatusLineVisible(false); 167 } 168 169 public void assistSessionStarted(ContentAssistEvent event) { 170 fAssistant.setStatusLineVisible(true); 171 } 172 173 public void selectionChanged(ICompletionProposal proposal, boolean smartToggle) { 174 if (proposal instanceof IStatusLineProposal) { 175 IStatusLineProposal statusLineProposal= (IStatusLineProposal)proposal; 176 String message= statusLineProposal.getStatusMessage(); 177 if (message != null) { 178 fAssistant.setStatusMessage(message); 179 } else { 180 fAssistant.setStatusMessage(""); } 182 } else { 183 fAssistant.setStatusMessage(""); } 185 } 186 }); 187 } 188 189 192 public ICompletionProposal[] computeQuickAssistProposals(IQuickAssistInvocationContext quickAssistContext) { 193 ITextViewer viewer= quickAssistContext.getSourceViewer(); 194 int documentOffset= quickAssistContext.getOffset(); 195 196 IEditorPart part= fAssistant.getEditor(); 197 198 ICompilationUnit cu= JavaUI.getWorkingCopyManager().getWorkingCopy(part.getEditorInput()); 199 IAnnotationModel model= JavaUI.getDocumentProvider().getAnnotationModel(part.getEditorInput()); 200 201 int length= viewer != null ? viewer.getSelectedRange().y : 0; 202 AssistContext context= new AssistContext(cu, documentOffset, length); 203 204 Annotation[] annotations= fAssistant.getAnnotationsAtOffset(); 205 206 fErrorMessage= null; 207 208 ICompletionProposal[] res= null; 209 if (model != null && annotations != null) { 210 ArrayList proposals= new ArrayList (10); 211 IStatus status= collectProposals(context, model, annotations, true, !fAssistant.isUpdatedOffset(), proposals); 212 res= (ICompletionProposal[]) proposals.toArray(new ICompletionProposal[proposals.size()]); 213 if (!status.isOK()) { 214 fErrorMessage= status.getMessage(); 215 JavaPlugin.log(status); 216 } 217 } 218 219 if (res == null || res.length == 0) { 220 return new ICompletionProposal[] { new ChangeCorrectionProposal(CorrectionMessages.NoCorrectionProposal_description, new NullChange(""), 0, null) }; } 222 if (res.length > 1) { 223 Arrays.sort(res, new CompletionProposalComparator()); 224 } 225 return res; 226 } 227 228 public static IStatus collectProposals(IInvocationContext context, IAnnotationModel model, Annotation[] annotations, boolean addQuickFixes, boolean addQuickAssists, Collection proposals) { 229 ArrayList problems= new ArrayList (); 230 231 for (int i= 0; i < annotations.length; i++) { 233 Annotation curr= annotations[i]; 234 if (curr instanceof IJavaAnnotation) { 235 ProblemLocation problemLocation= getProblemLocation((IJavaAnnotation) curr, model); 236 if (problemLocation != null) { 237 problems.add(problemLocation); 238 } 239 } else if (addQuickFixes && curr instanceof SimpleMarkerAnnotation) { 240 collectMarkerProposals((SimpleMarkerAnnotation) curr, proposals); 242 } 243 } 244 MultiStatus resStatus= null; 245 246 IProblemLocation[] problemLocations= (IProblemLocation[]) problems.toArray(new IProblemLocation[problems.size()]); 247 if (addQuickFixes) { 248 IStatus status= collectCorrections(context, problemLocations, proposals); 249 if (!status.isOK()) { 250 resStatus= new MultiStatus(JavaUI.ID_PLUGIN, IStatus.ERROR, CorrectionMessages.JavaCorrectionProcessor_error_quickfix_message, null); 251 resStatus.add(status); 252 } 253 } 254 if (addQuickAssists) { 255 IStatus status= collectAssists(context, problemLocations, proposals); 256 if (!status.isOK()) { 257 if (resStatus == null) { 258 resStatus= new MultiStatus(JavaUI.ID_PLUGIN, IStatus.ERROR, CorrectionMessages.JavaCorrectionProcessor_error_quickassist_message, null); 259 } 260 resStatus.add(status); 261 } 262 } 263 if (resStatus != null) { 264 return resStatus; 265 } 266 return Status.OK_STATUS; 267 } 268 269 private static ProblemLocation getProblemLocation(IJavaAnnotation javaAnnotation, IAnnotationModel model) { 270 int problemId= javaAnnotation.getId(); 271 if (problemId != -1) { 272 Position pos= model.getPosition((Annotation) javaAnnotation); 273 if (pos != null) { 274 return new ProblemLocation(pos.getOffset(), pos.getLength(), javaAnnotation); } 276 } 277 return null; 278 } 279 280 private static void collectMarkerProposals(SimpleMarkerAnnotation annotation, Collection proposals) { 281 IMarker marker= annotation.getMarker(); 282 IMarkerResolution[] res= IDE.getMarkerHelpRegistry().getResolutions(marker); 283 if (res.length > 0) { 284 for (int i= 0; i < res.length; i++) { 285 proposals.add(new MarkerResolutionProposal(res[i], marker)); 286 } 287 } 288 } 289 290 private static abstract class SafeCorrectionProcessorAccess implements ISafeRunnable { 291 private MultiStatus fMulti= null; 292 private ContributedProcessorDescriptor fDescriptor; 293 294 public void process(ContributedProcessorDescriptor[] desc) { 295 for (int i= 0; i < desc.length; i++) { 296 fDescriptor= desc[i]; 297 SafeRunner.run(this); 298 } 299 } 300 301 public void process(ContributedProcessorDescriptor desc) { 302 fDescriptor= desc; 303 SafeRunner.run(this); 304 } 305 306 public void run() throws Exception { 307 safeRun(fDescriptor); 308 } 309 310 protected abstract void safeRun(ContributedProcessorDescriptor processor) throws Exception ; 311 312 public void handleException(Throwable exception) { 313 if (fMulti == null) { 314 fMulti= new MultiStatus(JavaUI.ID_PLUGIN, IStatus.OK, CorrectionMessages.JavaCorrectionProcessor_error_status, null); 315 } 316 fMulti.merge(new Status(IStatus.ERROR, JavaUI.ID_PLUGIN, IStatus.ERROR, CorrectionMessages.JavaCorrectionProcessor_error_status, exception)); 317 } 318 319 public IStatus getStatus() { 320 if (fMulti == null) { 321 return Status.OK_STATUS; 322 } 323 return fMulti; 324 } 325 326 } 327 328 private static class SafeCorrectionCollector extends SafeCorrectionProcessorAccess { 329 private final IInvocationContext fContext; 330 private final Collection fProposals; 331 private IProblemLocation[] fLocations; 332 333 public SafeCorrectionCollector(IInvocationContext context, Collection proposals) { 334 fContext= context; 335 fProposals= proposals; 336 } 337 338 public void setProblemLocations(IProblemLocation[] locations) { 339 fLocations= locations; 340 } 341 342 public void safeRun(ContributedProcessorDescriptor desc) throws Exception { 343 IQuickFixProcessor curr= (IQuickFixProcessor) desc.getProcessor(fContext.getCompilationUnit()); 344 if (curr != null) { 345 IJavaCompletionProposal[] res= curr.getCorrections(fContext, fLocations); 346 if (res != null) { 347 for (int k= 0; k < res.length; k++) { 348 fProposals.add(res[k]); 349 } 350 } 351 } 352 } 353 } 354 355 private static class SafeAssistCollector extends SafeCorrectionProcessorAccess { 356 private final IInvocationContext fContext; 357 private final IProblemLocation[] fLocations; 358 private final Collection fProposals; 359 360 public SafeAssistCollector(IInvocationContext context, IProblemLocation[] locations, Collection proposals) { 361 fContext= context; 362 fLocations= locations; 363 fProposals= proposals; 364 } 365 366 public void safeRun(ContributedProcessorDescriptor desc) throws Exception { 367 IQuickAssistProcessor curr= (IQuickAssistProcessor) desc.getProcessor(fContext.getCompilationUnit()); 368 if (curr != null) { 369 IJavaCompletionProposal[] res= curr.getAssists(fContext, fLocations); 370 if (res != null) { 371 for (int k= 0; k < res.length; k++) { 372 fProposals.add(res[k]); 373 } 374 } 375 } 376 } 377 } 378 379 private static class SafeHasAssist extends SafeCorrectionProcessorAccess { 380 private final IInvocationContext fContext; 381 private boolean fHasAssists; 382 383 public SafeHasAssist(IInvocationContext context) { 384 fContext= context; 385 fHasAssists= false; 386 } 387 388 public boolean hasAssists() { 389 return fHasAssists; 390 } 391 392 public void safeRun(ContributedProcessorDescriptor desc) throws Exception { 393 IQuickAssistProcessor processor= (IQuickAssistProcessor) desc.getProcessor(fContext.getCompilationUnit()); 394 if (processor != null && processor.hasAssists(fContext)) { 395 fHasAssists= true; 396 } 397 } 398 } 399 400 private static class SafeHasCorrections extends SafeCorrectionProcessorAccess { 401 private final ICompilationUnit fCu; 402 private final int fProblemId; 403 private boolean fHasCorrections; 404 405 public SafeHasCorrections(ICompilationUnit cu, int problemId) { 406 fCu= cu; 407 fProblemId= problemId; 408 fHasCorrections= false; 409 } 410 411 public boolean hasCorrections() { 412 return fHasCorrections; 413 } 414 415 public void safeRun(ContributedProcessorDescriptor desc) throws Exception { 416 IQuickFixProcessor processor= (IQuickFixProcessor) desc.getProcessor(fCu); 417 if (processor != null && processor.hasCorrections(fCu, fProblemId)) { 418 fHasCorrections= true; 419 } 420 } 421 } 422 423 424 public static IStatus collectCorrections(IInvocationContext context, IProblemLocation[] locations, Collection proposals) { 425 ContributedProcessorDescriptor[] processors= getCorrectionProcessors(); 426 SafeCorrectionCollector collector= new SafeCorrectionCollector(context, proposals); 427 for (int i= 0; i < processors.length; i++) { 428 ContributedProcessorDescriptor curr= processors[i]; 429 IProblemLocation[] handled= getHandledProblems(locations, curr); 430 if (handled != null) { 431 collector.setProblemLocations(handled); 432 collector.process(curr); 433 } 434 } 435 return collector.getStatus(); 436 } 437 438 private static IProblemLocation[] getHandledProblems(IProblemLocation[] locations, ContributedProcessorDescriptor processor) { 439 boolean allHandled= true; 441 ArrayList res= null; 442 for (int i= 0; i < locations.length; i++) { 443 IProblemLocation curr= locations[i]; 444 if (processor.canHandleMarkerType(curr.getMarkerType())) { 445 if (!allHandled) { if (res == null) { 447 res= new ArrayList (locations.length - i); 448 } 449 res.add(curr); 450 } 451 } else if (allHandled) { 452 if (i > 0) { res= new ArrayList (locations.length - i); 454 for (int k= 0; k < i; k++) { 455 res.add(locations[k]); 456 } 457 } 458 allHandled= false; 459 } 460 } 461 if (allHandled) { 462 return locations; 463 } 464 if (res == null) { 465 return null; 466 } 467 return (IProblemLocation[]) res.toArray(new IProblemLocation[res.size()]); 468 } 469 470 public static IStatus collectAssists(IInvocationContext context, IProblemLocation[] locations, Collection proposals) { 471 ContributedProcessorDescriptor[] processors= getAssistProcessors(); 472 SafeAssistCollector collector= new SafeAssistCollector(context, locations, proposals); 473 collector.process(processors); 474 475 return collector.getStatus(); 476 } 477 478 481 public String getErrorMessage() { 482 return fErrorMessage; 483 } 484 485 489 public boolean canFix(Annotation annotation) { 490 return hasCorrections(annotation); 491 } 492 493 497 public boolean canAssist(IQuickAssistInvocationContext invocationContext) { 498 if (invocationContext instanceof IInvocationContext) 499 return hasAssists((IInvocationContext)invocationContext); 500 return false; 501 } 502 503 } 504 | Popular Tags |