Add TextRange2d

This commit is contained in:
Clément Fournier
2022-04-02 22:26:17 +02:00
parent 911347541e
commit 15d98409db
23 changed files with 296 additions and 76 deletions

View File

@ -437,7 +437,7 @@ final class ApexTreeBuilder extends AstVisitor<AdditionalPassScope> {
Chars trimmed = commentText.subSequence("//".length(), commentText.length()).trimStart();
if (trimmed.startsWith(suppressMarker)) {
Chars userMessage = trimmed.subSequence(suppressMarker.length(), trimmed.length()).trim();
suppressMap.put(source.lineAtOffset(startIdx), userMessage.toString());
suppressMap.put(source.lineColumnAtOffset(startIdx).getLine(), userMessage.toString());
}
}
}

View File

@ -14,6 +14,7 @@ import net.sourceforge.pmd.Report.SuppressedViolation;
import net.sourceforge.pmd.annotation.InternalApi;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.document.FileLocation;
import net.sourceforge.pmd.lang.document.TextRange2d;
import net.sourceforge.pmd.lang.rule.AbstractRule;
import net.sourceforge.pmd.lang.rule.RuleViolationFactory;
import net.sourceforge.pmd.processor.AbstractPMDProcessor;
@ -131,7 +132,7 @@ public final class RuleContext {
FileLocation location = node.getReportLocation();
if (beginLine != -1 && endLine != -1) {
location = FileLocation.location(location.getFileName(), beginLine, 1, endLine, 1);
location = FileLocation.location(location.getFileName(), TextRange2d.range2d(beginLine, 1, endLine, 1));
}
RuleViolation violation = fact.createViolation(rule, node, location, makeMessage(message, formatArgs));

View File

@ -12,6 +12,7 @@ import net.sourceforge.pmd.Rule;
import net.sourceforge.pmd.RuleViolation;
import net.sourceforge.pmd.annotation.InternalApi;
import net.sourceforge.pmd.lang.document.FileLocation;
import net.sourceforge.pmd.lang.document.TextRange2d;
/**
* A {@link RuleViolation} implementation that is immutable, and therefore cache friendly
@ -41,7 +42,7 @@ public final class CachedRuleViolation implements RuleViolation {
final String className, final String methodName, final String variableName) {
this.mapper = mapper;
this.description = description;
this.location = FileLocation.location(fileName, beginLine, beginColumn, endLine, endColumn);
this.location = FileLocation.location(fileName, TextRange2d.range2d(beginLine, beginColumn, endLine, endColumn));
this.ruleClassName = ruleClassName;
this.ruleName = ruleName;
this.ruleTargetLanguage = ruleTargetLanguage;

View File

@ -153,8 +153,14 @@ public final class FileLocation {
* @throws IllegalArgumentException If the line and column are not correctly ordered
* @throws IllegalArgumentException If the start offset or length are negative
*/
public static FileLocation location(String fileName, int beginLine, int beginColumn, int endLine, int endColumn) {
return new FileLocation(fileName, beginLine, beginColumn, endLine, endColumn);
public static FileLocation location(String fileName, TextRange2d range2d) {
TextPos2d start = range2d.getStartPos();
TextPos2d end = range2d.getEndPos();
return new FileLocation(fileName,
start.getLine(),
start.getColumn(),
end.getLine(),
end.getColumn());
}

View File

@ -64,7 +64,7 @@ final class RootTextDocument extends BaseCloseable implements TextDocument {
@Override
public FileLocation toLocation(TextRegion region) {
checkInRange(region);
checkInRange(region, this.getLength());
SourceCodePositioner positioner = content.getPositioner();
// We use longs to return both numbers at the same time
@ -90,8 +90,18 @@ final class RootTextDocument extends BaseCloseable implements TextDocument {
}
@Override
public TextPos2d lineColumnAtOffset(int offset) {
long longPos = content.getPositioner().lineColFromOffset(offset, true);
public boolean isInRange(TextPos2d textPos2d) {
if (textPos2d.getLine() <= content.getPositioner().getNumLines()) {
int maxColumn = content.getPositioner().offsetOfEndOfLine(textPos2d.getLine());
return textPos2d.getColumn()
< content.getPositioner().columnFromOffset(textPos2d.getLine(), maxColumn);
}
return false;
}
@Override
public TextPos2d lineColumnAtOffset(int offset, boolean inclusive) {
long longPos = content.getPositioner().lineColFromOffset(offset, inclusive);
return TextPos2d.pos2d(
SourceCodePositioner.unmaskLine(longPos),
SourceCodePositioner.unmaskCol(longPos)
@ -113,9 +123,9 @@ final class RootTextDocument extends BaseCloseable implements TextDocument {
return TextRegion.fromBothOffsets(first, last);
}
void checkInRange(TextRegion region) {
if (region.getEndOffset() > getLength()) {
throw regionOutOfBounds(region.getStartOffset(), region.getEndOffset(), getLength());
static void checkInRange(TextRegion region, int length) {
if (region.getEndOffset() > length) {
throw regionOutOfBounds(region.getStartOffset(), region.getEndOffset(), length);
}
}

View File

@ -131,6 +131,9 @@ final class SourceCodePositioner {
*/
public int offsetFromLineColumn(final int line, final int column) {
if (!isValidLine(line)) {
if (line == lineOffsets.length && column == 1) {
return sourceCodeLength;
}
return -1;
}
@ -172,6 +175,10 @@ final class SourceCodePositioner {
return lineOffsets.length - 1;
}
public int getNumLines() {
return getLastLine();
}
/**
* Returns the last column number of the last line in the document.
*/

View File

@ -4,6 +4,8 @@
package net.sourceforge.pmd.lang.document;
import static net.sourceforge.pmd.lang.document.RootTextDocument.checkInRange;
import java.io.Closeable;
import java.io.IOException;
import java.io.Reader;
@ -36,6 +38,26 @@ public interface TextDocument extends Closeable {
// todo text edition (there are some reverted commits in the branch
// with part of this, including a lot of tests)
/*
Summary of different coordinate systems:
Coordinate system: Line/column Offset
==============================================================
Position: TextPos2d int >= 0
Range: TextRange2d TextRegion
(FileLocation is similar to TextRange2d in terms of position info)
Conversions:
line/column -> offset: offsetAtLineColumn
offset -> line/column: lineColumnAtOffset
Range conversions:
TextRegion -> TextRange2d: toRegion
TextRange2d -> TextRegion: toRange2d
TextRegion -> FileLocation: toLocation
TextRange2d -> FileLocation: toLocation
*/
/**
* Returns the language version that should be used to parse this file.
*/
@ -122,16 +144,40 @@ public interface TextDocument extends Closeable {
FileLocation toLocation(TextRegion region);
/**
* Create a location from its positions as lines/columns. The file
* name is the display name of this document.
* Turn a text region into a {@link FileLocation}. The file name is
* the display name of this document.
*
* @param bline Start line
* @param bcol Start column
* @param eline End line
* @param ecol End column
* @return A new file position
*
* @throws IndexOutOfBoundsException If the argument is not a valid region in this document
*/
default FileLocation createLocation(int bline, int bcol, int eline, int ecol) {
return FileLocation.location(getDisplayName(), bline, bcol, eline, ecol);
default FileLocation toLocation(TextRange2d range) {
int startOffset = offsetAtLineColumn(range.getEndPos());
if (startOffset < 0) {
throw new IndexOutOfBoundsException("Region out of bounds: " + range.displayString());
}
TextRegion region = TextRegion.caretAt(startOffset);
checkInRange(region, this.getLength());
return FileLocation.location(getDisplayName(), range);
}
/**
* Turn a text region to a {@link TextRange2d}.
*/
default TextRange2d toRange2d(TextRegion region) {
TextPos2d start = lineColumnAtOffset(region.getStartOffset(), true);
TextPos2d end = lineColumnAtOffset(region.getEndOffset(), false);
return TextRange2d.range2d(start, end);
}
/**
* Turn a {@link TextRange2d} into a {@link TextRegion}.
*/
default TextRegion toRegion(TextRange2d region) {
return TextRegion.fromBothOffsets(
offsetAtLineColumn(region.getStartPos()),
offsetAtLineColumn(region.getEndPos())
);
}
@ -145,6 +191,11 @@ public interface TextDocument extends Closeable {
*/
int offsetAtLineColumn(int line, int column);
/**
* Returns true if the position is valid in this document.
*/
boolean isInRange(TextPos2d textPos2d);
/**
* Returns the offset at the line and number.
*/
@ -159,35 +210,24 @@ public interface TextDocument extends Closeable {
*
* @throws IndexOutOfBoundsException if the offset is out of bounds
*/
TextPos2d lineColumnAtOffset(int offset);
/**
* Determines the line number at the given offset (inclusive).
*
* @return the line number at the given index
*
* @throws IndexOutOfBoundsException If the argument is not a valid offset in this document
*/
default int lineAtOffset(int offset) {
return lineColumnAtOffset(offset).getLine();
default TextPos2d lineColumnAtOffset(int offset) {
return lineColumnAtOffset(offset, true);
}
/**
* Returns the region that spans from the given position to the other.
* Returns the line and column at the given offset (inclusive).
*
* @throws IllegalArgumentException if start > end
* @throws NullPointerException If either argument is null
* @param offset A source offset (0-based), can range in {@code [0, length]}.
* @param inclusive If the offset falls right after a line terminator,
* two behaviours are possible. If the parameter is true,
* choose the position at the start of the next line.
* Otherwise choose the offset at the end of the line.
*
* @throws IndexOutOfBoundsException if the offset is out of bounds
*/
default TextRegion rangeBetween(TextPos2d start, TextPos2d end) {
if (start.compareTo(end) > 0) {
throw new IllegalArgumentException(start.toTupleString() + " comes after " + end.toTupleString());
}
TextPos2d lineColumnAtOffset(int offset, boolean inclusive);
int startPos = offsetAtLineColumn(start);
int endPos = offsetAtLineColumn(end) + 1;
return TextRegion.fromBothOffsets(startPos, endPos);
}
/**
* Closing a document closes the underlying {@link TextFile}.

View File

@ -0,0 +1,92 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.document;
import java.util.Objects;
/**
* A place in a text document, represented as line/column information.
*/
public final class TextRange2d implements Comparable<TextRange2d> {
private final int startLine;
private final int startCol;
private final int endLine;
private final int endCol;
public TextRange2d(int startLine, int startCol, int endLine, int endCol) {
this.startLine = startLine;
this.startCol = startCol;
this.endLine = endLine;
this.endCol = endCol;
}
public TextPos2d getStartPos() {
return TextPos2d.pos2d(startLine, startCol);
}
public TextPos2d getEndPos() {
return TextPos2d.pos2d(endLine, endCol);
}
public String displayString() {
return "(" + startCol + ", " + endCol
+ ")-(" + endLine + ", " + endCol + ")";
}
public static TextRange2d range2d(TextPos2d start, TextPos2d end) {
return new TextRange2d(start.getLine(), start.getColumn(), end.getLine(), end.getColumn());
}
public static TextRange2d range2d(int bline, int bcol, int eline, int ecol) {
return new TextRange2d(bline, bcol, eline, ecol);
}
public static TextRange2d fullLine(int line, int lineLength) {
return new TextRange2d(line, 1, line, 1 + lineLength);
}
@Override
public int compareTo(TextRange2d o) {
int cmp = getStartPos().compareTo(o.getStartPos());
if (cmp != 0) {
return cmp;
}
return getEndPos().compareTo(o.getEndPos());
}
public boolean contains(TextRange2d range) {
return getStartPos().compareTo(range.getStartPos()) <= 0 && getEndPos().compareTo(range.getEndPos()) >= 0;
}
public boolean contains(TextPos2d pos) {
return getStartPos().compareTo(pos) <= 0 && getEndPos().compareTo(pos) >= 0;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
TextRange2d that = (TextRange2d) o;
return this.getStartPos().equals(that.getStartPos())
&& this.getEndPos().equals(that.getEndPos());
}
@Override
public int hashCode() {
return Objects.hash(getStartPos(), getEndPos());
}
@Override
public String toString() {
return "[" + getStartPos() + " - " + getEndPos() + ']';
}
}

View File

@ -14,7 +14,6 @@ import java.util.Collections;
import org.junit.Test;
import net.sourceforge.pmd.Report.SuppressedViolation;
import net.sourceforge.pmd.lang.ast.DummyNode;
import net.sourceforge.pmd.lang.ast.DummyRoot;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.rule.AbstractRule;
@ -70,8 +69,8 @@ public class AbstractRuleTest {
public void testCreateRV() {
MyRule r = new MyRule();
r.setRuleSetName("foo");
DummyNode s = new DummyRoot().withFileName("filename");
s.setCoords(5, 5, 5, 10);
DummyRoot s = new DummyRoot().withFileName("filename");
s.setCoordsReplaceText(5, 5, 5, 10);
RuleViolation rv = new ParametricRuleViolation(r, s, r.getMessage());
assertEquals("Line number mismatch!", 5, rv.getBeginLine());
assertEquals("Filename mismatch!", "filename", rv.getFilename());
@ -83,8 +82,8 @@ public class AbstractRuleTest {
@Test
public void testCreateRV2() {
MyRule r = new MyRule();
DummyNode s = new DummyRoot().withFileName("filename");
s.setCoords(5, 5, 5, 10);
DummyRoot s = new DummyRoot().withFileName("filename");
s.setCoordsReplaceText(5, 5, 5, 10);
RuleViolation rv = new ParametricRuleViolation(r, s, "specificdescription");
assertEquals("Line number mismatch!", 5, rv.getBeginLine());
assertEquals("Filename mismatch!", "filename", rv.getFilename());
@ -103,8 +102,8 @@ public class AbstractRuleTest {
r.definePropertyDescriptor(PropertyFactory.intProperty("testInt").desc("description").require(inRange(0, 100)).defaultValue(10).build());
r.setMessage("Message ${packageName} ${className} ${methodName} ${variableName} ${testInt} ${noSuchProperty}");
DummyNode s = new DummyRoot().withFileName("filename");
s.setCoords(5, 1, 6, 1);
DummyRoot s = new DummyRoot().withFileName("filename");
s.setCoordsReplaceText(5, 1, 6, 1);
s.setImage("TestImage");
RuleViolation rv = RuleContextTest.getReportForRuleApply(r, s).getViolations().get(0);
@ -114,7 +113,7 @@ public class AbstractRuleTest {
@Test
public void testRuleSuppress() {
DummyRoot n = new DummyRoot().withNoPmdComments(Collections.singletonMap(5, ""));
n.setCoords(5, 1, 6, 1);
n.setCoordsReplaceText(5, 1, 6, 1);
RuleViolation violation = DefaultRuleViolationFactory.defaultInstance().createViolation(new MyRule(), n, n.getReportLocation(), "specificdescription");
SuppressedViolation suppressed = DefaultRuleViolationFactory.defaultInstance().suppressOrNull(n, violation);

View File

@ -76,7 +76,8 @@ public class ReportTest {
}
private static DummyNode getNode(int line, int column) {
DummyNode parent = new DummyRoot();
DummyRoot parent = new DummyRoot();
parent.fakeTextWithNLines(line + 10, column);
DummyNode s = new DummyNode();
parent.setCoords(line, column, line, column + 1);
parent.addChild(s, 0);

View File

@ -475,7 +475,7 @@ public class RuleSetTest {
private RootNode makeCompilationUnits(String filename) {
DummyRoot node = new DummyRoot();
node.setCoords(1, 1, 10, 1);
node.setCoordsReplaceText(1, 1, 2, 1);
node.setImage("Foo");
node.withFileName(filename);
return node;

View File

@ -15,7 +15,6 @@ import java.util.Random;
import org.junit.Test;
import net.sourceforge.pmd.lang.ast.DummyNode;
import net.sourceforge.pmd.lang.ast.DummyRoot;
import net.sourceforge.pmd.lang.rule.MockRule;
import net.sourceforge.pmd.lang.rule.ParametricRuleViolation;
@ -70,8 +69,8 @@ public class RuleViolationComparatorTest {
private RuleViolation createJavaRuleViolation(Rule rule, String fileName, int beginLine, String description,
int beginColumn, int endLine, int endColumn) {
DummyNode simpleNode = new DummyRoot().withFileName(fileName);
simpleNode.setCoords(beginLine, beginColumn, endLine, endColumn);
DummyRoot simpleNode = new DummyRoot().withFileName(fileName);
simpleNode.setCoordsReplaceText(beginLine, beginColumn, endLine, endColumn);
return new ParametricRuleViolation(rule, simpleNode, description);
}
}

View File

@ -24,8 +24,8 @@ public class RuleViolationTest {
@Test
public void testConstructor1() {
Rule rule = new MockRule("name", "desc", "msg", "rulesetname");
DummyNode s = new DummyRoot().withFileName("filename");
s.setCoords(2, 1, 2, 3);
DummyRoot s = new DummyRoot().withFileName("filename");
s.setCoordsReplaceText(2, 1, 2, 3);
RuleViolation r = new ParametricRuleViolation(rule, s, rule.getMessage());
assertEquals("object mismatch", rule, r.getRule());
assertEquals("line number is wrong", 2, r.getBeginLine());
@ -35,8 +35,8 @@ public class RuleViolationTest {
@Test
public void testConstructor2() {
Rule rule = new MockRule("name", "desc", "msg", "rulesetname");
DummyNode s = new DummyRoot().withFileName("filename");
s.setCoords(2, 1, 2, 3);
DummyRoot s = new DummyRoot().withFileName("filename");
s.setCoordsReplaceText(2, 1, 2, 3);
RuleViolation r = new ParametricRuleViolation(rule, s, "description");
assertEquals("object mismatch", rule, r.getRule());
assertEquals("line number is wrong", 2, r.getBeginLine());
@ -48,11 +48,11 @@ public class RuleViolationTest {
public void testComparatorWithDifferentFilenames() {
Rule rule = new MockRule("name", "desc", "msg", "rulesetname");
Comparator<RuleViolation> comp = RuleViolation.DEFAULT_COMPARATOR;
DummyNode s = new DummyRoot().withFileName("filename1");
s.setCoords(10, 1, 11, 3);
DummyRoot s = new DummyRoot().withFileName("filename1");
s.setCoordsReplaceText(10, 1, 11, 3);
RuleViolation r1 = new ParametricRuleViolation(rule, s, "description");
DummyNode s1 = new DummyRoot().withFileName("filename2");
s1.setCoords(10, 1, 11, 3);
DummyRoot s1 = new DummyRoot().withFileName("filename2");
s1.setCoordsReplaceText(10, 1, 11, 3);
RuleViolation r2 = new ParametricRuleViolation(rule, s1, "description");
assertEquals(-1, comp.compare(r1, r2));
assertEquals(1, comp.compare(r2, r1));
@ -62,10 +62,10 @@ public class RuleViolationTest {
public void testComparatorWithSameFileDifferentLines() {
Rule rule = new MockRule("name", "desc", "msg", "rulesetname");
Comparator<RuleViolation> comp = RuleViolation.DEFAULT_COMPARATOR;
DummyNode s = new DummyRoot().withFileName("filename1");
s.setCoords(10, 1, 15, 10);
DummyNode s1 = new DummyRoot().withFileName("filename1");
s1.setCoords(20, 1, 25, 10);
DummyRoot s = new DummyRoot().withFileName("filename1");
s.setCoordsReplaceText(10, 1, 15, 10);
DummyRoot s1 = new DummyRoot().withFileName("filename1");
s1.setCoordsReplaceText(20, 1, 25, 10);
RuleViolation r1 = new ParametricRuleViolation(rule, s, "description");
RuleViolation r2 = new ParametricRuleViolation(rule, s1, "description");
assertTrue(comp.compare(r1, r2) < 0);

View File

@ -41,6 +41,7 @@ import net.sourceforge.pmd.lang.document.FileLocation;
import net.sourceforge.pmd.lang.document.TextDocument;
import net.sourceforge.pmd.lang.document.TextFile;
import net.sourceforge.pmd.lang.document.TextFileContent;
import net.sourceforge.pmd.lang.document.TextRange2d;
@SuppressWarnings("deprecation")
public class FileAnalysisCacheTest {
@ -116,7 +117,7 @@ public class FileAnalysisCacheTest {
final RuleViolation rv = mock(RuleViolation.class);
when(rv.getFilename()).thenReturn(sourceFile.getDisplayName());
when(rv.getLocation()).thenReturn(FileLocation.location(sourceFile.getDisplayName(), 1, 2, 3, 4));
when(rv.getLocation()).thenReturn(FileLocation.location(sourceFile.getDisplayName(), TextRange2d.range2d(1, 2, 3, 4)));
final net.sourceforge.pmd.Rule rule = mock(net.sourceforge.pmd.Rule.class, Mockito.RETURNS_SMART_NULLS);
when(rule.getLanguage()).thenReturn(mock(Language.class));
when(rv.getRule()).thenReturn(rule);

View File

@ -19,6 +19,7 @@ import org.junit.Test;
import net.sourceforge.pmd.lang.TokenManager;
import net.sourceforge.pmd.lang.ast.GenericToken;
import net.sourceforge.pmd.lang.document.FileLocation;
import net.sourceforge.pmd.lang.document.TextRange2d;
import net.sourceforge.pmd.lang.document.TextRegion;
public class BaseTokenFilterTest {
@ -58,7 +59,7 @@ public class BaseTokenFilterTest {
@Override
public FileLocation getReportLocation() {
return FileLocation.location("n/a", 0, 0, 0, 0);
return FileLocation.location("n/a", TextRange2d.range2d(0, 0, 0, 0));
}
@Override

View File

@ -49,7 +49,7 @@ public class DummyLanguageModule extends BaseLanguageModule {
public Parser getParser() {
return task -> {
DummyRoot node = new DummyRoot();
node.setCoords(1, 1, 2, 10);
node.setCoords(1, 1, 1, 1);
node.setImage("Foo");
node.withFileName(task.getFileDisplayName());
node.withLanguage(task.getLanguageVersion());

View File

@ -10,6 +10,7 @@ import java.util.Map;
import net.sourceforge.pmd.lang.ast.impl.AbstractNode;
import net.sourceforge.pmd.lang.ast.impl.GenericNode;
import net.sourceforge.pmd.lang.document.FileLocation;
import net.sourceforge.pmd.lang.document.TextRange2d;
public class DummyNode extends AbstractNode<DummyNode, DummyNode> implements GenericNode<DummyNode> {
private final boolean findBoundary;
@ -58,7 +59,7 @@ public class DummyNode extends AbstractNode<DummyNode, DummyNode> implements Gen
@Override
public FileLocation getReportLocation() {
return getTextDocument().createLocation(bline, bcol, eline, ecol);
return getTextDocument().toLocation(TextRange2d.range2d(bline, bcol, eline, ecol));
}
public void setImage(String image) {

View File

@ -12,6 +12,7 @@ import net.sourceforge.pmd.lang.LanguageRegistry;
import net.sourceforge.pmd.lang.LanguageVersion;
import net.sourceforge.pmd.lang.ast.impl.GenericNode;
import net.sourceforge.pmd.lang.document.TextDocument;
import net.sourceforge.pmd.lang.document.TextPos2d;
public class DummyRoot extends DummyNode implements GenericNode<DummyNode>, RootNode {
@ -31,11 +32,42 @@ public class DummyRoot extends DummyNode implements GenericNode<DummyNode>, Root
return this;
}
public DummyRoot fakeTextWithNLines(int numLines, int lineWidth) {
StringBuilder sb = new StringBuilder(numLines * lineWidth);
for (int i = 0; i < numLines; i++) {
for (int j = 0; j < lineWidth; j++) {
sb.append('@');
}
sb.append('\n');
}
this.sourceText = sb.toString();
return this;
}
public DummyRoot withNoPmdComments(Map<Integer, String> suppressMap) {
this.suppressMap = suppressMap;
return this;
}
@Override
public DummyNode setCoords(int bline, int bcol, int eline, int ecol) {
@SuppressWarnings("PMD.CloseResource")
TextDocument doc = getAstInfo().getTextDocument();
checkInRange(bline, bcol, doc);
checkInRange(eline, ecol, doc);
return super.setCoords(bline, bcol, eline, ecol);
}
public DummyNode setCoordsReplaceText(int bline, int bcol, int eline, int ecol) {
fakeTextWithNLines(eline, Math.max(bcol, ecol));
return setCoords(bline, bcol, eline, ecol);
}
private void checkInRange(int line, int col, TextDocument doc) {
TextPos2d start = TextPos2d.pos2d(line, col);
assert doc.isInRange(start) : "position out of range " + start + ", text:\n" + sourceText;
}
public DummyRoot withFileName(String filename) {
this.filename = filename;

View File

@ -160,6 +160,33 @@ public class TextDocumentTest {
assertEquals(11, doc.offsetAtLineColumn(3, 1));
}
@Test
public void testCoordinateRoundTripWithEndOfLine() {
TextDocument doc = TextDocument.readOnlyString("bonjour\noa\n", dummyVersion);
TextRange2d inputRange = TextRange2d.fullLine(1, "bonjour\n".length());
TextRegion lineRange = doc.createLineRange(1, 1);
TextRegion region = doc.toRegion(inputRange);
assertEquals(TextRegion.fromOffsetLength(0, "bonjour\n".length()), region);
assertEquals(TextRegion.fromOffsetLength(0, "bonjour\n".length()), lineRange);
TextRange2d roundTrip = doc.toRange2d(region);
assertEquals(inputRange, roundTrip);
}
@Test
public void testCoordinateRoundTripSimple() {
TextDocument doc = TextDocument.readOnlyString("bonjour\noa\n", dummyVersion);
TextRange2d inputRange = TextRange2d.fullLine(1, "bonjour".length());
TextRegion region = doc.toRegion(inputRange);
assertEquals(TextRegion.fromOffsetLength(0, "bonjour".length()), region);
TextRange2d roundTrip = doc.toRange2d(region);
assertEquals(inputRange, roundTrip);
}
@Test
public void testLineRange() {
TextDocument doc = TextDocument.readOnlyString("bonjour\noha\ntristesse", dummyVersion);

View File

@ -81,8 +81,8 @@ public abstract class AbstractRendererTest {
}
protected DummyNode createNode(int beginLine, int beginColumn, int endLine, int endColumn) {
DummyNode node = new DummyRoot().withFileName(getSourceCodeFilename());
node.setCoords(beginLine, beginColumn, endLine, endColumn);
DummyRoot node = new DummyRoot().withFileName(getSourceCodeFilename());
node.setCoordsReplaceText(beginLine, beginColumn, endLine, endColumn);
return node;
}

View File

@ -144,10 +144,10 @@ public class SummaryHTMLRendererTest extends AbstractRendererTest {
assertEquals(getExpectedEmpty(), actual);
}
private Consumer<FileAnalysisListener> createEmptyReportWithSuppression() throws Exception {
private Consumer<FileAnalysisListener> createEmptyReportWithSuppression() {
return listener -> {
DummyRoot root = new DummyRoot().withNoPmdComments(Collections.singletonMap(1, "test")).withFileName(getSourceCodeFilename());
root.setCoords(1, 10, 4, 5);
root.setCoordsReplaceText(1, 10, 4, 5);
RuleContext ruleContext = RuleContext.create(listener, new FooRule());
ruleContext.addViolationWithPosition(root, 1, 1, "suppress test");

View File

@ -6,6 +6,7 @@ package net.sourceforge.pmd.lang.java.ast;
import net.sourceforge.pmd.lang.ast.impl.javacc.JavaccToken;
import net.sourceforge.pmd.lang.document.FileLocation;
import net.sourceforge.pmd.lang.document.TextRange2d;
import net.sourceforge.pmd.lang.java.javadoc.JavadocTag;
public class JavadocElement extends Comment {
@ -16,7 +17,7 @@ public class JavadocElement extends Comment {
public JavadocElement(JavaccToken t, int theBeginLine, int theEndLine, int theBeginColumn, int theEndColumn, JavadocTag theTag) {
super(t);
this.tag = theTag;
this.reportLoc = FileLocation.location("TODO", theBeginLine, theBeginColumn, theEndLine, theEndColumn);
this.reportLoc = FileLocation.location("TODO", TextRange2d.range2d(theBeginLine, theBeginColumn, theEndLine, theEndColumn));
}
public JavadocTag tag() {

View File

@ -6,6 +6,7 @@ package net.sourceforge.pmd.test.lang.ast;
import net.sourceforge.pmd.lang.ast.impl.AbstractNode;
import net.sourceforge.pmd.lang.document.FileLocation;
import net.sourceforge.pmd.lang.document.TextRange2d;
public class DummyNode extends AbstractNode<DummyNode, DummyNode> {
@ -13,7 +14,7 @@ public class DummyNode extends AbstractNode<DummyNode, DummyNode> {
private FileLocation location;
public void setCoords(int bline, int bcol, int eline, int ecol) {
this.location = FileLocation.location(":dummyFile:", bline, bcol, eline, ecol);
this.location = FileLocation.location(":dummyFile:", TextRange2d.range2d(bline, bcol, eline, ecol));
}
@Override