<commit_before>package com.intellij.psi.impl.smartPointers;

import com.intellij.injected.editor.DocumentWindow;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.RangeMarker;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiDocumentManagerImpl;
import org.jetbrains.annotations.Nullable;

class SmartPsiElementPointerImpl<E extends PsiElement> implements SmartPointerEx<E> {
  private static final Logger LOG = Logger.getInstance(
    "#com.intellij.psi.impl.smartPointers.SmartPsiElementPointerImpl");

  private E myElement;
  private SmartPointerElementInfo myElementInfo;
  private final Project myProject;

  public SmartPsiElementPointerImpl(Project project, E element) {
    myProject = project;
    ApplicationManager.getApplication().assertReadAccessAllowed();
    myElement = element;
    myElementInfo = null;

    // Assert document committed.
    PsiFile file = element.getContainingFile();
    if (file != null) {
      final PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(project);
      if (psiDocumentManager instanceof PsiDocumentManagerImpl) {
        Document doc = psiDocumentManager.getCachedDocument(file);
        if (doc != null) {
          //[ven] this is a really NASTY hack; when no smart pointer is kept on UsageInfo then remove this conditional
          if (!(element instanceof PsiFile)) {
            LOG.assertTrue(!psiDocumentManager.isUncommited(doc) || ((PsiDocumentManagerImpl)psiDocumentManager).isCommittingDocument(doc));
          }
        }
      }
    }
  }

  public boolean equals(Object obj) {
    if (!(obj instanceof SmartPsiElementPointer)) return false;
    SmartPsiElementPointer pointer = (SmartPsiElementPointer)obj;
    return Comparing.equal(pointer.getElement(), getElement());
  }

  public int hashCode() {
    PsiElement element = getElement();
    return element != null ? element.hashCode() : 0;
  }

  @Nullable
  public E getElement() {
    if (myElement != null && !myElement.isValid()) {
      if (myElementInfo == null) {
        myElement = null;
      }
      else {
        PsiElement restored = myElementInfo.restoreElement();
        if (restored != null && (!areElementKindEqual(restored, myElement) || !restored.isValid())) {
          restored = null;
        }

        myElement = (E) restored;
      }
    }

    if (myElementInfo != null && myElement != null) {
      Document document = myElementInfo.getDocumentToSynchronize();
      if (document != null && PsiDocumentManager.getInstance(myProject).isUncommited(document)) return myElement; // keep element info if document is modified
    }
    // myElementInfo = null;

    return myElement;
  }

  public PsiFile getContainingFile() {
    if (myElement != null) {
      return myElement.getContainingFile();
    }

    final Document doc = myElementInfo.getDocumentToSynchronize();
    if (doc == null) {
      final E resolved = getElement();
      return resolved != null ? resolved.getContainingFile() : null;
    }
    return PsiDocumentManager.getInstance(myProject).getPsiFile(doc);
  }

  @Nullable
  private SmartPointerElementInfo createElementInfo() {
    if (myElement instanceof PsiCompiledElement) return null;

    final PsiFile containingFile = myElement.getContainingFile();
    if (containingFile == null) return null;
    if (!myElement.isPhysical()) return null;

    for(SmartPointerElementInfoFactory factory: Extensions.getExtensions(SmartPointerElementInfoFactory.EP_NAME)) {
      final SmartPointerElementInfo result = factory.createElementInfo(myElement);
      if (result != null) {
        return result;
      }
    }

    return containingFile.getContext() != null ? new InjectedSelfElementInfo(myElement) : new SelfElementInfo(myElement);
  }

  private static boolean areElementKindEqual(PsiElement element1, PsiElement element2) {
    return element1.getClass().equals(element2.getClass()); //?
  }

  public void documentAndPsiInSync() {
    if (myElementInfo != null) {
      myElementInfo.documentAndPsiInSync();
    }
  }

