@Override @Nullable public SmartPointerElementInfo createElementInfo(@NotNull PsiElement element, @NotNull PsiFile containingFile) { if (element instanceof StubBasedPsiElement && containingFile instanceof PsiFileWithStubSupport) { PsiFileWithStubSupport stubFile = (PsiFileWithStubSupport)containingFile; StubTree stubTree = stubFile.getStubTree(); if (stubTree != null) { // use stubs when tree is not loaded StubBasedPsiElement stubPsi = (StubBasedPsiElement)element; int stubId = PsiAnchor.calcStubIndex(stubPsi); IStubElementType myStubElementType = stubPsi.getElementType(); IElementType contentElementType = ((PsiFileImpl)containingFile).getContentElementType(); if (stubId != -1 && contentElementType instanceof IStubFileElementType) { // TemplateDataElementType is not IStubFileElementType return new AnchorElementInfo(element, stubFile, stubId, myStubElementType); } } } PsiElement anchor = getAnchor(element); if (anchor != null) { return new AnchorElementInfo(anchor, containingFile); } return null; }
@Override protected Object stubTreeAndIndexDoNotMatch(@NotNull ObjectStubTree stubTree, PsiFileWithStubSupport psiFile) { final VirtualFile virtualFile = psiFile.getVirtualFile(); StubTree stubTreeFromIndex = (StubTree)StubTreeLoader.getInstance().readFromVFile(psiFile.getProject(), virtualFile); String details = "Please report the problem to JetBrains with the file attached"; details += StubTreeLoader.getInstance().getStubAstMismatchDiagnostics(virtualFile, psiFile, stubTree, null); details += "\n" + DebugUtil.currentStackTrace(); String fileText = psiFile instanceof PsiCompiledElement ? "compiled" : psiFile.getText(); return LogMessageEx.createEvent("PSI and index do not match", details, new Attachment(virtualFile.getPath() + "_file.txt", fileText), new Attachment("stubTree.txt", ((PsiFileStubImpl)stubTree.getRoot()).printTree()), new Attachment("stubTreeFromIndex.txt", stubTreeFromIndex == null ? "null" : ((PsiFileStubImpl)stubTreeFromIndex.getRoot()).printTree())); }
@Override @Nullable public SmartPointerElementInfo createElementInfo(@NotNull PsiElement element) { PsiFile containingFile = element.getContainingFile(); if (element instanceof StubBasedPsiElement && containingFile instanceof PsiFileWithStubSupport) { PsiFileWithStubSupport stubFile = (PsiFileWithStubSupport)containingFile; StubTree stubTree = stubFile.getStubTree(); if (stubTree != null) { // use stubs when tree is not loaded StubBasedPsiElement stubPsi = (StubBasedPsiElement)element; int stubId = PsiAnchor.calcStubIndex(stubPsi); IStubElementType myStubElementType = stubPsi.getElementType(); if (stubId != -1) { return new AnchorElementInfo(element, stubFile, stubId, myStubElementType); } } } PsiElement anchor = getAnchor(element); if (anchor != null) { return new AnchorElementInfo(anchor, containingFile); } return null; }
public String diagnoseNull() { try { PsiElement element = ApplicationManager.getApplication().runReadAction(new NullableComputable<PsiElement>() { @Override public PsiElement compute() { return restoreFromStubIndex((PsiFileWithStubSupport)getFile(), myIndex, myElementType, true); } }); return "No diagnostics, element=" + element + "@" + (element == null ? 0 : System.identityHashCode(element)); } catch (AssertionError e) { return e.getMessage() + "; current modCount=" + PsiManager.getInstance(getProject()).getModificationTracker().getModificationCount() + "; creation modCount=" + myCreationModCount; } }
@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(); return LogMessageEx.createEvent("PSI and index do not match", details, new Attachment(virtualFile != null ? virtualFile.getPath() + "_file.txt" : "vFile.txt", psiFile.getText()), new Attachment("stubTree.txt", ((PsiFileStubImpl)stubTree.getRoot()).printTree()), new Attachment("stubTreeFromIndex.txt", stubTreeFromIndex == null ? "null" : ((PsiFileStubImpl)stubTreeFromIndex.getRoot()).printTree())).toString(); }
public String diagnoseNull() { final PsiFile file = ApplicationManager.getApplication().runReadAction((Computable<PsiFile>)() -> getFile()); try { PsiElement element = ApplicationManager.getApplication().runReadAction( (NullableComputable<PsiElement>)() -> restoreFromStubIndex((PsiFileWithStubSupport)file, myIndex, myElementType, true)); return "No diagnostics, element=" + element + "@" + (element == null ? 0 : System.identityHashCode(element)); } catch (AssertionError e) { String msg = e.getMessage(); msg += file == null ? "\n no PSI file" : "\n current file stamp=" + (short)file.getModificationStamp(); final Document document = FileDocumentManager.getInstance().getCachedDocument(myVirtualFile); if (document != null) { msg += "\n committed=" + PsiDocumentManager.getInstance(myProject).isCommitted(document); msg += "\n saved=" + !FileDocumentManager.getInstance().isDocumentUnsaved(document); } return msg; } }
private static StubTree getOrCalcStubTree(PsiFile stubBindingRoot) { StubTree result = null; if (stubBindingRoot instanceof PsiFileWithStubSupport) { result = ((PsiFileWithStubSupport)stubBindingRoot).getStubTree(); if (result == null && stubBindingRoot instanceof PsiFileImpl) { result = ((PsiFileImpl)stubBindingRoot).calcStubTree(); } } return result; }
AnchorElementInfo(@NotNull PsiElement anchor, @NotNull PsiFileWithStubSupport containingFile, int stubId, @NotNull IStubElementType stubElementType) { super(containingFile.getProject(), new ProperTextRange(0, 0), anchor.getClass(), containingFile, containingFile.getLanguage(), false); myStubElementTypeAndId = pack(stubId, stubElementType); assert !(anchor instanceof PsiFile) : "FileElementInfo must be used for file: "+anchor; }
@Override public PsiElement retrieve() { return ApplicationManager.getApplication().runReadAction(new NullableComputable<PsiElement>() { @Override public PsiElement compute() { return restoreFromStubIndex((PsiFileWithStubSupport)getFile(), myIndex, myElementType, false); } }); }
public String diagnoseNull() { final PsiFile file = ApplicationManager.getApplication().runReadAction(new Computable<PsiFile>() { @Override public PsiFile compute() { return getFile(); } }); try { PsiElement element = ApplicationManager.getApplication().runReadAction(new NullableComputable<PsiElement>() { @Override public PsiElement compute() { return restoreFromStubIndex((PsiFileWithStubSupport)file, myIndex, myElementType, true); } }); return "No diagnostics, element=" + element + "@" + (element == null ? 0 : System.identityHashCode(element)); } catch (AssertionError e) { String msg = e.getMessage(); if (file == null) { msg += "\n no PSI file"; } else { msg += "\n current file stamp=" + (short)file.getModificationStamp(); } final Document document = FileDocumentManager.getInstance().getCachedDocument(myVirtualFile); if (document != null) { msg += "\n committed=" + PsiDocumentManager.getInstance(myProject).isCommitted(document); msg += "\n saved=" + !FileDocumentManager.getInstance().isDocumentUnsaved(document); } return msg; } }
AnchorElementInfo(@NotNull PsiElement anchor, @NotNull PsiFileWithStubSupport containingFile, int stubId, @NotNull IStubElementType stubElementType) { super(containingFile.getProject(), new ProperTextRange(0,0), anchor.getClass(), containingFile, containingFile.getLanguage()); this.stubId = stubId; myStubElementType = stubElementType; IElementType contentElementType = ((PsiFileImpl)containingFile).getContentElementType(); assert contentElementType instanceof IStubFileElementType : contentElementType; assert !(anchor instanceof PsiFile) : "FileElementInfo must be used for file: "+anchor; }
@Nonnull private static Attachment[] createAttachments(@Nonnull ObjectStubTree stubTree, @Nonnull PsiFileWithStubSupport psiFile, VirtualFile file, @Nullable StubTree stubTreeFromIndex) { List<Attachment> attachments = ContainerUtil.newArrayList(); attachments.add(new Attachment(file.getPath() + "_file.txt", psiFile instanceof PsiCompiledElement ? "compiled" : psiFile.getText())); attachments.add(new Attachment("stubTree.txt", ((PsiFileStubImpl)stubTree.getRoot()).printTree())); if (stubTreeFromIndex != null) { attachments.add(new Attachment("stubTreeFromIndex.txt", ((PsiFileStubImpl)stubTreeFromIndex.getRoot()).printTree())); } return attachments.toArray(Attachment.EMPTY_ARRAY); }
AnchorElementInfo(@Nonnull PsiElement anchor, @Nonnull PsiFileWithStubSupport containingFile, int stubId, @Nonnull IStubElementType stubElementType) { super(containingFile.getProject(), null, Identikit.fromTypes(anchor.getClass(), stubElementType, LanguageUtil.getRootLanguage(containingFile)), containingFile, false); myStubElementTypeAndId = pack(stubId, stubElementType); assert !(anchor instanceof PsiFile) : "FileElementInfo must be used for file: "+anchor; }
@Override @Nullable public PsiElement restoreElement() { long typeAndId = myStubElementTypeAndId; int stubId = (int)typeAndId; if (stubId != -1) { PsiFile file = restoreFile(); if (!(file instanceof PsiFileWithStubSupport)) return null; short index = (short)(typeAndId >> 32); IStubElementType stubElementType = (IStubElementType)IElementType.find(index); return PsiAnchor.restoreFromStubIndex((PsiFileWithStubSupport)file, stubId, stubElementType, false); } return super.restoreElement(); }
@Nullable public static PsiElement restoreFromStubIndex(PsiFileWithStubSupport fileImpl, int index, @Nonnull IStubElementType elementType, boolean throwIfNull) { if (fileImpl == null) { if (throwIfNull) throw new AssertionError("Null file"); return null; } StubTree tree = fileImpl.getStubTree(); if (tree == null) { if (fileImpl instanceof PsiFileImpl) { // Note: as far as this is a realization of StubIndexReference fileImpl#getContentElementType() must be instance of IStubFileElementType tree = ((PsiFileImpl)fileImpl).calcStubTree(); } else { if (throwIfNull) throw new AssertionError("Not PsiFileImpl: " + fileImpl.getClass()); return null; } } List<StubElement<?>> list = tree.getPlainList(); if (index >= list.size()) { if (throwIfNull) throw new AssertionError("Too large index: " + index + ">=" + list.size()); return null; } StubElement stub = list.get(index); if (stub.getStubType() != elementType) { if (throwIfNull) throw new AssertionError("Element type mismatch: " + stub.getStubType() + "!=" + elementType); return null; } return stub.getPsi(); }
@Override @Nullable public PsiFile getFile() { if (myProject.isDisposed() || !myVirtualFile.isValid()) { return null; } FileViewProvider viewProvider = PsiManager.getInstance(myProject).findViewProvider(myVirtualFile); PsiFile file = viewProvider == null ? null : viewProvider.getPsi(myLanguage); return file instanceof PsiFileWithStubSupport ? file : null; }
private void inconsistencyDetected(@NotNull ObjectStubTree stubTree, PsiFileWithStubSupport psiFile) { LOG.error(stubTreeAndIndexDoNotMatch(stubTree, psiFile)); onInternalError(psiFile.getVirtualFile()); }
@Nullable public static PsiElement restoreFromStubIndex(PsiFileWithStubSupport fileImpl, int index, @NotNull IStubElementType elementType, boolean throwIfNull) { if (fileImpl == null) { if (throwIfNull) throw new AssertionError("Null file"); return null; } StubTree tree = fileImpl.getStubTree(); boolean foreign = tree == null; if (foreign) { if (fileImpl instanceof PsiFileImpl) { // Note: as far as this is a realization of StubIndexReference fileImpl#getContentElementType() must be instance of IStubFileElementType tree = ((PsiFileImpl)fileImpl).calcStubTree(); } else { if (throwIfNull) throw new AssertionError("Not PsiFileImpl: " + fileImpl.getClass()); return null; } } List<StubElement<?>> list = tree.getPlainList(); if (index >= list.size()) { if (throwIfNull) throw new AssertionError("Too large index: " + index + ">=" + list.size()); return null; } StubElement stub = list.get(index); if (stub.getStubType() != elementType) { if (throwIfNull) throw new AssertionError("Element type mismatch: " + stub.getStubType() + "!=" + elementType); return null; } if (foreign) { final PsiElement cachedPsi = ((StubBase)stub).getCachedPsi(); if (cachedPsi != null) return cachedPsi; final ASTNode ast = fileImpl.findTreeForStub(tree, stub); if (ast != null) { return ast.getPsi(); } if (throwIfNull) throw new AssertionError("No AST for stub"); return null; } return stub.getPsi(); }
@Override protected <Psi extends PsiElement> void reportStubPsiMismatch(Psi psi, VirtualFile file, Class<Psi> requiredClass) { if (file == null) { super.reportStubPsiMismatch(psi, file, requiredClass); return; } StringWriter writer = new StringWriter(); //noinspection IOResourceOpenedButNotSafelyClosed PrintWriter out = new PrintWriter(writer); out.print("Invalid stub element type in index:"); out.printf("\nfile: %s\npsiElement: %s\nrequiredClass: %s\nactualClass: %s", file, psi, requiredClass, psi.getClass()); FileType fileType = file.getFileType(); Language language = fileType instanceof LanguageFileType ? LanguageSubstitutors.INSTANCE.substituteLanguage(((LanguageFileType)fileType).getLanguage(), file, psi.getProject()) : Language.ANY; out.printf("\nvirtualFile: size:%s; stamp:%s; modCount:%s; fileType:%s; language:%s", file.getLength(), file.getModificationStamp(), file.getModificationCount(), fileType.getName(), language.getID()); Document document = FileDocumentManager.getInstance().getCachedDocument(file); if (document != null) { boolean committed = PsiDocumentManager.getInstance(psi.getProject()).isCommitted(document); boolean saved = !FileDocumentManager.getInstance().isDocumentUnsaved(document); out.printf("\ndocument: size:%s; stamp:%s; committed:%s; saved:%s", document.getTextLength(), document.getModificationStamp(), committed, saved); } PsiFile psiFile = psi.getManager().findFile(file); if (psiFile != null) { out.printf("\npsiFile: size:%s; stamp:%s; class:%s; language:%s", psiFile.getTextLength(), psiFile.getViewProvider().getModificationStamp(), psiFile.getClass().getName(), psiFile.getLanguage().getID()); } StubTree stub = psiFile instanceof PsiFileWithStubSupport ? ((PsiFileWithStubSupport)psiFile).getStubTree() : null; FileElement treeElement = stub == null && psiFile instanceof PsiFileImpl? ((PsiFileImpl)psiFile).getTreeElement() : null; if (stub != null) { out.printf("\nstubInfo: " + stub.getDebugInfo()); } else if (treeElement != null) { out.printf("\nfileAST: size:%s; parsed:%s", treeElement.getTextLength(), treeElement.isParsed()); } out.printf("\nindexing info: " + StubUpdatingIndex.getIndexingStampInfo(file)); LOG.error(writer.toString()); }
/*** * Returns a message to log when stub tree and index do not match */ protected abstract String stubTreeAndIndexDoNotMatch(StubTree stubTree, PsiFileWithStubSupport psiFile, List<StubElement<?>> plained, VirtualFile virtualFile, StubTree stubTreeFromIndex);
private void inconsistencyDetected(@Nonnull ObjectStubTree stubTree, @Nonnull PsiFileWithStubSupport psiFile) { LOG.error(StubTreeLoader.getInstance().stubTreeAndIndexDoNotMatch("PSI and index do not match.", stubTree, psiFile)); onInternalError(psiFile.getVirtualFile()); }
@Nonnull public RuntimeException stubTreeAndIndexDoNotMatch(@Nonnull String _message, @Nonnull ObjectStubTree stubTree, @Nonnull PsiFileWithStubSupport psiFile) { VirtualFile file = psiFile.getViewProvider().getVirtualFile(); StubTree stubTreeFromIndex = (StubTree)readFromVFile(psiFile.getProject(), file); Document document = FileDocumentManager.getInstance().getDocument(file); IndexingStampInfo indexingStampInfo = getIndexingStampInfo(file); boolean upToDate = indexingStampInfo != null && indexingStampInfo.isUpToDate(document, file, psiFile); String msg = _message + "\nPlease report the problem to 'consulo.io' with the files attached\n"; if (upToDate) { msg += "INDEXED VERSION IS THE CURRENT ONE"; } msg += " file=" + psiFile; msg += ", file.class=" + psiFile.getClass(); msg += ", file.lang=" + psiFile.getLanguage(); msg += ", modStamp=" + psiFile.getModificationStamp(); if (!(psiFile instanceof PsiCompiledElement)) { String text = psiFile.getText(); PsiFile fromText = PsiFileFactory.getInstance(psiFile.getProject()).createFileFromText(psiFile.getName(), psiFile.getFileType(), text); if (fromText.getLanguage().equals(psiFile.getLanguage())) { boolean consistent = DebugUtil.psiToString(psiFile, true).equals(DebugUtil.psiToString(fromText, true)); if (consistent) { msg += "\n tree consistent"; } else { msg += "\n AST INCONSISTENT, perhaps after incremental reparse; " + fromText; } } } msg += "\n stub debugInfo=" + stubTree.getDebugInfo(); msg += "\nlatestIndexedStub=" + stubTreeFromIndex; if (stubTreeFromIndex != null) { msg += "\n same size=" + (stubTree.getPlainList().size() == stubTreeFromIndex.getPlainList().size()); msg += "\n debugInfo=" + stubTreeFromIndex.getDebugInfo(); } FileViewProvider viewProvider = psiFile.getViewProvider(); msg += "\n viewProvider=" + viewProvider; msg += "\n viewProvider stamp: " + viewProvider.getModificationStamp(); msg += "; file stamp: " + file.getModificationStamp(); msg += "; file modCount: " + file.getModificationCount(); msg += "; file length: " + file.getLength(); 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(psiFile.getProject()).isCommitted(document); } msg += "\nin many projects: " + hasPsiInManyProjects(file); msg += "\nindexing info: " + indexingStampInfo; Attachment[] attachments = createAttachments(stubTree, psiFile, file, stubTreeFromIndex); // separate methods and separate exception classes for EA to treat these situations differently return upToDate ? handleUpToDateMismatch(msg, attachments) : new RuntimeExceptionWithAttachments(msg, attachments); }
@Override public PsiElement retrieve() { return ApplicationManager.getApplication().runReadAction( (NullableComputable<PsiElement>)() -> restoreFromStubIndex((PsiFileWithStubSupport)getFile(), myIndex, myElementType, false)); }
/*** * Returns a message to log when stub tree and index do not match */ protected abstract Object stubTreeAndIndexDoNotMatch(@NotNull ObjectStubTree stubTree, PsiFileWithStubSupport psiFile);