private void queueElement(
      @NotNull PsiElement child,
      final boolean whitespaceOptimizationAllowed,
      @NotNull PsiTreeChangeEvent event) {
    ApplicationManager.getApplication().assertIsDispatchThread();
    PsiFile file = event.getFile();
    if (file == null) file = child.getContainingFile();
    if (file == null) {
      myFileStatusMap.markAllFilesDirty(child);
      return;
    }

    if (!child.isValid()) return;

    PsiDocumentManagerImpl pdm = (PsiDocumentManagerImpl) PsiDocumentManager.getInstance(myProject);
    Document document = pdm.getCachedDocument(file);
    if (document != null) {
      if (pdm.getSynchronizer().getTransaction(document) == null) {
        // content reload, language level change or some other big change
        myFileStatusMap.markAllFilesDirty(child);
        return;
      }

      List<Pair<PsiElement, Boolean>> toUpdate = changedElements.get(document);
      if (toUpdate == null) {
        toUpdate = new SmartList<>();
        changedElements.put(document, toUpdate);
      }
      toUpdate.add(Pair.create(child, whitespaceOptimizationAllowed));
    }
  }
  private void updateByChange(
      @NotNull PsiElement child,
      @NotNull final Document document,
      final boolean whitespaceOptimizationAllowed) {
    ApplicationManager.getApplication().assertIsDispatchThread();
    final PsiFile file;
    try {
      file = child.getContainingFile();
    } catch (PsiInvalidElementAccessException e) {
      myFileStatusMap.markAllFilesDirty(e);
      return;
    }
    if (file == null || file instanceof PsiCompiledElement) {
      myFileStatusMap.markAllFilesDirty(child);
      return;
    }
    VirtualFile virtualFile = file.getVirtualFile();
    if (virtualFile != null && shouldBeIgnored(virtualFile)) {
      // ignore workspace.xml
      return;
    }

    int fileLength = file.getTextLength();
    if (!file.getViewProvider().isPhysical()) {
      myFileStatusMap.markFileScopeDirty(
          document, new TextRange(0, fileLength), fileLength, "Non-physical file update: " + file);
      return;
    }

    PsiElement element =
        whitespaceOptimizationAllowed
                && UpdateHighlightersUtil.isWhitespaceOptimizationAllowed(document)
            ? child
            : child.getParent();
    while (true) {
      if (element == null || element instanceof PsiFile || element instanceof PsiDirectory) {
        myFileStatusMap.markAllFilesDirty("Top element: " + element);
        return;
      }

      final PsiElement scope = getChangeHighlightingScope(element);
      if (scope != null) {
        myFileStatusMap.markFileScopeDirty(
            document, scope.getTextRange(), fileLength, "Scope: " + scope);
        return;
      }

      element = element.getParent();
    }
  }
  public GeneralHighlightingPass(
      @NotNull Project project,
      @NotNull PsiFile file,
      @NotNull Document document,
      int startOffset,
      int endOffset,
      boolean updateAll,
      @NotNull ProperTextRange priorityRange,
      @Nullable Editor editor) {
    super(project, document, PRESENTABLE_NAME, file, true);
    myStartOffset = startOffset;
    myEndOffset = endOffset;
    myUpdateAll = updateAll;
    myPriorityRange = priorityRange;
    myEditor = editor;

    LOG.assertTrue(file.isValid());
    setId(Pass.UPDATE_ALL);
    myHasErrorElement =
        !isWholeFileHighlighting() && Boolean.TRUE.equals(myFile.getUserData(HAS_ERROR_ELEMENT));
    FileStatusMap fileStatusMap =
        ((DaemonCodeAnalyzerImpl) DaemonCodeAnalyzer.getInstance(myProject)).getFileStatusMap();
    myErrorFound = !isWholeFileHighlighting() && fileStatusMap.wasErrorFound(myDocument);

    myApplyCommand =
        new Runnable() {
          @Override
          public void run() {
            ProperTextRange range = new ProperTextRange(myStartOffset, myEndOffset);
            MarkupModel model = DocumentMarkupModel.forDocument(myDocument, myProject, true);
            UpdateHighlightersUtil.cleanFileLevelHighlights(myProject, Pass.UPDATE_ALL, myFile);
            final EditorColorsScheme colorsScheme = getColorsScheme();
            UpdateHighlightersUtil.setHighlightersInRange(
                myProject,
                myDocument,
                range,
                colorsScheme,
                myHighlights,
                (MarkupModelEx) model,
                Pass.UPDATE_ALL);
          }
        };

    // initial guess to show correct progress in the traffic light icon
    setProgressLimit(document.getTextLength() / 2); // approx number of PSI elements = file length/2
    myGlobalScheme = EditorColorsManager.getInstance().getGlobalScheme();
  }
 @Override
 public void beforeChildrenChange(@NotNull PsiTreeChangeEvent event) {
   // this event sent always before every PSI change, even not significant one (like after quick
   // typing/backspacing char)
   // mark file dirty just in case
   PsiFile psiFile = event.getFile();
   if (psiFile != null) {
     myFileStatusMap.markFileScopeDirtyDefensively(psiFile, event);
   }
 }
 @Override
 public void propertyChanged(@NotNull PsiTreeChangeEvent event) {
   String propertyName = event.getPropertyName();
   if (!propertyName.equals(PsiTreeChangeEvent.PROP_WRITABLE)) {
     Object oldValue = event.getOldValue();
     if (oldValue instanceof VirtualFile && shouldBeIgnored((VirtualFile) oldValue)) {
       // ignore workspace.xml
       return;
     }
     myFileStatusMap.markAllFilesDirty(event);
   }
 }