  public void fastenBelt() {
    if (myElementInfo != null && myElement != null && myElement.isValid()) return;

    if (myElementInfo == null && myElement != null && myElement.isValid()) {
      myElementInfo = createElementInfo();
    }
  }

  private static class InjectedSelfElementInfo extends SelfElementInfo {
    private DocumentWindow myDocument;

    InjectedSelfElementInfo(PsiElement anchor) {
      super(anchor);

      assert myFile.getContext() != null;
    }

    protected TextRange getPersistentAnchorRange(final PsiElement anchor, final Document document) {
      final TextRange textRange = super.getPersistentAnchorRange(anchor, document);
      if (!(document instanceof DocumentWindow)) return textRange;
      myDocument = ((DocumentWindow)document);
      return myDocument.injectedToHost(textRange);
    }

    protected int getSyncEndOffset() {
      return super.getSyncEndOffset() - (myDocument != null ? myDocument.injectedToHost(0):0);
    }

    protected int getSyncStartOffset() {
      return super.getSyncStartOffset() - (myDocument != null ? myDocument.injectedToHost(0):0);
    }
  }

  private static class SelfElementInfo implements SmartPointerElementInfo {
    protected final PsiFile myFile;
    private final RangeMarker myMarker;
    private int mySyncStartOffset;
    private int mySyncEndOffset;
    private boolean mySyncMarkerIsValid;
    private Class myType;

