Exemple #1
0
  @Override
  @SuppressWarnings({"CloneDoesntDeclareCloneNotSupportedException", "CloneDoesntCallSuperClone"})
  protected PsiFileImpl clone() {
    FileViewProvider viewProvider = getViewProvider();
    FileViewProvider providerCopy = viewProvider.clone();
    final Language language = getLanguage();
    if (providerCopy == null) {
      throw new AssertionError(
          "Unable to clone the view provider: " + viewProvider + "; " + language);
    }
    PsiFileImpl clone = BlockSupportImpl.getFileCopy(this, providerCopy);
    copyCopyableDataTo(clone);

    if (getTreeElement() != null) {
      // not set by provider in clone
      final FileElement treeClone = (FileElement) calcTreeElement().clone();
      clone.setTreeElementPointer(
          treeClone); // should not use setTreeElement here because cloned file still have
                      // VirtualFile (SCR17963)
      treeClone.setPsi(clone);
    }

    if (viewProvider.isEventSystemEnabled()) {
      clone.myOriginalFile = this;
    } else if (myOriginalFile != null) {
      clone.myOriginalFile = myOriginalFile;
    }

    return clone;
  }
 @Override
 protected PsiFile getPsiInner(@NotNull final Language target) {
   PsiFileImpl file = myRoots.get(target);
   if (file == null) {
     if (isPhysical()) {
       VirtualFile virtualFile = getVirtualFile();
       if (isIgnored()) return null;
       VirtualFile parent = virtualFile.getParent();
       if (parent != null) {
         getManager().findDirectory(parent);
       }
     }
     if (target != getBaseLanguage() && !getLanguages().contains(target)) {
       return null;
     }
     file = (PsiFileImpl) createFile(target);
     if (file == null) return null;
     if (myOriginal != null) {
       final PsiFile originalFile = myOriginal.getPsi(target);
       if (originalFile != null) {
         file.setOriginalFile(originalFile);
       }
     }
     file = ConcurrencyUtil.cacheOrGet(myRoots, target, file);
   }
   return file;
 }
 @Override
 public void markInvalidated() {
   for (PsiFileImpl file : myRoots.values()) {
     file.markInvalidated();
   }
   super.markInvalidated();
 }
  @NotNull
  public static PsiFileImpl getFileCopy(
      @NotNull PsiFileImpl originalFile, @NotNull FileViewProvider providerCopy) {
    FileViewProvider viewProvider = originalFile.getViewProvider();
    Language language = originalFile.getLanguage();

    PsiFile file = providerCopy.getPsi(language);
    if (file != null && !(file instanceof PsiFileImpl)) {
      throw new RuntimeException(
          "View provider "
              + viewProvider
              + " refused to provide PsiFileImpl for "
              + language
              + details(providerCopy, viewProvider));
    }

    PsiFileImpl newFile = (PsiFileImpl) file;

    if (newFile == null
        && language == PlainTextLanguage.INSTANCE
        && originalFile == viewProvider.getPsi(viewProvider.getBaseLanguage())) {
      newFile = (PsiFileImpl) providerCopy.getPsi(providerCopy.getBaseLanguage());
    }

    if (newFile == null) {
      throw new RuntimeException(
          "View provider "
              + viewProvider
              + " refused to parse text with "
              + language
              + details(providerCopy, viewProvider));
    }

    return newFile;
  }
  public static void doActualPsiChange(@NotNull final PsiFile file, final DiffLog diffLog) {
    file.getViewProvider().beforeContentsSynchronized();

    try {
      final Document document = file.getViewProvider().getDocument();
      PsiDocumentManagerImpl documentManager =
          (PsiDocumentManagerImpl) PsiDocumentManager.getInstance(file.getProject());
      PsiToDocumentSynchronizer.DocumentChangeTransaction transaction =
          documentManager.getSynchronizer().getTransaction(document);

      final PsiFileImpl fileImpl = (PsiFileImpl) file;

      if (transaction == null) {
        final PomModel model = PomManager.getModel(fileImpl.getProject());

        model.runTransaction(
            new PomTransactionBase(fileImpl, model.getModelAspect(TreeAspect.class)) {
              @Override
              public PomModelEvent runInner() {
                return new TreeAspectEvent(model, diffLog.performActualPsiChange(file));
              }
            });
      } else {
        diffLog.performActualPsiChange(file);
      }
    } catch (IncorrectOperationException e) {
      LOG.error(e);
    }
  }
  @NotNull
  public static DiffLog mergeTrees(
      @NotNull final PsiFileImpl fileImpl,
      @NotNull final ASTNode oldRoot,
      @NotNull final ASTNode newRoot,
      @NotNull ProgressIndicator indicator) {
    if (newRoot instanceof FileElement) {
      ((FileElement) newRoot).setCharTable(fileImpl.getTreeElement().getCharTable());
    }

    try {
      newRoot.putUserData(TREE_TO_BE_REPARSED, oldRoot);
      if (isReplaceWholeNode(fileImpl, newRoot)) {
        DiffLog treeChangeEvent =
            replaceElementWithEvents((CompositeElement) oldRoot, (CompositeElement) newRoot);
        fileImpl.putUserData(TREE_DEPTH_LIMIT_EXCEEDED, Boolean.TRUE);

        return treeChangeEvent;
      }
      newRoot
          .getFirstChildNode(); // maybe reparsed in PsiBuilderImpl and have thrown exception here
    } catch (ReparsedSuccessfullyException e) {
      // reparsed in PsiBuilderImpl
      return e.getDiffLog();
    } finally {
      newRoot.putUserData(TREE_TO_BE_REPARSED, null);
    }

    final ASTShallowComparator comparator = new ASTShallowComparator(indicator);
    final ASTStructure treeStructure = createInterruptibleASTStructure(newRoot, indicator);

    DiffLog diffLog = new DiffLog();
    diffTrees(oldRoot, diffLog, comparator, treeStructure, indicator);
    return diffLog;
  }
