简体   繁体   English

如何为自定义Java标记添加Eclipse Quick Fix?

[英]How can I add an Eclipse Quick Fix for a custom Java marker?

I'd like to report custom problems for Java files to the Problems View of Eclipse and provide Quick Fixes for them. 我想将Eclipse文件的自定义问题报告给Eclipse的Problems View,并为它们提供快速修复。

The standard way to do is to use the extension point org.eclipse.core.resources.markers to declare a custom marker and add markers by calling org.eclipse.core.resources.IResource.createMarker(String) . 标准方法是使用扩展点org.eclipse.core.resources.markers来声明自定义标记并通过调用org.eclipse.core.resources.IResource.createMarker(String)添加标记。 Then, one can use the extension point org.eclipse.ui.ide.markerResolution to provide a Quick Fix for the custom markers. 然后,可以使用扩展点org.eclipse.ui.ide.markerResolution为自定义标记提供快速修复。

The above approach is a language-independent method of creating and resolving resource markers. 上述方法是一种与语言无关的创建和解析资源标记的方法。 The downside is that I have to write some boilerplate code to resolve my custom Java problems. 缺点是我必须编写一些样板代码来解决我的自定义Java问题。 Instead, I'd like to be reuse IQuickFixProcessor . 相反,我想重用IQuickFixProcessor That is, I'd like to resolve my custom Java markers using the extension point org.eclipse.jdt.ui.quickFixProcessors . 也就是说,我想使用扩展点org.eclipse.jdt.ui.quickFixProcessors解析我的自定义Java标记。 Using this extension point, I no longer have to parse the Java file in which the marker is found, I don't have to build the bindings and find the AST node covering the marker. 使用此扩展点,我不再需要解析找到标记的Java文件,我不必构建绑定并找到覆盖标记的AST节点。 If I don't reuse org.eclipse.jdt.internal.ui.text.correction.CorrectionMarkerResolutionGenerator and its dependencies, I'll end up duplicating most of it. 如果我不重用org.eclipse.jdt.internal.ui.text.correction.CorrectionMarkerResolutionGenerator及其依赖项,我最终会重复大部分内容。

How can I provide Quick Fixes for my custom Java markers using the JDT infrastructure? 如何使用JDT基础结构为我的自定义Java标记提供快速修复?

Attempt 1: 尝试1:

I defined my custom marker as follows: 我将自定义标记定义如下:

<extension
  id="custom.marker"
  name="Custom Java Problem"
  point="org.eclipse.core.resources.markers">
    <super type="org.eclipse.jdt.core.problem"/>
    <super type="org.eclipse.core.resources.problemmarker"/>
    <super type="org.eclipse.core.resources.textmarker"/>
    <persistent value="true"/>
</extension>

Then, I added instances of the above marker by invoking method IResource.createMarker("custom.marker") . 然后,我通过调用方法IResource.createMarker("custom.marker")添加了上述标记的实例。

Next, I defined a custom Quick Fix processor. 接下来,我定义了一个自定义Quick Fix处理器。

<extension
  point="org.eclipse.jdt.ui.quickFixProcessors">
  <quickFixProcessor
    class="quickfixes.CustomQuickFixProcessor"
    id="quickfixes.quickFixProcessor">
  </quickFixProcessor>
</extension>

My custom markers show up in the Problems View of Eclipse, but when I right-click on a custom problem, the Quick Fix menu item is disabled. 我的自定义标记出现在Eclipse的Problems View中,但是当我右键单击自定义问题时,Quick Fix菜单项被禁用。

Attempt 2: 尝试2:

I repalced IMarker marker = resource.createMarker("custom.marker"); 我重新调整了IMarker marker = resource.createMarker("custom.marker"); by IMarker marker = resource.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER); 通过IMarker marker = resource.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER); . As a result of this change, when I right-click on a custom problem in the Problems View, the Quick Fix menu item becomes available, but, when I select it, a dialog pops up that says there is no fix available for the selected problem. 作为此更改的结果,当我右键单击“问题视图”中的自定义问题时,“快速修复”菜单项变为可用,但是,当我选择它时,会弹出一个对话框,指出没有可用的选项问题。 However, I verified that CustomQuickFixProcessor.hasCorrections(ICompilationUnit, int) gets called and returns true , but, CustomQuickFixProcessor.getCorrections(IInvocationContext, IProblemLocation[]) doesn't get invoked. 但是,我验证了CustomQuickFixProcessor.hasCorrections(ICompilationUnit, int)被调用并返回true ,但是,不会调用CustomQuickFixProcessor.getCorrections(IInvocationContext, IProblemLocation[])

