Question

During a refactoring of some legacy code the need came up to create our own Eclipse Quick Fix to do some small corrections to the code. This (in itself) was simple enough following this article (in German): http://jaxenter.de/artikel/Eclipse-JDT-um-eigene-Quickfixes-erweitern

The quick fix (IQuickFixProcessor) is added through the extension point org.eclipse.jdt.ui.quickFixProcessors which creates a IJavaCompletionProposal to do the work. The IQuickFixProcessor has an AST readily available to do the code changes on.

The problem I am facing now, is that I can only apply the Quick Fix to one problem at a time. If I select multiple Problems (all of the same type, so my custom Quick Fix is applicable), I get the error "The selected problems do not have a common applicable quick fix".

How can I create a Quick Fix, that can be used for multiple problems of the same type?

Using the extension point org.eclipse.ui.ide.markerResolution as suggested by Acanda seems to be very difficult to implement for Java source files. For one there is no AST available, only an IMarker instance. How do I get the AST CompilationUnit and the offending ASTNode for an IMarker?

More general: Is there an API bridge in JDT to work with IMarker instances`?

Était-ce utile?

La solution

To support fixing multiple problems at the same time your quick fix has to implement org.eclipse.ui.views.markers.WorkbenchMarkerResolution and must be registered using the extention point org.eclipse.ui.ide.markerResolution. The following example is from the Eclipse plug-in eclipse-pmd:

<extension
     point="org.eclipse.ui.ide.markerResolution">
   <markerResolutionGenerator
        class="ch.acanda.eclipse.pmd.java.resolution.PMDMarkerResolutionGenerator"
        markerType="ch.acanda.eclipse.pmd.core.pmdMarker">
   </markerResolutionGenerator>
</extension>

It is indeed a bit tricky to create a CompilationUnit from an IMarker and even trickier to find the offending ASTNode. Have a look at the abstract class ASTQuickFix from eclipse-pmd. It creates a CompilationUnit from an IMarker and delegates finding the ASTNode to its subclasses which can define their own node finding strategy, e.g. NodeWithinPositionNodeFinder.

Autres conseils

To get a ASTNode for a IMarker:

public ASTNode getASTNodeFromMarker(IMarker marker) {
    IResource res = marker.getResource();
    if (res.getType() == IResource.FILE) {
        IFile f = (IFile)res;
        ICompilationUnit cu = (ICompilationUnit)JavaCore.create(f);
        CompilationUnit astRoot = getAstRoot(cu);
        int start = marker.getAttribute(IMarker.CHAR_START, 0);
        int end = marker.getAttribute(IMarker.CHAR_END, 0);
        NodeFinder nf = new NodeFinder(astRoot, start, end-start);
        return nf.getCoveringNode();
    }
    return null;
}

private CompilationUnit getAstRoot(ITypeRoot typeRoot) {
    CompilationUnit root = SharedASTProvider.getAST(typeRoot, SharedASTProvider.WAIT_YES, null);
    if (root == null) {
        ASTParser astParser = ASTParser.newParser(AST.JLS8);
        astParser.setSource(typeRoot);
        astParser.setResolveBindings(true);
        astParser.setStatementsRecovery(true);
        astParser.setBindingsRecovery(true);
        root = (CompilationUnit)astParser.createAST(null);
    }
    return root;  // may return null if no source available for typeRoot
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top