Skip to content

Commit 1cd3084

Browse files
authored
Merge pull request github#11121 from smowton/smowton/fix/java-wildcard-extraction
Kotlin: fix extraction of Java nested wildcards; wildcards in return types
2 parents 68face8 + ca04779 commit 1cd3084

File tree

6 files changed

+36
-3
lines changed

6 files changed

+36
-3
lines changed

java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -963,9 +963,9 @@ open class KotlinUsesExtractor(
963963
private fun wildcardAdditionAllowed(v: Variance, t: IrType, addByDefault: Boolean, javaVariance: Variance?) =
964964
when {
965965
t.hasAnnotation(jvmWildcardAnnotation) -> true
966-
!addByDefault -> false
967966
// If a Java declaration specifies a variance, introduce it even if it's pointless (e.g. ? extends FinalClass, or ? super Object)
968967
javaVariance == v -> true
968+
!addByDefault -> false
969969
v == Variance.IN_VARIANCE -> !(t.isNullableAny() || t.isAny())
970970
v == Variance.OUT_VARIANCE -> extendsAdditionAllowed(t)
971971
else -> false
@@ -1006,8 +1006,9 @@ open class KotlinUsesExtractor(
10061006
null
10071007
} ?: t
10081008

1009-
private fun getJavaTypeArgument(jt: JavaType, idx: Int) =
1009+
private fun getJavaTypeArgument(jt: JavaType, idx: Int): JavaType? =
10101010
when(jt) {
1011+
is JavaWildcardType -> jt.bound?.let { getJavaTypeArgument(it, idx) }
10111012
is JavaClassifierType -> jt.typeArguments.getOrNull(idx)
10121013
is JavaArrayType -> if (idx == 0) jt.componentType else null
10131014
else -> null
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
public class JavaDefns2 {
2+
3+
// Currently known not to work: the Comparable<? extends X> case, which Kotlin sees as Comparable<*> because the
4+
// wildcard goes the opposite direction to the variance declared on Comparable's type parameter.
5+
6+
public static void takesComparable(Comparable<CharSequence> invar, Comparable<? super CharSequence> contravar) { }
7+
8+
public static void takesNestedComparable(Comparable<Comparable<? super CharSequence>> innerContravar, Comparable<? super Comparable<CharSequence>> outerContravar) { }
9+
10+
public static void takesArrayOfComparable(Comparable<CharSequence>[] invar, Comparable<? super CharSequence>[] contravar) { }
11+
12+
public static Comparable<? super CharSequence> returnsWildcard() { return null; }
13+
14+
public static Comparable<CharSequence> returnsInvariant() { return null; }
15+
16+
public JavaDefns2(Comparable<CharSequence> invar, Comparable<? super CharSequence> contravar) { }
17+
18+
}

java/ql/integration-tests/all-platforms/kotlin/kotlin_java_lowering_wildcards/kotlinuser.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,6 @@ fun user() {
77
JavaDefns.takesArrayOfComparable(acs, acs)
88

99
val constructed = JavaDefns(cs, cs)
10+
11+
JavaDefns2.takesComparable(cs, cs)
1012
}

java/ql/integration-tests/all-platforms/kotlin/kotlin_java_lowering_wildcards/test.expected

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,16 @@
88
| JavaDefns | takesComparable | invar | Comparable<CharSequence> |
99
| JavaDefns | takesNestedComparable | innerContravar | Comparable<Comparable<? super CharSequence>> |
1010
| JavaDefns | takesNestedComparable | outerContravar | Comparable<? super Comparable<CharSequence>> |
11+
| JavaDefns2 | JavaDefns2 | p0 | Comparable<CharSequence> |
12+
| JavaDefns2 | JavaDefns2 | p1 | Comparable<? super CharSequence> |
13+
| JavaDefns2 | returnsInvariant | return | Comparable<CharSequence> |
14+
| JavaDefns2 | returnsWildcard | return | Comparable<? super CharSequence> |
15+
| JavaDefns2 | takesArrayOfComparable | p0 | Comparable<CharSequence>[] |
16+
| JavaDefns2 | takesArrayOfComparable | p1 | Comparable<? super CharSequence>[] |
17+
| JavaDefns2 | takesComparable | p0 | Comparable<CharSequence> |
18+
| JavaDefns2 | takesComparable | p1 | Comparable<? super CharSequence> |
19+
| JavaDefns2 | takesNestedComparable | p0 | Comparable<Comparable<? super CharSequence>> |
20+
| JavaDefns2 | takesNestedComparable | p1 | Comparable<? super Comparable<CharSequence>> |
1121
| KotlinDefns | returnsContravar | return | Comparable<CharSequence> |
1222
| KotlinDefns | returnsContravarForced | return | Comparable<? super CharSequence> |
1323
| KotlinDefns | returnsCovar | return | List<CharSequence> |
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
from create_database_utils import *
22

3+
# Compile the JavaDefns2 copy outside tracing, to make sure the Kotlin view of it matches the Java view seen by the traced javac compilation of JavaDefns.java below.
4+
runSuccessfully(["javac", "JavaDefns2.java"])
35
run_codeql_database_create(["kotlinc kotlindefns.kt", "javac JavaUser.java JavaDefns.java -cp .", "kotlinc -cp . kotlinuser.kt"], lang="java")

java/ql/integration-tests/all-platforms/kotlin/kotlin_java_lowering_wildcards/test.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import java
22

33
predicate isInterestingClass(Class c) {
4-
[c, c.(NestedType).getEnclosingType()].getName().matches(["KotlinDefns%", "JavaDefns"])
4+
[c, c.(NestedType).getEnclosingType()].getName().matches(["KotlinDefns%", "JavaDefns%"])
55
}
66

77
from Callable c, string paramOrReturnName, Type paramOrReturnType

0 commit comments

Comments
 (0)