This commit is contained in:
Clément Fournier
2022-03-07 19:59:50 +01:00
parent dee330293f
commit 3b8d7a32a7
8 changed files with 119 additions and 104 deletions

View File

@ -23,15 +23,17 @@ public final class CharStreamFactory {
/**
* A char stream that doesn't perform any escape translation.
*/
public static CharStream simpleCharStream(Reader input) {
public static CharStream simpleCharStream(Reader input) throws IOException {
return simpleCharStream(input, JavaccTokenDocument::new);
}
/**
* A char stream that doesn't perform any escape translation.
*/
public static CharStream simpleCharStream(Reader input, Function<? super TextDocument, ? extends JavaccTokenDocument> documentMaker) {
String source = toString(input);
public static CharStream simpleCharStream(Reader input,
Function<? super TextDocument, ? extends JavaccTokenDocument> documentMaker)
throws IOException {
String source = IOUtils.toString(input);
JavaccTokenDocument document = documentMaker.apply(TextDocument.readOnlyString(source, CpdCompat.dummyVersion()));
return new SimpleCharStream(document);
}
@ -39,31 +41,18 @@ public final class CharStreamFactory {
/**
* A char stream that translates java unicode sequences.
*/
public static CharStream javaCharStream(Reader input) {
public static CharStream javaCharStream(Reader input) throws IOException {
return javaCharStream(input, JavaccTokenDocument::new);
}
/**
* A char stream that translates java unicode sequences.
*/
public static CharStream javaCharStream(Reader input, Function<? super TextDocument, ? extends JavaccTokenDocument> documentMaker) {
String source = toString(input);
public static CharStream javaCharStream(Reader input, Function<? super TextDocument, ? extends JavaccTokenDocument> documentMaker)
throws IOException {
String source = IOUtils.toString(input);
JavaccTokenDocument tokens = documentMaker.apply(TextDocument.readOnlyString(source, CpdCompat.dummyVersion()));
return new JavaCharStream(tokens);
}
/**
* @deprecated This shouldn't be used. IOExceptions should be handled properly,
* ie it should be expected that creating a parse may throw an IOException,
* in both CPD and PMD
*/
@Deprecated
public static String toString(Reader dstream) {
try (Reader r = dstream) {
return IOUtils.toString(r);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -119,8 +119,7 @@ public final class TextRegion implements Comparable<TextRegion> {
* characters before this region. If the delta is negative, then this
* shifts the start of the region to the right (but the end stays fixed).
*
* @throws AssertionError If startOffset - delta is negative
* @throws AssertionError If delta is negative and the
* @throws AssertionError If the parameter cannot produce a valid region
*/
public TextRegion growLeft(int delta) {
assert (delta + length) >= 0 : "Left delta " + delta + " would produce a negative length region" + parThis();
@ -148,8 +147,7 @@ public final class TextRegion implements Comparable<TextRegion> {
*
* @return The intersection, if it exists
*/
@Nullable
public static TextRegion intersect(TextRegion r1, TextRegion r2) {
public static @Nullable TextRegion intersect(TextRegion r1, TextRegion r2) {
int start = Math.max(r1.getStartOffset(), r2.getStartOffset());
int end = Math.min(r1.getEndOffset(), r2.getEndOffset());

View File

@ -5,12 +5,18 @@
package net.sourceforge.pmd.lang.document;
import static net.sourceforge.pmd.util.CollectionUtil.listOf;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.io.StringWriter;
import java.util.List;
import org.junit.Assert;
import org.junit.Test;
import net.sourceforge.pmd.util.CollectionUtil;
@ -23,46 +29,46 @@ public class CharsTest {
@Test
public void wrapStringRoundTrip() {
String s = "ooo";
Assert.assertSame(s, Chars.wrap(s).toString());
assertSame(s, Chars.wrap(s).toString());
}
@Test
public void wrapCharsRoundTrip() {
Chars s = Chars.wrap("ooo");
Assert.assertSame(s, Chars.wrap(s));
assertSame(s, Chars.wrap(s));
}
@Test
public void appendChars() {
StringBuilder sb = new StringBuilder();
Chars bc = Chars.wrap("abcd").slice(1, 2);
Assert.assertEquals("bc", bc.toString());
assertEquals("bc", bc.toString());
bc.appendChars(sb);
Assert.assertEquals("bc", sb.toString());
assertEquals("bc", sb.toString());
}
@Test
public void appendCharsWithOffsets() {
StringBuilder sb = new StringBuilder();
Chars bc = Chars.wrap("abcd").slice(1, 2);
Assert.assertEquals("bc", bc.toString());
assertEquals("bc", bc.toString());
bc.appendChars(sb, 0, 1);
Assert.assertEquals("b", sb.toString());
assertEquals("b", sb.toString());
}
@Test
public void write() throws IOException {
StringWriter writer = new StringWriter();
Chars bc = Chars.wrap("abcd").slice(1, 2);
Assert.assertEquals("bc", bc.toString());
assertEquals("bc", bc.toString());
bc.write(writer, 0, 1);
Assert.assertEquals("b", writer.toString());
assertEquals("b", writer.toString());
writer = new StringWriter();
bc.writeFully(writer);
Assert.assertEquals("bc", writer.toString());
assertEquals("bc", writer.toString());
}
@Test
@ -71,97 +77,97 @@ public class CharsTest {
Chars bc = Chars.wrap("abcd").slice(1, 2);
bc.getChars(0, arr, 1, 2);
Assert.assertArrayEquals(arr, new char[] {0, 'b', 'c', 0});
assertArrayEquals(arr, new char[] {0, 'b', 'c', 0});
Assert.assertThrows(IndexOutOfBoundsException.class, () -> bc.getChars(2, arr, 0, 1));
Assert.assertThrows(IndexOutOfBoundsException.class, () -> bc.getChars(-1, arr, 0, 1));
Assert.assertThrows(IndexOutOfBoundsException.class, () -> bc.getChars(0, arr, 0, 3));
Assert.assertThrows(IndexOutOfBoundsException.class, () -> bc.getChars(0, arr, 4, 3));
Assert.assertThrows(NullPointerException.class, () -> bc.getChars(0, null, 0, 0));
assertThrows(IndexOutOfBoundsException.class, () -> bc.getChars(2, arr, 0, 1));
assertThrows(IndexOutOfBoundsException.class, () -> bc.getChars(-1, arr, 0, 1));
assertThrows(IndexOutOfBoundsException.class, () -> bc.getChars(0, arr, 0, 3));
assertThrows(IndexOutOfBoundsException.class, () -> bc.getChars(0, arr, 4, 3));
assertThrows(NullPointerException.class, () -> bc.getChars(0, null, 0, 0));
}
@Test
public void indexOf() {
Chars bc = Chars.wrap("aaaaabcdb").slice(5, 2);
// --
Assert.assertEquals(0, bc.indexOf('b', 0));
Assert.assertEquals(1, bc.indexOf('c', 0));
assertEquals(0, bc.indexOf('b', 0));
assertEquals(1, bc.indexOf('c', 0));
Assert.assertEquals(-1, bc.indexOf('b', 1));
Assert.assertEquals(-1, bc.indexOf('d', 0));
assertEquals(-1, bc.indexOf('b', 1));
assertEquals(-1, bc.indexOf('d', 0));
Assert.assertEquals(-1, bc.indexOf('x', 0));
Assert.assertEquals(-1, bc.indexOf('a', -1));
assertEquals(-1, bc.indexOf('x', 0));
assertEquals(-1, bc.indexOf('a', -1));
}
@Test
public void indexOfString() {
Chars bc = Chars.wrap("aaaaabcdb").slice(5, 2);
// --
Assert.assertEquals(0, bc.indexOf("b", 0));
Assert.assertEquals(0, bc.indexOf("bc", 0));
Assert.assertEquals(1, bc.indexOf("c", 0));
assertEquals(0, bc.indexOf("b", 0));
assertEquals(0, bc.indexOf("bc", 0));
assertEquals(1, bc.indexOf("c", 0));
Assert.assertEquals(-1, bc.indexOf("b", 1));
Assert.assertEquals(-1, bc.indexOf("bc", 1));
Assert.assertEquals(-1, bc.indexOf("d", 0));
Assert.assertEquals(-1, bc.indexOf("bcd", 0));
assertEquals(-1, bc.indexOf("b", 1));
assertEquals(-1, bc.indexOf("bc", 1));
assertEquals(-1, bc.indexOf("d", 0));
assertEquals(-1, bc.indexOf("bcd", 0));
Assert.assertEquals(-1, bc.indexOf("x", 0));
Assert.assertEquals(-1, bc.indexOf("ab", -1));
assertEquals(-1, bc.indexOf("x", 0));
assertEquals(-1, bc.indexOf("ab", -1));
bc = Chars.wrap("aaaaabcdbxdb").slice(5, 5);
// -----
Assert.assertEquals(3, bc.indexOf("bx", 0));
assertEquals(3, bc.indexOf("bx", 0));
bc = Chars.wrap("aaaaabcbxdb").slice(5, 5);
// -----
Assert.assertEquals(2, bc.indexOf("bx", 0));
assertEquals(2, bc.indexOf("bx", 0));
}
@Test
public void startsWith() {
Chars bc = Chars.wrap("abcdb").slice(1, 2);
Assert.assertTrue(bc.startsWith("bc"));
Assert.assertTrue(bc.startsWith("bc", 0));
Assert.assertTrue(bc.startsWith("c", 1));
Assert.assertTrue(bc.startsWith('c', 1)); //with a char
Assert.assertTrue(bc.startsWith("", 1));
Assert.assertTrue(bc.startsWith("", 0));
assertTrue(bc.startsWith("bc"));
assertTrue(bc.startsWith("bc", 0));
assertTrue(bc.startsWith("c", 1));
assertTrue(bc.startsWith('c', 1)); //with a char
assertTrue(bc.startsWith("", 1));
assertTrue(bc.startsWith("", 0));
Assert.assertFalse(bc.startsWith("c", 0));
Assert.assertFalse(bc.startsWith('c', 0)); //with a char
assertFalse(bc.startsWith("c", 0));
assertFalse(bc.startsWith('c', 0)); //with a char
Assert.assertFalse(bc.startsWith("bcd", 0));
Assert.assertFalse(bc.startsWith("xcd", 0));
assertFalse(bc.startsWith("bcd", 0));
assertFalse(bc.startsWith("xcd", 0));
Assert.assertFalse(bc.startsWith("b", -1));
Assert.assertFalse(bc.startsWith('b', -1)); //with a char
assertFalse(bc.startsWith("b", -1));
assertFalse(bc.startsWith('b', -1)); //with a char
Assert.assertFalse(bc.startsWith("", -1));
Assert.assertFalse(bc.startsWith("", 5));
assertFalse(bc.startsWith("", -1));
assertFalse(bc.startsWith("", 5));
}
@Test
public void trimNoop() {
Chars bc = Chars.wrap("abcdb").slice(1, 2);
Assert.assertEquals("bc", bc.toString());
Assert.assertEquals("bc", bc.trimStart().toString());
Assert.assertEquals("bc", bc.trimEnd().toString());
Assert.assertEquals("bc", bc.trim().toString());
assertEquals("bc", bc.toString());
assertEquals("bc", bc.trimStart().toString());
assertEquals("bc", bc.trimEnd().toString());
assertEquals("bc", bc.trim().toString());
}
@Test
public void trimStartAndEnd() {
Chars bc = Chars.wrap("a bc db").slice(1, 6);
// ------
Assert.assertEquals(" bc ", bc.toString());
Assert.assertEquals("bc ", bc.trimStart().toString());
Assert.assertEquals(" bc", bc.trimEnd().toString());
Assert.assertEquals("bc", bc.trim().toString());
assertEquals(" bc ", bc.toString());
assertEquals("bc ", bc.trimStart().toString());
assertEquals(" bc", bc.trimEnd().toString());
assertEquals("bc", bc.trim().toString());
}
@Test
@ -169,12 +175,12 @@ public class CharsTest {
Chars bc = Chars.wrap("a bc db").slice(1, 6);
// ------
Assert.assertEquals(' ', bc.charAt(0));
Assert.assertEquals('b', bc.charAt(3));
Assert.assertEquals('c', bc.charAt(4));
Assert.assertEquals(' ', bc.charAt(5));
Assert.assertThrows(IndexOutOfBoundsException.class, () -> bc.charAt(-1));
Assert.assertThrows(IndexOutOfBoundsException.class, () -> bc.charAt(7));
assertEquals(' ', bc.charAt(0));
assertEquals('b', bc.charAt(3));
assertEquals('c', bc.charAt(4));
assertEquals(' ', bc.charAt(5));
assertThrows(IndexOutOfBoundsException.class, () -> bc.charAt(-1));
assertThrows(IndexOutOfBoundsException.class, () -> bc.charAt(7));
}
@Test
@ -183,7 +189,14 @@ public class CharsTest {
Chars bc = Chars.wrap("a \n \r\nbc db").slice(1, 9);
// ------------
List<String> lines = CollectionUtil.map(bc.lines(), Chars::toString);
Assert.assertEquals(listOf(" ", " ", "bc "), lines);
assertEquals(listOf(" ", " ", "bc "), lines);
}
@Test
public void linesTest2() {
Chars bc = Chars.wrap("aa\n");
List<String> lines = CollectionUtil.map(bc.lines(), Chars::toString);
assertEquals(listOf("aa"), lines);
}
@Test
@ -192,14 +205,14 @@ public class CharsTest {
Chars chars = Chars.wrap("a_a_b_c_s").slice(2, 5);
// -----
Assert.assertEquals(Chars.wrap("a_b_c"), chars);
Assert.assertNotEquals("a_b_c", chars);
assertEquals(Chars.wrap("a_b_c"), chars);
assertNotEquals("a_b_c", chars);
Assert.assertEquals(Chars.wrap("a_b_c").hashCode(), chars.hashCode());
Assert.assertEquals(chars, chars);
assertEquals(Chars.wrap("a_b_c").hashCode(), chars.hashCode());
assertEquals(chars, chars);
Assert.assertEquals("a_b_c".hashCode(), Chars.wrap("a_b_c").hashCode());
Assert.assertEquals("a_b_c".hashCode(), chars.hashCode());
assertEquals("a_b_c".hashCode(), Chars.wrap("a_b_c").hashCode());
assertEquals("a_b_c".hashCode(), chars.hashCode());
}
@ -209,14 +222,14 @@ public class CharsTest {
Chars chars = Chars.wrap("a_a_b_c_s").slice(2, 5);
// -----
Assert.assertTrue(chars.contentEquals("a_b_c"));
Assert.assertTrue(chars.contentEquals(Chars.wrap("a_b_c")));
assertTrue(chars.contentEquals("a_b_c"));
assertTrue(chars.contentEquals(Chars.wrap("a_b_c")));
Assert.assertFalse(chars.contentEquals("a_b_c_--"));
Assert.assertFalse(chars.contentEquals(Chars.wrap("a_b_c_")));
Assert.assertFalse(chars.contentEquals(Chars.wrap("a_b-c")));
assertFalse(chars.contentEquals("a_b_c_--"));
assertFalse(chars.contentEquals(Chars.wrap("a_b_c_")));
assertFalse(chars.contentEquals(Chars.wrap("a_b-c")));
Assert.assertTrue(chars.contentEquals(Chars.wrap("A_B_C"), true));
assertTrue(chars.contentEquals(Chars.wrap("A_B_C"), true));
}
}

View File

@ -5,6 +5,7 @@
package net.sourceforge.pmd.lang.document;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;
import org.junit.Rule;
import org.junit.Test;
@ -139,6 +140,19 @@ public class TextDocumentTest {
assertEquals(1 + "bonjour".length(), withLines.getEndColumn());
}
@Test
public void testLineRange() {
TextDocument doc = TextDocument.readOnlyString("bonjour\noha\ntristesse", dummyVersion);
assertEquals(Chars.wrap("bonjour\n"), doc.sliceText(doc.createLineRange(1, 1)));
assertEquals(Chars.wrap("bonjour\noha\n"), doc.sliceText(doc.createLineRange(1, 2)));
assertEquals(Chars.wrap("oha\n"), doc.sliceText(doc.createLineRange(2, 2)));
assertEquals(Chars.wrap("oha\ntristesse"), doc.sliceText(doc.createLineRange(2, 3)));
assertThrows(IndexOutOfBoundsException.class, () -> doc.createLineRange(2, 1));
assertThrows(IndexOutOfBoundsException.class, () -> doc.createLineRange(1, 5));
assertThrows(IndexOutOfBoundsException.class, () -> doc.createLineRange(0, 2));
}
@Test
public void testRegionOutOfBounds() {
TextDocument doc = TextDocument.readOnlyString("bonjour\noha\ntristesse", dummyVersion);

View File

@ -86,7 +86,7 @@ public class CPPTokenizer extends JavaCCTokenizer {
@Override
protected CharStream makeCharStream(Reader sourceCode) {
protected CharStream makeCharStream(Reader sourceCode) throws IOException {
return CppCharStream.newCppCharStream(sourceCode);
}

View File

@ -8,9 +8,9 @@ import java.io.IOException;
import java.io.Reader;
import java.util.regex.Pattern;
import org.apache.commons.io.IOUtils;
import org.checkerframework.checker.nullness.qual.Nullable;
import net.sourceforge.pmd.lang.ast.impl.javacc.CharStreamFactory;
import net.sourceforge.pmd.lang.ast.impl.javacc.JavaccTokenDocument;
import net.sourceforge.pmd.lang.ast.impl.javacc.SimpleCharStream;
import net.sourceforge.pmd.lang.document.CpdCompat;
@ -67,8 +67,8 @@ public class CppCharStream extends SimpleCharStream {
return CONTINUATION.matcher(image).replaceAll("");
}
public static CppCharStream newCppCharStream(Reader dstream) {
String source = CharStreamFactory.toString(dstream);
public static CppCharStream newCppCharStream(Reader dstream) throws IOException {
String source = IOUtils.toString(dstream);
JavaccTokenDocument document = new JavaccTokenDocument(TextDocument.readOnlyString(source, CpdCompat.dummyVersion())) {
@Override
protected @Nullable String describeKindImpl(int kind) {

View File

@ -44,7 +44,7 @@ public class JavaTokenizer extends JavaCCTokenizer {
}
@Override
protected CharStream makeCharStream(Reader sourceCode) {
protected CharStream makeCharStream(Reader sourceCode) throws IOException {
return CharStreamFactory.javaCharStream(sourceCode, InternalApiBridge::javaTokenDoc);
}

View File

@ -4,6 +4,7 @@
package net.sourceforge.pmd.cpd;
import java.io.IOException;
import java.io.Reader;
import java.util.regex.Pattern;
@ -31,7 +32,7 @@ public class PythonTokenizer extends JavaCCTokenizer {
}
@Override
protected CharStream makeCharStream(Reader sourceCode) {
protected CharStream makeCharStream(Reader sourceCode) throws IOException {
return CharStreamFactory.simpleCharStream(sourceCode, PythonTokenDocument::new);
}