@Override
  protected PsiElement restoreBySignatureTokens(@NotNull PsiFile file,
                                                @NotNull PsiElement parent,
                                                @NotNull String type,
                                                @NotNull StringTokenizer tokenizer,
                                                @Nullable StringBuilder processingInfoStorage)
  {
    if (!TYPE_MARKER.equals(type)) {
      if (processingInfoStorage != null) {
        processingInfoStorage.append(String.format(
          "Stopping '%s' provider because given signature doesn't have expected type - can work with '%s' but got '%s'%n",
          getClass().getName(), TYPE_MARKER, type
        ));
      }
      return null;
    }
    int start;
    int end;
    try {
      start = Integer.parseInt(tokenizer.nextToken());
      end = Integer.parseInt(tokenizer.nextToken());
    }
    catch (NumberFormatException e) {
      return null;
    }
    if (processingInfoStorage != null) {
      processingInfoStorage.append(String.format("Parsed target offsets - [%d; %d)%n", start, end));
    }

    int index = 0;
    if (tokenizer.hasMoreTokens()) {
      try {
        index = Integer.parseInt(tokenizer.nextToken());
      }
      catch (NumberFormatException e) {
        // Do nothing
      }
    }
    Language language = file.getLanguage();
    if (tokenizer.hasMoreTokens()) {
      String languageId = tokenizer.nextToken();
      Language languageFromSignature = Language.findLanguageByID(languageId);
      if (languageFromSignature == null) {
        if (processingInfoStorage != null) {
          processingInfoStorage.append(String.format("Couldn't find language for id %s", languageId));
        }
      }
      else {
        language = languageFromSignature;
      }
    }

    FileViewProvider viewProvider = file.getViewProvider();
    PsiElement element = viewProvider.findElementAt(start, language);
    if (element == null) {
      return null;
    }
    PsiElement result = findElement(start, end, index, element, processingInfoStorage);
    if (result != null) {
      return result;
    }
    else if (processingInfoStorage != null) {
      processingInfoStorage.append(String.format(
        "Failed to find an element by the given offsets for language %s. Started by the element '%s' (%s)",
        language, element, element.getText()
      ));
    }
    PsiFile psiFile = viewProvider.getPsi(language);
    if (psiFile == null) {
      if (processingInfoStorage != null) {
        processingInfoStorage.append(String.format("Couldn't find PSI for language %s", language.toString()));
      }
      return null;
    }
    final PsiElement injectedStartElement = InjectedLanguageUtil.findElementAtNoCommit(psiFile, start);
    if (processingInfoStorage != null) {
      processingInfoStorage.append(String.format(
        "Trying to find injected element starting from the '%s'%s%n",
        injectedStartElement, injectedStartElement == null ? "" : String.format("(%s)", injectedStartElement.getText())
      ));
    }
    if (injectedStartElement != null && injectedStartElement != element) {
      return findElement(start, end, index, injectedStartElement, processingInfoStorage);
    }
    return null;
  }
@Override
  protected PsiElement restoreBySignatureTokens(@NotNull PsiFile file,
                                                @NotNull PsiElement parent,
                                                @NotNull String type,
                                                @NotNull StringTokenizer tokenizer,
                                                @Nullable StringBuilder processingInfoStorage)