How to trigger an existing Inspection

Answered

Hi,

I am writing a plugin for WebStorm. And I am trying to "manually" trigger an existing inspection (on a certain scope) inside my own plugin. To be specific: I am trying to trigger ESLint from code and direct it to run on a file or the entire project. (ESLint is the available inspection tool from Code Quality Tools.)

I have seen several methods, as com.intellij.lang.javascript.inspections.JSInspection#checkFile, so I assume there is a way to do it. (probably in the non-api source)

Is there a way to generally get and trigger an existing inspection tool? Or is there a way at least to trigger a specific tool like ESLint or JSLint?

(I know there is a way to check the availability of such a tool, as answered in a previous post: https://intellij-support.jetbrains.com/hc/en-us/community/posts/360002480860-Detecting-a-change-in-Settings-enabling-disabling-a-tool)

Thanks in advance!

5 comments
Comment actions Permalink

Small update: I don't know if this is the proper/right way to do it, but managed to get ahold of an inspection object as follows:

InspectionToolWrapper inspectionToolWrapper = inspectionProfile.getInspectionTool(EslintInspection.SHORT_NAME, currentProject);
EslintInspection eslintInspection = (EslintInspection) inspectionToolWrapper.getTool();

However, when I "manually" trigger it, with the code:

PsiFile psiFile = ...;
final InspectionManager inspectionManager = InspectionManager.getInstance(currentProject);
eslintInspection.checkFile(psiFile, inspectionManager, false);

I get an error that checkFile "should not be called, use visitFile in createVisitor instead". Therefore I have not approached this properly.

I am doing all of the above in the implementation of an action event. My use case is basically triggering an inspection on clicking a menu item.

Should I implement and own LocalInspectionTool?

I will further look into, but would appreciate any pointers/examples on the matter.

0
Comment actions Permalink

Another update, I apologize, this is starting to look/sound like a monologue: I followed an approach similar to https://intellij-support.jetbrains.com/hc/en-us/community/posts/206111999/comments/206110915. So, as related to my previous post, I did not implement an own LocalInspectionTool, but reused Eslint as follows. My code:

InspectionManagerEx inspectionManagerEx = (InspectionManagerEx) InspectionManager.getInstance(currentProject);
GlobalInspectionContext context = inspectionManager.createNewGlobalContext(false);
InspectionToolWrapper inspectionToolWrapper = inspectionProfile.getInspectionTool(EslintInspection.SHORT_NAME, currentProject);
List<ProblemDescriptor> problemDescriptors = InspectionEngine.runInspectionOnFile(psiFile, inspectionToolWrapper, context);

But the list contains one element, with the message/value: "ESLint: Can not get result from language service". Therefore, I am still missing something or doing something the wrong way.

If anybody can lend a helping thought, that would be appreciated.

0
Comment actions Permalink

Andrei, Hi!

The code above looks good, there doesn't seem to be any reason to implement LocalInspectionTool yourself.

A guess: are you running this on the EDT thread?
If yes, it's likely there's an error reported in the IDE like the one below (in the bottom right corner of the IDE window or in idea.log):

There is an assertion in JSLanguageServiceUtil#awaitLanguageService that prohibits waiting for results from an external service on the EDT for performance reasons. So you should try to do it on a pooled thread, for example, by wrapping the code above with a method of ProgressManager that transfers the execution to a pooled thread (runProcessWithProgressSynchronously, runProcessWithProgressAsynchronously(Task), depending on wether you need to return a result back to the EDT) like below:

private static List<ProblemDescriptor> getProblemDescriptors(Project project,
InspectionToolWrapper inspectionToolWrapper, PsiFile psiFile) {
InspectionManagerEx inspectionManagerEx = (InspectionManagerEx)InspectionManager.getInstance(project);
GlobalInspectionContext context = inspectionManagerEx.createNewGlobalContext(false);
try {
return ProgressManager.getInstance()
.runProcessWithProgressSynchronously(() -> ReadAction
.compute(() -> InspectionEngine.runInspectionOnFile(psiFile, inspectionToolWrapper, context)),
"Getting Problems from ESLint", true, project);
}
catch (Exception e) {
throw new RuntimeException(e);
}
}


But it is also absolutely unclear from the API that the code requires a background thread. We should make this a clear assertion with instructions on how to fix the error, instead of almost-silently returning null. I've created an issue to fix this: WEB-36895

PS.
It's great to see that you're developing a plugin for WebStorm and ESLint.
I'm the developer responsible for JS linters support in WebStom/IDEA, so it's likely that if you have any additional problems, I might be able to help you.
If you'd like, you can email me at maxim.kropotv<at>jetbrains.com with a short description of what you're trying to accomplish with your plugin.
This way, I might be able to give you on overview of what other APIs could be useful or should be added to support your plugin before you hit issues like this one. Alternatively, I'll try my best to route the requests to the relevant people.

0
Comment actions Permalink

Hi Maxim!

Indeed, your guess turns out to be the correct cause. And your fix solves the problem: the inspection related code works fine in the pooled thread; I get the correct results from the EslintInspection.

However, I did not see an exception in the idea.log. And indeed a clearer suggested-fix-message/requirement in the API would be great.

Therefore, again, you got me out of the "deadlock". My problem in this post is solved.

Many thanks!

PS We can continue a short API discussion via email :-). Thanks for the contact details.

 

0
Comment actions Permalink

Hi Maxim!

How do I use the result of getdescriptors(), Make it visible in code annotate.  I am trying to "manually" trigger an existing inspection (on a certain scope) inside my own plugin.

0

Please sign in to leave a comment.