diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/concatenation/Jdk5StringConcatenationPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/concatenation/Jdk5StringConcatenationPredicate.java new file mode 100644 index 000000000000..eedaf39a648c --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/concatenation/Jdk5StringConcatenationPredicate.java @@ -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); + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/concatenation/ReplaceConcatenationWithFormatStringIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/concatenation/ReplaceConcatenationWithFormatStringIntention.java index ff4318730190..6d3a93053003 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/concatenation/ReplaceConcatenationWithFormatStringIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/concatenation/ReplaceConcatenationWithFormatStringIntention.java @@ -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 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 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 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 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); + } } diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/concatenation/string_format/HexadecimalLiteral.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/concatenation/string_format/HexadecimalLiteral.java new file mode 100644 index 000000000000..aceb1a6a60d9 --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/concatenation/string_format/HexadecimalLiteral.java @@ -0,0 +1,3 @@ +class C { + String s = "or not" + 0x10; +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/concatenation/string_format/HexadecimalLiteral_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/concatenation/string_format/HexadecimalLiteral_after.java new file mode 100644 index 000000000000..897397e05dfc --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/concatenation/string_format/HexadecimalLiteral_after.java @@ -0,0 +1,3 @@ +class C { + String s = String.format("or not16"); +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/concatenation/string_format/LineSeparator.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/concatenation/string_format/LineSeparator.java new file mode 100644 index 000000000000..f1700c3f5bde --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/concatenation/string_format/LineSeparator.java @@ -0,0 +1,5 @@ +class C { + void printName(String firstName, String lastName) { + System.out.println( "My first name is " + firstName + " and my last name is " + lastName ); + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/concatenation/string_format/LineSeparator_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/concatenation/string_format/LineSeparator_after.java new file mode 100644 index 000000000000..716953fb69c9 --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/concatenation/string_format/LineSeparator_after.java @@ -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); + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/concatenation/string_format/NumericBinaryExpression.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/concatenation/string_format/NumericBinaryExpression.java new file mode 100644 index 000000000000..bcbf1cc0b52a --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/concatenation/string_format/NumericBinaryExpression.java @@ -0,0 +1,3 @@ +class C { + String s = 1 + 2 + " to be"; +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/concatenation/string_format/NumericBinaryExpression_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/concatenation/string_format/NumericBinaryExpression_after.java new file mode 100644 index 000000000000..c0a0050575b4 --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/concatenation/string_format/NumericBinaryExpression_after.java @@ -0,0 +1,3 @@ +class C { + String s = String.format("%d to be", 1 + 2); +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/concatenation/string_format/Parameters.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/concatenation/string_format/Parameters.java new file mode 100644 index 000000000000..1d7c3331712a --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/concatenation/string_format/Parameters.java @@ -0,0 +1,5 @@ +class C { + String foo(double d, String s) { + return "asdf" + d + ", " + s; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/concatenation/string_format/Parameters_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/concatenation/string_format/Parameters_after.java new file mode 100644 index 000000000000..f06bb490833c --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/concatenation/string_format/Parameters_after.java @@ -0,0 +1,5 @@ +class C { + String foo(double d, String s) { + return String.format("asdf%s, %s", d, s); + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/concatenation/string_format/PercentInLiteral.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/concatenation/string_format/PercentInLiteral.java new file mode 100644 index 000000000000..a22743c29d64 --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/concatenation/string_format/PercentInLiteral.java @@ -0,0 +1,3 @@ +class C { + String s = "10%" + '\''; +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/concatenation/string_format/PercentInLiteral_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/concatenation/string_format/PercentInLiteral_after.java new file mode 100644 index 000000000000..d986b371a45d --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/concatenation/string_format/PercentInLiteral_after.java @@ -0,0 +1,3 @@ +class C { + String s = String.format("10%%'"); +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/concatenation/ReplaceConcatenationWithFormatStringTest.java b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/concatenation/ReplaceConcatenationWithFormatStringTest.java new file mode 100644 index 000000000000..1829e88d69b6 --- /dev/null +++ b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/concatenation/ReplaceConcatenationWithFormatStringTest.java @@ -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"; + } +}