Groovy: fix inline in GString, replaceWithExpression
authorMaxim Medvedev <maxim.medvedev@jetbrains.com>
Mon, 5 Oct 2009 12:33:02 +0000 (16:33 +0400)
committerMaxim Medvedev <maxim.medvedev@jetbrains.com>
Mon, 5 Oct 2009 12:34:37 +0000 (16:34 +0400)
plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/conversions/ConvertConcatenationToGstringIntention.java
plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/conversions/ConvertGStringToStringIntention.java
plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/conversions/RemoveUnnecessaryBracesInGStringIntention.java
plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/PsiImplUtil.java
plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GrStringUtil.java [new file with mode: 0644]
plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/inline/GroovyInlineVariableUtil.java

index d897e7b3fba95421e15b8b54af3e74edf908c85d..dab13895ee9365b28851e4a17ec63f4fd78df53d 100644 (file)
@@ -34,6 +34,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrRefere
 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral;
 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrString;
 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression;
+import org.jetbrains.plugins.groovy.lang.psi.util.GrStringUtil;
 
 /**
  * @author Maxim.Medvedev
@@ -52,18 +53,10 @@ public class ConvertConcatenationToGstringIntention extends Intention {
   protected void processIntention(@NotNull PsiElement element) throws IncorrectOperationException {
     StringBuilder builder = new StringBuilder(element.getTextLength());
     performIntention((GrBinaryExpression)element, builder);
-    final String delimiter;
-    final String content = builder.toString();
-    if (content.contains("\n")) {
-      delimiter = "\"\"\"";
-    }
-    else {
-      delimiter = "\"";
-    }
     final GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(element.getProject());
-    final GrExpression newExpr = factory.createExpressionFromText(delimiter + content + delimiter);
+    final GrExpression newExpr = factory.createExpressionFromText(GrStringUtil.addQuotes(builder.toString(), true));
     final GrExpression expression = ((GrBinaryExpression)element).replaceWithExpression(newExpr, true);
-    RemoveUnnecessaryBracesInGStringIntention.performIntention(expression, true);
+    GrStringUtil.removeUnnecessaryBracesInGString((GrString)expression);
   }
 
   private static void performIntention(GrBinaryExpression expr, StringBuilder builder) {
@@ -75,27 +68,11 @@ public class ConvertConcatenationToGstringIntention extends Intention {
 
   private static void getOperandText(GrExpression operand, StringBuilder builder) {
     if (operand instanceof GrString) {
-      final GrString grString = (GrString)operand;
-      final String text = operand.getText();
-      final boolean isPlain = grString.isPlainString();
-      if (isPlain) {
-        builder.append(text.substring(1, text.length() - 1));
-      }
-      else {
-        builder.append(text.substring(3, text.length() - 3));
-      }
+      builder.append(GrStringUtil.removeQuotes(operand.getText()));
     }
     else if (operand instanceof GrLiteral) {
-      final String text = operand.getText();
-      if (text.startsWith("\"\"\"") || text.startsWith("'''")) {
-        escape(text.substring(3, text.length() - 3), builder);
-      }
-      else if (text.startsWith("\"") || text.startsWith("'") || text.startsWith("/")) {
-        escape(text.substring(1, text.length() - 1), builder);
-      }
-      else {
-        builder.append(text);
-      }
+      String text = GrStringUtil.escapeSymbolsForGString(GrStringUtil.removeQuotes(operand.getText()));
+      builder.append(text);
     }
     else if (MyPredicate.satisfiedBy(operand, false)) {
       performIntention((GrBinaryExpression)operand, builder);
@@ -156,36 +133,6 @@ public class ConvertConcatenationToGstringIntention extends Intention {
     }
   }
 
-  private static void escape(String s, StringBuilder b) {
-    final char[] chars = s.toCharArray();
-    final int len = chars.length - 1;
-    int i;
-    for (i = 0; i < len; i++) {
-      if (chars[i] == '\\') {
-        if (chars[i + 1] == '\'') {
-          b.append('\'');
-          i++;
-        }
-        else if (chars[i + 1] == 'n') {
-          b.append('\n');
-          i++;
-        }
-        else {
-          b.append(chars[i]);
-          i++;
-          b.append(chars[i]);
-        }
-        continue;
-      }
-      if (chars[i] == '"' || chars[i] == '$') b.append('\\');
-      b.append(chars[i]);
-    }
-    if (i == len) {
-      if (chars[i] == '"') b.append('\\');
-      b.append(chars[i]);
-    }
-  }
-
   private static class MyPredicate implements PsiElementPredicate {
     public boolean satisfiedBy(PsiElement element) {
       return satisfiedBy(element, true);
index c05aaa2c34d38f81fc193e2fe7a1c8d6b85c55ab..f2ce4535a5b48135658471405780c9beabc204da 100644 (file)
@@ -17,6 +17,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrBinary
 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral;
+import org.jetbrains.plugins.groovy.lang.psi.util.GrStringUtil;
 
 import java.util.ArrayList;
 
@@ -126,44 +127,7 @@ public class ConvertGStringToStringIntention extends Intention {
     }
     if (text.length() == 0) return null;
 
-    String escaped = escape(text);
-    if (escaped.contains("\n")) {
-      return "'''" + escaped + "'''";
-    }
-    else {
-      return "'" + escaped + "'";
-    }
-  }
-
-  private static String escape(String contents) {
-    StringBuilder b = new StringBuilder(contents.length() * 2);
-    final char[] chars = contents.toCharArray();
-    final int len = chars.length - 1;
-    int i;
-    for (i = 0; i < len; i++) {
-      if (chars[i] == '\\') {
-        if (chars[i + 1] == '"' || chars[i + 1] == '$') {
-          i++;
-          b.append(chars[i]);
-        }
-        else if (chars[i + 1] == 'n') {
-          b.append('\n');
-          i++;
-        }
-        else {
-          b.append('\\');
-          i++;
-          b.append(chars[i]);
-        }
-        continue;
-      }
-      if (chars[i] == '\'') b.append('\\');
-      b.append(chars[i]);
-    }
-    if (i == len) {
-      if (chars[i] == '\'') b.append('\\');
-      b.append(chars[i]);
-    }
-    return b.toString();
+    String escaped = GrStringUtil.escapeSymbolsForString(text);
+    return GrStringUtil.addQuotes(escaped, false);
   }
 }
index 7adf96974026efb73ab7d42154184f6deae3e0bd..9e1ba32fda80f67c828ccdc6f977c44b8fd91083 100644 (file)
 
 package org.jetbrains.plugins.groovy.intentions.conversions;
 
-import com.intellij.openapi.util.Comparing;
 import com.intellij.psi.PsiElement;
-import com.intellij.psi.impl.source.tree.LeafPsiElement;
 import com.intellij.util.IncorrectOperationException;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.plugins.groovy.intentions.base.ErrorUtil;
 import org.jetbrains.plugins.groovy.intentions.base.Intention;
 import org.jetbrains.plugins.groovy.intentions.base.PsiElementPredicate;
-import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
-import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement;
-import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
-import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
-import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrString;
+import org.jetbrains.plugins.groovy.lang.psi.util.GrStringUtil;
 
 /**
  * @author Maxim.Medvedev
@@ -43,21 +37,10 @@ public class RemoveUnnecessaryBracesInGStringIntention extends Intention {
 
   @Override
   protected void processIntention(@NotNull PsiElement element) throws IncorrectOperationException {
-    performIntention(element, false);
+    GrStringUtil.removeUnnecessaryBracesInGString((GrString)element);
   }
 
-  public static void performIntention(PsiElement element, boolean checkAvailable) {
-    if (checkAvailable && !MyPredicate.isIntentionAvailable(element)) return;
-    for (PsiElement child : element.getChildren()) {
-      if (MyPredicate.checkClosableBlock(child)) {
-        final GrReferenceExpression refExpr = (GrReferenceExpression)((GrClosableBlock)child).getStatements()[0];
-        final GrReferenceExpression copy = (GrReferenceExpression)refExpr.copy();
-        ((GrClosableBlock)child).replaceWithExpression(copy, false);
-      }
-    }
-  }
-
-  static class MyPredicate implements PsiElementPredicate {
+  public static class MyPredicate implements PsiElementPredicate {
     public boolean satisfiedBy(PsiElement element) {
       return isIntentionAvailable(element);
     }
@@ -68,35 +51,10 @@ public class RemoveUnnecessaryBracesInGStringIntention extends Intention {
       if (ErrorUtil.containsError(element)) return false;
 
       for (PsiElement child : element.getChildren()) {
-        if (checkClosableBlock(child)) return true;
+        if (GrStringUtil.checkClosableBlockInGStringForUnnecessaryBraces(child)) return true;
       }
       return false;
     }
-
-    public static boolean checkClosableBlock(PsiElement element) {
-      if (!(element instanceof GrClosableBlock)) return false;
-      GrClosableBlock block = (GrClosableBlock)element;
-
-      final GrStatement[] statements = block.getStatements();
-      if (statements.length != 1) return false;
-
-      if (!(statements[0] instanceof GrReferenceExpression)) return false;
-
-      final PsiElement next = block.getNextSibling();
-      if (!(next instanceof LeafPsiElement)) return false;
-
-      char nextChar = next.getText().charAt(0);
-      if (nextChar == '"' || nextChar == '$') {
-        return true;
-      }
-      final GroovyPsiElementFactory elementFactory = GroovyPsiElementFactory.getInstance(element.getProject());
-      final GrExpression gString = elementFactory.createExpressionFromText("\"$" + statements[0].getText() + nextChar + '"');
-      final GrReferenceExpression refExpr = (GrReferenceExpression)statements[0];
-      final PsiElement refExprCopy = gString.getChildren()[0];
-      if (!(refExprCopy instanceof GrReferenceExpression)) return false;
-
-      return Comparing.equal(refExpr.getName(), ((GrReferenceExpression)refExprCopy).getName());
-    }
   }
 }
 
index af874a7e552ef0cf8d2d4300231eade97f2fd18c..f86b193c8bac126e174d8d9723510b60a8b4b98e 100644 (file)
@@ -25,8 +25,6 @@ import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.psi.*;
 import com.intellij.psi.infos.CandidateInfo;
 import com.intellij.psi.search.GlobalSearchScope;
-import com.intellij.psi.search.LocalSearchScope;
-import com.intellij.psi.search.SearchScope;
 import com.intellij.psi.util.MethodSignature;
 import com.intellij.psi.util.MethodSignatureUtil;
 import com.intellij.psi.util.PsiTreeUtil;
@@ -41,8 +39,8 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
 import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaration;
 import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral;
 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression;
-import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMember;
 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
 import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.arithmetic.*;
 import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.bitwise.GrAndExpressionImpl;
@@ -52,9 +50,9 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.logical
 import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.logical.GrLogicalOrExpressionImpl;
 import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.regex.GrRegexExpressionImpl;
 import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.relational.GrEqualityExpressionImpl;
+import org.jetbrains.plugins.groovy.lang.psi.util.GrStringUtil;
 import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
 
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
@@ -65,9 +63,10 @@ public class PsiImplUtil {
   private static final Logger LOG = Logger.getInstance("org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil");
   private static final String MAIN_METHOD = "main";
 
-  public static GrExpression replaceExpression(GrExpression oldExpr,
-                                               GrExpression newExpr,
-                                               boolean removeUnnecessaryParentheses) {
+  private PsiImplUtil() {
+  }
+
+  public static GrExpression replaceExpression(GrExpression oldExpr, GrExpression newExpr, boolean removeUnnecessaryParentheses) {
     ASTNode oldNode = oldExpr.getNode();
     PsiElement oldParent = oldExpr.getParent();
     if (oldParent == null) throw new PsiInvalidElementAccessException(oldExpr);
@@ -76,27 +75,35 @@ public class PsiImplUtil {
 
     if (newExpr instanceof GrApplicationStatement && !(oldExpr instanceof GrApplicationStatement)) {
       GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(oldExpr.getProject());
-      newExpr = factory.createMethodCallByAppCall(((GrApplicationStatement) newExpr));
+      newExpr = factory.createMethodCallByAppCall(((GrApplicationStatement)newExpr));
     }
 
     // Remove unnecessary parentheses
     if (removeUnnecessaryParentheses && oldParent instanceof GrParenthesizedExpression) {
-      return ((GrExpression) oldParent).replaceWithExpression(newExpr, removeUnnecessaryParentheses);
+      return ((GrExpression)oldParent).replaceWithExpression(newExpr, removeUnnecessaryParentheses);
     }
 
     // check priorities
     GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(oldExpr.getProject());
-    if (oldParent instanceof GrExpression && !(oldParent instanceof GrParenthesizedExpression)) {
-      GrExpression parentExpr = (GrExpression) oldParent;
+    if (GrStringUtil.isReplacedExpressionInGStringInjection(oldExpr)) {
+      if (newExpr instanceof GrLiteral) {
+        return GrStringUtil.replaceExpressionInjectionByLiteral(oldExpr, ((GrLiteral)newExpr));
+      }
+      else if (!(newExpr instanceof GrReferenceExpression)){
+        newExpr = factory.createExpressionFromText("{" + newExpr.getText() + "}");
+      }
+    }
+    else if (oldParent instanceof GrExpression && !(oldParent instanceof GrParenthesizedExpression)) {
+      GrExpression parentExpr = (GrExpression)oldParent;
       int parentPriorityLevel = getExprPriorityLevel(parentExpr);
       int newPriorityLevel = getExprPriorityLevel(newExpr);
       if (parentPriorityLevel > newPriorityLevel) {
         newExpr = factory.createParenthesizedExpr(newExpr);
-      } else if (parentPriorityLevel == newPriorityLevel && parentPriorityLevel != 0) {
+      }
+      else if (parentPriorityLevel == newPriorityLevel && parentPriorityLevel != 0) {
         if (parentExpr instanceof GrBinaryExpression) {
-          GrBinaryExpression binaryExpression = (GrBinaryExpression) parentExpr;
-          if (isNotAssociative(binaryExpression) &&
-              oldExpr.equals(binaryExpression.getRightOperand())) {
+          GrBinaryExpression binaryExpression = (GrBinaryExpression)parentExpr;
+          if (isNotAssociative(binaryExpression) && oldExpr.equals(binaryExpression.getRightOperand())) {
             newExpr = factory.createParenthesizedExpr(newExpr);
           }
         }
@@ -107,7 +114,7 @@ public class PsiImplUtil {
     assert newNode != null && parentNode != null;
     parentNode.replaceChild(oldNode, newNode);
 
-    return ((GrExpression) newNode.getPsi());
+    return ((GrExpression)newNode.getPsi());
   }
 
   private static boolean isNotAssociative(GrBinaryExpression binaryExpression) {
@@ -123,25 +130,7 @@ public class PsiImplUtil {
         || binaryExpression instanceof GrPowerExpressionImpl;
   }
 
-  public static SearchScope getUseScope(GrMember member) {
-    if (member.hasModifierProperty(PsiModifier.PRIVATE)) {
-      return new LocalSearchScope(member.getContainingFile()); //todo: what does GLS say?
-    }
-
-    return member.getManager().getSearchHelper().getUseScope(member);
-  }
-
-  public static PsiNamedElement[] getMethodVariants(GrReferenceExpression methodReference) {
-    final GroovyResolveResult[] results = methodReference.getSameNameVariants(); //will ignore argument types
-    List<PsiNamedElement> elements = new ArrayList<PsiNamedElement>();
-    for (GroovyResolveResult result : results) {
-      final PsiElement element = result.getElement();
-      if (element instanceof PsiNamedElement) elements.add((PsiNamedElement) element);
-    }
-
-    return elements.toArray(new PsiNamedElement[elements.size()]);
-  }
-
+  @Nullable
   public static GrExpression getRuntimeQualifier(GrReferenceExpression refExpr) {
     GrExpression qualifier = refExpr.getQualifierExpression();
     if (qualifier == null) {
@@ -180,8 +169,10 @@ public class PsiImplUtil {
       PsiElement next = varDecl.getNextSibling();
 
       // remove redundant semicolons
+      //noinspection ConstantConditions
       while (next != null && next.getNode() != null && next.getNode().getElementType() == mSEMI) {
         PsiElement tmpNext = next.getNextSibling();
+        //noinspection ConstantConditions
         owner.removeChild(next.getNode());
         next = tmpNext;
       }
@@ -198,6 +189,7 @@ public class PsiImplUtil {
     PsiUtil.reformatCode(varDecl);
   }
 
+  @Nullable
   public static PsiElement realPrevious(PsiElement previousLeaf) {
     while (previousLeaf != null &&
         (previousLeaf instanceof PsiWhiteSpace ||
@@ -208,16 +200,6 @@ public class PsiImplUtil {
     return previousLeaf;
   }
 
-  public static PsiElement realNext(PsiElement nextLeaf) {
-    while (nextLeaf != null &&
-        (nextLeaf instanceof PsiWhiteSpace ||
-            nextLeaf instanceof PsiComment ||
-            nextLeaf instanceof PsiErrorElement)) {
-      nextLeaf = nextLeaf.getNextSibling();
-    }
-    return nextLeaf;
-  }
-
   private static int getExprPriorityLevel(GrExpression expr) {
     int priority = 0;
     //if (expr instanceof GrNewExpression) priority = 1;
@@ -280,6 +262,7 @@ public class PsiImplUtil {
     return MethodSignatureUtil.isSubsignature(superSignatureCandidate, subSignature);
   }
 
+  @Nullable
   public static PsiElement getOriginalElement(PsiClass clazz, PsiFile containingFile) {
     VirtualFile vFile = containingFile.getVirtualFile();
     final JavaPsiFacade facade = JavaPsiFacade.getInstance(clazz.getProject());
@@ -317,6 +300,7 @@ public class PsiImplUtil {
     return original != null ? original : clazz;
   }
 
+  @Nullable
   public static PsiMethod extractUniqueElement(@NotNull GroovyResolveResult[] results) {
     if (results.length != 1) return null;
     final PsiElement element = results[0].getElement();
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GrStringUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GrStringUtil.java
new file mode 100644 (file)
index 0000000..22d97e2
--- /dev/null
@@ -0,0 +1,235 @@
+package org.jetbrains.plugins.groovy.lang.psi.util;
+
+import com.intellij.openapi.util.Comparing;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.impl.source.tree.LeafPsiElement;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrString;
+
+/**
+ * @author Maxim.Medvedev
+ */
+public class GrStringUtil {
+  private static final String TRIPLE_QUOTES = "'''";
+  private static final String QUOTE = "'";
+  private static final String DOUBLE_QUOTES = "\"";
+  private static final String TRIPLE_DOUBLE_QUOTES = "\"\"\"";
+
+  private GrStringUtil() {
+  }
+
+  public static String escapeSymbolsForGString(String s) {
+    StringBuilder b = new StringBuilder();
+    final char[] chars = s.toCharArray();
+    final int len = chars.length - 1;
+    int i;
+    for (i = 0; i < len; i++) {
+      if (chars[i] == '\\') {
+        final char next = chars[i + 1];
+        if (next == '\'') {
+          b.append('\'');
+          i++;
+        }
+        else if (next == 'n') {
+          b.append('\n');
+          i++;
+        }
+        else if (next == '"') {
+          b.append('"');
+          i++;
+        }
+        else {
+          b.append(chars[i]);
+          i++;
+          b.append(chars[i]);
+        }
+        continue;
+      }
+      if (chars[i] == '"' || chars[i] == '$') b.append('\\');
+      b.append(chars[i]);
+    }
+    if (i == len) {
+      if (chars[i] == '"') b.append('\\');
+      b.append(chars[i]);
+    }
+    return b.toString();
+  }
+
+  public static String escapeSymbolsForString(String s) {
+    StringBuilder b = new StringBuilder();
+    final char[] chars = s.toCharArray();
+    final int len = chars.length - 1;
+    int i;
+    for (i = 0; i < len; i++) {
+      if (chars[i] == '\\') {
+        final char next = chars[i + 1];
+        if (next == '"' || next == '$') {
+          b.append(next);
+        }
+        else if (next == 'n') {
+          b.append('\n');
+        }
+        else if (next == '\'') {
+          b.append(next);
+        }
+        else {
+          b.append('\\');
+          b.append(next);
+        }
+        i++;
+        continue;
+      }
+      if (chars[i] == '\'') b.append('\\');
+      b.append(chars[i]);
+    }
+
+    if (i == len) {
+      if (chars[i] == '\'') b.append('\\');
+      b.append(chars[i]);
+    }
+    return b.toString();
+
+  }
+
+  public static String removeQuotes(String s) {
+    if (s.startsWith(TRIPLE_QUOTES) || s.startsWith(TRIPLE_DOUBLE_QUOTES)) {
+      return s.substring(3, s.length() - 3);
+    }
+    else if (s.startsWith(QUOTE) || s.startsWith(DOUBLE_QUOTES)) {
+      return s.substring(1, s.length() - 1);
+    }
+    return s;
+  }
+
+  public static String addQuotes(String s, boolean forGString) {
+    if (forGString) {
+      if (s.contains("\n")) {
+        return TRIPLE_DOUBLE_QUOTES + s + TRIPLE_DOUBLE_QUOTES;
+      }
+      else {
+        return DOUBLE_QUOTES + s + DOUBLE_QUOTES;
+      }
+    }
+    else {
+      if (s.contains("\n")) {
+        return TRIPLE_QUOTES + s + TRIPLE_QUOTES;
+      }
+      else {
+        return QUOTE + s + QUOTE;
+      }
+    }
+  }
+
+  public static boolean isReplacedExpressionInGStringInjection(GrExpression replacedExpression) {
+    PsiElement parent = replacedExpression.getParent();
+    if (parent instanceof GrClosableBlock) {
+      parent = parent.getParent();
+    }
+    return parent instanceof GrString;
+  }
+
+  /**
+   * @param injection - expected that injection must have GrString parent
+   * @param literal
+   * @return
+   */
+  public static GrExpression replaceExpressionInjectionByLiteral(PsiElement injection, GrLiteral literal) {
+    if (injection.getParent() instanceof GrClosableBlock) {
+      injection = injection.getParent();
+    }
+    GrString grString= (GrString)injection.getParent();
+
+    int injectionNumber = -1;
+    for (PsiElement child : grString.getChildren()) {
+      injectionNumber++;
+      if (child == injection) {
+        break;
+      }
+    }
+    if (injectionNumber == -1) return grString;
+
+    GrString grStringWithBraces = addAllBracesInGString(grString);
+    injection = grStringWithBraces.getChildren()[injectionNumber];
+
+    final int offset = injection.getStartOffsetInParent();
+    final TextRange range = new TextRange(offset - 1, offset + injection.getTextLength());
+
+    if (literal instanceof GrString) {
+      literal = addAllBracesInGString((GrString)literal);
+    }
+
+    String literalText = literal.getText();
+    if (isPlainString(literal)) {
+      literalText = escapeSymbolsForGString(literalText);
+    }
+
+    String text = StringUtil.replaceSubstring(grStringWithBraces.getText(), range, removeQuotes(literalText));
+
+    GrExpression newGrString = GroovyPsiElementFactory.getInstance(grString.getProject()).createExpressionFromText(text);
+    if (newGrString instanceof GrString) {
+      removeUnnecessaryBracesInGString((GrString)newGrString);
+    }
+    return grString.replaceWithExpression(newGrString, true);
+  }
+
+  public static GrString addAllBracesInGString(GrString grString) {
+    StringBuilder newString = new StringBuilder();
+
+    for (PsiElement child = grString.getFirstChild(); child != null; child = child.getNextSibling()) {
+      if (child instanceof GrReferenceExpression) {
+        newString.append('{').append(child.getText()).append('}');
+      }
+      else {
+        newString.append(child.getText());
+      }
+    }
+    return (GrString)GroovyPsiElementFactory.getInstance(grString.getProject()).createExpressionFromText(newString.toString());
+  }
+
+  public static boolean checkClosableBlockInGStringForUnnecessaryBraces(PsiElement element) {
+    if (!(element instanceof GrClosableBlock)) return false;
+    GrClosableBlock block = (GrClosableBlock)element;
+
+    final GrStatement[] statements = block.getStatements();
+    if (statements.length != 1) return false;
+
+    if (!(statements[0] instanceof GrReferenceExpression)) return false;
+
+    final PsiElement next = block.getNextSibling();
+    if (!(next instanceof LeafPsiElement)) return false;
+
+    char nextChar = next.getText().charAt(0);
+    if (nextChar == '"' || nextChar == '$') {
+      return true;
+    }
+    final GroovyPsiElementFactory elementFactory = GroovyPsiElementFactory.getInstance(element.getProject());
+    final GrExpression gString = elementFactory.createExpressionFromText("\"$" + statements[0].getText() + nextChar + '"');
+    final GrReferenceExpression refExpr = (GrReferenceExpression)statements[0];
+    final PsiElement refExprCopy = gString.getChildren()[0];
+    if (!(refExprCopy instanceof GrReferenceExpression)) return false;
+
+    return Comparing.equal(refExpr.getName(), ((GrReferenceExpression)refExprCopy).getName());
+  }
+
+  public static void removeUnnecessaryBracesInGString(GrString grString) {
+    for (PsiElement child : grString.getChildren()) {
+      if (checkClosableBlockInGStringForUnnecessaryBraces(child)) {
+        final GrReferenceExpression refExpr = (GrReferenceExpression)((GrClosableBlock)child).getStatements()[0];
+        final GrReferenceExpression copy = (GrReferenceExpression)refExpr.copy();
+        ((GrClosableBlock)child).replaceWithExpression(copy, false);
+      }
+    }
+  }
+
+  public static boolean isPlainString(@NotNull GrLiteral literal) {
+    return literal.getText().startsWith("'");
+  }
+}
index 32eadb3648d1128ff2dba417f9b72fd1a2c2fc97..9020f226140976cc2683ab12edc76e2fa8ff7fa3 100644 (file)
@@ -35,8 +35,6 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrAssignmentExpression;
 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrParenthesizedExpression;
