mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-06 11:50:54 +07:00
Java: fix IOE on replacing single character string operation
GitOrigin-RevId: 26ba697294eebb109148b86672a22e7aa2e921e4
This commit is contained in:
committed by
intellij-monorepo-bot
parent
26bbaa3c5f
commit
e7c55493a1
@@ -101,14 +101,16 @@ public final class PsiLiteralUtil {
|
||||
}
|
||||
}
|
||||
|
||||
// convert text to number according to radix specified
|
||||
// if number is more than maxBits bits long, throws NumberFormatException
|
||||
/**
|
||||
* convert text to number according to radix specified
|
||||
* if number is more than maxBits bits long, throws NumberFormatException
|
||||
*/
|
||||
public static long parseDigits(final String text, final int bitsInRadix, final int maxBits) throws NumberFormatException {
|
||||
final int radix = 1 << bitsInRadix;
|
||||
final int textLength = text.length();
|
||||
if (textLength == 0) {
|
||||
throw new NumberFormatException(text);
|
||||
}
|
||||
final int radix = 1 << bitsInRadix;
|
||||
long integer = textLength == 1 ? 0 : Long.parseLong(text.substring(0, textLength - 1), radix);
|
||||
if ((integer & (-1L << (maxBits - bitsInRadix))) != 0) {
|
||||
throw new NumberFormatException(text);
|
||||
@@ -143,29 +145,29 @@ public final class PsiLiteralUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a string that contains a character (e.g. ""\n"" or ""\\"", etc.)
|
||||
* Convert a string that contains a single character (e.g. ""\n"" or ""\\"", etc.)
|
||||
* to a character literal string (e.g. "'\n'" or "'\\'", etc.)
|
||||
*
|
||||
* @param text a string to convert
|
||||
* @return the converted string
|
||||
* @param expression a single character string
|
||||
* @return the character literal string
|
||||
*/
|
||||
@NotNull
|
||||
public static String charLiteralForCharString(@NotNull final String text) {
|
||||
final int length = text.length();
|
||||
if (length <= 1) return text;
|
||||
|
||||
final String character = text.substring(1, length - 1);
|
||||
final String charLiteral;
|
||||
if ("'".equals(character)) {
|
||||
charLiteral = "'\\''";
|
||||
@Nullable
|
||||
public static String charLiteralString(PsiLiteralExpression expression) {
|
||||
final Object value = expression.getValue();
|
||||
if (!(value instanceof String) || ((CharSequence)value).length() > 1) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
else if ("\\\"".equals(character)) {
|
||||
charLiteral = "'\"'";
|
||||
final String content = expression.isTextBlock()
|
||||
? getTextBlockText(expression)
|
||||
: getStringLiteralContent(expression);
|
||||
if (content == null) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
charLiteral = '\'' + character + '\'';
|
||||
switch (content) {
|
||||
case "'": return "'\\''";
|
||||
case "\\\"": return "'\"'";
|
||||
default: return '\'' + content + '\'';
|
||||
}
|
||||
return charLiteral;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -293,10 +295,9 @@ public final class PsiLiteralUtil {
|
||||
int i = parseBackSlash(s, start);
|
||||
if (i == -1) return -1;
|
||||
int prev = start;
|
||||
int nextIdx;
|
||||
int nSlashes = 1;
|
||||
while (i < s.length()) {
|
||||
nextIdx = parseBackSlash(s, i);
|
||||
int nextIdx = parseBackSlash(s, i);
|
||||
if (nextIdx != -1) {
|
||||
result.append(s, prev, i);
|
||||
prev = i;
|
||||
@@ -517,8 +518,8 @@ public final class PsiLiteralUtil {
|
||||
if (Character.isWhitespace(s.charAt(index))) return index;
|
||||
index = parseUnicodeEscapeBackwards(s, index, Character::isWhitespace);
|
||||
if (index < 0) return -1;
|
||||
int nBackSlashes = 1;
|
||||
index--;
|
||||
int nBackSlashes = 1;
|
||||
if (index >= 0 && s.charAt(index) == '\\') {
|
||||
nBackSlashes++;
|
||||
nBackSlashes += countBackSlashes(s, index - 1);
|
||||
@@ -724,7 +725,6 @@ public final class PsiLiteralUtil {
|
||||
|
||||
curOffset += linePrefixLength;
|
||||
|
||||
int charIdx;
|
||||
int nextIdx = 0;
|
||||
while (true) {
|
||||
if (from == charsSoFar) {
|
||||
@@ -733,7 +733,7 @@ public final class PsiLiteralUtil {
|
||||
if (to == charsSoFar) {
|
||||
return new TextRange(mappedFrom, curOffset + nextIdx);
|
||||
}
|
||||
charIdx = nextIdx;
|
||||
int charIdx = nextIdx;
|
||||
nextIdx = getCharEndIndex(line, charIdx);
|
||||
if (nextIdx == -1) break;
|
||||
charsSoFar++;
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
// "Fix all 'Redundant 'String' operation' problems in file" "true"
|
||||
class X {
|
||||
void x(String message) {
|
||||
boolean underline = message.charAt(1) == '_';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// "Fix all 'Redundant 'String' operation' problems in file" "true"
|
||||
class X {
|
||||
void x(String message) {
|
||||
boolean underline = message.<caret>substring(1, 2).equals("""
|
||||
_""");
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,6 @@ public class RedundantStringOperationInspectionFixTest extends LightQuickFixPara
|
||||
|
||||
@Override
|
||||
protected @NotNull LightProjectDescriptor getProjectDescriptor() {
|
||||
return LightJavaCodeInsightFixtureTestCase.JAVA_11;
|
||||
return LightJavaCodeInsightFixtureTestCase.JAVA_15;
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,8 @@ import com.intellij.codeInspection.CleanupLocalInspectionTool;
|
||||
import com.intellij.codeInspection.ProblemDescriptor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.PsiLiteralExpression;
|
||||
import com.intellij.psi.PsiType;
|
||||
import com.intellij.psi.util.PsiLiteralUtil;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
@@ -43,9 +44,7 @@ public class LengthOneStringsInConcatenationInspection extends BaseInspection im
|
||||
public String buildErrorString(Object... infos) {
|
||||
final String string = (String)infos[0];
|
||||
final String escapedString = StringUtil.escapeStringCharacters(string);
|
||||
return InspectionGadgetsBundle.message(
|
||||
"expression.can.be.replaced.problem.descriptor",
|
||||
escapedString);
|
||||
return InspectionGadgetsBundle.message("expression.can.be.replaced.problem.descriptor", escapedString);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -53,24 +52,24 @@ public class LengthOneStringsInConcatenationInspection extends BaseInspection im
|
||||
return new ReplaceStringsWithCharsFix();
|
||||
}
|
||||
|
||||
private static class ReplaceStringsWithCharsFix
|
||||
extends InspectionGadgetsFix {
|
||||
private static class ReplaceStringsWithCharsFix extends InspectionGadgetsFix {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"length.one.strings.in.concatenation.replace.quickfix");
|
||||
return InspectionGadgetsBundle.message("length.one.strings.in.concatenation.replace.quickfix");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFix(Project project, ProblemDescriptor descriptor) {
|
||||
final PsiExpression expression = (PsiExpression)descriptor.getPsiElement();
|
||||
final PsiLiteralExpression expression = (PsiLiteralExpression)descriptor.getPsiElement();
|
||||
if (ExpressionUtils.isConversionToStringNecessary(expression, false)) {
|
||||
return;
|
||||
}
|
||||
final String text = expression.getText();
|
||||
final String charLiteral = PsiLiteralUtil.charLiteralForCharString(text);
|
||||
final String charLiteral = PsiLiteralUtil.charLiteralString(expression);
|
||||
if (charLiteral == null) {
|
||||
return;
|
||||
}
|
||||
PsiReplacementUtil.replaceExpression(expression, charLiteral);
|
||||
}
|
||||
}
|
||||
@@ -80,8 +79,7 @@ public class LengthOneStringsInConcatenationInspection extends BaseInspection im
|
||||
return new LengthOneStringsInConcatenationVisitor();
|
||||
}
|
||||
|
||||
private static class LengthOneStringsInConcatenationVisitor
|
||||
extends BaseInspectionVisitor {
|
||||
private static class LengthOneStringsInConcatenationVisitor extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitLiteralExpression(@NotNull PsiLiteralExpression expression) {
|
||||
|
||||
@@ -627,8 +627,7 @@ public class RedundantStringOperationInspection extends AbstractBaseJavaLocalIns
|
||||
@NotNull private final String myConverted;
|
||||
private final boolean myEquality;
|
||||
|
||||
SubstringToCharAtQuickFix(@NotNull final String text,
|
||||
final @NotNull String converted, boolean equality) {
|
||||
SubstringToCharAtQuickFix(@NotNull final String text, final @NotNull String converted, boolean equality) {
|
||||
myText = text;
|
||||
myConverted = converted;
|
||||
myEquality = equality;
|
||||
@@ -683,7 +682,7 @@ public class RedundantStringOperationInspection extends AbstractBaseJavaLocalIns
|
||||
}
|
||||
|
||||
private static @NonNls @Nullable String getTargetString(@NotNull final PsiMethodCallExpression call,
|
||||
@NotNull Function<@NotNull PsiElement, @NotNull String> textExtractor) {
|
||||
@NotNull Function<@NotNull PsiElement, @NotNull String> textExtractor) {
|
||||
final PsiMethodCallExpression qualifierCall = MethodCallUtils.getQualifierMethodCall(call);
|
||||
if (qualifierCall == null) return null;
|
||||
|
||||
@@ -693,23 +692,18 @@ public class RedundantStringOperationInspection extends AbstractBaseJavaLocalIns
|
||||
final PsiExpression[] args = qualifierCall.getArgumentList().getExpressions();
|
||||
if (args.length != 2) return null;
|
||||
|
||||
final PsiExpression equalTo = call.getArgumentList().getExpressions()[0];
|
||||
|
||||
final String eqSign = isNegated(call, false) ? "!=" : "==";
|
||||
|
||||
final String equalToValue = PsiLiteralUtil.charLiteralForCharString(textExtractor.apply(equalTo));
|
||||
|
||||
final PsiLiteralExpression equalTo = (PsiLiteralExpression)call.getArgumentList().getExpressions()[0];
|
||||
final String equalToValue = PsiLiteralUtil.charLiteralString(equalTo);
|
||||
return String.format("%s.charAt(%s) %s %s",
|
||||
textExtractor.apply(receiver),
|
||||
textExtractor.apply(args[0]),
|
||||
eqSign,
|
||||
isNegated(call, false) ? "!=" : "==",
|
||||
equalToValue
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class RemoveRedundantChangeCaseFix implements LocalQuickFix {
|
||||
private final @NotNull String caseRedundant;
|
||||
private final @NotNull PlaceCaseEqualType myPlaceCaseEqualType;
|
||||
@@ -916,14 +910,9 @@ public class RedundantStringOperationInspection extends AbstractBaseJavaLocalIns
|
||||
private final @IntentionName String myName;
|
||||
|
||||
private StringConstructorFix(boolean noArguments) {
|
||||
if (noArguments) {
|
||||
myName = InspectionGadgetsBundle.message(
|
||||
"inspection.redundant.string.replace.with.empty.fix.name");
|
||||
}
|
||||
else {
|
||||
myName = InspectionGadgetsBundle.message(
|
||||
"inspection.redundant.string.replace.with.arg.fix.name");
|
||||
}
|
||||
myName = noArguments
|
||||
? InspectionGadgetsBundle.message("inspection.redundant.string.replace.with.empty.fix.name")
|
||||
: InspectionGadgetsBundle.message("inspection.redundant.string.replace.with.arg.fix.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -9,44 +9,43 @@ import com.siyeh.ig.performance.LengthOneStringsInConcatenationInspection;
|
||||
/**
|
||||
* @author Fabrice TIERCELIN
|
||||
*/
|
||||
@SuppressWarnings("SingleCharacterStringConcatenation")
|
||||
public class LengthOneStringsInConcatenationFixTest extends IGQuickFixesTestCase {
|
||||
@SuppressWarnings("SingleCharacterStringConcatenation")
|
||||
public void testFirstConcatenationOperand() {
|
||||
doExpressionTest(InspectionGadgetsBundle.message("length.one.strings.in.concatenation.replace.quickfix"),
|
||||
"\"f\"/**/ + \"bar\"", "'f' + \"bar\"");
|
||||
}
|
||||
|
||||
@SuppressWarnings("SingleCharacterStringConcatenation")
|
||||
public void testSecondConcatenationOperand() {
|
||||
doExpressionTest(InspectionGadgetsBundle.message("length.one.strings.in.concatenation.replace.quickfix"),
|
||||
"\"foo\" + /**/\"b\"", "\"foo\" + 'b'");
|
||||
}
|
||||
|
||||
@SuppressWarnings("SingleCharacterStringConcatenation")
|
||||
public void testThirdConcatenationOperand() {
|
||||
doExpressionTest(InspectionGadgetsBundle.message("length.one.strings.in.concatenation.replace.quickfix"),
|
||||
"\"foo\" + 1 + /**/\"c\"", "\"foo\" + 1 + 'c'");
|
||||
}
|
||||
|
||||
@SuppressWarnings("SingleCharacterStringConcatenation")
|
||||
public void testAppendMethodParameter() {
|
||||
doExpressionTest(InspectionGadgetsBundle.message("length.one.strings.in.concatenation.replace.quickfix"),
|
||||
"new StringBuilder().append(/**/\"c\")", "new StringBuilder().append('c')");
|
||||
}
|
||||
|
||||
@SuppressWarnings("SingleCharacterStringConcatenation")
|
||||
public void testNewLine() {
|
||||
doExpressionTest(InspectionGadgetsBundle.message("length.one.strings.in.concatenation.replace.quickfix"),
|
||||
"\"\\n\"/**/ + \"bar\"", "'\\n' + \"bar\"");
|
||||
}
|
||||
|
||||
@SuppressWarnings("SingleCharacterStringConcatenation")
|
||||
public void testTextBlock() {
|
||||
doExpressionTest(InspectionGadgetsBundle.message("length.one.strings.in.concatenation.replace.quickfix"),
|
||||
"\"string\" + /**/\"\"\"\n !\"\"\"", "\"string\" + '!'");
|
||||
}
|
||||
|
||||
public void testQuote() {
|
||||
doExpressionTest(InspectionGadgetsBundle.message("length.one.strings.in.concatenation.replace.quickfix"),
|
||||
"\"\\'\"/**/ + \"bar\"", "'\\'' + \"bar\"");
|
||||
}
|
||||
|
||||
@SuppressWarnings("SingleCharacterStringConcatenation")
|
||||
public void testDoubleQuote() {
|
||||
doExpressionTest(InspectionGadgetsBundle.message("length.one.strings.in.concatenation.replace.quickfix"),
|
||||
"\"\\\"\"/**/ + \"bar\"", "'\"' + \"bar\"");
|
||||
|
||||
Reference in New Issue
Block a user