Skip to content

Commit 8266a22

Browse files
committed
Kotlin: fix method types when an inherited method implements a collection type
In this circumstance the compiler seems to generate a specialised version of the implementing function with its argument type replaced by the interface-implementing child class' type parameter. However it stores a back-pointer to the real declared function, which we should use as the call target.
1 parent 85790fc commit 8266a22

File tree

5 files changed

+81
-1
lines changed

5 files changed

+81
-1
lines changed

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

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.ir.IrStatement
1717
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
1818
import org.jetbrains.kotlin.ir.backend.js.utils.realOverrideTarget
1919
import org.jetbrains.kotlin.ir.declarations.*
20+
import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyFunction
2021
import org.jetbrains.kotlin.ir.expressions.*
2122
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
2223
import org.jetbrains.kotlin.ir.symbols.*
@@ -2011,6 +2012,18 @@ open class KotlinFileExtractor(
20112012
}
20122013
}
20132014

2015+
private fun getCalleeRealOverrideTarget(f: IrFunction): IrFunction {
2016+
val target = f.target.realOverrideTarget
2017+
return if (overridesCollectionsMethodWithAlteredParameterTypes(f))
2018+
// Cope with the case where an inherited callee can be rewritten with substituted parameter types
2019+
// if the child class uses it to implement a collections interface
2020+
// (for example, `class A { boolean contains(Object o) { ... } }; class B<T> extends A implements Set<T> { ... }`
2021+
// leads to generating a function `A.contains(B::T)`, with `initialSignatureFunction` pointing to `A.contains(Object)`.
2022+
(target as? IrLazyFunction)?.initialSignatureFunction ?: target
2023+
else
2024+
target
2025+
}
2026+
20142027
fun extractRawMethodAccess(
20152028
syntacticCallTarget: IrFunction,
20162029
locId: Label<DbLocation>,
@@ -2028,7 +2041,7 @@ open class KotlinFileExtractor(
20282041
extractClassTypeArguments: Boolean = false,
20292042
superQualifierSymbol: IrClassSymbol? = null) {
20302043

2031-
val callTarget = syntacticCallTarget.target.realOverrideTarget
2044+
val callTarget = getCalleeRealOverrideTarget(syntacticCallTarget)
20322045
val methodId = getCalleeMethodId(callTarget, drType, extractClassTypeArguments)
20332046
if (methodId == null) {
20342047
logger.warn("No method to bind call to for raw method access")
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import java.util.*;
2+
3+
public class Test {
4+
5+
public boolean contains(Object o) { return false; }
6+
7+
}
8+
9+
class SetImpl<T> extends Test implements Set<T> {
10+
11+
public int size() {
12+
return 0;
13+
}
14+
15+
public boolean isEmpty() {
16+
return false;
17+
}
18+
19+
public Iterator<T> iterator() {
20+
return null;
21+
}
22+
23+
public Object[] toArray() {
24+
return new Object[0];
25+
}
26+
27+
public <T1> T1[] toArray(T1[] a) {
28+
return null;
29+
}
30+
31+
public boolean add(T t) {
32+
return false;
33+
}
34+
35+
public boolean remove(Object o) {
36+
return false;
37+
}
38+
39+
public boolean containsAll(Collection<?> c) {
40+
return false;
41+
}
42+
43+
public boolean addAll(Collection<? extends T> c) {
44+
return false;
45+
}
46+
47+
public boolean retainAll(Collection<?> c) {
48+
return false;
49+
}
50+
51+
public boolean removeAll(Collection<?> c) {
52+
return false;
53+
}
54+
55+
public void clear() {
56+
57+
}
58+
59+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
| user.kt:1:42:1:58 | contains(...) |
2+
| user.kt:1:63:1:74 | contains(...) |
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import java
2+
3+
from MethodAccess ma
4+
where ma.getEnclosingCallable().fromSource()
5+
select ma
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
private fun user(s: SetImpl<String>) = s.contains("Hello") && "world" in s

0 commit comments

Comments
 (0)