Exemple #7
0
 protected PsiFileImpl cloneImpl(FileElement treeElementClone) {
   PsiFileImpl clone = (PsiFileImpl) super.clone();
   clone.setTreeElementPointer(
       treeElementClone); // should not use setTreeElement here because cloned file still have
                          // VirtualFile (SCR17963)
   treeElementClone.setPsi(clone);
   return clone;
 }
 @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);
 }
  @NotNull
  private static DiffLog makeFullParse(
      ASTNode parent,
      @NotNull CharSequence newFileText,
      int textLength,
      @NotNull PsiFileImpl fileImpl,
      @NotNull ProgressIndicator indicator) {
    if (fileImpl instanceof PsiCodeFragment) {
      final FileElement holderElement =
          new DummyHolder(fileImpl.getManager(), null).getTreeElement();
      holderElement.rawAddChildren(
          fileImpl.createContentLeafElement(
              holderElement.getCharTable().intern(newFileText, 0, textLength)));
      DiffLog diffLog = new DiffLog();
      diffLog.appendReplaceFileElement(
          (FileElement) parent, (FileElement) holderElement.getFirstChildNode());

      return diffLog;
    } else {
      FileViewProvider viewProvider = fileImpl.getViewProvider();
      viewProvider.getLanguages();
      FileType fileType = viewProvider.getVirtualFile().getFileType();
      String fileName = fileImpl.getName();
      final LightVirtualFile lightFile =
          new LightVirtualFile(
              fileName,
              fileType,
              newFileText,
              viewProvider.getVirtualFile().getCharset(),
              fileImpl.getViewProvider().getModificationStamp());
      lightFile.setOriginalFile(viewProvider.getVirtualFile());

      FileViewProvider copy = viewProvider.createCopy(lightFile);
      if (copy.isEventSystemEnabled()) {
        throw new AssertionError(
            "Copied view provider must be non-physical for reparse to deliver correct events: "
                + viewProvider);
      }
      copy.getLanguages();
      SingleRootFileViewProvider.doNotCheckFileSizeLimit(
          lightFile); // optimization: do not convert file contents to bytes to determine if we
      // should codeinsight it
      PsiFileImpl newFile = getFileCopy(fileImpl, copy);

      newFile.setOriginalFile(fileImpl);

      final FileElement newFileElement = (FileElement) newFile.getNode();
      final FileElement oldFileElement = (FileElement) fileImpl.getNode();

      DiffLog diffLog = mergeTrees(fileImpl, oldFileElement, newFileElement, indicator);

      ((PsiManagerEx) fileImpl.getManager()).getFileManager().setViewProvider(lightFile, null);
      return diffLog;
    }
  }
 @Nullable
 private PsiFileSystemItem doResolve(FileIncludeInfo info, PsiFile context) {
   PsiFileImpl psiFile =
       (PsiFileImpl)
           myPsiFileFactory.createFileFromText("dummy.txt", StdFileTypes.PLAIN_TEXT, info.path);
   psiFile.setOriginalFile(context);
   return new FileReferenceSet(psiFile) {
     @Override
     protected boolean useIncludingFileAsContext() {
       return false;
     }
   }.resolve();
 }
 @Override
 public void contentsSynchronized() {
   super.contentsSynchronized();
   Set<Language> languages = getLanguages();
   for (Iterator<Map.Entry<Language, PsiFileImpl>> iterator = myRoots.entrySet().iterator();
       iterator.hasNext(); ) {
     Map.Entry<Language, PsiFileImpl> entry = iterator.next();
     if (!languages.contains(entry.getKey())) {
       PsiFileImpl file = entry.getValue();
       iterator.remove();
       file.markInvalidated();
     }
   }
 }
  private static CompletionContext createCompletionContext(
      PsiFile hostCopy, int hostStartOffset, OffsetMap hostMap, PsiFile originalFile) {
    CompletionAssertions.assertHostInfo(hostCopy, hostMap);

    InjectedLanguageManager injectedLanguageManager =
        InjectedLanguageManager.getInstance(hostCopy.getProject());
    CompletionContext context;
    PsiFile injected = InjectedLanguageUtil.findInjectedPsiNoCommit(hostCopy, hostStartOffset);
    if (injected != null) {
      if (injected instanceof PsiFileImpl) {
        ((PsiFileImpl) injected).setOriginalFile(originalFile);
      }
      DocumentWindow documentWindow = InjectedLanguageUtil.getDocumentWindow(injected);
      CompletionAssertions.assertInjectedOffsets(
          hostStartOffset, injectedLanguageManager, injected, documentWindow);

      context =
          new CompletionContext(injected, translateOffsetMapToInjected(hostMap, documentWindow));
    } else {
      context = new CompletionContext(hostCopy, hostMap);
    }

    CompletionAssertions.assertFinalOffsets(originalFile, context, injected);

    return context;
  }
  @Override
  @NotNull
  public DiffLog reparseRange(
      @NotNull final PsiFile file,
      @NotNull TextRange changedPsiRange,
      @NotNull final CharSequence newFileText,
      @NotNull final ProgressIndicator indicator) {
    final PsiFileImpl fileImpl = (PsiFileImpl) file;

    final Couple<ASTNode> reparseableRoots =
        findReparseableRoots(fileImpl, changedPsiRange, newFileText);
    return reparseableRoots != null
        ? mergeTrees(fileImpl, reparseableRoots.first, reparseableRoots.second, indicator)
        : makeFullParse(
            fileImpl.getTreeElement(), newFileText, newFileText.length(), fileImpl, indicator);
  }
 private ASTNode notBoundInExistingAst(
     PsiFileImpl file, FileElement treeElement, StubTree stubTree) {
   @NonNls
   String message =
       "this="
           + this.getClass()
           + "; file.isPhysical="
           + file.isPhysical()
           + "; node="
           + myNode
           + "; file="
           + file
           + "; tree="
           + treeElement
           + "; stubTree="
           + stubTree;
   PsiElement each = this;
   while (each != null) {
     message += "\n each of class " + each.getClass();
     if (each instanceof StubBasedPsiElementBase) {
       message +=
           "; node="
               + ((StubBasedPsiElementBase) each).myNode
               + "; stub="
               + ((StubBasedPsiElementBase) each).myStub;
       each = ((StubBasedPsiElementBase) each).getParentByStub();
     } else {
       break;
     }
   }
   throw new AssertionError(message);
 }
  @Override
  @Nullable
  protected PsiFile createFile(@NotNull final Language lang) {
    if (lang == getTemplateDataLanguage()) {

      final PsiFileImpl file =
          (PsiFileImpl)
              LanguageParserDefinitions.INSTANCE.forLanguage(StdLanguages.HTML).createFile(this);
      file.setContentElementType(EmbeddedPerlTokens.HTML_TEMPLATE_DATA);
      return file;
    }

    if (lang == getBaseLanguage()) {
      return LanguageParserDefinitions.INSTANCE.forLanguage(lang).createFile(this);
    }
    return null;
  }
 @Override
 public long getModificationStamp() {
   if (!myFile.isContentsLoaded()) {
     unsetPsiContent();
     return SingleRootFileViewProvider.this.getModificationStamp();
   }
   return myModificationStamp;
 }
  public static int calcStubIndex(@NotNull StubBasedPsiElement psi) {
    if (psi instanceof PsiFile) {
      return 0;
    }

    final StubElement liveStub = psi.getStub();
    if (liveStub != null) {
      return ((StubBase) liveStub).id;
    }

    PsiFileImpl file = (PsiFileImpl) psi.getContainingFile();
    final StubTree stubTree = file.calcStubTree();
    for (StubElement<?> stb : stubTree.getPlainList()) {
      if (stb.getPsi() == psi) {
        return ((StubBase) stb).id;
      }
    }

    return -1; // it is possible via custom stub builder intentionally not producing stubs for
    // stubbed elements
  }
  private static boolean isReplaceWholeNode(@NotNull PsiFileImpl fileImpl, @NotNull ASTNode newRoot)
      throws ReparsedSuccessfullyException {
    final Boolean data = fileImpl.getUserData(DO_NOT_REPARSE_INCREMENTALLY);
    if (data != null) fileImpl.putUserData(DO_NOT_REPARSE_INCREMENTALLY, null);

    boolean explicitlyMarkedDeep = Boolean.TRUE.equals(data);

    if (explicitlyMarkedDeep || isTooDeep(fileImpl)) {
      return true;
    }

    final ASTNode childNode =
        newRoot
            .getFirstChildNode(); // maybe reparsed in PsiBuilderImpl and have thrown exception here
    boolean childTooDeep = isTooDeep(childNode);
    if (childTooDeep) {
      childNode.putUserData(TREE_DEPTH_LIMIT_EXCEEDED, null);
      fileImpl.putUserData(TREE_DEPTH_LIMIT_EXCEEDED, Boolean.TRUE);
    }
    return childTooDeep;
  }
  @Override
  @NotNull
  public ASTNode getNode() {
    ASTNode node = myNode;
    if (node == null) {
      ApplicationManager.getApplication().assertReadAccessAllowed();
      PsiFileImpl file = (PsiFileImpl) getContainingFile();
      synchronized (file.getStubLock()) {
        node = myNode;
        if (node == null) {
          NonCancelableSection criticalSection =
              ProgressIndicatorProvider.startNonCancelableSectionIfSupported();
          try {
            if (!file.isValid()) throw new PsiInvalidElementAccessException(this);
            FileElement treeElement = file.getTreeElement();
            StubTree stubTree = file.getStubTree();
            if (treeElement != null) {
              return notBoundInExistingAst(file, treeElement, stubTree);
            }
            final FileElement fileElement = file.loadTreeElement();
            node = myNode;
            if (node == null) {
              @NonNls
              String message =
                  "Failed to bind stub to AST for element "
                      + getClass()
                      + " in "
                      + (file.getVirtualFile() == null
                          ? "<unknown file>"
                          : file.getVirtualFile().getPath())
                      + "\nFile stub tree:\n"
                      + (stubTree != null
                          ? StringUtil.trimLog(
                              ((PsiFileStubImpl) stubTree.getRoot()).printTree(), 1024)
                          : " is null")
                      + "\nLoaded file AST:\n"
                      + StringUtil.trimLog(DebugUtil.treeToString(fileElement, true), 1024);
              throw new IllegalArgumentException(message);
            }
          } finally {
            criticalSection.done();
          }
        }
      }
    }

    return node;
  }
 @Override
 public CharSequence getText() {
   if (!myFile.isContentsLoaded()) {
     unsetPsiContent();
     return getContents();
   }
   if (myContent != null) return myContent;
   return myContent =
       ApplicationManager.getApplication()
           .runReadAction(
               new Computable<CharSequence>() {
                 public CharSequence compute() {
                   return myFile.calcTreeElement().getText();
                 }
               });
 }
  @Override
  public PsiElement getMirror() {
    TreeElement mirrorTreeElement = myMirrorFileElement;
    if (mirrorTreeElement == null) {
      synchronized (myMirrorLock) {
        mirrorTreeElement = myMirrorFileElement;
        if (mirrorTreeElement == null) {
          VirtualFile file = getVirtualFile();
          PsiClass[] classes = getClasses();
          String fileName =
              (classes.length > 0 ? classes[0].getName() : file.getNameWithoutExtension())
                  + JavaFileType.DOT_DEFAULT_EXTENSION;

          final Document document = FileDocumentManager.getInstance().getDocument(file);
          assert document != null : file.getUrl();

          CharSequence mirrorText = document.getImmutableCharSequence();
          boolean internalDecompiler = StringUtil.startsWith(mirrorText, BANNER);
          PsiFileFactory factory = PsiFileFactory.getInstance(getManager().getProject());
          PsiFile mirror =
              factory.createFileFromText(fileName, JavaLanguage.INSTANCE, mirrorText, false, false);
          mirror.putUserData(PsiUtil.FILE_LANGUAGE_LEVEL_KEY, getLanguageLevel());

          mirrorTreeElement = SourceTreeToPsiMap.psiToTreeNotNull(mirror);
          try {
            final TreeElement finalMirrorTreeElement = mirrorTreeElement;
            ProgressManager.getInstance()
                .executeNonCancelableSection(
                    new Runnable() {
                      @Override
                      public void run() {
                        setMirror(finalMirrorTreeElement);
                        putUserData(CLS_DOCUMENT_LINK_KEY, document);
                      }
                    });
          } catch (InvalidMirrorException e) {
            //noinspection ThrowableResultOfMethodCallIgnored
            LOG.error(file.getUrl(), internalDecompiler ? e : wrapException(e, file));
          }

          ((PsiFileImpl) mirror).setOriginalFile(this);
          myMirrorFileElement = mirrorTreeElement;
        }
      }
    }
    return mirrorTreeElement.getPsi();
  }
 protected PsiFile getPsiInner(final Language target) {
   PsiFile file = myRoots.get(target);
   if (file == null) {
     if (isPhysical()) {
       VirtualFile virtualFile = getVirtualFile();
       VirtualFile parent = virtualFile.getParent();
       if (parent != null) {
         getManager().findDirectory(parent);
       }
     }
     file = createFile(target);
     if (file == null) return null;
     if (myOriginal != null) {
       final PsiFile originalFile = myOriginal.getPsi(target);
       if (originalFile != null) {
         ((PsiFileImpl) file).setOriginalFile(originalFile);
       }
     }
     file = ConcurrencyUtil.cacheOrGet(myRoots, target, file);
   }
   return file;
 }
