mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
Kotlin: fix extraction of Java nested wildcards; wildcards in return types
This fixes two mistakes: return-type extraction not imposing a wildcard where a Java prototype explicitly uses one, and nested wildcard detection quietly failing due to not looking through a `JavaWildcardType` correctly. I add a variant of the `kotlin_java_lowering_wildcards` test where Java prototypes are only seen from Kotlin, to be sure extraction is working as expected.
This commit is contained in:
@@ -963,9 +963,9 @@ open class KotlinUsesExtractor(
|
||||
private fun wildcardAdditionAllowed(v: Variance, t: IrType, addByDefault: Boolean, javaVariance: Variance?) =
|
||||
when {
|
||||
t.hasAnnotation(jvmWildcardAnnotation) -> true
|
||||
!addByDefault -> false
|
||||
// If a Java declaration specifies a variance, introduce it even if it's pointless (e.g. ? extends FinalClass, or ? super Object)
|
||||
javaVariance == v -> true
|
||||
!addByDefault -> false
|
||||
v == Variance.IN_VARIANCE -> !(t.isNullableAny() || t.isAny())
|
||||
v == Variance.OUT_VARIANCE -> extendsAdditionAllowed(t)
|
||||
else -> false
|
||||
@@ -1006,8 +1006,9 @@ open class KotlinUsesExtractor(
|
||||
null
|
||||
} ?: t
|
||||
|
||||
private fun getJavaTypeArgument(jt: JavaType, idx: Int) =
|
||||
private fun getJavaTypeArgument(jt: JavaType, idx: Int): JavaType? =
|
||||
when(jt) {
|
||||
is JavaWildcardType -> jt.bound?.let { getJavaTypeArgument(it, idx) }
|
||||
is JavaClassifierType -> jt.typeArguments.getOrNull(idx)
|
||||
is JavaArrayType -> if (idx == 0) jt.componentType else null
|
||||
else -> null
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
public class JavaDefns2 {
|
||||
|
||||
// Currently known not to work: the Comparable<? extends X> case, which Kotlin sees as Comparable<*> because the
|
||||
// wildcard goes the opposite direction to the variance declared on Comparable's type parameter.
|
||||
|
||||
public static void takesComparable(Comparable<CharSequence> invar, Comparable<? super CharSequence> contravar) { }
|
||||
|
||||
public static void takesNestedComparable(Comparable<Comparable<? super CharSequence>> innerContravar, Comparable<? super Comparable<CharSequence>> outerContravar) { }
|
||||
|
||||
public static void takesArrayOfComparable(Comparable<CharSequence>[] invar, Comparable<? super CharSequence>[] contravar) { }
|
||||
|
||||
public static Comparable<? super CharSequence> returnsWildcard() { return null; }
|
||||
|
||||
public static Comparable<CharSequence> returnsInvariant() { return null; }
|
||||
|
||||
public JavaDefns2(Comparable<CharSequence> invar, Comparable<? super CharSequence> contravar) { }
|
||||
|
||||
}
|
||||
@@ -7,4 +7,6 @@ fun user() {
|
||||
JavaDefns.takesArrayOfComparable(acs, acs)
|
||||
|
||||
val constructed = JavaDefns(cs, cs)
|
||||
|
||||
JavaDefns2.takesComparable(cs, cs)
|
||||
}
|
||||
|
||||
@@ -8,6 +8,16 @@
|
||||
| JavaDefns | takesComparable | invar | Comparable<CharSequence> |
|
||||
| JavaDefns | takesNestedComparable | innerContravar | Comparable<Comparable<? super CharSequence>> |
|
||||
| JavaDefns | takesNestedComparable | outerContravar | Comparable<? super Comparable<CharSequence>> |
|
||||
| JavaDefns2 | JavaDefns2 | p0 | Comparable<CharSequence> |
|
||||
| JavaDefns2 | JavaDefns2 | p1 | Comparable<? super CharSequence> |
|
||||
| JavaDefns2 | returnsInvariant | return | Comparable<CharSequence> |
|
||||
| JavaDefns2 | returnsWildcard | return | Comparable<? super CharSequence> |
|
||||
| JavaDefns2 | takesArrayOfComparable | p0 | Comparable<CharSequence>[] |
|
||||
| JavaDefns2 | takesArrayOfComparable | p1 | Comparable<? super CharSequence>[] |
|
||||
| JavaDefns2 | takesComparable | p0 | Comparable<CharSequence> |
|
||||
| JavaDefns2 | takesComparable | p1 | Comparable<? super CharSequence> |
|
||||
| JavaDefns2 | takesNestedComparable | p0 | Comparable<Comparable<? super CharSequence>> |
|
||||
| JavaDefns2 | takesNestedComparable | p1 | Comparable<? super Comparable<CharSequence>> |
|
||||
| KotlinDefns | returnsContravar | return | Comparable<CharSequence> |
|
||||
| KotlinDefns | returnsContravarForced | return | Comparable<? super CharSequence> |
|
||||
| KotlinDefns | returnsCovar | return | List<CharSequence> |
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from create_database_utils import *
|
||||
|
||||
# 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.
|
||||
runSuccessfully(["javac", "JavaDefns2.java"])
|
||||
run_codeql_database_create(["kotlinc kotlindefns.kt", "javac JavaUser.java JavaDefns.java -cp .", "kotlinc -cp . kotlinuser.kt"], lang="java")
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import java
|
||||
|
||||
predicate isInterestingClass(Class c) {
|
||||
[c, c.(NestedType).getEnclosingType()].getName().matches(["KotlinDefns%", "JavaDefns"])
|
||||
[c, c.(NestedType).getEnclosingType()].getName().matches(["KotlinDefns%", "JavaDefns%"])
|
||||
}
|
||||
|
||||
from Callable c, string paramOrReturnName, Type paramOrReturnType
|
||||
|
||||
Reference in New Issue
Block a user