[java] Fix #5097 - problem with unchecked conversion

This commit is contained in:
Clément Fournier 2024-11-15 15:23:52 +01:00
parent f803aa36dc
commit 5931b6601c
No known key found for this signature in database
GPG Key ID: 6F9389D8E390BD4C
4 changed files with 79 additions and 3 deletions

View File

@ -717,6 +717,12 @@ public final class TypeOps {
// no unchecked warning.
return allArgsAreUnboundedWildcards(sargs) ? Convertibility.UNCHECKED_NO_WARNING
: Convertibility.UNCHECKED_WARNING;
} else if (sargs.isEmpty()) {
// C<T1...TN> <: |C|
// JLS 4.10.2
// unchecked conversion converts a raw type to a generic type
// subtyping converts a generic type to its raw type
return Convertibility.SUBTYPING;
}
if (targs.size() != sargs.size()) {

View File

@ -13,14 +13,14 @@ import io.kotest.property.Exhaustive
import io.kotest.property.checkAll
import io.kotest.property.exhaustive.ints
import io.kotest.property.forAll
import net.sourceforge.pmd.lang.test.ast.shouldBeA
import net.sourceforge.pmd.lang.java.ast.ParserTestCtx
import net.sourceforge.pmd.lang.java.symbols.internal.UnresolvedClassStore
import net.sourceforge.pmd.lang.java.symbols.internal.asm.createUnresolvedAsmSymbol
import net.sourceforge.pmd.lang.java.types.TypeConversion.*
import net.sourceforge.pmd.lang.java.types.TypeOps.Convertibility.*
import net.sourceforge.pmd.lang.java.types.TypeConversion.capture
import net.sourceforge.pmd.lang.java.types.TypeOps.Convertibility.UNCHECKED_NO_WARNING
import net.sourceforge.pmd.lang.java.types.testdata.ComparableList
import net.sourceforge.pmd.lang.java.types.testdata.SomeEnum
import net.sourceforge.pmd.lang.test.ast.shouldBeA
import kotlin.test.assertTrue
/**
@ -187,6 +187,9 @@ class SubtypingTest : FunSpec({
Class shouldBeUncheckedSubtypeOf `Class{String}`
ts.STRING shouldBeSubtypeOf `Comparable{Wildcard}`
val unresolvedT = ts.createUnresolvedAsmSymbol("foo")
unresolvedT[`?`] shouldBeSubtypeOf ts.rawType(unresolvedT)
}
test("Test wildcard subtyping") {

View File

@ -702,4 +702,39 @@ class C {
buildItem.methodType.symbol shouldBe buildItemDecl
}
}
parserTest("Unresolved type should also allow unchecked conversion") {
// The problem here is that ConstraintViolation<?> is not convertible to ConstraintViolation,
// because ConstraintViolation is not on the classpath.
val (acu, _) = parser.parseWithTypeInferenceSpy(
"""
import java.util.Set;
class Foo {
private void foo(ConstraintViolation constraintViolation) {
constraintViolation.toString();
}
public void foos(Set<ConstraintViolation<?>> constraintViolations) {
constraintViolations.forEach(this::foo);
}
}
"""
)
// val (foreach) = acu.methodCalls().toList()
val constraintViolationT = acu.descendants(ASTClassType::class.java)
.filter { it.simpleName == "ConstraintViolation" }
.firstOrThrow().typeMirror.symbol as JClassSymbol
val (fooDecl) = acu.methodDeclarations().toList { it.symbol }
val (mref) = acu.descendants(ASTMethodReference::class.java).toList()
acu.withTypeDsl {
mref.referencedMethod.symbol shouldBe fooDecl
mref shouldHaveType java.util.function.Consumer::class[constraintViolationT[`?`]]
}
}
})

View File

@ -2218,4 +2218,36 @@ public class ObtainViaTest {
}
]]></code>
</test-code>
<test-code>
<description>#5097 UnusedPrivateMethod with unresolved target for method reference</description>
<expected-problems>0</expected-problems>
<code><![CDATA[package com.mytest;
import jakarta.validation.ConstraintViolation; //imported from jakarta.validation:jakarta.validation-api:3.0.2
import java.util.List;
import java.util.Set;
public class UnusedPrivateMethodFalsePositive {
//this does not trigger UnusedPrivateMethod
private void doWork(List obj) {
obj.toString();
}
public void execute(Set<List<?>> listOfLists) {
listOfLists.forEach(this::doWork);
}
//BUT this does???
//UnusedPrivateMethod - this as a false positive - but what is different?
private void addValidationError(ConstraintViolation constraintViolation) {
constraintViolation.toString();
}
public void addValidationErrors(Set<ConstraintViolation<?>> constraintViolations) {
constraintViolations.forEach(this::addValidationError);
}
}
]]></code>
</test-code>
</test-data>