Exemple #23
0
 @Override
 public void putInfo(@NotNull Map<String, String> info) {
   PsiFileImpl.putInfo(this, info);
 }
 protected void removeFile(final Language language) {
   PsiFileImpl file = myRoots.remove(language);
   if (file != null) {
     file.markInvalidated();
   }
 }
 public void beforeDocumentChanged() {
   final PsiFileImpl psiFile = (PsiFileImpl) getCachedPsi(getBaseLanguage());
   if (psiFile != null && psiFile.isContentsLoaded() && getContent() instanceof DocumentContent) {
     setContent(new PsiFileContent(psiFile, getModificationStamp()));
   }
 }
  /**
   * This method searches ast node that could be reparsed incrementally and returns pair of target
   * reparseable node and new replacement node. Returns null if there is no any chance to make
   * incremental parsing.
   */
  @Nullable
  public Couple<ASTNode> findReparseableRoots(
      @NotNull PsiFileImpl file,
      @NotNull TextRange changedPsiRange,
      @NotNull CharSequence newFileText) {
    Project project = file.getProject();
    final FileElement fileElement = file.getTreeElement();
    final CharTable charTable = fileElement.getCharTable();
    int lengthShift = newFileText.length() - fileElement.getTextLength();

    if (fileElement.getElementType() instanceof ITemplateDataElementType || isTooDeep(file)) {
      // unable to perform incremental reparse for template data in JSP, or in exceptionally deep
      // trees
      return null;
    }

    final ASTNode leafAtStart =
        fileElement.findLeafElementAt(Math.max(0, changedPsiRange.getStartOffset() - 1));
    final ASTNode leafAtEnd =
        fileElement.findLeafElementAt(
            Math.min(changedPsiRange.getEndOffset(), fileElement.getTextLength() - 1));
    ASTNode node =
        leafAtStart != null && leafAtEnd != null
            ? TreeUtil.findCommonParent(leafAtStart, leafAtEnd)
            : fileElement;
    Language baseLanguage = file.getViewProvider().getBaseLanguage();

    while (node != null && !(node instanceof FileElement)) {
      IElementType elementType = node.getElementType();
      if (elementType instanceof IReparseableElementType) {
        final TextRange textRange = node.getTextRange();
        final IReparseableElementType reparseable = (IReparseableElementType) elementType;

        if (baseLanguage.isKindOf(reparseable.getLanguage())
            && textRange.getLength() + lengthShift > 0) {
          final int start = textRange.getStartOffset();
          final int end = start + textRange.getLength() + lengthShift;
          if (end > newFileText.length()) {
            reportInconsistentLength(file, newFileText, node, start, end);
            break;
          }

          CharSequence newTextStr = newFileText.subSequence(start, end);

          if (reparseable.isParsable(node.getTreeParent(), newTextStr, baseLanguage, project)) {
            ASTNode chameleon = reparseable.createNode(newTextStr);
            if (chameleon != null) {
              DummyHolder holder =
                  DummyHolderFactory.createHolder(
                      file.getManager(), null, node.getPsi(), charTable);
              holder.getTreeElement().rawAddChildren((TreeElement) chameleon);

              if (holder.getTextLength() != newTextStr.length()) {
                String details =
                    ApplicationManager.getApplication().isInternal()
                        ? "text=" + newTextStr + "; treeText=" + holder.getText() + ";"
                        : "";
                LOG.error("Inconsistent reparse: " + details + " type=" + elementType);
              }

              return Couple.of(node, chameleon);
            }
          }
        }
      }
      node = node.getTreeParent();
    }
    return null;
  }