[java] Fix #5047 - type inference with enum #5052

Merge pull request #5052 from oowekyala:issue5047-inference-with-enum
This commit is contained in:
Andreas Dangel 2024-06-13 11:25:46 +02:00
commit 0dd8fc791b
No known key found for this signature in database
GPG Key ID: 93450DF2DF9A3FA3
7 changed files with 244 additions and 111 deletions

View File

@ -7581,6 +7581,15 @@
"bug",
"code"
]
},
{
"login": "anuragagarwal561994",
"name": "Anurag Agarwal",
"avatar_url": "https://avatars.githubusercontent.com/u/6075379?v=4",
"profile": "https://github.com/anuragagarwal561994",
"contributions": [
"bug"
]
}
],
"contributorsPerLine": 7,

File diff suppressed because it is too large Load Diff

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-bestpractices
* [#5047](https://github.com/pmd/pmd/issues/5047): \[java] UnusedPrivateMethod FP for Generics & Overloads
* plsql
* [#1934](https://github.com/pmd/pmd/issues/1934): \[plsql] ParseException with MERGE statement in anonymous block
* [#2779](https://github.com/pmd/pmd/issues/2779): \[plsql] Error while parsing statement with (Oracle) DML Error Logging

View File

@ -218,7 +218,7 @@ public final class TypeOps {
@Override
public Boolean visitInferenceVar(InferenceVar t, JTypeMirror s) {
if (pure) {
return t == s;
return t == s || t.getBounds(BoundKind.EQ).contains(s);
}
if (s instanceof JPrimitiveType) {

View File

@ -79,7 +79,7 @@ public final class InferenceVar implements SubstVar {
* Returns the bounds of a certain kind that apply to
* this variable.
*/
Set<JTypeMirror> getBounds(BoundKind kind) {
public Set<JTypeMirror> getBounds(BoundKind kind) {
return boundSet.bounds.getOrDefault(kind, Collections.emptySet());
}

View File

@ -407,4 +407,51 @@ public class BadIntersection {
acu.firstMethodCall() shouldHaveType java.util.List::class[t_Animal]
}
}
parserTest("#5047 inference failed with enum") {
val (acu, spy) = parser.parseWithTypeInferenceSpy(
"""
interface Function<T,R> { R apply(T t); }
public class Main {
public enum OptOutStatus {
UNKNOWN_STATUS(3L);
private final long id;
OptOutStatus(long id) {
this.id = id;
}
public long id() {
return this.id;
}
}
static class Utils {
private Long getValue(OptOutStatus val) {
return getValue(val, OptOutStatus::id);
}
private <T extends Enum<T>> Long getValue(T enumValue, Function<T, Long> fn) {
if (enumValue == null) {
return null;
}
return fn.apply(enumValue);
}
}
}
""".trimIndent()
)
val (_, _, optOutEnum) = acu.declaredTypeSignatures()
val (_, getValue2) = acu.methodDeclarations().filter { it.name == "getValue" }.toList()
spy.shouldBeOk {
val info = acu.firstMethodCall().overloadSelectionInfo
info::isFailed shouldBe false
info.methodType shouldBeSomeInstantiationOf getValue2.genericSignature
info.methodType.formalParameters[0] shouldBe optOutEnum
}
}
})

View File

@ -2002,4 +2002,76 @@ class FooTest{
}
]]></code>
</test-code>
<test-code>
<description>UnusedPrivateMethod for Generics and Overloads #5047</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
import java.util.function.Function;
public class Main {
public static void main(String[] args) {
new Utils().printValue();
}
public enum ConsentStatus {
NOT_APPLICABLE(0L),
NO_CONSENT(1L),
CONSENT(2L),
UNKNOWN_STATUS(3L);
private final long id;
ConsentStatus(long id) {
this.id = id;
}
public long id() {
return this.id;
}
}
public enum OptOutStatus {
NOT_APPLICABLE(0L),
OPTED_OUT(1L),
DID_NOT_OPT_OUT(2L),
UNKNOWN_STATUS(3L);
private final long id;
OptOutStatus(long id) {
this.id = id;
}
public long id() {
return this.id;
}
}
static class Utils {
public void printValue() {
System.out.println(getValue(ConsentStatus.CONSENT));
System.out.println(getValue(ConsentStatus.NO_CONSENT));
System.out.println(getValue(OptOutStatus.DID_NOT_OPT_OUT));
System.out.println(getValue(OptOutStatus.OPTED_OUT));
}
private Long getValue(ConsentStatus val) {
return getValue(val, ConsentStatus::id);
}
private Long getValue(OptOutStatus val) {
return getValue(val, OptOutStatus::id);
}
private <T extends Enum<T>> Long getValue(T enumValue, Function<T, Long> fn) {
if (enumValue == null) {
return null;
}
return fn.apply(enumValue);
}
}
}
]]></code>
</test-code>
</test-data>