How to keep inspections created by LocalInspectionTool in place

Hello everyone,

this issue is connected to http://devnet.jetbrains.com/message/5504591#5504591

What I am trying to achieve

I am using LocalInspectionTool to show sonar issues in:

*) Settings -> Inspections; "Sonar" group , each "Sonar" Intellij Inspection == Sonar rule
Bildschirmfoto 2014-04-29 um 11.09.44.png
**) in the result if running analysis for that rules
Bildschirmfoto 2014-04-29 um 11.13.43.png
***) in editor directly as code annotations:
Bildschirmfoto 2014-04-29 um 11.15.06.png
My Problem

If I change the code, then inspections in code should stay connected to the marked line and only disappear if I explicitelly delete that line of code, until a new analysis is done.
If new analysis is done, the annotations needs to be updated instantly in editor. This does not work using LocalInspectionTool.
What I tried so far:

PsiManager.getInstance(project).addPsiTreeChangeListener(new PsiTreeChangeAdapter() {
      @Override
      public void beforeChildrenChange(@NotNull PsiTreeChangeEvent event) {
        // is triggerd on every small change of any file
      }


This way I can immediatelly trigger a new sonar analysis. I also instantly remember that and which script is running.
After Analysis is done the results are stored in my own cache.

Later on in LocalInspectionTool I do

@NotNull
  @Override
  public PsiElementVisitor buildVisitor(final @NotNull ProblemsHolder holder, final boolean isOnTheFly) {
    return new PsiElementVisitor() {
      @Override
      public void visitFile(PsiFile psiFile) {
         if (analysisIsRunningFor(psiFile)) {
             // do not reread issues from cache and keep already created ProblemDescriptors in place
             return;
         } else {
           // read analysis result from cache and annotate code using com.intellij.codeInspection.ProblemDescriptor
           addDescriptors(checkFile( ... ) );
         }
      }



Unfortunatelly this does not work as expected.

After I change the code and let say produce a compile error, then it seems intellij rerun my LocalInspectionTool,
then it see My inspection did not generate any ProblemDescriptor and did not show anything until it is blocked by the analysisIsRunningFor() precondition.


But also after the new analysis is done, the new generated issues are saved into the cache, but intellij does not trigger my LocalInspectionTool again,
so new code annotations do not appear and the result is that code is not annotated at all any more.

Before analysis:
Bildschirmfoto 2014-04-29 um 12.30.53.png

After analysis:
Bildschirmfoto 2014-04-29 um 12.10.29.png

Can you help me with my two main problems:

*) How to keep already created ProblemDescriptions in place, also if I edit the code and produce compile errors and the line of code is moved?
**) How can I trigger running of a LocalInspectionTool on a File after analysis is done?
***) I want to keep the Sonar Rule == Intellij Inspection connection, how is it possible if I do not use LocalInspectionTool?

Many thx for reading and any help!

4 comments

UPDATE:

final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(psiFile.getProject());
    final Document document = documentManager.getDocument(psiFile.getContainingFile());
    if (document == null) {
      return null;
    }

    final Editor[] editors = EditorFactory.getInstance().getEditors(document);
    if (editors.length == 1) {
      SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
          final int fixedLineNumber = 5;
          final MarkupModel markupModel = editors[0].getMarkupModel();
          TextAttributes textAttributes = new TextAttributes(Color.BLACK, Color.WHITE, Color.YELLOW, EffectType.WAVE_UNDERSCORE, 1);
          final RangeHighlighter lineHighlighter = markupModel.addLineHighlighter(fixedLineNumber, 1, textAttributes);
        }
      });

    }


Using markupModel.addLineHighlighter I am able to create makrings in editor which do not disappear during editing the source code.
But I am missing the popup on mouse over, also that popup has a F1 functionallity...  I really don't want to reinvent the wheel and create all of this manually.
My next question is: how do I create highlighting for a ProblemDescriptor manually without LocalInspectionTool ?

Something like:

editor.addProblemDescriptorHighlighting(problemDescriptor) 


is it possible somehow?

Just one more question:
What is UnfairLocalInspectionTool for? There is no javadoc or any explanation, also nothing to implement.

0

UPDATE:

figured out how to trigger LocalInspectionTool manually, but it unfortunatelly just returns the ProblemDescriptor objects
How do I trigger rendering of List<ProblemDescriptor> in Editor?

private static List<ProblemDescriptor> runInspectionOnFile(@NotNull PsiFile file,
                                                             @NotNull LocalInspectionTool inspectionTool) {
    InspectionManagerEx inspectionManager = (InspectionManagerEx) InspectionManager.getInstance(file.getProject());
    GlobalInspectionContext context = inspectionManager.createNewGlobalContext(false);
    final List<ProblemDescriptor> problemDescriptors = InspectionEngine.runInspectionOnFile(file, new LocalInspectionToolWrapper(inspectionTool), context);
    return problemDescriptors;
  }

0

to finish my monolog here is how you can trigger rendering of LocalInspectionTool by your own code:

          // rendering representation of ProblemDescriptors calculated during execution of LocalInspectionPass
          final java.util.List<HighlightInfo> infos = localInspectionsPass.getInfos();

          UpdateHighlightersUtil.setHighlightersToEditor(
              project,
              document.get(),
              0,
              document.get().getTextLength(),
              infos,
              null,
              0
          );

0

Thanks, your monolog was pretty useful :)

Just to complement what you said, I was able to get things working by putting this together:

 
    def runInspection(psiFile: PsiFile) = {
      import scala.collection.JavaConversions._
      val project = psiFile.getProject
      val document = PsiDocumentManager.getInstance(project).getDocument(psiFile)
      val localInspectionsPass = new LocalInspectionsPass(psiFile,
                                                           document,
                                                           0,
                                                           document.getTextLength,
                                                           LocalInspectionsPass.EMPTY_PRIORITY_RANGE,
                                                           true,
                                                           HighlightInfoProcessor.getEmpty)

      val inspectionManagerEx = InspectionManager.getInstance(project).asInstanceOf[InspectionManagerEx]

      ProgressManager.getInstance().runProcess(new Runnable {
        override def run(): Unit = {
          localInspectionsPass.doInspectInBatch(inspectionManagerEx.createNewGlobalContext(false),
                                                 inspectionManagerEx,
                                                 List(new LocalInspectionToolWrapper(new MyInspection)))

          UpdateHighlightersUtil.setHighlightersToEditor(psiFile.getProject,
                                                          document,
                                                          0,
                                                          document.getTextLength,
                                                          localInspectionsPass.getInfos,
                                                          null,
                                                          Pass.UPDATE_ALL)
        }
      }, new EmptyProgressIndicator)
    }

 
Things would not play ball till I wrapped the code block with ProgressManager.getInstance().runProcess.

0

Please sign in to leave a comment.