@Override
  public <K> Collection<K> getAllKeys(final StubIndexKey<K, ?> indexKey, @NotNull Project project) {
    FileBasedIndex.getInstance()
        .ensureUpToDate(StubUpdatingIndex.INDEX_ID, project, GlobalSearchScope.allScope(project));

    final MyIndex<K> index = (MyIndex<K>) myIndices.get(indexKey);
    try {
      return index.getAllKeys();
    } catch (StorageException e) {
      forceRebuild(e);
    } catch (RuntimeException e) {
      final Throwable cause = e.getCause();
      if (cause instanceof IOException || cause instanceof StorageException) {
        forceRebuild(e);
      }
      throw e;
    }
    return Collections.emptyList();
  }
  public StubIndexImpl(FileBasedIndex fileBasedIndex /* need this to ensure initialization order*/)
      throws IOException {
    final boolean forceClean = Boolean.TRUE == ourForcedClean.getAndSet(Boolean.FALSE);

    final StubIndexExtension<?, ?>[] extensions =
        Extensions.getExtensions(StubIndexExtension.EP_NAME);
    boolean needRebuild = false;
    for (StubIndexExtension extension : extensions) {
      //noinspection unchecked
      needRebuild |= registerIndexer(extension, forceClean);
    }
    if (needRebuild) {
      if (ApplicationManager.getApplication().isUnitTestMode()) {
        requestRebuild();
      } else {
        forceRebuild(new Throwable());
      }
    }
    dropUnregisteredIndices();
  }
  @Override
  public <Key, Psi extends PsiElement> Collection<Psi> get(
      @NotNull final StubIndexKey<Key, Psi> indexKey,
      @NotNull final Key key,
      final Project project,
      final GlobalSearchScope scope) {
    FileBasedIndex.getInstance().ensureUpToDate(StubUpdatingIndex.INDEX_ID, project, scope);

    final PersistentFS fs = (PersistentFS) ManagingFS.getInstance();
    final PsiManager psiManager = PsiManager.getInstance(project);

    final List<Psi> result = new ArrayList<Psi>();
    final MyIndex<Key> index = (MyIndex<Key>) myIndices.get(indexKey);

    try {
      try {
        // disable up-to-date check to avoid locks on attempt to acquire index write lock while
        // holding at the same time the readLock for this index
        FileBasedIndex.disableUpToDateCheckForCurrentThread();
        index.getReadLock().lock();
        final ValueContainer<TIntArrayList> container = index.getData(key);

        container.forEach(
            new ValueContainer.ContainerAction<TIntArrayList>() {
              @Override
              public void perform(final int id, final TIntArrayList value) {
                final VirtualFile file = IndexInfrastructure.findFileByIdIfCached(fs, id);
                if (file != null && (scope == null || scope.contains(file))) {
                  StubTree stubTree = null;

                  final PsiFile _psifile = psiManager.findFile(file);
                  PsiFileWithStubSupport psiFile = null;

                  if (_psifile != null && !(_psifile instanceof PsiPlainTextFile)) {
                    if (_psifile instanceof PsiFileWithStubSupport) {
                      psiFile = (PsiFileWithStubSupport) _psifile;
                      stubTree = psiFile.getStubTree();
                      if (stubTree == null && psiFile instanceof PsiFileImpl) {
                        stubTree = ((PsiFileImpl) psiFile).calcStubTree();
                      }
                    }
                  }

                  if (stubTree != null || psiFile != null) {
                    if (stubTree == null) {
                      stubTree = StubTreeLoader.getInstance().readFromVFile(project, file);
                      if (stubTree != null) {
                        final List<StubElement<?>> plained = stubTree.getPlainList();
                        for (int i = 0; i < value.size(); i++) {
                          final StubElement<?> stub = plained.get(value.get(i));
                          final ASTNode tree = psiFile.findTreeForStub(stubTree, stub);

                          if (tree != null) {
                            if (tree.getElementType() == stubType(stub)) {
                              result.add((Psi) tree.getPsi());
                            } else {
                              String persistedStubTree =
                                  ((PsiFileStubImpl) stubTree.getRoot()).printTree();

                              String stubTreeJustBuilt =
                                  ((PsiFileStubImpl)
                                          ((IStubFileElementType)
                                                  ((PsiFileImpl) psiFile).getContentElementType())
                                              .getBuilder()
                                              .buildStubTree(psiFile))
                                      .printTree();

                              StringBuilder builder = new StringBuilder();
                              builder.append("Oops\n");

                              builder.append("Recorded stub:-----------------------------------\n");
                              builder.append(persistedStubTree);
                              builder.append(
                                  "\nAST built stub: ------------------------------------\n");
                              builder.append(stubTreeJustBuilt);
                              builder.append("\n");
                              LOG.info(builder.toString());

                              // requestReindex() may want to acquire write lock (for indices not
                              // requiring content loading)
                              // thus, because here we are under read lock, need to use invoke later
                              ApplicationManager.getApplication()
                                  .invokeLater(
                                      new Runnable() {
                                        @Override
                                        public void run() {
                                          FileBasedIndex.getInstance().requestReindex(file);
                                        }
                                      },
                                      ModalityState.NON_MODAL);
                            }
                          }
                        }
                      }
                    } else {
                      final List<StubElement<?>> plained = stubTree.getPlainList();
                      for (int i = 0; i < value.size(); i++) {
                        result.add((Psi) plained.get(value.get(i)).getPsi());
                      }
                    }
                  }
                }
              }
            });
      } finally {
        index.getReadLock().unlock();
        FileBasedIndex.enableUpToDateCheckForCurrentThread();
      }
    } catch (StorageException e) {
      forceRebuild(e);
    } catch (RuntimeException e) {
      final Throwable cause = FileBasedIndex.getCauseToRebuildIndex(e);
      if (cause != null) {
        forceRebuild(cause);
      } else {
        throw e;
      }
    }

    return result;
  }