Skip to content

Commit 84a7742

Browse files
committed
handle cases where there are conflicting super methods
1 parent f5e97e2 commit 84a7742

File tree

4 files changed

+115
-19
lines changed

4 files changed

+115
-19
lines changed

api/src/main/kotlin/com/google/devtools/ksp/symbol/KSFunctionDeclaration.kt

+4
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ interface KSFunctionDeclaration : KSDeclaration, KSDeclarationContainer {
7676
* Calling `findOverridee` on `C.x` will return `B.x`.
7777
* Calling `findOverridee` on `C.y` will return `A.y`.
7878
*
79+
* When there are multiple super interfaces implementing the function, the closest declaration
80+
* to the current containing declaration is selected. If they are in the same level, the
81+
* function of the first specified interface (in source) will be returned.
82+
*
7983
* @return [KSFunctionDeclaration] for the original function, if overriding, otherwise null.
8084
* Calling [findOverridee] is expensive and should be avoided if possible.
8185
*/

compiler-plugin/src/main/kotlin/com/google/devtools/ksp/processor/OverrideeProcessor.kt

+27-3
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,15 @@ class OverrideeProcessor: AbstractTestProcessor() {
3030
override fun toResult() = results
3131

3232
override fun process(resolver: Resolver) {
33-
logSubject(resolver, "Subject");
34-
logSubject(resolver, "JavaSubject.Subject");
35-
logSubject(resolver, "lib.Subject");
33+
logSubject(resolver, "Subject")
34+
logSubject(resolver, "JavaSubject.Subject")
35+
logSubject(resolver, "lib.Subject")
36+
logSubject(resolver, "ConflictingSubject1")
37+
logSubject(resolver, "ConflictingSubject2")
38+
logSubject(resolver, "ConflictingSubject3")
39+
logSubject(resolver, "ConflictingSubject4")
40+
logSubject(resolver, "OverrideOrder1")
41+
logSubject(resolver, "OverrideOrder2")
3642
}
3743

3844
private fun logSubject(resolver: Resolver, qName:String) {
@@ -73,3 +79,21 @@ class OverrideeProcessor: AbstractTestProcessor() {
7379
private val IGNORED_METHOD_NAMES = listOf("equals", "hashCode", "toString")
7480
}
7581
}
82+
83+
interface MyInterface {
84+
fun openFoo(): Int { return 1}
85+
fun absFoo(): Unit
86+
}
87+
88+
interface MyInterface2 {
89+
fun absFoo(): Unit
90+
}
91+
92+
abstract class MyAbstract: MyInterface {
93+
override fun absFoo(): Unit {val a = 1}
94+
override fun openFoo(): Int { return 2 }
95+
}
96+
97+
class Subject2: MyInterface, MyAbstract() {
98+
override fun absFoo(): Unit = TODO()
99+
}

compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/utils.kt

+19-15
Original file line numberDiff line numberDiff line change
@@ -287,23 +287,27 @@ internal fun DeclarationDescriptor.findPsi(): PsiElement? {
287287
* @see KSFunctionDeclaration.findOverridee for docs.
288288
*/
289289
internal fun FunctionDescriptor.findClosestOverridee(): FunctionDescriptor? {
290-
val overriddenDescriptors = this.original.overriddenDescriptors
291290
// When there is an intermediate class between the overridden and our function, we might receive
292291
// a FAKE_OVERRIDE function which is not desired as we are trying to find the actual
293292
// declared method.
294-
// First we try to find a non-fake function and if we cannot find, then we check the overridee
295-
// of the fake override.
296-
overriddenDescriptors.singleOrNull {
297-
it.kind != CallableMemberDescriptor.Kind.FAKE_OVERRIDE
298-
}?.let {
299-
// always return the original. otherwise, returned function might have type arguments
300-
// substituted when the function is resolved from a `.class` file (does not happen for
301-
// functions resolved from kotlin or java source code)
302-
return it.original
293+
294+
// we also want to return the closes function declaration. That is either the closest
295+
// class / interface method OR in case of equal distance (e.g. diamon dinheritance), pick the
296+
// one declared first in the code.
297+
298+
val queue = ArrayDeque<FunctionDescriptor>()
299+
queue.add(this)
300+
301+
while (queue.isNotEmpty()) {
302+
val current = queue.removeFirst()
303+
val overriddenDescriptors = current.original.overriddenDescriptors
304+
overriddenDescriptors.firstOrNull {
305+
it.kind != CallableMemberDescriptor.Kind.FAKE_OVERRIDE
306+
}?.let {
307+
return it.original
308+
}
309+
// if all methods are fake, add them to the queue
310+
queue.addAll(overriddenDescriptors)
303311
}
304-
// if there is no declared function, there might be a fake override and we need to find its
305-
// overridee.
306-
return overriddenDescriptors.singleOrNull {
307-
it.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE
308-
}?.findClosestOverridee()
312+
return null
309313
}

compiler-plugin/testData/api/overridee.kt

+65-1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,18 @@
5151
// Subject.openGrandBaseFun() -> GrandBase.openGrandBaseFun()
5252
// Subject.overriddenAbstractGrandBaseFun() -> Base.overriddenAbstractGrandBaseFun()
5353
// Subject.overriddenGrandBaseFun() -> Base.overriddenGrandBaseFun()
54+
// ConflictingSubject1:
55+
// ConflictingSubject1.absFoo() -> MyInterface.absFoo()
56+
// ConflictingSubject2:
57+
// ConflictingSubject2.absFoo() -> MyAbstract.absFoo()
58+
// ConflictingSubject3:
59+
// ConflictingSubject3.absFoo() -> MyInterface.absFoo()
60+
// ConflictingSubject4:
61+
// ConflictingSubject4.absFoo() -> MyInterface2.absFoo()
62+
// OverrideOrder1:
63+
// OverrideOrder1.foo() -> GrandBaseInterface2.foo()
64+
// OverrideOrder2:
65+
// OverrideOrder2.foo() -> GrandBaseInterface1.foo()
5466
// END
5567
// MODULE: lib
5668
// FILE: lib.kt
@@ -115,6 +127,58 @@ abstract class Subject: Base<String>() {
115127
fun companionMethod(): String =TODO()
116128
}
117129
}
130+
131+
// FILE: conflictingOverrides.kt
132+
interface MyInterface {
133+
fun absFoo(): Unit
134+
}
135+
136+
interface MyInterface2 {
137+
fun absFoo(): Unit
138+
}
139+
140+
abstract class MyAbstract: MyInterface {
141+
override fun absFoo(): Unit {val a = 1}
142+
}
143+
144+
class ConflictingSubject1: MyInterface, MyAbstract() {
145+
override fun absFoo(): Unit = TODO()
146+
}
147+
148+
class ConflictingSubject2: MyAbstract(), MyInterface {
149+
override fun absFoo(): Unit = TODO()
150+
}
151+
152+
class ConflictingSubject3: MyInterface, MyInterface2 {
153+
override fun absFoo(): Unit = TODO()
154+
}
155+
156+
class ConflictingSubject4: MyInterface2, MyInterface {
157+
override fun absFoo(): Unit = TODO()
158+
}
159+
160+
// FILE: overrideOrder.kt
161+
interface GrandBaseInterface1 {
162+
fun foo(): Unit
163+
}
164+
165+
interface GrandBaseInterface2 {
166+
fun foo(): Unit
167+
}
168+
169+
interface BaseInterface1 : GrandBaseInterface1 {
170+
}
171+
172+
interface BaseInterface2 : GrandBaseInterface2 {
173+
}
174+
175+
class OverrideOrder1 : BaseInterface1, GrandBaseInterface2 {
176+
override fun foo() = TODO()
177+
}
178+
class OverrideOrder2 : BaseInterface2, GrandBaseInterface1 {
179+
override fun foo() = TODO()
180+
}
181+
118182
// FILE: JavaSubject.java
119183
public class JavaSubject {
120184
static abstract class GrandBase {
@@ -154,4 +218,4 @@ public class JavaSubject {
154218
return null;
155219
}
156220
}
157-
}
221+
}

0 commit comments

Comments
 (0)