@NotNull
 private static Collection<PsiLanguageInjectionHost> collectInjectionHosts(
     @NotNull PsiFile file, @NotNull TextRange range) {
   Stack<PsiElement> toProcess = new Stack<PsiElement>();
   for (PsiElement e = file.findElementAt(range.getStartOffset());
       e != null;
       e = e.getNextSibling()) {
     if (e.getTextRange().getStartOffset() >= range.getEndOffset()) {
       break;
     }
     toProcess.push(e);
   }
   if (toProcess.isEmpty()) {
     return Collections.emptySet();
   }
   Set<PsiLanguageInjectionHost> result = null;
   while (!toProcess.isEmpty()) {
     PsiElement e = toProcess.pop();
     if (e instanceof PsiLanguageInjectionHost) {
       if (result == null) {
         result = ContainerUtilRt.newHashSet();
       }
       result.add((PsiLanguageInjectionHost) e);
     } else {
       for (PsiElement child = e.getFirstChild(); child != null; child = child.getNextSibling()) {
         if (e.getTextRange().getStartOffset() >= range.getEndOffset()) {
           break;
         }
         toProcess.push(child);
       }
     }
   }
   return result == null ? Collections.<PsiLanguageInjectionHost>emptySet() : result;
 }
  private static TextRange preprocess(@NotNull final ASTNode node, @NotNull TextRange range) {
    TextRange result = range;
    PsiElement psi = node.getPsi();
    if (!psi.isValid()) {
      for (PreFormatProcessor processor : Extensions.getExtensions(PreFormatProcessor.EP_NAME)) {
        result = processor.process(node, result);
      }
      return result;
    }

    PsiFile file = psi.getContainingFile();

    // We use a set here because we encountered a situation when more than one PSI leaf points to
    // the same injected fragment
    // (at least for sql injected into sql).
    final LinkedHashSet<TextRange> injectedFileRangesSet = ContainerUtilRt.newLinkedHashSet();

    if (!psi.getProject().isDefault()) {
      List<DocumentWindow> injectedDocuments =
          InjectedLanguageUtil.getCachedInjectedDocuments(file);
      if (!injectedDocuments.isEmpty()) {
        for (DocumentWindow injectedDocument : injectedDocuments) {
          injectedFileRangesSet.add(
              TextRange.from(injectedDocument.injectedToHost(0), injectedDocument.getTextLength()));
        }
      } else {
        Collection<PsiLanguageInjectionHost> injectionHosts = collectInjectionHosts(file, range);
        PsiLanguageInjectionHost.InjectedPsiVisitor visitor =
            new PsiLanguageInjectionHost.InjectedPsiVisitor() {
              @Override
              public void visit(
                  @NotNull PsiFile injectedPsi,
                  @NotNull List<PsiLanguageInjectionHost.Shred> places) {
                for (PsiLanguageInjectionHost.Shred place : places) {
                  Segment rangeMarker = place.getHostRangeMarker();
                  injectedFileRangesSet.add(
                      TextRange.create(rangeMarker.getStartOffset(), rangeMarker.getEndOffset()));
                }
              }
            };
        for (PsiLanguageInjectionHost host : injectionHosts) {
          InjectedLanguageUtil.enumerate(host, visitor);
        }
      }
    }

    if (!injectedFileRangesSet.isEmpty()) {
      List<TextRange> ranges = ContainerUtilRt.newArrayList(injectedFileRangesSet);
      Collections.reverse(ranges);
      for (TextRange injectedFileRange : ranges) {
        int startHostOffset = injectedFileRange.getStartOffset();
        int endHostOffset = injectedFileRange.getEndOffset();
        if (startHostOffset >= range.getStartOffset() && endHostOffset <= range.getEndOffset()) {
          PsiFile injected = InjectedLanguageUtil.findInjectedPsiNoCommit(file, startHostOffset);
          if (injected != null) {
            int startInjectedOffset =
                range.getStartOffset() > startHostOffset
                    ? startHostOffset - range.getStartOffset()
                    : 0;
            int endInjectedOffset = injected.getTextLength();
            if (range.getEndOffset() < endHostOffset) {
              endInjectedOffset -= endHostOffset - range.getEndOffset();
            }
            final TextRange initialInjectedRange =
                TextRange.create(startInjectedOffset, endInjectedOffset);
            TextRange injectedRange = initialInjectedRange;
            for (PreFormatProcessor processor :
                Extensions.getExtensions(PreFormatProcessor.EP_NAME)) {
              injectedRange = processor.process(injected.getNode(), injectedRange);
            }

            // Allow only range expansion (not reduction) for injected context.
            if ((initialInjectedRange.getStartOffset() > injectedRange.getStartOffset()
                    && initialInjectedRange.getStartOffset() > 0)
                || (initialInjectedRange.getEndOffset() < injectedRange.getEndOffset()
                    && initialInjectedRange.getEndOffset() < injected.getTextLength())) {
              range =
                  TextRange.create(
                      range.getStartOffset()
                          + injectedRange.getStartOffset()
                          - initialInjectedRange.getStartOffset(),
                      range.getEndOffset()
                          + initialInjectedRange.getEndOffset()
                          - injectedRange.getEndOffset());
            }
          }
        }
      }
    }

    for (PreFormatProcessor processor : Extensions.getExtensions(PreFormatProcessor.EP_NAME)) {
      result = processor.process(node, result);
    }

    return result;
  }