-fix handling of string concatenations starting with a binary expression of a different type

-only enable for jdk5 and higher
-added test
This commit is contained in:
Bas Leijdekkers
2011-05-15 14:28:31 +02:00
parent 064413b817
commit 8e9a8ac43f
13 changed files with 153 additions and 43 deletions
@@ -0,0 +1,35 @@
/*
* Copyright 2003-2011 Dave Griffith, Bas Leijdekkers
*
* 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 com.siyeh.ipp.concatenation;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiUtil;
import com.siyeh.ipp.base.PsiElementPredicate;
import com.siyeh.ipp.psiutils.ConcatenationUtils;
import com.siyeh.ipp.psiutils.ErrorUtil;
class Jdk5StringConcatenationPredicate implements PsiElementPredicate {
public boolean satisfiedBy(PsiElement element) {
if (!PsiUtil.isLanguageLevel5OrHigher(element)) {
return false;
}
if(!ConcatenationUtils.isConcatenation(element)) {
return false;
}
return !ErrorUtil.containsError(element);
}
}
@@ -31,7 +31,7 @@ public class ReplaceConcatenationWithFormatStringIntention
@Override
@NotNull
protected PsiElementPredicate getElementPredicate() {
return new SimpleStringConcatenationPredicate(true);
return new Jdk5StringConcatenationPredicate();
}
@Override
@@ -128,50 +128,49 @@ public class ReplaceConcatenationWithFormatStringIntention
return true;
}
void buildFormatString(PsiBinaryExpression expression,
StringBuilder formatString,
List<PsiExpression> formatParameters) {
final PsiExpression lhs = expression.getLOperand();
appendFormatString(lhs, formatString, formatParameters);
final PsiExpression rhs = expression.getROperand();
if (rhs != null) {
appendFormatString(rhs, formatString, formatParameters);
private static void buildFormatString(
PsiExpression expression, StringBuilder formatString,
List<PsiExpression> formatParameters) {
if (expression instanceof PsiLiteralExpression) {
final PsiLiteralExpression literalExpression =
(PsiLiteralExpression) expression;
final Object value = literalExpression.getValue();
final String text =
String.valueOf(value).replace("%", "%%").replace(
"\\'", "'");
formatString.append(text);
} else if (expression instanceof PsiBinaryExpression) {
final PsiType type = expression.getType();
if (type != null && type.equalsToText("java.lang.String")) {
final PsiBinaryExpression binaryExpression =
(PsiBinaryExpression) expression;
final PsiExpression lhs = binaryExpression.getLOperand();
buildFormatString(lhs, formatString, formatParameters);
final PsiExpression rhs = binaryExpression.getROperand();
if (rhs != null) {
buildFormatString(rhs, formatString, formatParameters);
}
} else {
addFormatParameter(expression, formatString, formatParameters);
}
} else {
addFormatParameter(expression, formatString, formatParameters);
}
}
private void appendFormatString(PsiExpression lhs,
StringBuilder formatString,
List<PsiExpression> formatParameters) {
if (lhs instanceof PsiLiteralExpression) {
final String text = lhs.getText();
final int length = text.length();
final PsiType type = lhs.getType();
if (type != null && (type.equalsToText("java.lang.String") ||
type.equalsToText("char"))) {
if (length > 2) {
formatString.append(
text.substring(1, length - 1).replace("%", "%%")
.replace("\\'", "'"));
}
} else {
formatString.append(text);
}
} else if (lhs instanceof PsiBinaryExpression) {
final PsiBinaryExpression binaryExpression =
(PsiBinaryExpression) lhs;
buildFormatString(binaryExpression, formatString, formatParameters);
} else {
final PsiType type = lhs.getType();
if (type != null &&
(type.equalsToText("long") ||
type.equalsToText("int") ||
type.equalsToText("java.lang.Long") ||
type.equalsToText("java.lang.Integer"))) {
formatString.append("%d");
} else {
formatString.append("%s");
}
formatParameters.add(lhs);
}
private static void addFormatParameter(PsiExpression expression,
StringBuilder formatString,
List<PsiExpression> formatParameters) {
final PsiType type = expression.getType();
if (type != null &&
(type.equalsToText("long") ||
type.equalsToText("int") ||
type.equalsToText("java.lang.Long") ||
type.equalsToText("java.lang.Integer"))) {
formatString.append("%d");
} else {
formatString.append("%s");
}
formatParameters.add(expression);
}
}
@@ -0,0 +1,3 @@
class C {
String s = "or not" <caret>+ 0x10;
}
@@ -0,0 +1,3 @@
class C {
String s = String.format("or not16");
}
@@ -0,0 +1,5 @@
class C {
void printName(String firstName, String lastName) {
System.out.println( "My first name is " <caret>+ firstName + " and my last name is " + lastName );
}
}
@@ -0,0 +1,5 @@
class C {
void printName(String firstName, String lastName) {
System.out.printf("My first name is %s and my last name is %s%n", firstName, lastName);
}
}
@@ -0,0 +1,3 @@
class C {
String s = 1 + 2 +<caret> " to be";
}
@@ -0,0 +1,3 @@
class C {
String s = String.format("%d to be", 1 + 2);
}
@@ -0,0 +1,5 @@
class C {
String foo(double d, String s) {
return "asdf" + d <caret>+ ", " + s;
}
}
@@ -0,0 +1,5 @@
class C {
String foo(double d, String s) {
return String.format("asdf%s, %s", d, s);
}
}
@@ -0,0 +1,3 @@
class C {
String s = "10%" <caret>+ '\'';
}
@@ -0,0 +1,3 @@
class C {
String s = String.format("10%%'");
}
@@ -0,0 +1,38 @@
/*
* Copyright 2011 Bas Leijdekkers
*
* 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 com.siyeh.ipp.concatenation;
import com.siyeh.IntentionPowerPackBundle;
import com.siyeh.ipp.IPPTestCase;
public class ReplaceConcatenationWithFormatStringTest extends IPPTestCase {
public void testNumericBinaryExpression() { doTest(); }
public void testHexadecimalLiteral() { doTest(); }
public void testPercentInLiteral() { doTest(); }
public void testParameters() { doTest(); }
public void testLineSeparator() { doTest(); }
@Override
protected String getIntentionName() {
return IntentionPowerPackBundle.message(
"replace.concatenation.with.format.string.intention.name");
}
@Override
protected String getRelativePath() {
return "concatenation/string_format";
}
}