Cleanup trimming logic

This commit is contained in:
Clément Fournier committed 2022-04-24 19:19:19 +02:00
1 parent 8a73559eb8
commit 4943dda381
7 files changed
+92 -46

No files matched your search

@@ -436,7 +436,7 @@ final class ApexTreeBuilder extends AstVisitor<AdditionalPassScope> {
if (checkForCommentSuppression && commentText.startsWith("//")) {
Chars trimmed = commentText.subSequence("//".length(), commentText.length()).trimStart();
if (trimmed.startsWith(suppressMarker)) {
Chars userMessage = trimmed.subSequence(suppressMarker.length(), trimmed.length()).trim();
Chars userMessage = trimmed.subSequence(suppressMarker.length()).trim();
suppressMap.put(source.lineColumnAtOffset(startIdx).getLine(), userMessage.toString());
}
}
@@ -11,6 +11,7 @@ import java.util.Iterator;
import net.sourceforge.pmd.PMD;
import net.sourceforge.pmd.cpd.renderer.CPDRenderer;
import net.sourceforge.pmd.lang.document.Chars;
import net.sourceforge.pmd.util.StringUtil;
public class SimpleRenderer implements Renderer, CPDRenderer {
@@ -49,8 +50,9 @@ public class SimpleRenderer implements Renderer, CPDRenderer {
String source = match.getSourceCodeSlice();
if (trimLeadingWhitespace) {
for (String line : StringUtil.linesWithTrimIndent(source)) {
writer.append(line).append(PMD.EOL);
for (Chars line : StringUtil.linesWithTrimIndent(source)) {
line.writeFully(writer);
writer.append(PMD.EOL);
}
return;
}
@@ -363,6 +363,14 @@ public final class Chars implements CharSequence {
return slice(start, end - start);
}
/**
* Returns the subsequence that starts at the given offset and ends
* at the end of this string. Similar to {@link String#substring(int)}.
*/
public Chars subSequence(int start) {
return slice(start, len - start);
}
/**
* Slice a region of text.
*
@@ -415,11 +423,11 @@ public final class Chars implements CharSequence {
}
private static void validateRangeWithAssert(int off, int len, int bound) {
assert len >= 0 && off >= 0 && (off + len) <= bound : invalidRange(off, len, bound);
assert len >= 0 && off >= 0 && off + len <= bound : invalidRange(off, len, bound);
}
private static void validateRange(int off, int len, int bound) {
if (len < 0 || off < 0 || (off + len) > bound) {
if (len < 0 || off < 0 || off + len > bound) {
throw new IndexOutOfBoundsException(invalidRange(off, len, bound));
}
}
@@ -429,7 +437,7 @@ public final class Chars implements CharSequence {
}
@Override
public String toString() {
public @NonNull String toString() {
// this already avoids the copy if start == 0 && len == str.length()
return str.substring(start, start + len);
}
@@ -548,7 +556,7 @@ public final class Chars implements CharSequence {
private final int max = start + len;
@Override
public int read(char[] cbuf, int off, int len) {
public int read(char @NonNull [] cbuf, int off, int len) {
if (len < 0 || off < 0 || off + len > cbuf.length) {
throw new IndexOutOfBoundsException();
}
@@ -40,6 +40,7 @@ import org.pcollections.PSet;
import net.sourceforge.pmd.annotation.InternalApi;
import net.sourceforge.pmd.internal.util.AssertionUtil;
import net.sourceforge.pmd.internal.util.IteratorUtil;
import net.sourceforge.pmd.lang.document.Chars;
/**
* Generic collection and array-related utility functions for java.util types.
@@ -635,6 +636,16 @@ public final class CollectionUtil {
return sb;
}
public static @NonNull StringBuilder joinCharsIntoStringBuilder(List<Chars> lines, String delimiter) {
return joinOn(
new StringBuilder(),
lines,
(buf, line) -> line.appendChars(buf),
delimiter
);
}
/**
* Merge the second map into the first. If some keys are in common,
* merge them using the merge function, like {@link Map#merge(Object, Object, BiFunction)}.
@@ -279,8 +279,7 @@ public final class StringUtil {
* the left without misaligning them.
*
* <p>Note: the spec is described in
* <a
* href='https://docs.oracle.com/en/java/javase/16/docs/api/java.base/java/lang/String.html#stripIndent()'>String#stripIndent</a>
* <a href='https://docs.oracle.com/en/java/javase/16/docs/api/java.base/java/lang/String.html#stripIndent()'>String#stripIndent</a>
*
* <quote>
* The minimum indentation (min) is determined as follows:
@@ -309,33 +308,36 @@ public final class StringUtil {
return maxCommonWs;
}
/**
* Returns a list of
*/
public static List<Chars> linesWithTrimIndent(String source) {
List<String> lines = Arrays.asList(source.split("\n"));
List<Chars> result = lines.stream().map(Chars::wrap).collect(CollectionUtil.toMutableList());
trimIndentInPlace(result);
return result;
}
/**
* Trims off the leading characters off the strings up to the trimDepth
* specified. Returns the same strings if trimDepth = 0
*
* @return String[]
* @param lines mutable list
*/
private static String[] trimStartOn(String[] strings, int trimDepth) {
if (trimDepth == 0) {
return strings;
public static void trimIndentInPlace(List<Chars> lines) {
int trimDepth = maxCommonLeadingWhitespaceForAll(lines);
if (trimDepth > 0) {
lines.replaceAll(chars -> chars.length() >= trimDepth
? chars.subSequence(trimDepth).trimEnd()
: chars.trimEnd());
}
String[] results = new String[strings.length];
for (int i = 0; i < strings.length; i++) {
results[i] = strings[i].substring(trimDepth);
}
return results;
}
/**
* Trim common indentation in the lines of the string, like
* {@link #appendWithoutCommonPrefix(List, int, StringBuilder)}.
*
*/
public static StringBuilder trimIndent(Chars string) {
List<Chars> lines = string.lineStream().collect(Collectors.toList());
List<Chars> lines = string.lineStream().collect(CollectionUtil.toMutableList());
trimIndentInPlace(lines);
StringBuilder sb = new StringBuilder(string.length());
trimIndentIntoStringBuilder(lines, sb);
return sb;
@@ -365,7 +367,7 @@ public final class StringUtil {
Chars line = lines.get(i);
// remove common whitespace prefix
if (line.length() >= prefixLength && !StringUtils.isBlank(line)) {
line = line.subSequence(prefixLength, line.length());
line = line.subSequence(prefixLength);
}
// trim trailing whitespace
line = line.trimEnd();
@@ -398,17 +400,21 @@ public final class StringUtil {
}
}
int lastNonBlankLine = string.indexOf('\n', offsetOfLastNonBlankChar);
int firstNonBlankLine = string.lastIndexOf('\n', offsetOfFirstNonBlankChar);
// look backwards before the first non-blank char
int cutFromInclusive = string.lastIndexOf('\n', offsetOfFirstNonBlankChar);
// If firstNonBlankLineStart == -1, ie we're on the first line,
// we want to start at zero: then we add 1 to get 0
// If firstNonBlankLineStart >= 0, then it's the index of the
// \n, we want to cut right after that, so we add 1.
cutFromInclusive += 1;
return string.subSequence(
minus1Default(firstNonBlankLine, 0),
minus1Default(lastNonBlankLine, string.length())
);
}
// look forwards after the last non-blank char
int cutUntilExclusive = string.indexOf('\n', offsetOfLastNonBlankChar);
if (cutUntilExclusive == StringUtils.INDEX_NOT_FOUND) {
cutUntilExclusive = string.length();
}
private static int minus1Default(int i, int defaultValue) {
return i == -1 ? defaultValue : i;
return string.subSequence(cutFromInclusive, cutUntilExclusive);
}
@@ -420,15 +426,6 @@ public final class StringUtil {
return count;
}
public static String[] linesWithTrimIndent(String source) {
String[] lines = source.split("\n");
int trimDepth = maxCommonLeadingWhitespaceForAll(Arrays.asList(lines));
if (trimDepth > 0) {
lines = trimStartOn(lines, trimDepth);
}
return lines;
}
/**
* Are the two String values the same. The Strings can be optionally trimmed
@@ -94,6 +94,7 @@ public class StringUtilTest {
assertTrimIndent(" \n b \n c\n ",
"\nb\nc\n");
assertTrimIndent("", "");
}
private void assertTrimIndent(String input, String output) {
@@ -107,4 +108,28 @@ public class StringUtilTest {
assertThat(StringUtil.elide("abc", 2, ".."), equalTo(".."));
assertThat(StringUtil.elide("abc", 3, ".."), equalTo("abc"));
}
@Test
public void substringAfterLast() {
assertEquals("abc", StringUtil.substringAfterLast("a.abc", '.'));
assertEquals("abc", StringUtil.substringAfterLast("abc", '.'));
}
@Test
public void trimBlankLines() {
assertTrimBlankLinesEquals(" \n \n abc \n \n de \n \n ",
" abc \n \n de ");
assertTrimBlankLinesEquals("", "");
}
private void assertTrimBlankLinesEquals(String input, String output) {
assertEquals(
Chars.wrap(output),
StringUtil.trimBlankLines(Chars.wrap(input))
);
}
@Test
public void linesWithTrimIndent() {
}
}
@@ -12,6 +12,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import net.sourceforge.pmd.lang.document.Chars;
import net.sourceforge.pmd.util.CollectionUtil;
import net.sourceforge.pmd.util.StringUtil;
/**
@@ -83,8 +84,10 @@ public final class ASTStringLiteral extends AbstractLiteral implements ASTLitera
static String determineTextBlockContent(Chars image) {
List<Chars> lines = getContentLines(image);
StringBuilder sb = new StringBuilder(image.length());
StringUtil.trimIndentIntoStringBuilder(lines, sb);
// remove common prefix
StringUtil.trimIndentInPlace(lines);
// join with normalized end of line
StringBuilder sb = CollectionUtil.joinCharsIntoStringBuilder(lines, "\n");
interpretEscapeSequences(sb);
return sb.toString();
}