Merge branch 'bug-1425'

This commit is contained in:
Andreas Dangel
2015-10-16 12:36:06 +02:00
11 changed files with 185 additions and 31 deletions

View File

@ -104,6 +104,35 @@ public class ASTLiteral extends AbstractJavaTypeNode {
return isString;
}
/**
* Tries to reconstruct the original string literal.
* If the original length is greater than the parsed String literal, then
* probably some unicode escape sequences have been used.
*
* @return
*/
public String getEscapedStringLiteral() {
String image = getImage();
if (!isStringLiteral() && !isCharLiteral()) {
return image;
}
int fullLength = getEndColumn() - getBeginColumn();
if (fullLength > image.length()) {
StringBuilder result = new StringBuilder(fullLength);
for (int i = 0; i < image.length(); i++) {
char c = image.charAt(i);
if (c < 0x20 || c > 0xff || image.length() == 1) {
String hex = "0000" + Integer.toHexString(c);
result.append("\\u").append(hex.substring(hex.length() - 4));
} else {
result.append(c);
}
}
return result.toString();
}
return image;
}
/**
* Returns true if this is a String literal with only one character.
* Handles octal and escape characters.

View File

@ -143,9 +143,11 @@ public class AvoidDuplicateLiteralsRule extends AbstractJavaRule {
for (Map.Entry<String, List<ASTLiteral>> entry : literals.entrySet()) {
List<ASTLiteral> occurrences = entry.getValue();
if (occurrences.size() >= threshold) {
Object[] args = new Object[] { entry.getKey(), Integer.valueOf(occurrences.size()),
Integer.valueOf(occurrences.get(0).getBeginLine()) };
addViolation(data, occurrences.get(0), args);
ASTLiteral first = occurrences.get(0);
String rawImage = first.getEscapedStringLiteral();
Object[] args = new Object[] { rawImage, Integer.valueOf(occurrences.size()),
Integer.valueOf(first.getBeginLine()) };
addViolation(data, first, args);
}
}
}

View File

@ -1,5 +1,6 @@
package net.sourceforge.pmd.lang.java.ast;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@ -54,6 +55,50 @@ public class ASTLiteralTest extends ParserTst {
assertTrue(((ASTLiteral)(literals.iterator().next())).isCharLiteral());
}
@Test
public void testStringUnicodeEscapesNotEscaped() {
ASTLiteral literal = new ASTLiteral(1);
literal.setStringLiteral();
literal.setImage("abcüabc");
literal.testingOnly__setBeginColumn(1);
literal.testingOnly__setEndColumn(7);
assertEquals("abcüabc", literal.getEscapedStringLiteral());
assertEquals("abcüabc", literal.getImage());
}
@Test
public void testStringUnicodeEscapesInvalid() {
ASTLiteral literal = new ASTLiteral(1);
literal.setStringLiteral();
literal.setImage("abc\\uXYZAabc");
literal.testingOnly__setBeginColumn(1);
literal.testingOnly__setEndColumn(12);
assertEquals("abc\\uXYZAabc", literal.getEscapedStringLiteral());
assertEquals("abc\\uXYZAabc", literal.getImage());
}
@Test
public void testStringUnicodeEscapesValid() {
ASTLiteral literal = new ASTLiteral(1);
literal.setStringLiteral();
literal.setImage("abc\u1234abc");
literal.testingOnly__setBeginColumn(1);
literal.testingOnly__setEndColumn(12);
assertEquals("abc\\u1234abc", literal.getEscapedStringLiteral());
assertEquals("abcሴabc", literal.getImage());
}
@Test
public void testCharacterUnicodeEscapesValid() {
ASTLiteral literal = new ASTLiteral(1);
literal.setCharLiteral();
literal.setImage("\u0030");
literal.testingOnly__setBeginColumn(1);
literal.testingOnly__setEndColumn(6);
assertEquals("\\u0030", literal.getEscapedStringLiteral());
assertEquals("0", literal.getImage());
}
private static final String TEST1 =
"public class Foo {" + PMD.EOL +
" String x = \"foo\";" + PMD.EOL +
@ -88,8 +133,4 @@ public class ASTLiteralTest extends ParserTst {
"public class Foo {" + PMD.EOL +
" char x = 'x';" + PMD.EOL +
"}";
public static junit.framework.Test suite() {
return new junit.framework.JUnit4TestAdapter(ASTLiteralTest.class);
}
}

View File

@ -8,19 +8,9 @@ import static org.junit.Assert.assertTrue;
import java.util.Set;
import net.sourceforge.pmd.Rule;
import net.sourceforge.pmd.testframework.SimpleAggregatorTst;
import org.junit.Test;
public class AvoidDuplicateLiteralsRuleTest extends SimpleAggregatorTst {
@Test
public void testAll() {
Rule rule = findRule("java-strings", "AvoidDuplicateLiterals");
rule.setProperty(AvoidDuplicateLiteralsRule.THRESHOLD_DESCRIPTOR, 2);
runTests(rule);
}
public class AvoidDuplicateLiteralsRuleTest {
@Test
public void testStringParserEmptyString() {
AvoidDuplicateLiteralsRule.ExceptionParser p = new AvoidDuplicateLiteralsRule.ExceptionParser(',');

View File

@ -12,6 +12,7 @@ public class StringsRulesTest extends SimpleAggregatorTst {
@Override
public void setUp() {
addRule(RULESET, "AppendCharacterWithChar");
addRule(RULESET, "AvoidDuplicateLiterals");
addRule(RULESET, "AvoidStringBufferField");
addRule(RULESET, "ConsecutiveAppendsShouldReuse");
addRule(RULESET, "ConsecutiveLiteralAppends");

View File

@ -165,4 +165,22 @@ public class Foo {
}
]]></code>
</test-code>
<test-code>
<description>#1425 Invalid XML Characters in Output</description>
<expected-problems>1</expected-problems>
<expected-messages>
<message>The String literal "Tokenizer \ud801\udc1ctest" appears 4 times in this file; the first occurrence is on line 2</message>
</expected-messages>
<code><![CDATA[
public class Duplicate {
String s1 = "Tokenizer \ud801\udc1ctest";
String s2 = "Tokenizer \ud801\udc1ctest";
String s3 = "Tokenizer \ud801\udc1ctest";
String s4 = "Tokenizer \ud801\udc1ctest";
char c = '\uffef';
char c\u0030 = 'a';
}
]]></code>
</test-code>
</test-data>