API for reporting/highlighting problems outside of inspections


I am looking for a simple way to report problems related to language elements to the user. I've read about LocalInspectionTool and am familiar with the ProblemDescriptor interface. However, for my purposes I require an API that would allow, given a PsiElement and a message, to report a problem directly, outside of the inspection context.

My plugin performs annotation processing of Java files. Annotation processors can report messages at various levels (error, warning, info) on program elements (e.g., on class fields). Therefore, I want to enhance my plugin to display the messages reported on program elements. You can see that I don't require a whole inspector, but rather an ability to report problems produced by an external tool (an annotation processor).

I've also come across the Annotator facility, but couldn't quite understand how it is used.

To sum up, I want to report messages on language elements and display them in the editor while controlling the following:

  1. The timing - report messages at any moment.
  2. The target - provide a PsiElement that needs to be highlighted and on which the message should appear.
  3. Removal of the reported message and highlighting.

I found UpdateHighlightersUtil.setHighlightersToEditor() to be useful - I can report messages on specific elements. This solves points 1 and 2 outlined inthe original post.

However, there is an issue with point 3 - how to correctly remove highlights? I can see that there is UpdateHighlightersUtil.removeHighlightersWithExactRange() but it accepts a Segment (i.e., a text range), meaning that I need to take care of obtaining text ranges of PsiElement-s myself, which is not straight-forward. For example, a file could have been edited after the initial highlight was set, which would likely invalidate the text range used to set it. To solve this problem I could remember PsiElement-s that had been highlighted by me, and later recalculate the ranges when I need to remove those highlights. However, this poses a few questions about the nature of highlights:
1. Can several problems be associated with the same highlighted text range? If so, then removing the whole highlight using a text range could lead to undesirable results.
2. If 1 is true, then does a highlight have an identity other than the text range on which it's defined?


After using UpdateHighlightersUtil.setHighlightersToEditor() I've noticed that multiple highlights reported on the same PSI element cannot coexist: the last one replaces the previous one. Also, reported highlights appear in the Problems tool window with the correct severity and provide a way to jump to the highlight's location, which is great, but the same problem with multiple highlights for the same PSI element persists here: only the last one is shown.

Is it possible to avoid the loss information with multiple highlights on the same element?


Possibly External Annotator would work in your case https://plugins.jetbrains.com/docs/intellij/syntax-highlighting-and-error-highlighting.html#external-tool. All above mentioned API is quite low-level.


@Yann Cebron If I understand correctly, External Annotators are controlled and run by some other component, which doesn't satisfy my requiremenet of having a lower-level control of the tool. Do correct me if I'm wrong.

I'd also like to share the approach I came up with, and which seems to be working. It takes advantage of manual manipulation of a Document's MarkupModel.  As I outlined above, 2 of my primary requirements are:
1. Adding highlights to PSI elements
2. Removing highlights from PSI elements

Here is how I approach them:
1. Use UpdateHighlightersUtil.setHighlightersToEditor() to add HighlightInfo instances, which I create with HighlightInfo.newHighlightInfo() and, most importantly, use my own ProblemGroup instance when building them to be able to identify them later. Alltogether this results into a Document's MarkupModel being updated, as well as the UI.  
2. To clear previously added highlights I take advantage of having used my own ProblemGroup instance. I obtain a Document from a PsiFile, then obtain its MarkupModel (through DocumentMarkupModel.forDocument()), and then go through existing highlights removing the ones I'm interested in:

Document document = PsiDocumentManager.getInstance(project).getDocument(psiFile);
MarkupModel markupModel = DocumentMarkupModel.forDocument(document, project, false);
if (markupModel == null)
ApplicationManager.getApplication().invokeLater(() -> {
           .filter(rh -> rh.getErrorStripeTooltip() instanceof HighlightInfo hi
                   && hi.getProblemGroup() == OUR_PROBLEM_GROUP)

Also, I would be glad if somebody could share some insight on the question asked in this comment:
> Is it possible to avoid the loss information with multiple highlights on the same element?

I guess it's possible since in the Problems window I can see multiple warnings for the same element produced by built-in inspections:


UPDATE: I figured it out. UpdateHighlightersUtil.setHighlightersToEditor() accepts a list of HighlightInfo which it applies to the given range. My mistake lied in applying highlights one by one, even when they referred to the same PSI element. After modifying the code to first group HighlightInfo by target PSI element and only then call UpdateHighlightersUtil.setHighlightersToEditor() with the list of grouped HighlightInfo, I can see multiple problems on the same PSI element at the same time.


I have encountered another issue. The Problems tool window, it seems, shows only problems related to the currently opened file in the editor. However, for my use case it is important to show problems from all Java files in a project. As far as I can tell, the Problems tool window will not satisfy this requirement. Therefore, a separate tool window will have to be provided by my plugin. Could somebody comment on that?


AFAIK that's correct.


Please sign in to leave a comment.