forked from phoedos/pmd
Merge branch 'pr-5341'
This commit is contained in:
commit
59864a7c6c
@ -25,6 +25,8 @@ This is a {{ site.pmd.release_type }} release.
|
|||||||
* [#5293](https://github.com/pmd/pmd/issues/5293): \[java] Deadlock when executing PMD in multiple threads
|
* [#5293](https://github.com/pmd/pmd/issues/5293): \[java] Deadlock when executing PMD in multiple threads
|
||||||
* [#5324](https://github.com/pmd/pmd/issues/5324): \[java] Issue with type inference of nested lambdas
|
* [#5324](https://github.com/pmd/pmd/issues/5324): \[java] Issue with type inference of nested lambdas
|
||||||
* [#5329](https://github.com/pmd/pmd/issues/5329): \[java] Type inference issue with unknown method ref in call chain
|
* [#5329](https://github.com/pmd/pmd/issues/5329): \[java] Type inference issue with unknown method ref in call chain
|
||||||
|
* java-bestpractices
|
||||||
|
* [#5083](https://github.com/pmd/pmd/issues/5083): \[java] UnusedPrivateMethod false positive when method reference has no target type
|
||||||
* java-performance
|
* java-performance
|
||||||
* [#5314](https://github.com/pmd/pmd/issues/5314): \[java] InsufficientStringBufferDeclarationRule: Lack of handling for char type parameters
|
* [#5314](https://github.com/pmd/pmd/issues/5314): \[java] InsufficientStringBufferDeclarationRule: Lack of handling for char type parameters
|
||||||
|
|
||||||
|
@ -36,7 +36,6 @@ import net.sourceforge.pmd.lang.java.types.internal.infer.ExprMirror.CtorInvocat
|
|||||||
import net.sourceforge.pmd.lang.java.types.internal.infer.ExprMirror.FunctionalExprMirror;
|
import net.sourceforge.pmd.lang.java.types.internal.infer.ExprMirror.FunctionalExprMirror;
|
||||||
import net.sourceforge.pmd.lang.java.types.internal.infer.ExprMirror.InvocationMirror;
|
import net.sourceforge.pmd.lang.java.types.internal.infer.ExprMirror.InvocationMirror;
|
||||||
import net.sourceforge.pmd.lang.java.types.internal.infer.ExprMirror.InvocationMirror.MethodCtDecl;
|
import net.sourceforge.pmd.lang.java.types.internal.infer.ExprMirror.InvocationMirror.MethodCtDecl;
|
||||||
import net.sourceforge.pmd.lang.java.types.internal.infer.ExprMirror.LambdaExprMirror;
|
|
||||||
import net.sourceforge.pmd.lang.java.types.internal.infer.ExprMirror.MethodRefMirror;
|
import net.sourceforge.pmd.lang.java.types.internal.infer.ExprMirror.MethodRefMirror;
|
||||||
import net.sourceforge.pmd.lang.java.types.internal.infer.ExprMirror.PolyExprMirror;
|
import net.sourceforge.pmd.lang.java.types.internal.infer.ExprMirror.PolyExprMirror;
|
||||||
import net.sourceforge.pmd.lang.java.types.internal.infer.InferenceVar.BoundKind;
|
import net.sourceforge.pmd.lang.java.types.internal.infer.InferenceVar.BoundKind;
|
||||||
@ -145,13 +144,19 @@ public final class Infer {
|
|||||||
LOG.logResolutionFail(rfe.getFailure());
|
LOG.logResolutionFail(rfe.getFailure());
|
||||||
// here we set expected if not null, the lambda will have the target type
|
// here we set expected if not null, the lambda will have the target type
|
||||||
expr.setInferredType(expected == null ? ts.UNKNOWN : expected);
|
expr.setInferredType(expected == null ? ts.UNKNOWN : expected);
|
||||||
|
expr.setFunctionalMethod(ts.UNRESOLVED_METHOD);
|
||||||
if (expr instanceof MethodRefMirror) {
|
if (expr instanceof MethodRefMirror) {
|
||||||
MethodRefMirror mref = (MethodRefMirror) expr;
|
MethodRefMirror mref = (MethodRefMirror) expr;
|
||||||
mref.setFunctionalMethod(ts.UNRESOLVED_METHOD);
|
if (!TypeOps.isUnresolved(mref.getTypeToSearch())) {
|
||||||
|
JMethodSig exactMethod = ExprOps.getExactMethod(mref);
|
||||||
|
if (exactMethod != null) {
|
||||||
|
// as a fallback, if the method reference is exact,
|
||||||
|
// we populate the compile time decl anyway.
|
||||||
|
mref.setCompileTimeDecl(exactMethod);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
mref.setCompileTimeDecl(ts.UNRESOLVED_METHOD);
|
mref.setCompileTimeDecl(ts.UNRESOLVED_METHOD);
|
||||||
} else {
|
|
||||||
LambdaExprMirror lambda = (LambdaExprMirror) expr;
|
|
||||||
lambda.setFunctionalMethod(ts.UNRESOLVED_METHOD);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,12 +5,12 @@
|
|||||||
package net.sourceforge.pmd.lang.java.types.internal.infer
|
package net.sourceforge.pmd.lang.java.types.internal.infer
|
||||||
|
|
||||||
import io.kotest.matchers.shouldBe
|
import io.kotest.matchers.shouldBe
|
||||||
|
import net.sourceforge.pmd.lang.java.ast.*
|
||||||
|
import net.sourceforge.pmd.lang.java.types.*
|
||||||
import net.sourceforge.pmd.lang.test.ast.component6
|
import net.sourceforge.pmd.lang.test.ast.component6
|
||||||
import net.sourceforge.pmd.lang.test.ast.component7
|
import net.sourceforge.pmd.lang.test.ast.component7
|
||||||
import net.sourceforge.pmd.lang.test.ast.shouldBe
|
import net.sourceforge.pmd.lang.test.ast.shouldBe
|
||||||
import net.sourceforge.pmd.lang.test.ast.shouldMatchN
|
import net.sourceforge.pmd.lang.test.ast.shouldMatchN
|
||||||
import net.sourceforge.pmd.lang.java.ast.*
|
|
||||||
import net.sourceforge.pmd.lang.java.types.*
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.function.*
|
import java.util.function.*
|
||||||
import java.util.stream.Collector
|
import java.util.stream.Collector
|
||||||
@ -331,12 +331,13 @@ class MethodRefInferenceTest : ProcessorTestSpec({
|
|||||||
|
|
||||||
val t_Archive = acu.firstTypeSignature()
|
val t_Archive = acu.firstTypeSignature()
|
||||||
val mref = acu.descendants(ASTMethodReference::class.java).firstOrThrow()
|
val mref = acu.descendants(ASTMethodReference::class.java).firstOrThrow()
|
||||||
|
val (getName) = acu.declaredMethodSignatures().toList()
|
||||||
val call = acu.firstMethodCall()
|
val call = acu.firstMethodCall()
|
||||||
|
|
||||||
spy.shouldHaveMissingCtDecl(call)
|
spy.shouldHaveMissingCtDecl(call)
|
||||||
|
|
||||||
acu.withTypeDsl {
|
acu.withTypeDsl {
|
||||||
mref.referencedMethod shouldBe ts.UNRESOLVED_METHOD
|
mref.referencedMethod shouldBe getName
|
||||||
mref shouldHaveType ts.UNKNOWN
|
mref shouldHaveType ts.UNKNOWN
|
||||||
call.methodType shouldBe ts.UNRESOLVED_METHOD
|
call.methodType shouldBe ts.UNRESOLVED_METHOD
|
||||||
call.overloadSelectionInfo.apply {
|
call.overloadSelectionInfo.apply {
|
||||||
@ -1093,4 +1094,38 @@ class Scratch {
|
|||||||
mref shouldHaveType t_Additioner
|
mref shouldHaveType t_Additioner
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parserTest("Method ref without target type still populates CTDecl if exact") {
|
||||||
|
val (acu, spy) = parser.parseWithTypeInferenceSpy(
|
||||||
|
"""
|
||||||
|
class GenerationType {
|
||||||
|
static {
|
||||||
|
foo(GenerationType::isAndroidType);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
foo(this::instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean instance(String data) {}
|
||||||
|
private static boolean isAndroidType(String data) {
|
||||||
|
return "android".equals(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
|
||||||
|
val (instance, static) = acu.declaredMethodSignatures()
|
||||||
|
|
||||||
|
val mrefs = acu.descendants(ASTMethodReference::class.java).toList()
|
||||||
|
val (staticMref, instanceMref) = mrefs
|
||||||
|
|
||||||
|
spy.shouldBeOk {
|
||||||
|
mrefs.forEach {
|
||||||
|
it shouldHaveType ts.UNKNOWN
|
||||||
|
it.functionalMethod shouldBe ts.UNRESOLVED_METHOD
|
||||||
|
}
|
||||||
|
instanceMref.referencedMethod shouldBe instance
|
||||||
|
staticMref.referencedMethod shouldBe static
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
@ -530,6 +530,7 @@ class C {
|
|||||||
val (mref) = acu.descendants(ASTMethodReference::class.java).toList()
|
val (mref) = acu.descendants(ASTMethodReference::class.java).toList()
|
||||||
|
|
||||||
val (lambdaCall, mrefCall) = acu.descendants(ASTMethodCall::class.java).toList()
|
val (lambdaCall, mrefCall) = acu.descendants(ASTMethodCall::class.java).toList()
|
||||||
|
val (fooDecl) = acu.declaredMethodSignatures().toList()
|
||||||
|
|
||||||
spy.shouldHaveNoApplicableMethods(lambdaCall)
|
spy.shouldHaveNoApplicableMethods(lambdaCall)
|
||||||
spy.shouldHaveNoApplicableMethods(mrefCall)
|
spy.shouldHaveNoApplicableMethods(mrefCall)
|
||||||
@ -540,7 +541,7 @@ class C {
|
|||||||
|
|
||||||
mref shouldHaveType ts.UNKNOWN
|
mref shouldHaveType ts.UNKNOWN
|
||||||
mref.functionalMethod shouldBe ts.UNRESOLVED_METHOD
|
mref.functionalMethod shouldBe ts.UNRESOLVED_METHOD
|
||||||
mref.referencedMethod shouldBe ts.UNRESOLVED_METHOD
|
mref.referencedMethod shouldBe fooDecl // still populated because unambiguous
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -562,6 +563,7 @@ class C {
|
|||||||
|
|
||||||
val (lambda) = acu.descendants(ASTLambdaExpression::class.java).toList()
|
val (lambda) = acu.descendants(ASTLambdaExpression::class.java).toList()
|
||||||
val (mref) = acu.descendants(ASTMethodReference::class.java).toList()
|
val (mref) = acu.descendants(ASTMethodReference::class.java).toList()
|
||||||
|
val (fooDecl) = acu.declaredMethodSignatures().toList()
|
||||||
|
|
||||||
spy.shouldHaveNoLambdaCtx(lambda)
|
spy.shouldHaveNoLambdaCtx(lambda)
|
||||||
spy.shouldHaveNoLambdaCtx(mref)
|
spy.shouldHaveNoLambdaCtx(mref)
|
||||||
@ -572,7 +574,7 @@ class C {
|
|||||||
|
|
||||||
mref shouldHaveType ts.UNKNOWN
|
mref shouldHaveType ts.UNKNOWN
|
||||||
mref.functionalMethod shouldBe ts.UNRESOLVED_METHOD
|
mref.functionalMethod shouldBe ts.UNRESOLVED_METHOD
|
||||||
mref.referencedMethod shouldBe ts.UNRESOLVED_METHOD
|
mref.referencedMethod shouldBe fooDecl // still populated because unambiguous
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2237,5 +2237,80 @@ public class ObtainViaTest {
|
|||||||
}
|
}
|
||||||
]]></code>
|
]]></code>
|
||||||
</test-code>
|
</test-code>
|
||||||
|
<test-code>
|
||||||
|
<description>UnusedPrivateMethod #5083 - method reference without target type</description>
|
||||||
|
<expected-problems>0</expected-problems>
|
||||||
|
<code><![CDATA[
|
||||||
|
@Getter
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
enum GenerationType {
|
||||||
|
APPLE_DESKTOP("https://apps.apple.com/app/id", GenerationType::isAppleType),
|
||||||
|
APPLE_ITUNES("https://itunes.apple.com/app/id", GenerationType::isAppleType),
|
||||||
|
SAMSUNG("https://www.samsung.com/us/appstore/app/", GenerationType::isSamsungType),
|
||||||
|
ROKU("https://channelstore.roku.com/details/", GenerationType::isRokuType),
|
||||||
|
AMAZON("https://www.amazon.com/dp/", GenerationType::isAmazonType),
|
||||||
|
ANDROID("https://play.google.com/store/apps/details?id=", GenerationType::isAndroidType);
|
||||||
|
|
||||||
|
private final String baseUrl;
|
||||||
|
private final Predicate<String> predicate;
|
||||||
|
|
||||||
|
private static boolean isAppleType(String data) {
|
||||||
|
return "apple".equals(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isRokuType(String data) {
|
||||||
|
return "roku".equals(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isSamsungType(String data) {
|
||||||
|
return "samsung".equals(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isAmazonType(String data) {
|
||||||
|
return "amazon".equals(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isAndroidType(String data) {
|
||||||
|
return "android".equals(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]]></code>
|
||||||
|
</test-code>
|
||||||
|
|
||||||
|
<test-code>
|
||||||
|
<description>UnusedPrivateMethod #5083 - method reference without target type (2)</description>
|
||||||
|
<expected-problems>0</expected-problems>
|
||||||
|
<code><![CDATA[
|
||||||
|
class GenerationType {
|
||||||
|
static {
|
||||||
|
foo(GenerationType::isAndroidType);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
foo(this::instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean instance(String data) {}
|
||||||
|
private static boolean isAndroidType(String data) {
|
||||||
|
return "android".equals(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]]></code>
|
||||||
|
</test-code>
|
||||||
|
|
||||||
|
<test-code>
|
||||||
|
<description>UnusedPrivateMethod #5083 - method reference without target type (3)</description>
|
||||||
|
<expected-problems>2</expected-problems>
|
||||||
|
<code><![CDATA[
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class Foo {
|
||||||
|
private void foo(AnotherUnresolvedType baz) {}
|
||||||
|
private void foo(UnresolvedType baz) {}
|
||||||
|
public void bar(Set<UnresolvedType> s) {
|
||||||
|
s.forEach(this::foo); // Not being able to resolve UnresolvedType and AnotherUnresolvedType means we can't tell which foo is being used here…
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]]></code>
|
||||||
|
</test-code>
|
||||||
|
|
||||||
</test-data>
|
</test-data>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user