【问题标题】:How can I add an Eclipse Quick Fix for a custom Java marker?如何为自定义 Java 标记添加 Eclipse 快速修复?
【发布时间】:2012-11-18 00:55:23
【问题描述】:

我想向 Eclipse 的问题视图报告 Java 文件的自定义问题并为它们提供快速修复。

标准的做法是使用扩展点org.eclipse.core.resources.markers 来声明一个自定义标记并通过调用org.eclipse.core.resources.IResource.createMarker(String) 添加标记。然后,可以使用扩展点org.eclipse.ui.ide.markerResolution 为自定义标记提供快速修复。

上述方法是一种独立于语言的创建和解析资源标记的方法。缺点是我必须编写一些样板代码来解决我的自定义 Java 问题。相反,我想重用IQuickFixProcessor。也就是说,我想使用扩展点org.eclipse.jdt.ui.quickFixProcessors 解析我的自定义Java 标记。使用这个扩展点,我不再需要解析找到标记的 Java 文件,我不必构建绑定并找到覆盖标记的 AST 节点。如果我不重用 org.eclipse.jdt.internal.ui.text.correction.CorrectionMarkerResolutionGenerator 及其依赖项,我最终会复制大部分内容。

如何使用 JDT 基础架构为我的自定义 Java 标记提供快速修复?

尝试 1:

我将自定义标记定义如下:

<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>

然后,我通过调用IResource.createMarker("custom.marker") 方法添加了上述标记的实例。

接下来,我定义了一个自定义 Quick Fix 处理器。

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

我的自定义标记显示在 Eclipse 的问题视图中,但是当我右键单击自定义问题时,快速修复菜单项被禁用。

尝试 2:

我将IMarker marker = resource.createMarker("custom.marker"); 替换为IMarker marker = resource.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);。由于此更改,当我右键单击“问题视图”中的自定义问题时,“快速修复”菜单项变为可用,但是,当我选择它时,会弹出一个对话框,显示所选内容没有可用的修复程序问题。但是,我验证了CustomQuickFixProcessor.hasCorrections(ICompilationUnit, int) 被调用并返回true,但是CustomQuickFixProcessor.getCorrections(IInvocationContext, IProblemLocation[]) 没有被调用。

尝试 3:

尝试 3 是尝试 2 的延续。我将自定义标记的 IJavaModelMarker.ID 设置如下:

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

因此,当我将鼠标悬停在编辑器中的自定义标记上或单击 Java 编辑器左边距的 light-build 时,CustomQuickFixProcessor.getCorrections 会被调用。但是,当我在“问题视图”中选择标记时,右键单击该标记,然后选择“快速修复”菜单项,CustomQuickFixProcessor.getCorrections 不会被调用,并且会出现一个对话框,指出没有可用的快速修复。

我在调试模式下运行 JDT,看看为什么当我从问题视图调用快速修复时它不调用 CustomQuickFixProcessor.getCorrections。原来CorrectionMarkerResolutionGenerator.internalGetResolutions(IMarker) 找不到解决方案,因为CorrectionMarkerResolutionGenerator.hasProblem (context.getASTRoot().getProblems(), location) 在编译单元的 AST 中没有找到自定义问题。我不确定如何将我的自定义标记与编译单元的 AST 关联起来。

【问题讨论】:

  • 你有没有得到这个工作?

标签: java eclipse eclipse-jdt


【解决方案1】:

在这篇文章和调试器的大力帮助下,我得到了这个工作。这是你必须做的:

创建标记

plugin.xml

声明标记,使其扩展这三个现有标记(我认为都是必要的)

<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

创建标记时,设置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);

创建 QuickFixProcessor

plugin.xml

首先在plugin.xml 中声明它。确保您在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

这是快速修复处理器的基本框架。请注意,检查locations 是否确实有内容很重要。

如果您制作自己的标记类型(如上所述),我认为您可以硬编码 hasCorrections 以返回 true。但是要保存并遵循约定检查它是否与您的 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;
  }
}

