Подтвердить что ты не робот

Как добавить Eclipse Quick Fix для пользовательского маркера Java?

Я хочу сообщить о проблемах для файлов Java в представлении проблем Eclipse и предоставить им быстрые исправления.

Стандартный способ сделать это - использовать точку расширения org.eclipse.core.resources.markers, чтобы объявить пользовательский маркер и добавить маркеры, вызвав org.eclipse.core.resources.IResource.createMarker(String). Затем можно использовать точку расширения org.eclipse.ui.ide.markerResolution, чтобы обеспечить быстрое исправление для пользовательских маркеров.

Этот подход является независимым от языка методом создания и разрешения маркеров ресурсов. Недостатком является то, что я должен написать код шаблона для решения моих собственных проблем Java. Вместо этого я хотел бы повторно использовать IQuickFixProcessor. То есть, я хотел бы разрешить мои собственные маркеры Java, используя точку расширения org.eclipse.jdt.ui.quickFixProcessors. Используя эту точку расширения, мне больше не нужно разбирать файл Java, в котором найден маркер, мне не нужно создавать привязки и находить AST node, охватывающий маркер. Если я не буду повторно использовать org.eclipse.jdt.internal.ui.text.correction.CorrectionMarkerResolutionGenerator и его зависимости, я в конечном итоге дублирую большую часть.

Как я могу предоставить Quick Fixes для своих пользовательских маркеров Java с использованием инфраструктуры JDT?

Попытка 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);

Следовательно, CustomQuickFixProcessor.getCorrections вызывается, когда я наводил курсор на мой пользовательский маркер в редакторе или нажимал на light-build на левом поле редактора Java. Однако, когда я выбираю маркер в представлении проблем, щелкните правой кнопкой мыши маркер и выберите пункт меню быстрого исправления, CustomQuickFixProcessor.getCorrections не будет вызван и появится диалоговое окно, в котором говорится, что нет быстрых исправлений.

Я запускал JDT в режиме отладки, чтобы узнать, почему он не вызывает CustomQuickFixProcessor.getCorrections, когда я вызываю Quick Fix из представления проблем. Оказалось, что CorrectionMarkerResolutionGenerator.internalGetResolutions(IMarker) не находит разрешений, потому что CorrectionMarkerResolutionGenerator.hasProblem (context.getASTRoot().getProblems(), location) не находит пользовательскую проблему в AST для единицы компиляции. Я не уверен, как связать свои пользовательские маркеры с АСТ компиляционной единицы.

4b9b3361

Ответ 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. Убедитесь, что вы указали правильный id в handledMarkerTypes

<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. Но чтобы сохранить и следовать соглашению, убедитесь, что он соответствует вашему idd проблемы jdt.

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-идентификатора

Вам нужен MY_JDT_PROBLEM_ID уникальный! Выполните приведенный ниже код, чтобы распечатать весь текущий идентификатор, указанный в IProblem. Выберите в этих числах большой диапазон и выберите свой идентификатор в этом диапазоне.

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);
}

Надеюсь, я все вспомнил. Удачи.

Ответ 2

Ваш Попытка 1 не будет работать, причина:

Пользовательский интерфейс JDT определяет следующее расширение.

   <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 (...) не может вернуть исправление. Это происходит потому, что мы всегда возвращаем true или false для определенного маркера. Однако все экземпляры определенного маркера не могут быть "исправлены". Может быть, вы столкнулись с чем-то подобным?

Попытка 3: Какие все атрибуты вы устанавливаете на маркере? Поскольку CorrectionMarkerResolutionGenerator.hasProblem(...) проверяет его, вам необходимо установить атрибут IMarker.CHAR_START. Посмотри на org.eclipse.jdt.internal.core.eval.RequestorWrapper.acceptProblem(CategorizedProblem, char[], int), здесь создаются маркеры в ядре JDT.