Inspection Tool Extension
Hi,
I'm developing a simple integration for a static analysis tool with Clion. Currently I've had success in extending the LocalInspectionTool and overriding the checkFile method to call the tool and raise problems.
My problem is this works great on a single file code inspection, but not so well if the user selects to analyse multiple source files due to the concurrency and the static analysis tool trying to use locked files. Ultimately what I think I want is to find the class or method that initiates the inspection and has view of the scope of the inspection selected. If its single file inspection to continue to call checkFile, however if the scope contains multiple source files call another function I would implement as I can pass the list of source files to the tool to inspect in one go.
Any one able to give me a hand and point me in the right direction?
Cheers,
M
请先登录再写评论。
There are global tools but I hope that you don't need them until you need to perform more performance consuming analysis in batch mode. What exactly does "trying to use locked files" mean?
Thanks,
Anna
Hi Anna,
Thanks for your reply.
Regarding the "trying to use locked files" comment this is more to do with the static analysis tool I'm integrating. It creates a a directory and files in the local workspace which stores data on the analysis. Calling the inspection on more than one file it seems to run the checkFile process across multiple threads concurrently. So when one file is being analysed by the tool it writes and reads data to the file system, a second thread gets launched at the same time and tries to read/write to the same files causing an error in the static analysis tool.
It gives me two options, one is to continue as is, but find a way to call checkFile sequentially i.e <analysis-tool> run fileA.cpp and then <analysis-tool> run fileB.cpp
Or I can with the static analysis tool do this on one call i.e. <analysis-tool> run fileA.cpp fileB.cpp, however from checkFile I only have the scope of the current file to be inspected, which is why I was looking to see if there was a method higher up the chain I could override that contains the list of files to be analysed.
Cheers,
M
Unfortunately for us, analysis on different files from the scope runs sequentially. You may observe that analysis in the editor runs in parallel to the batch analysis though or that several batch analysis are run in parallel. Could you please check what parallel execution do you observe?
Hi Anna,
I assume it is the batch analysis I am talking about. Sorry about this long response, but a simplified version of my code is similar to this:
public class MyInspection extends LocalInspectionTool {
private static NotificationGroup GROUP_DISPLAY_ID =
new NotificationGroup("MyInspection",
NotificationDisplayType.NONE, true);
public static void out(String message, NotificationType level){
Notifications.Bus.notify(GROUP_DISPLAY_ID.createNotification(message, level));
}
@Nullable
@Override
public ProblemDescriptor[] checkFile(@NotNull PsiFile file, @NotNull InspectionManager manager, boolean isOnTheFly) {
// some checks here
out("Starting analysis on file: "+file.getName(), NotificationType.INFORMATION);
final List<ProblemDescriptor> descriptors = analyze(file, manager, document);
return descriptors.toArray(new ProblemDescriptor[descriptors.size()]);
}
public static List<ProblemDescriptor> analyze(@NotNull PsiFile file,
@NotNull InspectionManager manager,
@NotNull Document document) {
out(file.getName()+": create", NotificationType.INFORMATION);
create(file); // this runs a command line process
out(file.getName()+": scan", NotificationType.INFORMATION);
scan(file); // this runs a command line process
out(file.getName()+": get results", NotificationType.INFORMATION);
return getResults(file); // again runs a command line program
}
and I run the command line process using:
private static int runProcess(List<String> args, File workingDirectory) {ProcessBuilder pb = new ProcessBuilder(args);
pb.directory(workingDirectory);
pb = pb.redirectErrorStream(true);
Process proc = null;
StringBuilder output = new StringBuilder();
int exitVal = 0;
try {
proc = pb.start();
InputStream is = proc.getInputStream();
int c;
while ((c = is.read()) != -1) {
output.append((char) c);
}
exitVal = proc.waitFor();
} catch (InterruptedException | IOException e) {
out("Execution process failed" + e.getMessage(), NotificationType.ERROR);
}
if (output.length() > 0) {
out(output.toString(), NotificationType.INFORMATION);
}
return exitVal;
}
If I run on one file this seems ok, but if I do:
Code -> Inspect Code -> "Whole project" -> Ok
Firstly the output suggests that it runs 3 threads (inspecting 3 files at once) as it outputs something similar to:
I guess I have two issues:
#1 I'd like to restrict it to one checkfile call at a time e.g. A.cpp create -> scan -> getResults and then B.cpp create -> scan -> getResults
#2 As the command line call (runProcess()) takes a while normally the UI sometimes freezes up and then kills the inspection. I assume what I'm seeing is the same mentioned here: https://www.jetbrains.org/intellij/sdk/docs/basics/architectural_overview/general_threading_rules.html under "Preventing UI freezes". However if this is the case I cant really kill and restart the process as if the command line call takes a while to run, killing and restarting it will still take a while to run and need killing again. Is there any other options here to run long processes?
Best Regards,
M
Hi Michael,
did you considered using external annotators? `com.intellij.lang.annotation.ExternalAnnotator` and the corresponding inspection to store the settings: `com.intellij.codeInspection.ex.ExternalAnnotatorBatchInspection`. Looks feasible to your case to me.
Anna