[java] Make impl of ASTLiteral#getLiteralText() public

Fixes #4885
This commit is contained in:
Andreas Dangel
2024-06-20 15:26:21 +02:00
parent 5014bee7ba
commit 18c30415d0
10 changed files with 62 additions and 27 deletions

View File

@ -17,6 +17,8 @@ This is a {{ site.pmd.release_type }} release.
### 🐛 Fixed Issues
* apex
* [#5053](https://github.com/pmd/pmd/issues/5053): \[apex] CPD fails to parse string literals with escaped characters
* java
* [#4885](https://github.com/pmd/pmd/issues/4885): \[java] AssertionError: Method should be accessible
* java-bestpractices
* [#5047](https://github.com/pmd/pmd/issues/5047): \[java] UnusedPrivateMethod FP for Generics & Overloads
* plsql

View File

@ -4,7 +4,6 @@
package net.sourceforge.pmd.lang.rule.xpath.impl;
import static net.sourceforge.pmd.util.CollectionUtil.emptyList;
import static net.sourceforge.pmd.util.CollectionUtil.setOf;
import java.lang.invoke.MethodHandle;
@ -91,7 +90,7 @@ public class AttributeAxisIterator implements Iterator<Attribute> {
.filter(m -> isAttributeAccessor(nodeClass, m))
.map(m -> {
try {
return new MethodWrapper(m, nodeClass);
return new MethodWrapper(m);
} catch (ReflectiveOperationException e) {
throw AssertionUtil.shouldNotReachHere("Method '" + m + "' should be accessible, but: " + e, e);
}
@ -210,19 +209,13 @@ public class AttributeAxisIterator implements Iterator<Attribute> {
public final String name;
MethodWrapper(Method m, Class<?> nodeClass) throws IllegalAccessException, NoSuchMethodException {
MethodWrapper(Method m) throws IllegalAccessException {
this.method = m;
this.name = truncateMethodName(m.getName());
if (!Modifier.isPublic(m.getDeclaringClass().getModifiers())) {
// This is a public method of a non-public class.
// To call it from reflection we need to call it via invokevirtual,
// whereas the default handle would use invokespecial.
MethodType methodType = MethodType.methodType(m.getReturnType(), emptyList());
this.methodHandle = MethodWrapper.LOOKUP.findVirtual(nodeClass, m.getName(), methodType).asType(GETTER_TYPE);
} else {
this.methodHandle = LOOKUP.unreflect(m).asType(GETTER_TYPE);
}
// Note: We only support public methods on public types. If the method being called is implemented
// in a package-private class, this won't work.
// See git history here and https://github.com/pmd/pmd/issues/4885
this.methodHandle = LOOKUP.unreflect(m).asType(GETTER_TYPE);
}

View File

@ -8,16 +8,16 @@ import net.sourceforge.pmd.lang.ast.DummyNode;
import net.sourceforge.pmd.lang.document.Chars;
// This class is package private
// and provides the implementation for getValue(). This
// class is the DeclaringClass for that method.
class AbstractNode extends DummyNode implements ValueNode {
// and provides the implementation for getValue().
// This method is not accessible from outside this package,
// it is made available in the subclass ConcreteNode.
class AbstractNode extends DummyNode {
AbstractNode() {
}
@Override
public final Chars getValue() {
Chars getValue() {
return Chars.wrap("actual_value");
}
}

View File

@ -4,5 +4,11 @@
package net.sourceforge.pmd.lang.rule.xpath.impl.dummyast;
import net.sourceforge.pmd.lang.document.Chars;
public final class ConcreteNode extends AbstractNode implements ValueNode {
@Override
public Chars getValue() {
return super.getValue();
}
}

View File

@ -6,10 +6,12 @@ package net.sourceforge.pmd.lang.java.ast;
import org.checkerframework.checker.nullness.qual.NonNull;
import net.sourceforge.pmd.lang.document.Chars;
/**
* The boolean literal, either "true" or "false".
*/
public final class ASTBooleanLiteral extends AbstractLiteral {
public final class ASTBooleanLiteral extends AbstractLiteral implements ASTLiteral {
private boolean isTrue;
@ -32,6 +34,11 @@ public final class ASTBooleanLiteral extends AbstractLiteral {
return isTrue;
}
@Override
public Chars getLiteralText() {
return super.getLiteralText();
}
@Override
protected <P, R> R acceptVisitor(JavaVisitor<? super P, ? extends R> visitor, P data) {
return visitor.visit(this, data);

View File

@ -15,7 +15,7 @@ import net.sourceforge.pmd.lang.document.Chars;
* retrieve the actual runtime value. Use {@link #getLiteralText()} to
* retrieve the text.
*/
public final class ASTCharLiteral extends AbstractLiteral {
public final class ASTCharLiteral extends AbstractLiteral implements ASTLiteral {
ASTCharLiteral(int id) {
@ -39,4 +39,8 @@ public final class ASTCharLiteral extends AbstractLiteral {
return StringEscapeUtils.UNESCAPE_JAVA.translate(woDelims).charAt(0);
}
@Override
public Chars getLiteralText() {
return super.getLiteralText();
}
}

View File

@ -6,6 +6,8 @@ package net.sourceforge.pmd.lang.java.ast;
import org.checkerframework.checker.nullness.qual.Nullable;
import net.sourceforge.pmd.lang.document.Chars;
/**
* The null literal.
*
@ -15,7 +17,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
*
* </pre>
*/
public final class ASTNullLiteral extends AbstractLiteral {
public final class ASTNullLiteral extends AbstractLiteral implements ASTLiteral {
ASTNullLiteral(int id) {
super(id);
}
@ -35,4 +37,9 @@ public final class ASTNullLiteral extends AbstractLiteral {
public @Nullable Object getConstValue() {
return null;
}
@Override
public Chars getLiteralText() {
return super.getLiteralText();
}
}

View File

@ -14,7 +14,7 @@ import net.sourceforge.pmd.lang.java.types.JPrimitiveType;
/**
* A numeric literal of any type (double, int, long, float, etc).
*/
public final class ASTNumericLiteral extends AbstractLiteral {
public final class ASTNumericLiteral extends AbstractLiteral implements ASTLiteral {
/**
* True if this is an integral literal, ie int OR long,
@ -36,6 +36,11 @@ public final class ASTNumericLiteral extends AbstractLiteral {
return visitor.visit(this, data);
}
@Override
public Chars getLiteralText() {
return super.getLiteralText();
}
@Override
public @NonNull Number getConstValue() {
return (Number) super.getConstValue();

View File

@ -18,7 +18,7 @@ import net.sourceforge.pmd.util.StringUtil;
* in the source ({@link #getLiteralText()}). {@link #getConstValue()} allows to recover
* the actual runtime value, by processing escapes.
*/
public final class ASTStringLiteral extends AbstractLiteral {
public final class ASTStringLiteral extends AbstractLiteral implements ASTLiteral {
private static final String TEXTBLOCK_DELIMITER = "\"\"\"";
@ -36,6 +36,11 @@ public final class ASTStringLiteral extends AbstractLiteral {
return getText().toString();
}
@Override
public Chars getLiteralText() {
return super.getLiteralText();
}
void setTextBlock() {
this.isTextBlock = true;
}

View File

@ -10,8 +10,11 @@ import net.sourceforge.pmd.lang.rule.xpath.NoAttribute;
/**
* @author Clément Fournier
* @see ASTLiteral#getLiteralText()
* @see #getLiteralText()
*/
abstract class AbstractLiteral extends AbstractJavaExpr implements ASTLiteral {
// Note: This class must not implement ASTLiteral, see comment on #getLiteralText()
abstract class AbstractLiteral extends AbstractJavaExpr {
private JavaccToken literalToken;
@ -41,13 +44,16 @@ abstract class AbstractLiteral extends AbstractJavaExpr implements ASTLiteral {
return firstToken.getImageCs();
}
@Override
public final Chars getLiteralText() {
// This method represents ASTLiteral#getLiteralText().
// However, since this class is package private, this method is not reliably accessible
// via reflection/method handles (see https://github.com/pmd/pmd/issues/4885).
// Subclasses of this class need to implement ASTLiteral and override this method
// as public.
Chars getLiteralText() {
assert literalToken.getImageCs() != null;
return literalToken.getImageCs();
}
@Override
public boolean isCompileTimeConstant() {
return true; // note: NullLiteral overrides this to false