-import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
-import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrString;
 import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringBundle;
 import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringUtil;
 
@@ -76,29 +74,25 @@ public class GroovyInlineVariableUtil {
       }
 
       public void inlineUsage(final UsageInfo usage, final PsiElement referenced) {
-        GrExpression exprToBeReplaced = (GrExpression) usage.getElement();
+        GrExpression exprToBeReplaced = (GrExpression)usage.getElement();
         if (exprToBeReplaced == null) return;
         assert variable.getInitializerGroovy() != null;
         GrExpression initializerGroovy = variable.getInitializerGroovy();
         assert initializerGroovy != null;
         GrExpression tempExpr = initializerGroovy;
         while (tempExpr instanceof GrParenthesizedExpression) {
-          tempExpr = ((GrParenthesizedExpression) tempExpr).getOperand();
+          tempExpr = ((GrParenthesizedExpression)tempExpr).getOperand();
         }
         Project project = variable.getProject();
         GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(project);
         GrExpression newExpr;
-        if (exprToBeReplaced.getParent() instanceof GrString && !(tempExpr instanceof GrReferenceExpression)) {
-          newExpr = factory.createExpressionFromText("{" + tempExpr.getText() + "}");
-        }
-        else {
-          newExpr = factory.createExpressionFromText(tempExpr.getText());
-        }
+        newExpr = factory.createExpressionFromText(tempExpr.getText());
         newExpr = exprToBeReplaced.replaceWithExpression(newExpr, true);
         FileEditorManager manager = FileEditorManager.getInstance(project);
         Editor editor = manager.getSelectedTextEditor();
         GroovyRefactoringUtil.highlightOccurrences(project, editor, new PsiElement[]{newExpr});
-        WindowManager.getInstance().getStatusBar(project).setInfo(GroovyRefactoringBundle.message("press.escape.to.remove.the.highlighting"));
+        WindowManager.getInstance().getStatusBar(project)
+          .setInfo(GroovyRefactoringBundle.message("press.escape.to.remove.the.highlighting"));
       }
     };
   }