    public SelfElementInfo(PsiElement anchor) {
      LOG.assertTrue(anchor.isPhysical());
      myFile = anchor.getContainingFile();
      TextRange range = anchor.getTextRange();

      final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(myFile.getProject());
      Document document = documentManager.getDocument(myFile);

      // LOG.assertTrue(!documentManager.isUncommited(document));

      assert document != null : myFile.getName();<commit_msg>yet another issue with smart psi pointer in injected language, in this time due to prefix<commit_after>package com.intellij.psi.impl.smartPointers;

import com.intellij.injected.editor.DocumentWindow;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.RangeMarker;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiDocumentManagerImpl;
import org.jetbrains.annotations.Nullable;

class SmartPsiElementPointerImpl<E extends PsiElement> implements SmartPointerEx<E> {
  private static final Logger LOG = Logger.getInstance(
    "#com.intellij.psi.impl.smartPointers.SmartPsiElementPointerImpl");

  private E myElement;
  private SmartPointerElementInfo myElementInfo;
  private final Project myProject;

  public SmartPsiElementPointerImpl(Project project, E element) {
    myProject = project;
    ApplicationManager.getApplication().assertReadAccessAllowed();
    myElement = element;
    myElementInfo = null;

    // Assert document committed.
    PsiFile file = element.getContainingFile();
    if (file != null) {
      final PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(project);
      if (psiDocumentManager instanceof PsiDocumentManagerImpl) {
        Document doc = psiDocumentManager.getCachedDocument(file);
        if (doc != null) {
          //[ven] this is a really NASTY hack; when no smart pointer is kept on UsageInfo then remove this conditional
          if (!(element instanceof PsiFile)) {
            LOG.assertTrue(!psiDocumentManager.isUncommited(doc) || ((PsiDocumentManagerImpl)psiDocumentManager).isCommittingDocument(doc));
          }
        }
      }
    }
  }

  public boolean equals(Object obj) {
    if (!(obj instanceof SmartPsiElementPointer)) return false;
    SmartPsiElementPointer pointer = (SmartPsiElementPointer)obj;
    return Comparing.equal(pointer.getElement(), getElement());
  }

  public int hashCode() {
    PsiElement element = getElement();
    return element != null ? element.hashCode() : 0;
  }

  @Nullable
  public E getElement() {
    if (myElement != null && !myElement.isValid()) {
      if (myElementInfo == null) {
        myElement = null;
      }
      else {
        PsiElement restored = myElementInfo.restoreElement();
        if (restored != null && (!areElementKindEqual(restored, myElement) || !restored.isValid())) {
          restored = null;
        }

        myElement = (E) restored;
      }
    }

    if (myElementInfo != null && myElement != null) {
      Document document = myElementInfo.getDocumentToSynchronize();
      if (document != null && PsiDocumentManager.getInstance(myProject).isUncommited(document)) return myElement; // keep element info if document is modified
    }
    // myElementInfo = null;

    return myElement;
  }

  public PsiFile getContainingFile() {
    if (myElement != null) {
      return myElement.getContainingFile();
    }

    final Document doc = myElementInfo.getDocumentToSynchronize();
    if (doc == null) {
      final E resolved = getElement();
      return resolved != null ? resolved.getContainingFile() : null;
    }
    return PsiDocumentManager.getInstance(myProject).getPsiFile(doc);
  }

  @Nullable
  private SmartPointerElementInfo createElementInfo() {
    if (myElement instanceof PsiCompiledElement) return null;

    final PsiFile containingFile = myElement.getContainingFile();
    if (containingFile == null) return null;
    if (!myElement.isPhysical()) return null;

    for(SmartPointerElementInfoFactory factory: Extensions.getExtensions(SmartPointerElementInfoFactory.EP_NAME)) {
      final SmartPointerElementInfo result = factory.createElementInfo(myElement);
      if (result != null) {
        return result;
      }
    }

    return containingFile.getContext() != null ? new InjectedSelfElementInfo(myElement) : new SelfElementInfo(myElement);
  }

  private static boolean areElementKindEqual(PsiElement element1, PsiElement element2) {
    return element1.getClass().equals(element2.getClass()); //?
  }

  public void documentAndPsiInSync() {
    if (myElementInfo != null) {
      myElementInfo.documentAndPsiInSync();
    }
  }

  public void fastenBelt() {
    if (myElementInfo != null && myElement != null && myElement.isValid()) return;

    if (myElementInfo == null && myElement != null && myElement.isValid()) {
      myElementInfo = createElementInfo();
    }
  }

  private static class InjectedSelfElementInfo extends SelfElementInfo {
    private DocumentWindow myDocument;

    InjectedSelfElementInfo(PsiElement anchor) {
      super(anchor);

      assert myFile.getContext() != null;
    }

    protected TextRange getPersistentAnchorRange(final PsiElement anchor, final Document document) {
      final TextRange textRange = super.getPersistentAnchorRange(anchor, document);
      if (!(document instanceof DocumentWindow)) return textRange;
      myDocument = ((DocumentWindow)document);
      return myDocument.injectedToHost(textRange);
    }

    protected int getSyncEndOffset() {
      int syncEndOffset = super.getSyncEndOffset();
      return (myDocument != null ? myDocument.hostToInjected(syncEndOffset):syncEndOffset);
    }

    protected int getSyncStartOffset() {
      int syncStartOffset = super.getSyncStartOffset();
      return (myDocument != null ? myDocument.hostToInjected(syncStartOffset):syncStartOffset);
    }
  }

  private static class SelfElementInfo implements SmartPointerElementInfo {
    protected final PsiFile myFile;
    private final RangeMarker myMarker;
    private int mySyncStartOffset;
    private int mySyncEndOffset;
    private boolean mySyncMarkerIsValid;
    private Class myType;

    public SelfElementInfo(PsiElement anchor) {
      LOG.assertTrue(anchor.isPhysical());
      myFile = anchor.getContainingFile();
      TextRange range = anchor.getTextRange();

      final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(myFile.getProject());
      Document document = documentManager.getDocument(myFile);

      // LOG.assertTrue(!documentManager.isUncommited(document));

      assert document != null : myFile.getName();
{'fraction_non_alphanumeric': 0.09643026378139315, 'fraction_numerical': 0.001105670510187964, 'mean_word_length': 3.9195804195804196, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5110365', 'n_tokens_mistral': 3462, 'n_tokens_neox': 3389, 'n_words': 802}