forked from phoedos/pmd
Cleanup tests
Make DummyNode use offset/length coordinates
This commit is contained in:
@ -132,7 +132,7 @@ public final class RuleContext {
|
||||
|
||||
FileLocation location = node.getReportLocation();
|
||||
if (beginLine != -1 && endLine != -1) {
|
||||
location = FileLocation.location(location.getFileName(), TextRange2d.range2d(beginLine, 1, endLine, 1));
|
||||
location = FileLocation.range(location.getFileName(), TextRange2d.range2d(beginLine, 1, endLine, 1));
|
||||
}
|
||||
|
||||
RuleViolation violation = fact.createViolation(rule, node, location, makeMessage(message, formatArgs));
|
||||
|
@ -42,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, TextRange2d.range2d(beginLine, beginColumn, endLine, endColumn));
|
||||
this.location = FileLocation.range(fileName, TextRange2d.range2d(beginLine, beginColumn, endLine, endColumn));
|
||||
this.ruleClassName = ruleClassName;
|
||||
this.ruleName = ruleName;
|
||||
this.ruleTargetLanguage = ruleTargetLanguage;
|
||||
|
@ -145,7 +145,7 @@ 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, TextRange2d range2d) {
|
||||
public static FileLocation range(String fileName, TextRange2d range2d) {
|
||||
TextPos2d start = range2d.getStartPos();
|
||||
TextPos2d end = range2d.getEndPos();
|
||||
return new FileLocation(fileName,
|
||||
|
@ -163,7 +163,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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -17,12 +17,22 @@ public final class TextRange2d implements Comparable<TextRange2d> {
|
||||
private final int endCol;
|
||||
|
||||
public TextRange2d(int startLine, int startCol, int endLine, int endCol) {
|
||||
checkValid(startLine, startCol, endLine, endCol);
|
||||
this.startLine = startLine;
|
||||
this.startCol = startCol;
|
||||
this.endLine = endLine;
|
||||
this.endCol = endCol;
|
||||
}
|
||||
|
||||
private void checkValid(int startLine, int startCol, int endLine, int endCol) {
|
||||
if (startCol < 1 || startLine < 1 || endLine < 1 || endCol < 1) {
|
||||
throw new IllegalArgumentException(
|
||||
"Not a valid range (l" + startLine + ", c" + startCol + ")-"
|
||||
+ "(l" + endLine + ", c" + endCol + ")"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public TextPos2d getStartPos() {
|
||||
return TextPos2d.pos2d(startLine, startCol);
|
||||
|
@ -75,7 +75,7 @@ public class ReportTest {
|
||||
}
|
||||
|
||||
private static FileLocation getNode(int line, int column, String filename) {
|
||||
return FileLocation.location(
|
||||
return FileLocation.range(
|
||||
filename,
|
||||
TextRange2d.range2d(line, column, line, column)
|
||||
);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -9,12 +9,14 @@ import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import net.sourceforge.pmd.lang.DummyLanguageModule;
|
||||
import net.sourceforge.pmd.lang.ast.DummyNode;
|
||||
import net.sourceforge.pmd.lang.ast.DummyNode.DummyRootNode;
|
||||
import net.sourceforge.pmd.lang.document.FileLocation;
|
||||
import net.sourceforge.pmd.lang.document.TextFile;
|
||||
import net.sourceforge.pmd.lang.document.TextRange2d;
|
||||
import net.sourceforge.pmd.lang.rule.MockRule;
|
||||
import net.sourceforge.pmd.lang.rule.ParametricRuleViolation;
|
||||
|
||||
@ -68,25 +70,19 @@ public class RuleViolationTest {
|
||||
assertTrue(comp.compare(r2, r1) > 0);
|
||||
}
|
||||
|
||||
@Ignore("FIXME enabling this test means we don't respect the contract of Comparator!")
|
||||
@Test
|
||||
public void testComparatorWithSameFileSameLines() {
|
||||
Rule rule = new MockRule("name", "desc", "msg", "rulesetname");
|
||||
Comparator<RuleViolation> comp = RuleViolation.DEFAULT_COMPARATOR;
|
||||
DummyRootNode rootNode = new DummyRootNode();
|
||||
String filename = TextFile.UNKNOWN_FILENAME;
|
||||
|
||||
DummyNode s = new DummyNode();
|
||||
s.setCoords(10, 1, 15, 10);
|
||||
rootNode.addChild(s, 0);
|
||||
RuleViolation r1 = new ParametricRuleViolation(rule, s, "description");
|
||||
|
||||
DummyNode s1 = new DummyNode();
|
||||
s1.setCoords(10, 1, 15, 10);
|
||||
rootNode.addChild(s1, 1);
|
||||
RuleViolation r2 = new ParametricRuleViolation(rule, s1, "description");
|
||||
FileLocation loc = FileLocation.range(filename, TextRange2d.range2d(10, 1, 15, 10));
|
||||
RuleViolation r1 = new ParametricRuleViolation(rule, loc, "description");
|
||||
RuleViolation r2 = new ParametricRuleViolation(rule, loc, "description");
|
||||
|
||||
assertEquals(1, comp.compare(r1, r2));
|
||||
assertEquals(1, comp.compare(r2, r1));
|
||||
assertEquals(0, comp.compare(r1, r2));
|
||||
assertEquals(0, comp.compare(r2, r1));
|
||||
}
|
||||
|
||||
public static junit.framework.Test suite() {
|
||||
|
@ -117,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(), TextRange2d.range2d(1, 2, 3, 4)));
|
||||
when(rv.getLocation()).thenReturn(FileLocation.range(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);
|
||||
|
@ -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.TextFile;
|
||||
import net.sourceforge.pmd.lang.document.TextRange2d;
|
||||
import net.sourceforge.pmd.lang.document.TextRegion;
|
||||
|
||||
@ -59,7 +60,7 @@ public class BaseTokenFilterTest {
|
||||
|
||||
@Override
|
||||
public FileLocation getReportLocation() {
|
||||
return FileLocation.location("n/a", TextRange2d.range2d(0, 0, 0, 0));
|
||||
return FileLocation.range(TextFile.UNKNOWN_FILENAME, TextRange2d.range2d(1, 1, 1, 1));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -20,8 +20,6 @@ import net.sourceforge.pmd.lang.document.Chars;
|
||||
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.TextPos2d;
|
||||
import net.sourceforge.pmd.lang.document.TextRange2d;
|
||||
import net.sourceforge.pmd.lang.document.TextRegion;
|
||||
import net.sourceforge.pmd.lang.rule.ParametricRuleViolation;
|
||||
import net.sourceforge.pmd.lang.rule.impl.DefaultRuleViolationFactory;
|
||||
@ -115,14 +113,11 @@ public class DummyLanguageModule extends BaseLanguageModule {
|
||||
private static DummyRootNode readLispNode(ParserTask task) {
|
||||
TextDocument document = task.getTextDocument();
|
||||
final DummyRootNode root = new DummyRootNode().withTaskInfo(task);
|
||||
{
|
||||
TextPos2d endPos = document.getEntireRegion2d().getEndPos();
|
||||
root.setCoords(1, 1, endPos.getLine(), endPos.getColumn());
|
||||
}
|
||||
root.setRegion(document.getEntireRegion());
|
||||
|
||||
DummyNode top = root;
|
||||
int lastNodeStart = 0;
|
||||
Chars text = document.getContent().getNormalizedText();
|
||||
Chars text = document.getText();
|
||||
for (int i = 0; i < text.length(); i++) {
|
||||
char c = text.charAt(i);
|
||||
if (c == '(') {
|
||||
@ -130,7 +125,7 @@ public class DummyLanguageModule extends BaseLanguageModule {
|
||||
node.setParent(top);
|
||||
top.addChild(node, top.getNumChildren());
|
||||
// setup coordinates, temporary (will be completed when node closes)
|
||||
node.setCoords(document, TextRegion.caretAt(i));
|
||||
node.setRegion(TextRegion.caretAt(i));
|
||||
|
||||
// cut out image
|
||||
if (top.getImage() == null) {
|
||||
@ -148,9 +143,7 @@ public class DummyLanguageModule extends BaseLanguageModule {
|
||||
throw new ParseException("Unbalanced parentheses: " + text);
|
||||
}
|
||||
|
||||
TextPos2d endPos = document.toRange2d(TextRegion.caretAt(i)).getEndPos();
|
||||
TextPos2d startPos = top.getCoords().getStartPos();
|
||||
top.setCoords(TextRange2d.range2d(startPos, endPos));
|
||||
top.setRegion(TextRegion.fromBothOffsets(top.getTextRegion().getStartOffset(), i));
|
||||
|
||||
if (top.getImage() == null) {
|
||||
// cut out image (if node doesn't have children it hasn't been populated yet)
|
||||
|
@ -5,12 +5,12 @@
|
||||
package net.sourceforge.pmd.lang.ast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import net.sourceforge.pmd.internal.util.AssertionUtil;
|
||||
import net.sourceforge.pmd.lang.DummyLanguageModule;
|
||||
import net.sourceforge.pmd.lang.ast.Parser.ParserTask;
|
||||
import net.sourceforge.pmd.lang.ast.impl.AbstractNode;
|
||||
@ -18,22 +18,17 @@ import net.sourceforge.pmd.lang.ast.impl.GenericNode;
|
||||
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.TextRange2d;
|
||||
import net.sourceforge.pmd.lang.document.TextRegion;
|
||||
import net.sourceforge.pmd.lang.rule.xpath.Attribute;
|
||||
|
||||
public class DummyNode extends AbstractNode<DummyNode, DummyNode> implements GenericNode<DummyNode> {
|
||||
|
||||
private final boolean findBoundary;
|
||||
private final String xpathName;
|
||||
private final Map<String, String> userData = new HashMap<>();
|
||||
private String xpathName;
|
||||
private String image;
|
||||
private final List<Attribute> attributes = new ArrayList<>();
|
||||
|
||||
private int bline = 1;
|
||||
private int bcol = 1;
|
||||
private int eline = 1;
|
||||
private int ecol = 1;
|
||||
private TextRegion region = TextRegion.caretAt(0);
|
||||
|
||||
public DummyNode(String xpathName) {
|
||||
this(false, xpathName);
|
||||
@ -83,34 +78,29 @@ public class DummyNode extends AbstractNode<DummyNode, DummyNode> implements Gen
|
||||
}
|
||||
}
|
||||
|
||||
public DummyNode setCoords(int bline, int bcol, int eline, int ecol) {
|
||||
this.bline = bline;
|
||||
this.bcol = bcol;
|
||||
this.eline = eline;
|
||||
this.ecol = ecol;
|
||||
return this;
|
||||
@Override
|
||||
public TextRegion getTextRegion() {
|
||||
return region;
|
||||
}
|
||||
|
||||
public DummyNode setCoords(TextDocument document, TextRegion region) {
|
||||
FileLocation loc = document.toLocation(region);
|
||||
return setCoords(loc.getStartLine(), loc.getStartColumn(), loc.getEndLine(), loc.getEndColumn());
|
||||
}
|
||||
|
||||
public DummyNode setCoords(TextRange2d region) {
|
||||
return setCoords(region.getStartLine(), region.getStartColumn(), region.getEndLine(), region.getEndColumn());
|
||||
}
|
||||
|
||||
public TextRange2d getCoords() {
|
||||
return TextRange2d.range2d(bline, bcol, eline, ecol);
|
||||
public void setRegion(TextRegion region) {
|
||||
this.region = region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileLocation getReportLocation() {
|
||||
return getTextDocument().toLocation(TextRange2d.range2d(bline, bcol, eline, ecol));
|
||||
return getTextDocument().toLocation(region);
|
||||
}
|
||||
|
||||
/**
|
||||
* Nodes with an image that starts with `#` also set the xpath name.
|
||||
*/
|
||||
public void setImage(String image) {
|
||||
this.image = image;
|
||||
if (image.startsWith("#")) {
|
||||
xpathName = image.substring(1);
|
||||
assert AssertionUtil.isJavaIdentifier(xpathName) : "need an ident after '#': " + image;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -133,10 +123,6 @@ public class DummyNode extends AbstractNode<DummyNode, DummyNode> implements Gen
|
||||
return findBoundary;
|
||||
}
|
||||
|
||||
public Map<String, String> getUserData() {
|
||||
return userData;
|
||||
}
|
||||
|
||||
public void setXPathAttribute(String name, String value) {
|
||||
attributes.add(new Attribute(this, name, value));
|
||||
}
|
||||
|
@ -8,10 +8,12 @@ import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import net.sourceforge.pmd.lang.document.TextRegion;
|
||||
|
||||
public class DummyNodeWithListAndEnum extends DummyNode.DummyRootNode {
|
||||
public DummyNodeWithListAndEnum() {
|
||||
super();
|
||||
setCoords(1, 1, 1, 2);
|
||||
setRegion(TextRegion.fromOffsetLength(0, 1));
|
||||
}
|
||||
|
||||
public enum MyEnum {
|
||||
|
@ -20,6 +20,7 @@ import net.sourceforge.pmd.lang.LanguageRegistry;
|
||||
import net.sourceforge.pmd.lang.ast.DummyNode;
|
||||
import net.sourceforge.pmd.lang.ast.DummyNode.DummyRootNode;
|
||||
import net.sourceforge.pmd.lang.ast.DummyNodeWithDeprecatedAttribute;
|
||||
import net.sourceforge.pmd.lang.document.TextRegion;
|
||||
import net.sourceforge.pmd.lang.rule.xpath.XPathVersion;
|
||||
|
||||
public class XPathRuleTest {
|
||||
@ -151,7 +152,7 @@ public class XPathRuleTest {
|
||||
DummyRootNode root = new DummyRootNode();
|
||||
DummyNode dummy = new DummyNodeWithDeprecatedAttribute();
|
||||
root.addChild(dummy, 0);
|
||||
dummy.setCoords(1, 1, 1, 2);
|
||||
dummy.setRegion(TextRegion.fromOffsetLength(0, 1));
|
||||
return root;
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,6 @@ public class AttributeAxisIteratorTest {
|
||||
@Test
|
||||
public void testAttributeAxisIterator() {
|
||||
DummyNode dummyNode = new DummyNode();
|
||||
dummyNode.setCoords(1, 1, 2, 2);
|
||||
|
||||
AttributeAxisIterator it = new AttributeAxisIterator(dummyNode);
|
||||
|
||||
|
@ -8,6 +8,7 @@ package net.sourceforge.pmd.lang.rule.xpath.internal;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import net.sourceforge.pmd.lang.DummyLanguageModule;
|
||||
import net.sourceforge.pmd.lang.ast.DummyNode;
|
||||
import net.sourceforge.pmd.lang.ast.DummyNode.DummyRootNode;
|
||||
|
||||
@ -19,16 +20,13 @@ public class ElementNodeTest {
|
||||
|
||||
@Test
|
||||
public void testCompareOrder() {
|
||||
DummyRootNode root = new DummyRootNode();
|
||||
|
||||
DummyNode c0 = new DummyNode(false, "foo");
|
||||
c0.setCoords(1, 1, 2, 2);
|
||||
root.addChild(c0, 0);
|
||||
|
||||
DummyNode c1 = new DummyNode(false, "foo");
|
||||
c1.setCoords(2, 1, 2, 2);
|
||||
root.addChild(c1, 1);
|
||||
DummyRootNode root = DummyLanguageModule.parse(
|
||||
"(#foo)"
|
||||
+ "(#foo)"
|
||||
);
|
||||
|
||||
DummyNode c0 = root.getChild(0);
|
||||
DummyNode c1 = root.getChild(1);
|
||||
|
||||
Configuration configuration = Configuration.newConfiguration();
|
||||
|
||||
|
@ -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,8 @@ 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"));
|
||||
|
@ -1,10 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<pmd xmlns="http://pmd.sourceforge.net/report/2.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pmd.sourceforge.net/report/2.0.0 http://pmd.sourceforge.net/report_2_0_0.xsd" version="6.45.0-SNAPSHOT" timestamp="2022-03-31T17:55:43.046">
|
||||
<pmd xmlns="http://pmd.sourceforge.net/report/2.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pmd.sourceforge.net/report/2.0.0 http://pmd.sourceforge.net/report_2_0_0.xsd" version="" timestamp="">
|
||||
<file name="sample.dummy">
|
||||
<violation beginline="1" endline="2" begincolumn="1" endcolumn="1" rule="SampleXPathRule" ruleset="Test Ruleset" package="foo" externalInfoUrl="${pmd.website.baseurl}/rules/dummy/basic.xml#SampleXPathRule" priority="3">
|
||||
<violation beginline="1" endline="1" begincolumn="1" endcolumn="110" rule="SampleXPathRule" ruleset="Test Ruleset" package="foo" externalInfoUrl="${pmd.website.baseurl}/rules/dummy/basic.xml#SampleXPathRule" priority="3">
|
||||
Test Rule 2
|
||||
</violation>
|
||||
<violation beginline="1" endline="2" begincolumn="1" endcolumn="1" rule="DeprecatedRule" ruleset="Test Ruleset" package="foo" externalInfoUrl="${pmd.website.baseurl}/rules/dummy/basic.xml#deprecatedrule" priority="3">
|
||||
<violation beginline="1" endline="1" begincolumn="1" endcolumn="110" rule="DeprecatedRule" ruleset="Test Ruleset" package="foo" externalInfoUrl="${pmd.website.baseurl}/rules/dummy/basic.xml#deprecatedrule" priority="3">
|
||||
Test Rule 3
|
||||
</violation>
|
||||
</file>
|
||||
|
@ -17,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", TextRange2d.range2d(theBeginLine, theBeginColumn, theEndLine, theEndColumn));
|
||||
this.reportLoc = FileLocation.range("TODO", TextRange2d.range2d(theBeginLine, theBeginColumn, theEndLine, theEndColumn));
|
||||
}
|
||||
|
||||
public JavadocTag tag() {
|
||||
|
@ -14,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:", TextRange2d.range2d(bline, bcol, eline, ecol));
|
||||
this.location = FileLocation.range(":dummyFile:", TextRange2d.range2d(bline, bcol, eline, ecol));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
Reference in New Issue
Block a user