@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(); }