Как заставить плагин IntelliJ анализировать разрешения файла PsiReference?

У меня есть плагин IntelliJ, который передает разрешения PsiReference в «удаленный» класс, и у меня возникают проблемы, потому что метод resolve() возвращает значение null тогда и только тогда, когда я не перешел к удаленному файлу в редакторе во время текущего сеанса IntelliJ. Я подозреваю, что IntelliJ нужно подтолкнуть к анализу файла в каком-то смысле (когда вы переходите к файлу, вы можете видеть, что IntelliJ запускает какой-то синтаксический анализ, поскольку большая часть кода переходит от минимального выделения к полностью выделенному) но я не знаю, как это сделать. Я просмотрел PsiManager и PsiFile, где нашел несколько методов refresh() и reloadFromDisk(), но я предполагаю, что они имеют много побочных эффектов, которые мне не нужны и, вероятно, в любом случае не запустят синтаксический анализ. Подробности/пояснения ниже.

Код выглядит примерно так:

Файл 1, в котором я вызываю действие плагина на foo:

@AnnotationReferringToAnotherType(File2.class)
class File1 {
  String foo;
}

Файл 2, который плагин должен найти, чтобы выполнить действие над foo:

class File2 {
  @File3
  void mustBeLookedUpToHandleAction() {}
}

Файл 3 также необходимо найти:

@interface File3 {
  public enum SomeEnum {
    DEFAULT,
    SOMETHING_ELSE
  }

  SomeEnum value() default SomeEnum.DEFAULT;
}

Я выполняю действие над foo, а затем логика находит @AnnotationReferringToAnotherType в начале содержащего файла (Файл 1) и resolve()s в определении File2. Затем он ищет в File2 метод с аннотацией @File3. Поскольку аннотация @File3 для mustBeLookedUpToHandleAction не указывает его значение, плагин теперь должен найти определение @File3, чтобы определить значение по умолчанию. Все это работает совершенно гладко после загрузки IntelliJ. Неудачная часть — это resolve() от PsiReferenceExpression SomeEnum.DEFAULT до фактического определения DEFAULT в SomeEnum. Он постоянно возвращает null, пока я не перейду в редакторе к файлу 3, и после этого он работает каждый раз до конца сеанса. Кажется очевидным, что разрешения ссылок анализируются лениво, и если я смогу найти какой-нибудь способ запустить этот анализ, все должно быть в порядке?

Вы можете подумать: «Какого черта эта логика такая сложная?». Большая часть логики на самом деле находится в библиотеке, которую я использую - она ​​внутренняя, поэтому я могу внести некоторые изменения, но я сомневаюсь, что смогу внести фундаментальные изменения из-за этой проблемы, если эта проблема не окажется быть совершенно неуправляемым.


person Nick    schedule 05.12.2014    source источник
comment
Похоже, ответ может быть на confluence.jetbrains.com/display/IDEADEV/PSI+Cookbook - FileContentUtil.reparseFiles - я попробую и посмотрю, сработает ли это   -  person Nick    schedule 05.12.2014


Ответы (1)


Оказывается, это ошибка в IntelliJ: https://youtrack.jetbrains.com/issue/IDEA-133994

обходным путем является вызов getText() для одного из определений аннотаций PsiElement перед вызовом resolve() - например. когда у вас есть PsiAnnotationMethod для File3.value, позвоните getText() перед вызовом getDefaultValue().resolve()

детс:

Определение для File3 "заглушено", поэтому на самом деле доступны только основные компоненты его пси-дерева. Всякий раз, когда из заглушки запрашивается информация, которой у заглушки нет (например, при вызове getText), файл, содержащий заглушенное пси-дерево, будет полностью проанализирован, а заглушка заменена полным пси-деревом (см. https://confluence.jetbrains.com/display/IDEADEV/Indexing+and+PSI+Stubs+in+IntelliJ+IDEA). Конкретная реализация PsiAnnotationMethod.getDefaultValue вернет фиктивный PsiAnnotationMemberValue, если аннотация заглушена, и этот фиктивный элемент, по-видимому, не знает, как соблюдать resolve().

person Nick    schedule 06.12.2014