Пример #1
0
 private void clearStub(@NotNull String reason) {
   StubTree stubHolder = SoftReference.dereference(myStub);
   if (stubHolder != null) {
     ((PsiFileStubImpl<?>) stubHolder.getRoot()).clearPsi(reason);
   }
   myStub = null;
 }
 @Override
 protected String stubTreeAndIndexDoNotMatch(
     StubTree stubTree,
     PsiFileWithStubSupport psiFile,
     List<StubElement<?>> plained,
     VirtualFile virtualFile,
     StubTree stubTreeFromIndex) {
   String details = "Please report the problem to JetBrains with the file attached";
   details += "\npsiFile" + psiFile;
   details += "\npsiFile.class" + psiFile.getClass();
   details += "\npsiFile.lang" + psiFile.getLanguage();
   String fileText = psiFile instanceof PsiCompiledElement ? "compiled" : psiFile.getText();
   return LogMessageEx.createEvent(
           "PSI and index do not match",
           details,
           new Attachment(
               virtualFile != null ? virtualFile.getPath() + "_file.txt" : "vFile.txt", fileText),
           new Attachment("stubTree.txt", ((PsiFileStubImpl) stubTree.getRoot()).printTree()),
           new Attachment(
               "stubTreeFromIndex.txt",
               stubTreeFromIndex == null
                   ? "null"
                   : ((PsiFileStubImpl) stubTreeFromIndex.getRoot()).printTree()))
       .toString();
 }
Пример #3
0
  @Override
  @NotNull
  public StubTree getStubTree() {
    ApplicationManager.getApplication().assertReadAccessAllowed();

    StubTree stubTree = dereference(myStub);
    if (stubTree != null) return stubTree;

    // build newStub out of lock to avoid deadlock
    StubTree newStubTree =
        (StubTree) StubTreeLoader.getInstance().readOrBuild(getProject(), getVirtualFile(), this);
    if (newStubTree == null) {
      if (LOG.isDebugEnabled()) {
        LOG.debug("No stub for class file in index: " + getVirtualFile().getPresentableUrl());
      }
      newStubTree = new StubTree(new PsiJavaFileStubImpl("corrupted.classfiles", true));
    }

    synchronized (myStubLock) {
      stubTree = dereference(myStub);
      if (stubTree != null) return stubTree;

      stubTree = newStubTree;

      @SuppressWarnings("unchecked")
      PsiFileStubImpl<PsiFile> fileStub = (PsiFileStubImpl) stubTree.getRoot();
      fileStub.setPsi(this);

      myStub = new SoftReference<StubTree>(stubTree);
    }

    return stubTree;
  }
  @Override
  @Nullable
  public ObjectStubTree readOrBuild(
      Project project, final VirtualFile vFile, @Nullable PsiFile psiFile) {
    final ObjectStubTree fromIndices = readFromVFile(project, vFile);
    if (fromIndices != null) {
      return fromIndices;
    }

    try {
      final FileContent fc = new FileContentImpl(vFile, vFile.contentsToByteArray());
      fc.putUserData(IndexingDataKeys.PROJECT, project);
      if (psiFile != null && !vFile.getFileType().isBinary()) {
        fc.putUserData(
            IndexingDataKeys.FILE_TEXT_CONTENT_KEY, psiFile.getViewProvider().getContents());
        // but don't reuse psiFile itself to avoid loading its contents. If we load AST, the stub
        // will be thrown out anyway.
      }
      Stub element = StubTreeBuilder.buildStubTree(fc);
      if (element instanceof PsiFileStub) {
        StubTree tree = new StubTree((PsiFileStub) element);
        tree.setDebugInfo("created from file content");
        return tree;
      }
    } catch (IOException e) {
      LOG.info(
          e); // content can be not cached yet, and the file can be deleted on disk already, without
              // refresh
    }

    return null;
  }
