Merge, wip

This commit is contained in:
Clément Fournier committed 2022-04-24 11:50:33 +02:00
1 parent 64b9b25bef
commit 1da096b126
11 files changed
+117 -44

No files matched your search

@@ -130,12 +130,8 @@ public interface Node extends Reportable {
* to create a region.
*/
default TextRegion getTextRegion() {
@SuppressWarnings("PMD.CloseResource")
TextDocument document = getAstInfo().getTextDocument();
FileLocation loc = getReportLocation();
int startOffset = document.offsetAtLineColumn(loc.getStartPos());
int endOffset = document.offsetAtLineColumn(loc.getStartPos());
return TextRegion.fromBothOffsets(startOffset, endOffset);
return getAstInfo().getTextDocument().toRegion(loc.toRange2d());
}
@@ -59,6 +59,21 @@ abstract class BaseMappedDocument implements TextDocument {
return base.createLineRange(startLineInclusive, endLineInclusive);
}
@Override
public int offsetAtLineColumn(int line, int column) {
throw new UnsupportedOperationException();
}
@Override
public TextPos2d lineColumnAtOffset(int offset, boolean inclusive) {
throw new UnsupportedOperationException();
}
@Override
public boolean isInRange(TextPos2d textPos2d) {
return false;
}
@Override
public int inputOffset(int outOffset, boolean inclusive) {
if (outOffset < 0 || outOffset > getLength()) {
@@ -67,8 +82,13 @@ abstract class BaseMappedDocument implements TextDocument {
return base.inputOffset(localOffsetTransform(outOffset, inclusive), inclusive);
}
/**
* Output offset to input offset.
*/
protected abstract int localOffsetTransform(int outOffset, boolean inclusive);
protected abstract int inverseLocalOffsetTransform(int inOffset, boolean inclusive);
@Override
public void close() throws IOException {
@@ -4,6 +4,8 @@
package net.sourceforge.pmd.lang.document;
import java.util.function.ToIntFunction;
import org.checkerframework.checker.nullness.qual.Nullable;
import net.sourceforge.pmd.lang.LanguageVersion;
@@ -48,44 +50,71 @@ final class FragmentedTextDocument extends BaseMappedDocument implements TextDoc
@Override
protected int localOffsetTransform(int outOffset, boolean inclusive) {
return inputOffsetAt(outOffset, inclusive);
return offsetTransform(outOffset, inclusive,
Fragment::outToIn,
Fragment::outEnd,
Fragment::outStart
);
}
private int inputOffsetAt(int outputOffset, boolean inclusive) {
@Override
protected int inverseLocalOffsetTransform(int inOffset, boolean inclusive) {
return offsetTransform(inOffset, inclusive,
Fragment::inToOut,
Fragment::inEnd,
Fragment::inStart
);
}
interface OffsetMapper {
int mapOffset(Fragment fragment, int offset);
}
private int offsetTransform(int offset,
boolean inclusive,
OffsetMapper mapOffsetWhenContains,
ToIntFunction<Fragment> end,
ToIntFunction<Fragment> start) {
// caching the last accessed fragment instead of doing
// a linear search is critical for performance.
Fragment f = this.lastAccessedFragment;
if (f == null) {
return outputOffset;
return offset;
}
if (!f.contains(outputOffset)) {
// Whether the fragment contains the offset we're looking for.
// Will be true most of the time.
boolean containsOffset =
start.applyAsInt(f) >= offset && offset < end.applyAsInt(f);
if (!containsOffset) {
// Slow path, we must search for the fragment
// This optimisation is important, otherwise we have
// to search for very long times in some files
if (f.outEnd() < outputOffset) { // search forward
while (f.next != null && f.outEnd() < outputOffset) {
if (end.applyAsInt(f) < offset) { // search forward
while (f.next != null && end.applyAsInt(f) < offset) {
f = f.next;
}
} else { // search backwards
while (f.prev != null && outputOffset <= f.outStart()) {
while (f.prev != null && offset <= start.applyAsInt(f)) {
f = f.prev;
}
}
lastAccessedFragment = f;
}
if (!inclusive && f.outEnd() == outputOffset) {
if (!inclusive && end.applyAsInt(f) == offset) {
if (f.next != null) {
f = f.next;
lastAccessedFragment = f;
// fallthrough
} else {
return f.outToIn(outputOffset) + 1;
return mapOffsetWhenContains.mapOffset(f, offset) + 1;
}
}
return f.outToIn(outputOffset);
return mapOffsetWhenContains.mapOffset(f, offset);
}
@@ -150,8 +179,8 @@ final class FragmentedTextDocument extends BaseMappedDocument implements TextDoc
return inStart() + outOffset - outStart();
}
boolean contains(int outOffset) {
return outStart() <= outOffset && outEnd() > outOffset;
int inToOut(int inOffset) {
return inOffset - inStart() + outStart();
}
@Override
@@ -148,7 +148,7 @@ public interface TextDocument extends Closeable {
int inputOffset(int outOffset, boolean inclusive);
/**
* Translate a region given in the the coordinate system of this
* Translate a region given in the coordinate system of this
* document, to the coordinate system of the original document.
* This works as if creating a new region with both start and end
* offsets translated through {@link #inputOffset(int, boolean)}. The
@@ -160,6 +160,21 @@ public interface TextDocument extends Closeable {
*/
TextRegion inputRegion(TextRegion outputRegion);
/**
* Translate a 2D range given in the coordinate system of this
* document, to the coordinate system of the original document.
* This works as if creating a new region with both start and end
* offsets translated through {@link #inputOffset(int, boolean)}. The
* returned region may have a different length.
*
* @param outputRange Output region
*
* @return Input region
*/
default TextRange2d inputRange(TextRange2d outputRange) {
return toRange2d(inputRegion(toRegion(outputRange)));
}
/**
* Returns a reader over the text of this document.
@@ -176,16 +191,20 @@ public interface TextDocument extends Closeable {
}
/**
* Returns a text region that corresponds to the entire document.
* Returns a text region that corresponds to the entire document,
* in the coordinate system of this document.
*/
default TextRegion getEntireRegion() {
return TextRegion.fromOffsetLength(0, getLength());
}
/**
* Returns a 2D text range that corresponds to the entire document.
* Returns a 2D text range that corresponds to the entire document,
* in the coordinate system of this document.
*/
TextRange2d getEntireRegion2d();
default TextRange2d getEntireRegion2d() {
return toRange2d(getEntireRegion());
}
/**
* Returns a region that spans the text of all the given lines.
@@ -210,7 +229,9 @@ public interface TextDocument extends Closeable {
* the line/column information for both start and end offset of
* the region.
*
* @return A new file position
* @param region A region, in the coordinate system of this document
*
* @return A new file position, with absolute coordinates
*
* @throws IndexOutOfBoundsException If the argument is not a valid region in this document
*/
@@ -231,7 +252,7 @@ public interface TextDocument extends Closeable {
}
TextRegion region = TextRegion.caretAt(startOffset);
checkInRange(region, this.getLength());
return FileLocation.location(getDisplayName(), range);
return FileLocation.range(getDisplayName(), range);
}
/**
@@ -289,6 +310,8 @@ public interface TextDocument extends Closeable {
/**
* Returns the line and column at the given offset (inclusive).
* Both the input offset and the output range are in the coordinates
* of this document.
*
* @param offset A source offset (0-based), can range in {@code [0, length]}.
* @param inclusive If the offset falls right after a line terminator,
@@ -296,6 +319,8 @@ public interface TextDocument extends Closeable {
* choose the position at the start of the next line.
* Otherwise choose the offset at the end of the line.
*
* @return A position, in the coordinate system of this document
*
* @throws IndexOutOfBoundsException if the offset is out of bounds
*/
TextPos2d lineColumnAtOffset(int offset, boolean inclusive);
@@ -315,6 +340,17 @@ public interface TextDocument extends Closeable {
@Override
void close() throws IOException;
/**
* Create a new text document for the given text file. The document's
* coordinate system is the same as the original text file.
*
* @param textFile A text file
*
* @return A new text document
*
* @throws IOException If the file cannot be read ({@link TextFile#readContents()})
* @throws NullPointerException If the parameter is null
*/
static TextDocument create(TextFile textFile) throws IOException {
return new RootTextDocument(textFile);
}
@@ -11,6 +11,11 @@ import org.checkerframework.checker.nullness.qual.NonNull;
*/
public final class TextPos2d implements Comparable<TextPos2d> {
/**
* The position at the start of the document (line 1, column 1).
*/
public static TextPos2d DOCUMENT_START = new TextPos2d(1, 1);
private final int line;
private final int column;
@@ -122,8 +122,8 @@ public final class TextRegion implements Comparable<TextRegion> {
* @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();
assert (startOffset - delta) >= 0 : "Left delta " + delta + " would produce a region that starts before zero" + parThis();
assert delta + length >= 0 : "Left delta " + delta + " would produce a negative length region" + parThis();
assert startOffset - delta >= 0 : "Left delta " + delta + " would produce a region that starts before zero" + parThis();
return new TextRegion(startOffset - delta, delta + length);
}
@@ -135,7 +135,7 @@ public final class TextRegion implements Comparable<TextRegion> {
* @throws AssertionError If the delta is negative and less than the length of this region
*/
public TextRegion growRight(int delta) {
assert (delta + length) >= 0 : "Right delta " + delta + " would produce a negative length region" + parThis();
assert delta + length >= 0 : "Right delta " + delta + " would produce a negative length region" + parThis();
return new TextRegion(startOffset, delta + length);
}
@@ -181,15 +181,6 @@ public final class TextRegion implements Comparable<TextRegion> {
return new TextRegion(startOffset, length);
}
/**
* Builds a new region from offset and length.
*
* @throws AssertionError If either parameter is negative
*/
public static TextRegion caretAt(int offset) {
return fromOffsetLength(offset, 0);
}
/**
* Builds a new region from start and end offset.
*
@@ -75,10 +75,7 @@ public class ReportTest {
}
private static FileLocation getNode(int line, int column, String filename) {
return FileLocation.location(
filename,
TextRange2d.range2d(line, column, line, column)
);
return FileLocation.range(filename, TextRange2d.range2d(line, column, line, column));
}
public static String render(Renderer renderer, Consumer<? super FileAnalysisListener> listenerEffects) throws IOException {
@@ -70,7 +70,7 @@ public class RuleViolationComparatorTest {
private RuleViolation createJavaRuleViolation(Rule rule, String fileName, int beginLine, String description,
int beginColumn, int endLine, int endColumn) {
FileLocation loc = FileLocation.location(fileName, TextRange2d.range2d(beginLine, beginColumn, endLine, endColumn));
FileLocation loc = FileLocation.range(fileName, TextRange2d.range2d(beginLine, beginColumn, endLine, endColumn));
return new ParametricRuleViolation(rule, loc, description);
}
}
@@ -92,7 +92,7 @@ public abstract class AbstractRendererTest {
protected FileLocation createLocation(int beginLine, int beginColumn, int endLine, int endColumn) {
TextRange2d range2d = TextRange2d.range2d(beginLine, beginColumn, endLine, endColumn);
return FileLocation.location(getSourceCodeFilename(), range2d);
return FileLocation.range(getSourceCodeFilename(), range2d);
}
protected RuleViolation newRuleViolation(int beginLine, int beginColumn, int endLine, int endColumn, Rule rule) {
@@ -91,8 +91,7 @@ public class XMLRendererTest extends AbstractRendererTest {
}
private RuleViolation createRuleViolation(String description) {
FileLocation loc = FileLocation.location(getSourceCodeFilename(),
TextRange2d.range2d(1, 1, 1, 1));
FileLocation loc = FileLocation.range(getSourceCodeFilename(), TextRange2d.range2d(1, 1, 1, 1));
return new ParametricRuleViolation(new FooRule(), loc, description);
}
@@ -19,7 +19,7 @@ public class XSLTRendererTest {
@Test
public void testDefaultStylesheet() throws Exception {
XSLTRenderer renderer = new XSLTRenderer();
FileLocation loc = FileLocation.location("file", TextRange2d.range2d(1, 1, 1, 2));
FileLocation loc = FileLocation.range("file", TextRange2d.range2d(1, 1, 1, 2));
RuleViolation rv = new ParametricRuleViolation(new FooRule(), loc, "violation message");
String result = ReportTest.render(renderer, it -> it.onRuleViolation(rv));
Assert.assertTrue(result.contains("violation message"));