public static @Nullable Stub buildStubTree(@NotNull FileContent inputData, @NotNull StubBuilderType stubBuilderType) {
    Stub data = inputData.getUserData(stubElementKey);
    if (data != null) return data;

    synchronized (inputData) {
      data = inputData.getUserData(stubElementKey);
      if (data != null) return data;

      BinaryFileStubBuilder builder = stubBuilderType.getBinaryFileStubBuilder();
      if (builder != null) {
        data = handleStubBuilderException(inputData, stubBuilderType, () -> builder.buildStubTree(inputData));
        if (data instanceof PsiFileStubImpl && !((PsiFileStubImpl<?>)data).rootsAreSet()) {
          ((PsiFileStubImpl<?>)data).setStubRoots(new PsiFileStub[]{(PsiFileStubImpl<?>)data});
        }
      }
      else {
        CharSequence contentAsText = inputData.getContentAsText();
        PsiDependentFileContent fileContent = (PsiDependentFileContent)inputData;
        FileViewProvider viewProvider = fileContent.getPsiFile().getViewProvider();
        PsiFile psi = viewProvider.getStubBindingRoot();
        // if we load AST, it should be easily gc-able. See PsiFileImpl.createTreeElementPointer()
        data = psi.getManager().runInBatchFilesMode(() -> {
          psi.putUserData(IndexingDataKeys.FILE_TEXT_CONTENT_KEY, contentAsText);
          StubElement built = null;
          try {
            IStubFileElementType<?> stubFileElementType = ((PsiFileImpl)psi).getElementTypeForStubBuilder();
            if (stubFileElementType != null) {
              StubBuilder stubBuilder = stubFileElementType.getBuilder();
              if (stubBuilder instanceof LightStubBuilder) {
                LightStubBuilder.FORCED_AST.set(fileContent.getLighterAST());
              }
              built = handleStubBuilderException(inputData, stubBuilderType, () -> stubBuilder.buildStubTree(psi));
              List<Pair<IStubFileElementType<?>, PsiFile>> stubbedRoots = getStubbedRoots(viewProvider);
              List<PsiFileStub<?>> stubs = new ArrayList<>(stubbedRoots.size());
              stubs.add((PsiFileStub<?>)built);

              for (Pair<IStubFileElementType<?>, PsiFile> stubbedRoot : stubbedRoots) {
                PsiFile secondaryPsi = stubbedRoot.second;
                if (psi == secondaryPsi) continue;
                StubBuilder stubbedRootBuilder = stubbedRoot.first.getBuilder();
                if (stubbedRootBuilder instanceof LightStubBuilder) {
                  LightStubBuilder.FORCED_AST.set(new TreeBackedLighterAST(secondaryPsi.getNode()));
                }
                StubElement<?> element = handleStubBuilderException(inputData, stubBuilderType, () -> stubbedRootBuilder.buildStubTree(secondaryPsi));
                if (element instanceof PsiFileStub) {
                  stubs.add((PsiFileStub<?>)element);
                }
                ensureNormalizedOrder(element);
              }
              PsiFileStub<?>[] stubsArray = stubs.toArray(PsiFileStub.EMPTY_ARRAY);
              for (PsiFileStub<?> stub : stubsArray) {
                if (stub instanceof PsiFileStubImpl) {
                  ((PsiFileStubImpl<?>)stub).setStubRoots(stubsArray);
                }
              }
            }
          }
          finally {
            psi.putUserData(IndexingDataKeys.FILE_TEXT_CONTENT_KEY, null);
          }
          return built;
        });
      }

      ensureNormalizedOrder(data);
      inputData.putUserData(stubElementKey, data);
      return data;
    }
  }
public static @Nullable Stub buildStubTree(@NotNull FileContent inputData, @NotNull StubBuilderType stubBuilderType)