public ProblemDescriptorImpl(
      @NotNull PsiElement startElement,
      @NotNull PsiElement endElement,
      String descriptionTemplate,
      LocalQuickFix[] fixes,
      ProblemHighlightType highlightType,
      boolean isAfterEndOfLine,
      @Nullable TextRange rangeInElement,
      final boolean tooltip,
      @Nullable HintAction hintAction,
      boolean onTheFly) {

    super(fixes, descriptionTemplate);
    myShowTooltip = tooltip;
    myHintAction = hintAction;
    PsiFile startContainingFile = startElement.getContainingFile();
    LOG.assertTrue(
        startContainingFile != null && startContainingFile.isValid() || startElement.isValid(),
        startElement);
    PsiFile endContainingFile =
        startElement == endElement ? startContainingFile : endElement.getContainingFile();
    LOG.assertTrue(
        startElement == endElement
            || endContainingFile != null && endContainingFile.isValid()
            || endElement.isValid(),
        endElement);
    assertPhysical(startElement);
    if (startElement != endElement) assertPhysical(endElement);

    final TextRange startElementRange = startElement.getTextRange();
    LOG.assertTrue(startElementRange != null, startElement);
    final TextRange endElementRange = endElement.getTextRange();
    LOG.assertTrue(endElementRange != null, endElement);
    if (startElementRange.getStartOffset() >= endElementRange.getEndOffset()) {
      if (!(startElement instanceof PsiFile && endElement instanceof PsiFile)) {
        LOG.error(
            "Empty PSI elements should not be passed to createDescriptor. Start: "
                + startElement
                + ", end: "
                + endElement);
      }
    }

    myHighlightType = highlightType;
    final Project project =
        startContainingFile == null ? startElement.getProject() : startContainingFile.getProject();
    final SmartPointerManager manager = SmartPointerManager.getInstance(project);
    myStartSmartPointer = manager.createSmartPsiElementPointer(startElement, startContainingFile);
    myEndSmartPointer =
        startElement == endElement
            ? null
            : manager.createSmartPsiElementPointer(endElement, endContainingFile);

    myAfterEndOfLine = isAfterEndOfLine;
    myTextRangeInElement = rangeInElement;
  }
  @NotNull
  private List<AnnotationData> doCollect(
      @NotNull PsiModifierListOwner listOwner, boolean onlyWritable) {
    final List<PsiFile> files = findExternalAnnotationsFiles(listOwner);
    if (files == null) {
      return NO_DATA;
    }
    SmartList<AnnotationData> result = new SmartList<AnnotationData>();
    String externalName = getExternalName(listOwner, false);
    if (externalName == null) return NO_DATA;

    for (PsiFile file : files) {
      if (!file.isValid()) continue;
      if (onlyWritable && !file.isWritable()) continue;

      MostlySingularMultiMap<String, AnnotationData> fileData = getDataFromFile(file);

      ContainerUtil.addAll(result, fileData.get(externalName));
    }
    if (result.isEmpty()) {
      return NO_DATA;
    }
    result.trimToSize();
    return result;
  }
 /**
  * Retrieves indent options for PSI file from an associated document or (if not defined in the
  * document) from file indent options providers.
  *
  * @param file The PSI file to retrieve options for.
  * @param formatRange The text range within the file for formatting purposes or null if there is
  *     either no specific range or multiple ranges. If the range covers the entire file (full
  *     reformat), options stored in the document are ignored and indent options are taken from
  *     file indent options providers.
  * @param ignoreDocOptions Ignore options stored in the document and use file indent options
  *     providers even if there is no text range or the text range doesn't cover the entire file.
  * @param providerProcessor A callback object containing a reference to indent option provider
  *     which has returned indent options.
  * @return Indent options from the associated document or file indent options providers.
  * @see com.intellij.psi.codeStyle.FileIndentOptionsProvider
  */
 @NotNull
 public IndentOptions getIndentOptionsByFile(
     @Nullable PsiFile file,
     @Nullable TextRange formatRange,
     boolean ignoreDocOptions,
     @Nullable Processor<FileIndentOptionsProvider> providerProcessor) {
   if (file != null && file.isValid() && file.isWritable()) {
     boolean isFullReformat = isFileFullyCoveredByRange(file, formatRange);
     if (!ignoreDocOptions && !isFullReformat) {
       IndentOptions docOptions = IndentOptions.retrieveFromAssociatedDocument(file);
       if (docOptions != null) return docOptions;
     }
     FileIndentOptionsProvider[] providers =
         Extensions.getExtensions(FileIndentOptionsProvider.EP_NAME);
     for (FileIndentOptionsProvider provider : providers) {
       if (!isFullReformat || provider.useOnFullReformat()) {
         IndentOptions indentOptions = provider.getIndentOptions(this, file);
         if (indentOptions != null) {
           if (providerProcessor != null) {
             providerProcessor.process(provider);
           }
           logIndentOptions(file, provider, indentOptions);
           return indentOptions;
         }
       }
     }
     return getIndentOptions(file.getFileType());
   } else return OTHER_INDENT_OPTIONS;
 }
 public static Editor create(
     @NotNull final DocumentWindowImpl documentRange,
     @NotNull final EditorImpl editor,
     @NotNull final PsiFile injectedFile) {
   assert documentRange.isValid();
   assert injectedFile.isValid();
   EditorWindow window;
   synchronized (allEditors) {
     for (EditorWindow editorWindow : allEditors) {
       if (editorWindow.getDocument() == documentRange && editorWindow.getDelegate() == editor) {
         editorWindow.myInjectedFile = injectedFile;
         if (editorWindow.isValid()) {
           return editorWindow;
         }
       }
       if (editorWindow.getDocument().areRangesEqual(documentRange)) {
         // int i = 0;
       }
     }
     window = new EditorWindow(documentRange, editor, injectedFile, documentRange.isOneLine());
     allEditors.add(window);
   }
   assert window.isValid();
   return window;
 }
 @Nullable
 private static VirtualFile findInitialDir(@NotNull final PsiFile psiFileRequestor) {
   if (!psiFileRequestor.isValid()) {
     return null;
   }
   return ApplicationManager.getApplication()
       .runReadAction(
           new Computable<VirtualFile>() {
             @Override
             @Nullable
             public VirtualFile compute() {
               Project project = psiFileRequestor.getProject();
               VirtualFile virtualFile = psiFileRequestor.getVirtualFile();
               if (virtualFile != null) {
                 ProjectFileIndex fileIndex =
                     ProjectRootManager.getInstance(project).getFileIndex();
                 VirtualFile contentRoot = fileIndex.getContentRootForFile(virtualFile);
                 if (contentRoot != null) {
                   return contentRoot;
                 }
               }
               return project.getBaseDir();
             }
           });
 }
 private void updateRightTreeModel() {
   Set<PsiFile> deps = new HashSet<PsiFile>();
   Set<PsiFile> scope = getSelectedScope(myLeftTree);
   myIllegalsInRightTree = new HashSet<PsiFile>();
   for (PsiFile psiFile : scope) {
     Map<DependencyRule, Set<PsiFile>> illegalDeps = myIllegalDependencies.get(psiFile);
     if (illegalDeps != null) {
       for (final DependencyRule rule : illegalDeps.keySet()) {
         myIllegalsInRightTree.addAll(illegalDeps.get(rule));
       }
     }
     final Set<PsiFile> psiFiles = myDependencies.get(psiFile);
     if (psiFiles != null) {
       for (PsiFile file : psiFiles) {
         if (file != null && file.isValid()) {
           deps.add(file);
         }
       }
     }
   }
   deps.removeAll(scope);
   myRightTreeExpansionMonitor.freeze();
   myRightTree.setModel(buildTreeModel(deps, myRightTreeMarker));
   myRightTreeExpansionMonitor.restore();
   expandFirstLevel(myRightTree);
 }
  @NotNull
  public static <T extends PsiJavaCodeReferenceElement> JavaResolveResult[] multiResolveImpl(
      @NotNull T element,
      boolean incompleteCode,
      @NotNull ResolveCache.PolyVariantContextResolver<? super T> resolver) {

    FileASTNode fileElement = SharedImplUtil.findFileElement(element.getNode());
    if (fileElement == null) {
      PsiUtilCore.ensureValid(element);
      LOG.error("fileElement == null!");
      return JavaResolveResult.EMPTY_ARRAY;
    }
    PsiFile psiFile = SharedImplUtil.getContainingFile(fileElement);
    PsiManager manager = psiFile == null ? null : psiFile.getManager();
    if (manager == null) {
      PsiUtilCore.ensureValid(element);
      LOG.error("getManager() == null!");
      return JavaResolveResult.EMPTY_ARRAY;
    }
    boolean valid = psiFile.isValid();
    if (!valid) {
      PsiUtilCore.ensureValid(element);
      LOG.error("psiFile.isValid() == false!");
      return JavaResolveResult.EMPTY_ARRAY;
    }
    if (element instanceof PsiMethodReferenceExpression) {
      // method refs: do not cache results during parent conflict resolving, acceptable checks, etc
      final Map<PsiElement, PsiType> map = LambdaUtil.ourFunctionTypes.get();
      if (map != null && map.containsKey(element)) {
        return (JavaResolveResult[]) resolver.resolve(element, psiFile, incompleteCode);
      }
    }

    return multiResolveImpl(manager.getProject(), psiFile, element, incompleteCode, resolver);
  }
 public boolean isAvailable(PsiFile myFile) {
   return myFile != null
       && myFile.isValid()
       && myFile.getManager().isInProject(myFile)
       && myFile instanceof PsiJavaFile
       && ((PsiJavaFile) myFile).getClasses().length != 0
       && myTargetPackage != null;
 }
 @Override
 public boolean accept(PsiFile psiFile) {
   if (myFile == null || !myFile.equals(psiFile) || !myFile.isValid()) {
     return false;
   }
   return (myTodoFilter != null && myTodoFilter.accept(mySearchHelper, psiFile))
       || (myTodoFilter == null && mySearchHelper.getTodoItemsCount(psiFile) > 0);
 }
 private static boolean isCopyUpToDate(Document document, @NotNull PsiFile file) {
   if (!file.isValid()) {
     return false;
   }
   // the psi file cache might have been cleared by some external activity,
   // in which case PSI-document sync may stop working
   PsiFile current = PsiDocumentManager.getInstance(file.getProject()).getPsiFile(document);
   return current != null && current.getViewProvider().getPsi(file.getLanguage()) == file;
 }
  // returns editor,file where the action is available or null if there are none
  public static boolean availableFor(
      @NotNull PsiFile file, @NotNull Editor editor, @NotNull IntentionAction action) {
    if (!file.isValid()) return false;

    int offset = editor.getCaretModel().getOffset();
    PsiElement element = file.findElementAt(offset);
    boolean inProject = file.getManager().isInProject(file);
    return isAvailableHere(editor, file, element, inProject, action);
  }
 @Override
 public void reparseRange(PsiFile file, int startOffset, int endOffset, CharSequence newTextS)
     throws IncorrectOperationException {
   LOG.assertTrue(file.isValid());
   final PsiFileImpl psiFile = (PsiFileImpl) file;
   final Document document = psiFile.getViewProvider().getDocument();
   assert document != null;
   document.replaceString(startOffset, endOffset, newTextS);
   PsiDocumentManager.getInstance(psiFile.getProject()).commitDocument(document);
 }
  @Override
  public PsiElement restoreElement() {
    Segment segment = getPsiRange();
    if (segment == null) return null;

    PsiFile file = restoreFile();
    if (file == null || !file.isValid()) return null;

    return findElementInside(file, segment.getStartOffset(), segment.getEndOffset(), myType);
  }
 @Override
 protected void validateCache() {
   super.validateCache();
   if (myFile != null && !myFile.isValid()) {
     VirtualFile vFile = myFile.getVirtualFile();
     if (vFile.isValid()) {
       myFile = PsiManager.getInstance(myProject).findFile(vFile);
     } else {
       myFile = null;
     }
   }
 }
  @NotNull
  private static XmlFileHeader calcXmlFileHeader(final PsiFile file) {

    // if (file.getFileType() == XmlFileType.INSTANCE) {
    //  VirtualFile virtualFile = file.getVirtualFile();
    //  if (virtualFile instanceof VirtualFileWithId) {
    //    ObjectStubTree tree = StubTreeLoader.getInstance().readFromVFile(file.getProject(),
    // virtualFile);
    //    if (tree != null) {
    //      return ((FileStub)tree.getRoot()).getHeader();
    //    }
    //  }
    // }
    if (file instanceof XmlFile && file.getNode().isParsed()) {
      final XmlDocument document = ((XmlFile) file).getDocument();
      if (document != null) {
        String publicId = null;
        String systemId = null;
        final XmlProlog prolog = document.getProlog();
        if (prolog != null) {
          final XmlDoctype doctype = prolog.getDoctype();
          if (doctype != null) {
            publicId = doctype.getPublicId();
            systemId = doctype.getSystemId();
            if (systemId == null) {
              systemId = doctype.getDtdUri();
            }
          }
        }

        final XmlTag tag = document.getRootTag();
        if (tag != null) {
          String localName = tag.getLocalName();
          if (StringUtil.isNotEmpty(localName)) {
            if (tag.getPrevSibling() instanceof PsiErrorElement) {
              return XmlFileHeader.EMPTY;
            }

            String psiNs = tag.getNamespace();
            return new XmlFileHeader(
                localName,
                psiNs == XmlUtil.EMPTY_URI || Comparing.equal(psiNs, systemId) ? null : psiNs,
                publicId,
                systemId);
          }
        }
      }
      return XmlFileHeader.EMPTY;
    }

    if (!file.isValid()) return XmlFileHeader.EMPTY;
    return NanoXmlUtil.parseHeader(file);
  }
  private boolean isValid() {
    if (isDumbMode() && !DumbService.isDumbAware(this)) {
      return false;
    }

    if (myDocument != null && myDocument.getModificationStamp() != myInitialStamp) return false;
    if (myProject != null && myDocument != null) {
      PsiFile file = PsiDocumentManager.getInstance(myProject).getPsiFile(myDocument);
      if (file == null || !file.isValid()) return false;
    }

    return true;
  }
 public boolean isValid() {
   boolean valid =
       myNewVirtualFile.isValid()
           && (myAltFullRange == null && myInjectedFile.isValid()
               || myAltFullRange != null && myAltFullRange.isValid());
   if (valid) {
     for (Trinity<RangeMarker, RangeMarker, SmartPsiElementPointer> t : myMarkers) {
       if (!t.first.isValid() || !t.second.isValid() || t.third.getElement() == null) {
         valid = false;
         break;
       }
     }
   }
   return valid;
 }
  @Override
  public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
    if (file instanceof XmlFile && file.isValid() && AndroidFacet.getInstance(file) != null) {
      ResourceFolderType folderType = ResourceHelper.getFolderType(file);
      if (folderType == null) {
        return false;
      } else if (folderType != ResourceFolderType.VALUES) {
        return true;
      } else {
        return isAvailable(getValueTag(editor, file), file);
      }
    }

    return false;
  }
  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();
  }
 // returns number of hits
 static int processUsagesInFile(
     @NotNull final PsiFile psiFile,
     @NotNull final FindModel findModel,
     @NotNull final Processor<UsageInfo> consumer) {
   if (findModel.getStringToFind().isEmpty()) {
     if (!ApplicationManager.getApplication()
         .runReadAction((Computable<Boolean>) () -> consumer.process(new UsageInfo(psiFile)))) {
       throw new ProcessCanceledException();
     }
     return 1;
   }
   final VirtualFile virtualFile = psiFile.getVirtualFile();
   if (virtualFile == null) return 0;
   if (virtualFile.getFileType().isBinary()) return 0; // do not decompile .class files
   final Document document =
       ApplicationManager.getApplication()
           .runReadAction(
               (Computable<Document>)
                   () ->
                       virtualFile.isValid()
                           ? FileDocumentManager.getInstance().getDocument(virtualFile)
                           : null);
   if (document == null) return 0;
   final int[] offset = {0};
   int count = 0;
   int found;
   ProgressIndicator indicator =
       ProgressWrapper.unwrap(ProgressManager.getInstance().getProgressIndicator());
   TooManyUsagesStatus tooManyUsagesStatus = TooManyUsagesStatus.getFrom(indicator);
   do {
     tooManyUsagesStatus.pauseProcessingIfTooManyUsages(); // wait for user out of read action
     found =
         ApplicationManager.getApplication()
             .runReadAction(
                 (Computable<Integer>)
                     () -> {
                       if (!psiFile.isValid()) return 0;
                       return addToUsages(
                           document, consumer, findModel, psiFile, offset, USAGES_PER_READ_ACTION);
                     });
     count += found;
   } while (found != 0);
   return count;
 }
  public boolean isAvailable(@Nullable XmlTag tag, PsiFile file) {
    if (file instanceof XmlFile && file.isValid() && AndroidFacet.getInstance(file) != null) {
      ResourceFolderType folderType = ResourceHelper.getFolderType(file);
      if (folderType == null) {
        return false;
      } else if (folderType != ResourceFolderType.VALUES) {
        return true;
      } else {
        // In value files, you can invoke this action if the caret is on or inside an element (other
        // than the
        // root <resources> tag). Only accept the element if it has a known type with a known name.
        if (tag != null && tag.getAttributeValue(ATTR_NAME) != null) {
          return AndroidResourceUtil.getResourceForResourceTag(tag) != null;
        }
      }
    }

    return false;
  }
  private void invokeCompletion(final ExpressionContext context) {
    final Project project = context.getProject();
    final Editor editor = context.getEditor();

    final PsiFile psiFile = editor != null ? PsiUtilBase.getPsiFileInEditor(editor, project) : null;
    Runnable runnable =
        () -> {
          if (project.isDisposed()
              || editor == null
              || editor.isDisposed()
              || psiFile == null
              || !psiFile.isValid()) return;

          // it's invokeLater, so another completion could have started
          if (CompletionServiceImpl.getCompletionService().getCurrentCompletion() != null) return;

          CommandProcessor.getInstance()
              .executeCommand(
                  project,
                  () -> {
                    // if we're in some completion's insert handler, make sure our new completion
                    // isn't treated as the second invocation
                    CompletionServiceImpl.setCompletionPhase(CompletionPhase.NoCompletion);

                    invokeCompletionHandler(project, editor);
                    Lookup lookup = LookupManager.getInstance(project).getActiveLookup();

                    if (lookup != null) {
                      lookup.addLookupListener(
                          new MyLookupListener(context, myCheckCompletionChar));
                    }
                  },
                  "",
                  null);
        };
    ApplicationManager.getApplication().invokeLater(runnable);
  }
  private static boolean activatePsiElementIfOpen(
      @NotNull PsiElement elt, boolean searchForOpen, boolean requestFocus) {
    if (!elt.isValid()) return false;
    elt = elt.getNavigationElement();
    final PsiFile file = elt.getContainingFile();
    if (file == null || !file.isValid()) return false;

    VirtualFile vFile = file.getVirtualFile();
    if (vFile == null) return false;

    if (!EditorHistoryManager.getInstance(elt.getProject()).hasBeenOpen(vFile)) return false;

    final FileEditorManager fem = FileEditorManager.getInstance(elt.getProject());
    if (!fem.isFileOpen(vFile)) {
      fem.openFile(vFile, requestFocus, searchForOpen);
    }

    final TextRange range = elt.getTextRange();
    if (range == null) return false;

    final FileEditor[] editors = fem.getEditors(vFile);
    for (FileEditor editor : editors) {
      if (editor instanceof TextEditor) {
        final Editor text = ((TextEditor) editor).getEditor();
        final int offset = text.getCaretModel().getOffset();

        if (range.containsOffset(offset)) {
          // select the file
          fem.openFile(vFile, requestFocus, searchForOpen);
          return true;
        }
      }
    }

    return false;
  }
  @NotNull
  private List<Pair<PsiClass, VirtualFile>> doFindClasses(
      @NotNull String qName, @NotNull final GlobalSearchScope scope) {
    final Collection<PsiClass> classes =
        JavaFullClassNameIndex.getInstance().get(qName.hashCode(), myManager.getProject(), scope);
    if (classes.isEmpty()) return Collections.emptyList();
    List<Pair<PsiClass, VirtualFile>> result = new ArrayList<>(classes.size());
    for (PsiClass aClass : classes) {
      final String qualifiedName = aClass.getQualifiedName();
      if (qualifiedName == null || !qualifiedName.equals(qName)) continue;

      PsiFile file = aClass.getContainingFile();
      if (file == null) {
        throw new AssertionError("No file for class: " + aClass + " of " + aClass.getClass());
      }
      final boolean valid = file.isValid();
      VirtualFile vFile = file.getVirtualFile();
      if (!valid) {
        LOG.error(
            "Invalid file "
                + file
                + "; virtualFile:"
                + vFile
                + (vFile != null && !vFile.isValid() ? " (invalid)" : "")
                + "; id="
                + (vFile == null ? 0 : ((VirtualFileWithId) vFile).getId()),
            new PsiInvalidElementAccessException(aClass));
        continue;
      }
      if (!hasAcceptablePackage(vFile)) continue;

      result.add(Pair.create(aClass, vFile));
    }

    return result;
  }
  @Override
  public void startRunInjectors(@NotNull final Document hostDocument, final boolean synchronously) {
    if (myProject.isDisposed()) return;
    if (!synchronously && ApplicationManager.getApplication().isWriteAccessAllowed()) return;
    // use cached to avoid recreate PSI in alien project
    final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(myProject);
    final PsiFile hostPsiFile = documentManager.getCachedPsiFile(hostDocument);
    if (hostPsiFile == null) return;

    final ConcurrentList<DocumentWindow> injected =
        InjectedLanguageUtil.getCachedInjectedDocuments(hostPsiFile);
    if (injected.isEmpty()) return;

    if (myProgress.isCanceled()) {
      myProgress = new DaemonProgressIndicator();
    }
    final Set<DocumentWindow> newDocuments = Collections.synchronizedSet(new THashSet<>());
    final Processor<DocumentWindow> commitProcessor =
        documentWindow -> {
          if (myProject.isDisposed()) return false;
          ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
          if (indicator != null && indicator.isCanceled()) return false;
          if (documentManager.isUncommited(hostDocument) || !hostPsiFile.isValid())
            return false; // will be committed later

          // it is here where the reparse happens and old file contents replaced
          InjectedLanguageUtil.enumerate(
              documentWindow,
              hostPsiFile,
              (injectedPsi, places) -> {
                DocumentWindow newDocument =
                    (DocumentWindow) injectedPsi.getViewProvider().getDocument();
                if (newDocument != null) {
                  PsiDocumentManagerBase.checkConsistency(injectedPsi, newDocument);
                  newDocuments.add(newDocument);
                }
              });
          return true;
        };
    final Runnable commitInjectionsRunnable =
        () -> {
          if (myProgress.isCanceled()) return;
          JobLauncher.getInstance()
              .invokeConcurrentlyUnderProgress(
                  new ArrayList<>(injected), myProgress, true, commitProcessor);

          synchronized (ourInjectionPsiLock) {
            injected.clear();
            injected.addAll(newDocuments);
          }
        };

    if (synchronously) {
      if (Thread.holdsLock(PsiLock.LOCK)) {
        // hack for the case when docCommit was called from within PSI modification, e.g. in
        // formatter.
        // we can't spawn threads to do injections there, otherwise a deadlock is imminent
        ContainerUtil.process(new ArrayList<>(injected), commitProcessor);
      } else {
        commitInjectionsRunnable.run();
      }
    } else {
      JobLauncher.getInstance()
          .submitToJobThread(
              () ->
                  ApplicationManagerEx.getApplicationEx()
                      .tryRunReadAction(commitInjectionsRunnable),
              null);
    }
  }
 private boolean isValid() {
   return !isDisposed()
       && !myInjectedFile.getProject().isDisposed()
       && myInjectedFile.isValid()
       && myDocumentWindow.isValid();
 }
  @Override
  @Nullable
  public List<PsiFile> findExternalAnnotationsFiles(@NotNull PsiModifierListOwner listOwner) {
    final PsiFile containingFile = listOwner.getContainingFile();
    if (!(containingFile instanceof PsiJavaFile)) {
      return null;
    }
    final PsiJavaFile javaFile = (PsiJavaFile) containingFile;
    final String packageName = javaFile.getPackageName();
    final VirtualFile virtualFile = containingFile.getVirtualFile();
    if (virtualFile == null) return null;

    final List<PsiFile> files = myExternalAnnotations.get(virtualFile);
    if (files == NULL_LIST) return null;
    if (files != null) {
      boolean allValid = true;
      for (PsiFile file : files) {
        allValid &= file.isValid();
      }
      if (allValid) {
        return files;
      }
    }

    if (virtualFile == null) {
      return null;
    }

    Set<PsiFile> possibleAnnotationsXmls = new THashSet<PsiFile>();
    for (VirtualFile root : getExternalAnnotationsRoots(virtualFile)) {
      final VirtualFile ext =
          root.findFileByRelativePath(packageName.replace('.', '/') + "/" + ANNOTATIONS_XML);
      if (ext == null) continue;
      final PsiFile psiFile = myPsiManager.findFile(ext);
      if (psiFile == null) continue;
      possibleAnnotationsXmls.add(psiFile);
    }
    List<PsiFile> result;
    if (possibleAnnotationsXmls.isEmpty()) {
      myExternalAnnotations.put(virtualFile, NULL_LIST);
      result = null;
    } else {
      result = new SmartList<PsiFile>(possibleAnnotationsXmls);
      // sorting by writability: writable go first
      Collections.sort(
          result,
          new Comparator<PsiFile>() {
            @Override
            public int compare(PsiFile f1, PsiFile f2) {
              boolean w1 = f1.isWritable();
              boolean w2 = f2.isWritable();
              if (w1 == w2) {
                return 0;
              }
              return w1 ? -1 : 1;
            }
          });

      myExternalAnnotations.put(virtualFile, result);
    }
    return result;
  }
 @Override
 public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
   return file != null && file.isValid();
 }
 @Override
 public PsiFile getContainingFile() {
   PsiFile file = SharedImplUtil.getContainingFile(this);
   if (file == null || !file.isValid()) throw new PsiInvalidElementAccessException(this);
   return file;
 }