Attempt 3: 尝试3:

Attempt 3 is a continuation of Attempt 2. I set the IJavaModelMarker.ID of the custom marker as follows: 尝试3是尝试2的延续。我设置自定义标记的IJavaModelMarker.ID ,如下所示:

marker.setAttribute(IJavaModelMarker.ID, IProblem.ExternalProblemFixable);

Consequently, CustomQuickFixProcessor.getCorrections gets called when I hover over my custom marker in the editor or click on the light-build on the left margin of the Java editor. 因此,当我将鼠标悬停在编辑器中的自定义标记上或单击Java编辑器左边缘的灯光构建时,将调用CustomQuickFixProcessor.getCorrections However, when I select the marker in the Problems View, right-click on the marker, and select the Quick Fix menu item, CustomQuickFixProcessor.getCorrections doesn't get called and a dialog appears saying that no Quick Fixes are available. 但是,当我在“问题视图”中选择标记时,右键单击标记,然后选择“快速修复”菜单项,不会调用CustomQuickFixProcessor.getCorrections并出现一个对话框,指出没有可用的快速修复。

I ran JDT in debug mode to see why it doesn't call CustomQuickFixProcessor.getCorrections when I invoke the Quick Fix from the Problems View. 我在调试模式下运行JDT以查看当我从Problems视图调用Quick Fix时它不调用CustomQuickFixProcessor.getCorrections原因。 It turned out CorrectionMarkerResolutionGenerator.internalGetResolutions(IMarker) finds no resolutions because CorrectionMarkerResolutionGenerator.hasProblem (context.getASTRoot().getProblems(), location) doesn't find the custom problem in the AST of the compilation unit. 事实证明, CorrectionMarkerResolutionGenerator.internalGetResolutions(IMarker)找不到任何分辨率,因为CorrectionMarkerResolutionGenerator.hasProblem (context.getASTRoot().getProblems(), location)在编译单元的AST中找不到自定义问题。 I'm not sure how to associate my custom markers with the AST of the compilation unit. 我不确定如何将自定义标记与编译单元的AST相关联。

I got this working, with great help from this post and the debugger. 在这篇文章和调试器的帮助下,我得到了这个工作。 Here is what you have to do: 这是你要做的:

Creating the marker 创建标记

plugin.xml plugin.xml中

Declare the marker so it extends these three existing markers (I think all are necessary) 声明标记,以便扩展这三个现有标记(我认为一切都是必要的)

<extension
       id="mymarker"
       name="My Problem"
       point="org.eclipse.core.resources.markers">
    <super
          type="org.eclipse.jdt.core.problem">
    </super>
    <super
          type="org.eclipse.core.resources.problemmarker">
    </super>
    <super
          type="org.eclipse.core.resources.textmarker">
    </super>
    <persistent
          value="true">
    </persistent>
 </extension>

Java Java的

When you create the marker it is important that you set the IJavaModelMarker.ID field, and I think all the other fields listed here as well. 创建标记时,设置IJavaModelMarker.ID字段非常重要,我认为此处列出的所有其他字段也是如此。

// Must match the "id" attribute from plugin.xml
String MY_MARKER_ID = "com.example.my.plugin.mymarker"
// Must not be -1 or any of the values in org.eclipse.jdt.core.compiler.IProblem
int MY_JDT_PROBLEM_ID = 1234

// ....
IMarker marker = resource.createMarker(MY_MARKER_ID);
marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_WARNING);
marker.setAttribute(IMarker.MESSAGE, msg);
marker.setAttribute(IMarker.CHAR_START, start);
marker.setAttribute(IMarker.CHAR_END, end);
marker.setAttribute(IJavaModelMarker.ID, MY_JDT_PROBLEM_ID);

Creating the QuickFixProcessor 创建QuickFixProcessor

plugin.xml plugin.xml中

First declare it in plugin.xml . 首先在plugin.xml声明它。 Be sure your declare the right id in handledMarkerTypes 确保在handledMarkerTypes声明正确的id

