IDEA-83877 Broken 'Convert to GString' intention

This commit is contained in:
Maxim.Medvedev
2012-04-04 16:07:17 +04:00
parent ffa4b0e8a9
commit 1618027e48
4 changed files with 106 additions and 89 deletions
@@ -35,6 +35,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpres
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.GrLiteral;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrRegex;
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.impl.statements.expressions.TypesUtil;
@@ -87,14 +88,24 @@ public class ConvertConcatenationToGstringIntention extends Intention {
}
private static void getOperandText(@Nullable GrExpression operand, StringBuilder builder) {
if (operand instanceof GrString) {
if (operand instanceof GrRegex) {
StringBuilder b = new StringBuilder();
GrStringUtil.parseRegexCharacters(GrStringUtil.removeQuotes(operand.getText()), b, null, operand.getText().startsWith("/"));
GrStringUtil.escapeSymbolsForGString(b, false, false);
}
else if (operand instanceof GrString) {
builder.append(GrStringUtil.removeQuotes(operand.getText()));
}
else if (operand instanceof GrLiteral) {
final String text = GrStringUtil.removeQuotes(operand.getText());
Object value = ((GrLiteral)operand).getValue();
if (value == null) {
value = GrStringUtil.removeQuotes(operand.getText());
}
String text = value.toString();
StringBuilder buffer = new StringBuilder(text.length());
boolean containsLineFeeds = text.indexOf('\n') >= 0 || text.indexOf('\r') >= 0;
GrStringUtil.escapeStringCharacters(text.length(), text, "$", false, false, buffer);
GrStringUtil.escapeStringCharacters(text.length(), text, "$", false, true, buffer);
GrStringUtil.unescapeCharacters(buffer, containsLineFeeds?"'\"":"'", containsLineFeeds);
builder.append(buffer);
}
@@ -164,8 +175,10 @@ public class ConvertConcatenationToGstringIntention extends Intention {
}
public static boolean satisfiedBy(PsiElement element, boolean checkForParent) {
if (element instanceof GrLiteral && element.getText().startsWith("'")) return true;
if (element instanceof GrString || element instanceof GrLiteral && ((GrLiteral)element).getValue() instanceof String) return true;
if (!(element instanceof GrBinaryExpression)) return false;
GrBinaryExpression binaryExpression = (GrBinaryExpression)element;
if (!GroovyTokenTypes.mPLUS.equals(binaryExpression.getOperationTokenType())) return false;
@@ -180,9 +193,8 @@ public class ConvertConcatenationToGstringIntention extends Intention {
final PsiType type = binaryExpression.getType();
if (type == null) return false;
final PsiElementFactory factory = JavaPsiFacade.getElementFactory(element.getProject());
final PsiClassType stringType = TypesUtil.createType(CommonClassNames.JAVA_LANG_STRING, element);
final PsiClassType gstringType = factory.createTypeByFQClassName(GroovyCommonClassNames.GROOVY_LANG_GSTRING, element.getResolveScope());
final PsiClassType gstringType = TypesUtil.createType(GroovyCommonClassNames.GROOVY_LANG_GSTRING, element);
if (!(TypeConversionUtil.isAssignable(stringType, type) || TypeConversionUtil.isAssignable(gstringType, type))) return false;
return true;
@@ -242,13 +242,17 @@ public class GrStringUtil {
buffer.append(hexCode);
}
public static String escapeSymbolsForGString(String s, boolean isSingleLine, boolean forInjection) {
public static String escapeSymbolsForGString(CharSequence s, boolean isSingleLine, boolean forInjection) {
StringBuilder b = new StringBuilder();
escapeSymbolsForGString(s, isSingleLine, forInjection, b);
return b.toString();
}
private static void escapeSymbolsForGString(CharSequence s, boolean isSingleLine, boolean forInjection, StringBuilder b) {
escapeStringCharacters(s.length(), s, isSingleLine ? "$\"" : "$", isSingleLine, true, b);
if (!forInjection) {
unescapeCharacters(b, isSingleLine ? "'" : "'\"", true);
}
return b.toString();
}
public static String escapeSymbolsForString(String s, boolean isSingleLine, boolean forInjection) {
@@ -262,7 +266,7 @@ public class GrStringUtil {
@NotNull
public static StringBuilder escapeStringCharacters(int length,
@NotNull String str,
@NotNull CharSequence str,
@Nullable String additionalChars,
boolean escapeLineFeeds,
boolean escapeBackSlash,
@@ -0,0 +1,81 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.groovy.intentions;
import com.intellij.openapi.module.Module
import com.intellij.openapi.roots.ContentEntry
import com.intellij.openapi.roots.ModifiableRootModel
import com.intellij.openapi.roots.OrderRootType
import com.intellij.openapi.roots.libraries.Library
import com.intellij.openapi.vfs.JarFileSystem
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.testFramework.LightProjectDescriptor
import com.intellij.testFramework.fixtures.DefaultLightProjectDescriptor
import org.jetbrains.annotations.NotNull
import org.jetbrains.plugins.groovy.util.TestUtils
/**
* @author Maxim.Medvedev
*/
public class ConvertConcatenationToGstringTest extends GrIntentionTestCase {
private static final String CONVERT_TO_GSTRING = "Convert to GString";
@NotNull
@Override
protected LightProjectDescriptor getProjectDescriptor() {
return new DefaultLightProjectDescriptor() {
@Override
public void configureModule(Module module, ModifiableRootModel model, ContentEntry contentEntry) {
final Library.ModifiableModel modifiableModel = model.moduleLibraryTable.createLibrary("GROOVY").modifiableModel;
final VirtualFile groovyJar = JarFileSystem.instance.refreshAndFindFileByPath(TestUtils.mockGroovy1_7LibraryName + "!/");
modifiableModel.addRoot(groovyJar, OrderRootType.CLASSES);
modifiableModel.commit();
}
};
}
@Override
protected String getBasePath() {
return "${TestUtils.testDataPath}intentions/convertConcatenationToGstring/";
}
public void testSimpleCase() throws Exception {
doTest(CONVERT_TO_GSTRING, true);
}
public void testVeryComplicatedCase() throws Exception {
doTest(CONVERT_TO_GSTRING, true);
}
public void testQuotes() throws Exception {
doTest(CONVERT_TO_GSTRING, true);
}
public void testQuotes2() throws Exception {
doTest(CONVERT_TO_GSTRING, true);
}
public void _testQuotesInMultilineString() throws Exception {
doTest(CONVERT_TO_GSTRING, true);
}
public void testDot() {
doTest(CONVERT_TO_GSTRING, true);
}
}
@@ -1,80 +0,0 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.groovy.intentions;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.roots.ContentEntry;
import com.intellij.openapi.roots.ModifiableRootModel;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.vfs.JarFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.testFramework.LightProjectDescriptor;
import com.intellij.testFramework.fixtures.DefaultLightProjectDescriptor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.util.TestUtils;
/**
* @author Maxim.Medvedev
*/
public class ConvertConcatenationToGstringTest extends GrIntentionTestCase {
private static final String CONVERT_TO_GSTRING = "Convert to GString";
@NotNull
@Override
protected LightProjectDescriptor getProjectDescriptor() {
return new DefaultLightProjectDescriptor() {
@Override
public void configureModule(Module module, ModifiableRootModel model, ContentEntry contentEntry) {
final Library.ModifiableModel modifiableModel = model.getModuleLibraryTable().createLibrary("GROOVY").getModifiableModel();
final VirtualFile groovyJar = JarFileSystem.getInstance().refreshAndFindFileByPath(TestUtils.getMockGroovy1_7LibraryName() + "!/");
modifiableModel.addRoot(groovyJar, OrderRootType.CLASSES);
modifiableModel.commit();
}
};
}
@Override
protected String getBasePath() {
return TestUtils.getTestDataPath() + "intentions/convertConcatenationToGstring/";
}
public void testSimpleCase() throws Exception {
doTest(CONVERT_TO_GSTRING, true);
}
public void testVeryComplicatedCase() throws Exception {
doTest(CONVERT_TO_GSTRING, true);
}
public void testQuotes() throws Exception {
doTest(CONVERT_TO_GSTRING, true);
}
public void testQuotes2() throws Exception {
doTest(CONVERT_TO_GSTRING, true);
}
public void testQuotesInMultilineString() throws Exception {
doTest(CONVERT_TO_GSTRING, true);
}
public void testDot() {
doTest(CONVERT_TO_GSTRING, true);
}
}