找到一个好的 JDT ID

您需要一个独一无二的MY_JDT_PROBLEM_ID!运行下面的代码,打印IProblem 中定义的所有当前 ID。在这些数字中选择一个相当大的范围,然后在该范围内选择您的 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);
}

我希望我已经记住了一切。祝你好运。

【讨论】:

  • 如果您尝试从 Problems 视图调用 QuickFix,它会出现吗?感谢您的回答,我设法实现了可以从 Java 编辑器访问的自己的 QuickFix,但是在提到的视图中,此选项被禁用并且按 Ctrl+1 没有任何影响。
  • 不。我没有意识到这个问题。不知道怎么解决:(如果你找到解决办法,请在这里分享
  • 我找到了problematical spot。 Eclipse 使用此类查询来查找Problems 视图的快速修复。查询注册表包含对已定义markerTypes(扩展名org.eclipse.ui.ide.markerResolution)的查询。引用检查严格使用标记类型。由于我们不直接使用org.eclipse.jdt.core.problem,而是对其进行了扩展,因此我们没有得到这种类型的任何分辨率,因此无法快速修复视图。
  • 另见上述扩展的documentation。它说:the marker type for which this marker resolution generator applies. It does not apply to marker subtypes. 所以看来这个问题的唯一解决方案是直接使用这个扩展而不是quickFixProcessors
  • 否则您也可以尝试使用IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER 代替您自己的标记类型。
【解决方案2】:

您的尝试 1 不起作用,原因:

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>

即来自 JDT 的快速修复仅适用于 markerType="org.eclipse.jdt.core.problem"。

尝试 2: 即使在 JDT UI 实现中,也有一些情况,当 QuickFixProcessor#hasCorrections(...) 返回 true 但 QuickFixProcessor#getCorrections(...) 可能不会返回修复。这是因为我们总是为特定的标记返回真或假。但是,特定标记的所有实例可能不是“可修复的”。也许你遇到类似的事情?

尝试 3 : 您在标记上设置了哪些所有属性? 由于CorrectionMarkerResolutionGenerator.hasProblem(...) 会检查它,因此您至少需要设置 IMarker.CHAR_START 属性。看一下 org.eclipse.jdt.internal.core.eval.RequestorWrapper.acceptProblem(CategorizedProblem, char[], int),这是在 JDT Core 中创建标记的地方。

【讨论】:

  • 我希望如果CustomQuickFixProcessor.hasCorrections 为标记返回true,则为该标记调用CustomQuickFixProcessor.getCorrections。但是,这份合同在我的程序中不成立。
  • 在调试模式下运行 JDT 时,我意识到 JDT 会查找注释并将它们转换为问题位置(参见 CorrectionMarkerResolutionGenerator.findProblemLocation)。但是,此方法找不到与我的自定义标记相关的任何注释。这就是 JDT 不在我的标记上调用 CustomQuickFixProcessor.getCorrections 的原因吗?
  • 此外,方法CorrectionMarkerResolutionGenerator.createFromMarker 期望标记具有属性IJavaModelMarker.ID 的有效值。 JDT 标记设置了这个属性,但是,我的标记没有。这可能是 JDT 不在我的自定义标记上调用 CustomQuickFixProcessor.getCorrections 的另一个原因吗?
  • 是的,你在正确的轨道上。 ID 用于标识 Java 问题的类型,在 QuickFixProcessor 中使用。另外,我认为如果您创建“org.eclipse.jdt.core.problem”类型的标记并设置所有字段,则应自动创建注释(但我在这一点上可能是错误的)。
  • 我设置了marker的ID属性。这使得CustomQuickFixProcessor.getCorrections 在某些但不是所有调用快速修复的方法中被调用。请参阅我添加到问题中的“尝试 3”的描述。
猜你喜欢
  • 2014-01-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-14
  • 1970-01-01
  • 2021-04-07
  • 2010-11-03
  • 1970-01-01
相关资源
最近更新 更多