// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.intellij.lang.regexp.inspection;

import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.xml.XmlElement;
import com.intellij.xml.util.XmlStringUtil;
import org.intellij.lang.regexp.psi.impl.RegExpElementImpl;
import org.jetbrains.annotations.NotNull;

/**
 * @author Bas Leijdekkers
 */
public class RegExpReplacementUtil {

  private RegExpReplacementUtil() {}

  public static void replaceInContext(@NotNull PsiElement element, @NotNull String text) {
    final PsiFile file = element.getContainingFile();
    text = escapeForContext(text, file);
    final Document document = PsiDocumentManager.getInstance(element.getProject()).getDocument(file);
    assert document != null;
    final TextRange replaceRange = element.getTextRange();
    document.replaceString(replaceRange.getStartOffset(), replaceRange.getEndOffset(), text);
  }

  private static String escapeForContext(String text, PsiFile file) {
    final InjectedLanguageManager injectedLanguageManager = InjectedLanguageManager.getInstance(file.getProject());
    if (injectedLanguageManager.isInjectedFragment(file)) {
      final PsiElement context = file.getContext();
      ElementManipulator<PsiElement> manipulator = context == null ? null : ElementManipulators.getManipulator(context);
      if (manipulator != null) {
        // use element manipulator to process escape sequences correctly for all supported languages
        PsiElement copy = context.copy(); // create a copy to avoid original element modifications
        PsiElement newElement = manipulator.handleContentChange(copy, text);
        if (newElement != null) {
          String newElementText = newElement.getText();
          TextRange newRange = manipulator.getRangeInElement(newElement);
          return newElementText.substring(newRange.getStartOffset(), newRange.getEndOffset());
        }
      }
      if (RegExpElementImpl.isLiteralExpression(context)) {
        // otherwise, just pretend it is a Java-style string
        return StringUtil.escapeStringCharacters(text);
      }
      else if (context instanceof XmlElement) {
        return XmlStringUtil.escapeString(text);
      }
    }
    return text;
  }
}

@@ -17,10 +17,10 @@
 0-20
-18
+20
  Jet
@@ -666,16 +666,114 @@
 Util %7B%0A%0A
+  /**%0A   * Dummy text that never needs escaping%0A   */%0A  private static final String DUMMY = %22a%22;%0A%0A
   privat
@@ -1581,16 +1581,22 @@
 ;%0A      
+final 
 ElementM
@@ -1836,32 +1836,38 @@
 nguages%0A        
+final 
 PsiElement copy 
@@ -1949,16 +1949,22 @@
         
+final 
 PsiEleme
@@ -2016,16 +2016,24 @@
 ge(copy,
+ DUMMY +
  text);%0A
@@ -2076,16 +2076,22 @@
         
+final 
 String n
@@ -2138,16 +2138,22 @@
         
+final 
 TextRang
@@ -2275,16 +2275,33 @@
 Offset()
+ + DUMMY.length()
 , newRan

fix removing redundantly escaped * breaks the regexp (WEB-32548)