Пример #5
0
  public StubTree calcStubTree() {
    FileElement fileElement = calcTreeElement();
    synchronized (myStubFromTreeLock) {
      SoftReference<StubTree> ref = fileElement.getUserData(STUB_TREE_IN_PARSED_TREE);
      StubTree tree = SoftReference.dereference(ref);

      if (tree == null) {
        ApplicationManager.getApplication().assertReadAccessAllowed();
        IElementType contentElementType = getContentElementType();
        if (!(contentElementType instanceof IStubFileElementType)) {
          VirtualFile vFile = getVirtualFile();
          String message =
              "ContentElementType: "
                  + contentElementType
                  + "; file: "
                  + this
                  + "\n\t"
                  + "Boolean.TRUE.equals(getUserData(BUILDING_STUB)) = "
                  + Boolean.TRUE.equals(getUserData(BUILDING_STUB))
                  + "\n\t"
                  + "getTreeElement() = "
                  + getTreeElement()
                  + "\n\t"
                  + "vFile instanceof VirtualFileWithId = "
                  + (vFile instanceof VirtualFileWithId)
                  + "\n\t"
                  + "StubUpdatingIndex.canHaveStub(vFile) = "
                  + StubTreeLoader.getInstance().canHaveStub(vFile);
          rebuildStub();
          throw new AssertionError(message);
        }

        StubElement currentStubTree =
            ((IStubFileElementType) contentElementType).getBuilder().buildStubTree(this);
        if (currentStubTree == null) {
          throw new AssertionError(
              "Stub tree wasn't built for " + contentElementType + "; file: " + this);
        }

        tree = new StubTree((PsiFileStub) currentStubTree);
        tree.setDebugInfo("created in calcStubTree");
        try {
          TreeUtil.bindStubsToTree(this, tree);
        } catch (TreeUtil.StubBindingException e) {
          rebuildStub();
          throw new RuntimeException("Stub and PSI element type mismatch in " + getName(), e);
        }

        fileElement.putUserData(STUB_TREE_IN_PARSED_TREE, new SoftReference<StubTree>(tree));
      }

      return tree;
    }
  }
  @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
  @Nullable
  public ObjectStubTree readOrBuild(
      Project project, final VirtualFile vFile, @Nullable PsiFile psiFile) {
    final ObjectStubTree fromIndices = readFromVFile(project, vFile);
    if (fromIndices != null) {
      return fromIndices;
    }

    if (!canHaveStub(vFile)) {
      return null;
    }

    try {
      final FileContent fc = new FileContentImpl(vFile, vFile.contentsToByteArray());
      fc.putUserData(IndexingDataKeys.PROJECT, project);
      if (psiFile != null) {
        fc.putUserData(IndexingDataKeys.PSI_FILE, psiFile);
        if (!vFile.getFileType().isBinary()) {
          fc.putUserData(
              IndexingDataKeys.FILE_TEXT_CONTENT_KEY, psiFile.getViewProvider().getContents());
        }
        psiFile.putUserData(PsiFileImpl.BUILDING_STUB, true);
      }
      Stub element;
      try {
        element = StubTreeBuilder.buildStubTree(fc);
      } finally {
        if (psiFile != null) {
          psiFile.putUserData(PsiFileImpl.BUILDING_STUB, null);
        }
      }
      if (element instanceof PsiFileStub) {
        StubTree tree = new StubTree((PsiFileStub) element);
        tree.setDebugInfo("created from file content, timestamp=" + vFile.getTimeStamp());
        return tree;
      }
    } catch (IOException e) {
      LOG.info(
          e); // content can be not cached yet, and the file can be deleted on disk already, without
      // refresh
    }

    return null;
  }
Пример #8
0
  @Override
  public ASTNode findTreeForStub(StubTree tree, StubElement<?> stub) {
    final Iterator<StubElement<?>> stubs = tree.getPlainList().iterator();
    final StubElement<?> root = stubs.next();
    final CompositeElement ast = calcTreeElement();
    if (root == stub) return ast;

    return findTreeForStub(ast, stubs, stub);
  }
Пример #9
0
  @Override
  @Nullable
  public StubTree getStubTree() {
    ApplicationManager.getApplication().assertReadAccessAllowed();

    if (Boolean.TRUE.equals(getUserData(BUILDING_STUB))) return null;

    final StubTree derefd = derefStub();
    if (derefd != null) return derefd;
    if (getTreeElement() != null) return null;

    if (!(getContentElementType() instanceof IStubFileElementType)) return null;

    final VirtualFile vFile = getVirtualFile();
    if (!(vFile instanceof VirtualFileWithId)) return null;

    final PsiFile stubBindingRoot = getViewProvider().getStubBindingRoot();
    if (stubBindingRoot != this) {
      LOG.error(
          "Attempted to create stubs for non-root file: "
              + this
              + ", stub binding root: "
              + stubBindingRoot);
      return null;
    }

    ObjectStubTree tree = StubTreeLoader.getInstance().readOrBuild(getProject(), vFile, this);
    if (!(tree instanceof StubTree)) return null;
    StubTree stubHolder = (StubTree) tree;

    synchronized (PsiLock.LOCK) {
      if (getTreeElement() != null) return null;

      final StubTree derefdOnLock = derefStub();
      if (derefdOnLock != null) return derefdOnLock;

      //noinspection unchecked
      ((StubBase) stubHolder.getRoot()).setPsi(this);
      myStub = new SoftReference<StubTree>(stubHolder);
      return stubHolder;
    }
  }
