diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/TypeOps.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/TypeOps.java index 051ea91c027..a6ac8828196 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/TypeOps.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/TypeOps.java @@ -1170,6 +1170,13 @@ public JTypeMirror visitClass(JClassType t, RecursionStop recursionStop) { } else if (!upwards) { // If Ai is a type that mentions a restricted type variable, then Ai' is undefined. return NO_DOWN_PROJECTION; + } else if (u instanceof JWildcardType) { + // The rest of this function, below, treats u as the bound of a wildcard, + // but if u is already a wildcard (and therefore ai was a wildcard), we + // are already done. + newTargs.add(u); + change = true; + continue; } change = true; diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/TypeOpsTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/TypeOpsTest.kt index 55a1b19a82b..421a778c4a0 100644 --- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/TypeOpsTest.kt +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/TypeOpsTest.kt @@ -95,7 +95,44 @@ class TypeOpsTest : FunSpec({ } + test("#5167 problem in projection") { + val (acu, spy) = javaParser.parseWithTypeInferenceSpy( + """ +import java.lang.annotation.Annotation; +interface Bar { + Baz getBaz(); +} + +interface Predicate { + boolean check(T t); +} +interface Stream{ + T findSome(); +} +interface Baz{ + Stream> filterMethods(Predicate p); +} + +class Foo { + + private static Bar foo( + Bar type, Class annotation, boolean required) { + var method = type.getBaz().filterMethods(m -> true).findSome(); + return method; + } +} + """.trimIndent() + ) + + val (barT) = acu.declaredTypeSignatures() + val methodId = acu.varId("method") + + spy.shouldBeOk { + methodId shouldHaveType barT[`?`] + } + } } } + })