Fix scala text bounds

This commit is contained in:
Clément Fournier
2019-09-17 04:20:10 +02:00
parent ed428dd852
commit 95d6ea3f37
9 changed files with 158 additions and 14 deletions

View File

@ -6,6 +6,7 @@ package net.sourceforge.pmd.lang.ast.test
import io.kotlintest.should
import kotlin.reflect.KCallable
import kotlin.reflect.jvm.isAccessible
import io.kotlintest.shouldBe as ktShouldBe
/**
@ -21,6 +22,7 @@ private fun <N, V> assertWrapper(callable: KCallable<N>, right: V, asserter: (N,
fun formatName() = "::" + callable.name.removePrefix("get").decapitalize()
val value: N = try {
callable.isAccessible = true
callable.call()
} catch (e: Exception) {
throw RuntimeException("Couldn't fetch value for property ${formatName()}", e)

View File

@ -25,6 +25,12 @@
</delimiters>
</configuration>
</plugin>
<plugin>
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
</plugin>
</plugins>
</build>
@ -49,5 +55,10 @@
<artifactId>pmd-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-lang-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -14,7 +14,6 @@ import org.apache.commons.io.IOUtils;
import net.sourceforge.pmd.lang.AbstractParser;
import net.sourceforge.pmd.lang.ParserOptions;
import net.sourceforge.pmd.lang.TokenManager;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.ast.ParseException;
import net.sourceforge.pmd.lang.scala.ast.ASTSource;

View File

@ -18,21 +18,47 @@ import scala.meta.inputs.Position;
*/
abstract class AbstractScalaNode<T extends Tree> extends AbstractNode implements ScalaNode<T> {
private final T node;
private final Position pos;
/**
* Create the node and configure line numbers.
*
*
* @param treeNode
* the scala tree node this node wraps
*/
AbstractScalaNode(T treeNode) {
super(0);
node = treeNode;
Position pos = node.pos();
pos = node.pos();
beginLine = pos.startLine() + 1;
endLine = pos.endLine() + 1;
beginColumn = pos.startColumn() + 1;
endColumn = pos.endColumn() + 1;
endColumn = pos.endColumn();
}
@Override
public boolean isImplicit() {
return pos.end() - pos.start() == 0;
}
@Override
public int getBeginLine() {
return pos.startLine() + 1;
}
@Override
public int getBeginColumn() {
return pos.startColumn() + 1;
}
@Override
public int getEndLine() {
return pos.endLine() + 1;
}
@Override
public int getEndColumn() {
return pos.endColumn(); // no +1
}
@Override

View File

@ -11,14 +11,14 @@ import scala.meta.Tree;
/**
* A Base interface of a Scala Node. Defines several required methods of all
* nodes.
*
*
* @param <T>
* The Scala node type that extends Scala's Tree trait
*/
public interface ScalaNode<T extends Tree> extends Node {
/**
* Accept a visitor and traverse this node.
*
*
* @param <D>
* The type of the data input
* @param <R>
@ -34,12 +34,24 @@ public interface ScalaNode<T extends Tree> extends Node {
/**
* Get the underlying Scala Node.
*
*
* @return the Scala Node for this node
*/
T getNode();
/**
* Returns true if the node is implicit. If this node has no non-implicit
* descendant, then its text bounds identify an empty region of the source
* document. In that case, the {@linkplain #getEndColumn() end column} is
* smaller than the {@linkplain #getBeginColumn() begin column}.
*/
// TODO this would be useful on the node interface for 7.0.0.
// we could filter them out from violations transparently
// Apex has the same problem
boolean isImplicit();
@Override
ScalaNode<?> jjtGetChild(int idx);

View File

@ -1,8 +1,8 @@
/**
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.scala;
package net.sourceforge.pmd.lang.scala.ast;
import java.io.StringReader;
import java.util.ArrayList;

View File

@ -1,8 +1,8 @@
/**
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.scala.rule;
package net.sourceforge.pmd.lang.scala.rule;
import java.io.File;
import java.io.StringReader;
@ -30,7 +30,6 @@ import net.sourceforge.pmd.lang.scala.ScalaLanguageModule;
import net.sourceforge.pmd.lang.scala.ast.ASTTermApply;
import net.sourceforge.pmd.lang.scala.ast.ASTTermName;
import net.sourceforge.pmd.lang.scala.ast.ScalaNode;
import net.sourceforge.pmd.lang.scala.rule.ScalaRule;
public class ScalaRuleTest {
private static final String SCALA_TEST = "/parserFiles/helloworld.scala";

View File

@ -1,8 +1,8 @@
/**
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.scala.rule;
package net.sourceforge.pmd.lang.scala.rule;
import static org.junit.Assert.assertEquals;

View File

@ -0,0 +1,95 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.scala.ast
import io.kotlintest.should
import io.kotlintest.specs.FunSpec
import net.sourceforge.pmd.lang.LanguageRegistry
import net.sourceforge.pmd.lang.ast.Node
import net.sourceforge.pmd.lang.ast.test.matchNode
import net.sourceforge.pmd.lang.ast.test.shouldBe
import java.io.StringReader
class ScalaTreeTests : FunSpec({
test("Test line/column numbers") {
"""
class Foo {
val I = ""
}
""".trim().parseScala() should matchNode<ASTSource> {
child<ASTDefnClass> {
it.assertBounds(bline = 1, bcol = 1, eline = 3, ecol = 1)
it::isImplicit shouldBe false
child<ASTTypeName> {
it.assertBounds(bline = 1, bcol = 7, eline = 1, ecol = 9)
it::isImplicit shouldBe false
}
child<ASTCtorPrimary> {
it.assertBounds(bline = 1, bcol = 11, eline = 1, ecol = 10) // node has zero length
it::isImplicit shouldBe true
child<ASTNameAnonymous> {
it.assertBounds(bline = 1, bcol = 11, eline = 1, ecol = 10) // node has zero length
it::isImplicit shouldBe true
}
}
child<ASTTemplate> {
it.assertBounds(bline = 1, bcol = 11, eline = 3, ecol = 1)
it::isImplicit shouldBe false
child<ASTSelf> {
it.assertBounds(bline = 2, bcol = 2, eline = 2, ecol = 1) // node has zero length
it::isImplicit shouldBe true
child<ASTNameAnonymous> {
it.assertBounds(bline = 2, bcol = 2, eline = 2, ecol = 1) // node has zero length
it::isImplicit shouldBe true
}
}
child<ASTDefnVal> {
it.assertBounds(bline = 2, bcol = 2, eline = 2, ecol = 11)
it::isImplicit shouldBe false
child<ASTPatVar> {
it.assertBounds(bline = 2, bcol = 6, eline = 2, ecol = 6)
it::isImplicit shouldBe false
child<ASTTermName> {
it.assertBounds(bline = 2, bcol = 6, eline = 2, ecol = 6)
it::isImplicit shouldBe false
}
}
child<ASTLitString> {
it.assertBounds(bline = 2, bcol = 10, eline = 2, ecol = 11)
}
}
}
}
}
}
})
fun String.parseScala(): ASTSource {
val ver = LanguageRegistry.getLanguage("Scala").defaultVersion.languageVersionHandler
val parser = ver.getParser(ver.defaultParserOptions)
return parser.parse(":dummy:", StringReader(this)) as ASTSource
}
fun Node.assertBounds(bline: Int, bcol: Int, eline: Int, ecol: Int) {
this::getBeginLine shouldBe bline
this::getBeginColumn shouldBe bcol
this::getEndLine shouldBe eline
this::getEndColumn shouldBe ecol
}