Пример #10
0
  protected void reportStubAstMismatch(String message, StubTree stubTree, Document cachedDocument) {
    rebuildStub();
    clearStub("stub-psi mismatch");
    scheduleDropCachesWithInvalidStubPsi();

    String msg = message;
    msg += "\n file=" + this;
    msg += ", modStamp=" + getModificationStamp();
    msg += "\n stub debugInfo=" + stubTree.getDebugInfo();
    msg += "\n document before=" + cachedDocument;

    ObjectStubTree latestIndexedStub =
        StubTreeLoader.getInstance().readFromVFile(getProject(), getVirtualFile());
    msg += "\nlatestIndexedStub=" + latestIndexedStub;
    if (latestIndexedStub != null) {
      msg +=
          "\n   same size="
              + (stubTree.getPlainList().size() == latestIndexedStub.getPlainList().size());
      msg += "\n   debugInfo=" + latestIndexedStub.getDebugInfo();
    }

    FileViewProvider viewProvider = getViewProvider();
    msg += "\n viewProvider=" + viewProvider;
    msg += "\n viewProvider stamp: " + viewProvider.getModificationStamp();

    VirtualFile file = viewProvider.getVirtualFile();
    msg += "; file stamp: " + file.getModificationStamp();
    msg += "; file modCount: " + file.getModificationCount();

    Document document = FileDocumentManager.getInstance().getCachedDocument(file);
    if (document != null) {
      msg += "\n doc saved: " + !FileDocumentManager.getInstance().isDocumentUnsaved(document);
      msg += "; doc stamp: " + document.getModificationStamp();
      msg += "; doc size: " + document.getTextLength();
      msg += "; committed: " + PsiDocumentManager.getInstance(getProject()).isCommitted(document);
    }

    throw new AssertionError(msg + "\n------------\n");
  }
Пример #11
0
  @Override
  public void onContentReload() {
    ApplicationManager.getApplication().assertWriteAccessAllowed();

    synchronized (myStubLock) {
      StubTree stubTree = dereference(myStub);
      myStub = null;
      if (stubTree != null) {
        //noinspection unchecked
        ((PsiFileStubImpl) stubTree.getRoot()).clearPsi("cls onContentReload");
      }
    }

    ClsPackageStatementImpl packageStatement = new ClsPackageStatementImpl(this);
    synchronized (myMirrorLock) {
      putUserData(CLS_DOCUMENT_LINK_KEY, null);
      myMirrorFileElement = null;
      myPackageStatement = packageStatement;
    }

    myLanguageLevel = null;
  }
Пример #12
0
 @Nullable
 public StubElement getStub() {
   StubTree stubHolder = getStubTree();
   return stubHolder != null ? stubHolder.getRoot() : null;
 }
Пример #13
0
  private List<Pair<StubBasedPsiElementBase, CompositeElement>> calcStubAstBindings(
      final ASTNode root, final Document cachedDocument) {
    final StubTree stubTree = derefStub();
    if (stubTree == null) {
      return Collections.emptyList();
    }

    final Iterator<StubElement<?>> stubs = stubTree.getPlainList().iterator();
    stubs.next(); // Skip file stub;
    final List<Pair<StubBasedPsiElementBase, CompositeElement>> result =
        ContainerUtil.newArrayList();
    final StubBuilder builder = ((IStubFileElementType) getContentElementType()).getBuilder();

    LazyParseableElement.setSuppressEagerPsiCreation(true);
    try {
      ((TreeElement) root)
          .acceptTree(
              new RecursiveTreeElementWalkingVisitor() {
                @Override
                protected void visitNode(TreeElement node) {
                  CompositeElement parent = node.getTreeParent();
                  if (parent != null
                      && builder.skipChildProcessingWhenBuildingStubs(parent, node)) {
                    return;
                  }

                  IElementType type = node.getElementType();
                  if (type instanceof IStubElementType
                      && ((IStubElementType) type).shouldCreateStub(node)) {
                    if (!stubs.hasNext()) {
                      reportStubAstMismatch(
                          "Stub list is less than AST, last AST element: "
                              + node.getElementType()
                              + " "
                              + node,
                          stubTree,
                          cachedDocument);
                    }

                    final StubElement stub = stubs.next();
                    if (stub.getStubType() != node.getElementType()) {
                      reportStubAstMismatch(
                          "Stub and PSI element type mismatch in "
                              + getName()
                              + ": stub "
                              + stub
                              + ", AST "
                              + node.getElementType()
                              + "; "
                              + node,
                          stubTree,
                          cachedDocument);
                    }

                    PsiElement psi = stub.getPsi();
                    assert psi != null
                        : "Stub " + stub + " (" + stub.getClass() + ") has returned null PSI";
                    result.add(Pair.create((StubBasedPsiElementBase) psi, (CompositeElement) node));
                  }

                  super.visitNode(node);
                }
              });
    } finally {
      LazyParseableElement.setSuppressEagerPsiCreation(false);
    }
    if (stubs.hasNext()) {
      reportStubAstMismatch(
          "Stub list in " + getName() + " has more elements than PSI", stubTree, cachedDocument);
    }
    return result;
  }