private static @NotNull <E extends PsiElement> SmartPointerElementInfo doCreateElementInfo(@NotNull Project project,
                                                                                             @NotNull E element,
                                                                                             @Nullable PsiFile containingFile,
                                                                                             boolean forInjected) {
    if (element instanceof PsiDirectory) {
      return new DirElementInfo((PsiDirectory)element);
    }
    if (element instanceof PsiCompiledElement || containingFile == null) {
      if (element instanceof StubBasedPsiElement && element instanceof PsiCompiledElement) {
        if (element instanceof PsiFile) {
          return new FileElementInfo((PsiFile)element);
        }
        PsiAnchor.StubIndexReference stubReference = PsiAnchor.createStubReference(element, containingFile);
        if (stubReference != null) {
          return new ClsElementInfo(stubReference);
        }
      }
      return new HardElementInfo(element);
    }

    FileViewProvider viewProvider = containingFile.getViewProvider();
    if (viewProvider instanceof FreeThreadedFileViewProvider && hasReliableRange(element, containingFile)) {
      PsiLanguageInjectionHost hostContext = InjectedLanguageManager.getInstance(containingFile.getProject()).getInjectionHost(containingFile);
      TextRange elementRange = element.getTextRange();
      if (hostContext != null && elementRange != null) {
        SmartPsiElementPointer<PsiLanguageInjectionHost> hostPointer = SmartPointerManager.getInstance(project).createSmartPsiElementPointer(hostContext);
        return new InjectedSelfElementInfo(project, element, elementRange, containingFile, hostPointer);
      }
    }

    VirtualFile virtualFile = viewProvider.getVirtualFile();
    if (element instanceof PsiFile) {
      FileViewProvider restored = PsiManager.getInstance(project).findViewProvider(virtualFile);
      return restored != null && restored.getPsi(LanguageUtil.getRootLanguage(element)) == element
             ? new FileElementInfo((PsiFile)element)
             : new HardElementInfo(element);
    }

    if (!hasReliableRange(element, containingFile)) {
      return new HardElementInfo(element);
    }

    Document document = FileDocumentManager.getInstance().getCachedDocument(virtualFile);
    if (document != null &&
        ((PsiDocumentManagerBase)PsiDocumentManager.getInstance(project)).getSynchronizer().isDocumentAffectedByTransactions(document)) {
      LOG.error("Smart pointers must not be created during PSI changes");
    }

    SmartPointerElementInfo info = createAnchorInfo(element, containingFile);
    if (info != null) {
      return info;
    }

    TextRange elementRange = element.getTextRange();
    if (elementRange == null) {
      return new HardElementInfo(element);
    }
    Identikit.ByType identikit = Identikit.fromPsi(element, LanguageUtil.getRootLanguage(element));
    if (elementRange.isEmpty() &&
        identikit.findPsiElement(containingFile, elementRange.getStartOffset(), elementRange.getEndOffset()) != element) {
      // PSI has empty range, no text, but complicated structure (e.g. PSI built on C-style macro expansions). It can't be reliably
      // restored by just one offset in a file, so hold it on a hard reference
      return new HardElementInfo(element);
    }

    if (!containingFile.isPhysical() && document == null) {
      // there's no document whose events could be tracked and used for restoration by offset
      return new HardElementInfo(element);
    }

    ProperTextRange proper = ProperTextRange.create(elementRange);
    return new SelfElementInfo(proper, identikit, containingFile, forInjected);
  }
private static @NotNull <E extends PsiElement> SmartPointerElementInfo doCreateElementInfo(@NotNull Project project,
                                                                                             @NotNull E element,
                                                                                             @Nullable PsiFile containingFile,
                                                                                             boolean forInjected)