<extension
      point="org.eclipse.jdt.ui.quickFixProcessors">
   <quickFixProcessor
         class="com.example.my.plugin.ui.MyQuickFixProcessor"
         id="org.eclipse.jdt.ui.text.correction.QuickFixProcessor"
         name="My Quick Fix Processor">
      <handledMarkerTypes>
         <markerType
               id="com.example.my.plugin.mymarker">
         </markerType>
      </handledMarkerTypes>
   </quickFixProcessor>
</extension>

Java Java的

Here is the basic skeleton for the quick fix processor. 这是快速修复处理器的基本框架。 Note that it is important to check that locations actually has contents. 请注意,检查locations实际上是否包含内容非常重要。

If you make your own marker type (as described above) I think you can just hard-code hasCorrections to return true. 如果您创建自己的标记类型(如上所述),我认为您可以硬编码hasCorrections以返回true。 But to be save and to follow the convention check that it matches your jdt problem id. 但要保存并遵循约定检查它是否与您的jdt问题ID匹配。

public class MyQuickFixProcessor implements IQuickFixProcessor {

  @Override
  public IJavaCompletionProposal[] getCorrections(IInvocationContext context, IProblemLocation[] locations) throws CoreException {
    if (locations == null || locations.length == 0) {
      // https://bugs.eclipse.org/444120 Eclipse can call this method without
      // any locations, if a quick fix is requested without any problems.
      return null;
    }

    IJavaCompletionProposal[] proposals = ...
    //...
    return proposals;
  }

  @Override
  public boolean hasCorrections(ICompilationUnit unit, int problemId) {
    return problemId == MY_JDT_PROBLEM_ID;
  }
}

Finding a good JDT ID 找到一个好的JDT ID

You need a MY_JDT_PROBLEM_ID that is unique! 你需要一个独一无二的MY_JDT_PROBLEM_ID Run the code below, to print all the current ID's defined in IProblem . 运行下面的代码,打印IProblem定义的所有当前ID。 Pick a sizeable range in these numbers, and select you ID in that range. 选择这些数字中的相当大的范围,然后在该范围内选择您的ID。

Field[] fields = org.eclipse.jdt.core.compiler.IProblem.class.getFields();
List<Integer> ints = new ArrayList<>();
for (Field field : fields) {
  ints.add(field.getInt(null));
}
sort(ints);
for (Integer integer : ints) {
  System.out.printf("%16d %16o %16x%n", integer, integer, integer);
}

I hope I have remembered everything. 我希望我记得一切。 Good Luck. 祝好运。

Your Attempt 1 will not work, reason: 您的尝试1将无效,原因:

JDT UI defines the following extension. JDT UI定义了以下扩展。

   <extension
         point="org.eclipse.ui.ide.markerResolution">
      <markerResolutionGenerator
            markerType="org.eclipse.jdt.core.problem"
            class="org.eclipse.jdt.internal.ui.text.correction.CorrectionMarkerResolutionGenerator">
      </markerResolutionGenerator>

ie the quick fixes coming from JDT will work only for markerType="org.eclipse.jdt.core.problem". 即来自JDT的快速修复仅适用于markerType =“org.eclipse.jdt.core.problem”。

Attempt 2 : Even in JDT UI implementation there are cases, when QuickFixProcessor#hasCorrections(...) returns true but QuickFixProcessor#getCorrections(...) may not return a fix. 尝试2 :即使在JDT UI实现中,也有一些情况,当QuickFixProcessor#hasCorrections(...)返回true但QuickFixProcessor#getCorrections(...)可能不会返回修复。 This is because we always return true or false for a particular marker. 这是因为我们总是为特定标记返回true或false。 However, all instances of a particular marker may not be 'fixable'. 但是,特定标记的所有实例可能都不是“可修复的”。 Maybe you run into something similar ? 也许你碰到类似的东西?

Attempt 3 : What all attributes are you setting on the marker? 尝试3 :您在标记上设置的所有属性是什么? Since CorrectionMarkerResolutionGenerator.hasProblem(...) checks for it, you would need to set at least IMarker.CHAR_START attribute. 由于CorrectionMarkerResolutionGenerator.hasProblem(...)检查它,您需要至少设置IMarker.CHAR_START属性。 Have a look at org.eclipse.jdt.internal.core.eval.RequestorWrapper.acceptProblem(CategorizedProblem, char[], int) , this is where markers in JDT Core are created. 看看org.eclipse.jdt.internal.core.eval.RequestorWrapper.acceptProblem(CategorizedProblem, char[], int) ,这是创建JDT Core中的标记的地方。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM