Skip to content

Commit 80063b6

Browse files
committed
Quick-fix for DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE added #KT-15966 Fixed
1 parent b83b534 commit 80063b6

File tree

17 files changed

+349
-9
lines changed

17 files changed

+349
-9
lines changed

idea/idea-core/src/org/jetbrains/kotlin/idea/core/overrideImplement/OverrideMemberChooserObject.kt

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,13 @@ import org.jetbrains.kotlin.renderer.*
3838
import org.jetbrains.kotlin.resolve.descriptorUtil.setSingleOverridden
3939

4040
interface OverrideMemberChooserObject : ClassMember {
41-
enum class BodyType {
42-
NO_BODY,
43-
EMPTY,
44-
SUPER,
45-
QUALIFIED_SUPER
41+
sealed class BodyType {
42+
object NO_BODY : BodyType()
43+
object EMPTY : BodyType()
44+
object SUPER : BodyType()
45+
object QUALIFIED_SUPER : BodyType()
46+
47+
class Delegate(val receiverName: String) : BodyType()
4648
}
4749

4850
val descriptor: CallableMemberDescriptor
@@ -191,10 +193,15 @@ fun generateUnsupportedOrSuperCall(
191193
}
192194
else {
193195
return buildString {
194-
append("super")
195-
if (bodyType == OverrideMemberChooserObject.BodyType.QUALIFIED_SUPER) {
196-
val superClassFqName = IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(descriptor.containingDeclaration as ClassifierDescriptor)
197-
append("<").append(superClassFqName).append(">")
196+
if (bodyType is OverrideMemberChooserObject.BodyType.Delegate) {
197+
append(bodyType.receiverName)
198+
}
199+
else {
200+
append("super")
201+
if (bodyType == OverrideMemberChooserObject.BodyType.QUALIFIED_SUPER) {
202+
val superClassFqName = IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(descriptor.containingDeclaration as ClassifierDescriptor)
203+
append("<").append(superClassFqName).append(">")
204+
}
198205
}
199206
append(".").append(descriptor.name.render())
200207

idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,7 @@ class QuickFixRegistrar : QuickFixContributor {
429429
USAGE_IS_NOT_INLINABLE.registerFactory(AddInlineModifierFix.NoInlineFactory)
430430

431431
UNRESOLVED_REFERENCE.registerFactory(MakeConstructorParameterPropertyFix)
432+
DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE.registerFactory(SpecifyOverrideExplicitlyFix)
432433

433434
SUPERTYPE_IS_EXTENSION_FUNCTION_TYPE.registerFactory(ConvertExtensionToFunctionTypeFix)
434435

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*
2+
* Copyright 2010-2017 JetBrains s.r.o.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.jetbrains.kotlin.idea.quickfix
18+
19+
import com.intellij.codeInsight.intention.IntentionAction
20+
import com.intellij.openapi.editor.Editor
21+
import com.intellij.openapi.project.Project
22+
import org.jetbrains.kotlin.descriptors.ClassDescriptor
23+
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
24+
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
25+
import org.jetbrains.kotlin.diagnostics.Diagnostic
26+
import org.jetbrains.kotlin.diagnostics.Errors
27+
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
28+
import org.jetbrains.kotlin.idea.core.ShortenReferences
29+
import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideMemberChooserObject
30+
import org.jetbrains.kotlin.idea.core.overrideImplement.generateMember
31+
import org.jetbrains.kotlin.lexer.KtTokens
32+
import org.jetbrains.kotlin.psi.*
33+
import org.jetbrains.kotlin.renderer.DescriptorRenderer
34+
import org.jetbrains.kotlin.resolve.BindingContext
35+
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
36+
37+
class SpecifyOverrideExplicitlyFix(
38+
element: KtClassOrObject, private val signature: String
39+
) : KotlinQuickFixAction<KtClassOrObject>(element) {
40+
41+
override fun getText() = "Specify override for '$signature' explicitly"
42+
43+
override fun getFamilyName() = "Specify override explicitly"
44+
45+
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
46+
val element = element ?: return
47+
val context = element.analyzeFullyAndGetResult().bindingContext
48+
val delegatedDescriptor = context.diagnostics.forElement(element).mapNotNull {
49+
if (it.factory == Errors.DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE)
50+
Errors.DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE.cast(it).a
51+
else
52+
null
53+
}.firstOrNull {
54+
DescriptorRenderer.ONLY_NAMES_WITH_SHORT_TYPES.render(it) == signature
55+
} ?: return
56+
for (specifier in element.superTypeListEntries) {
57+
if (specifier is KtDelegatedSuperTypeEntry) {
58+
val superType = specifier.typeReference?.let { context[BindingContext.TYPE, it] } ?: continue
59+
val superTypeDescriptor = superType.constructor.declarationDescriptor as? ClassDescriptor ?: continue
60+
val overriddenDescriptor = delegatedDescriptor.overriddenDescriptors.find {
61+
it.containingDeclaration == superTypeDescriptor
62+
} ?: continue
63+
64+
val delegateExpression = specifier.delegateExpression as? KtNameReferenceExpression
65+
val delegateTargetDescriptor = context[BindingContext.REFERENCE_TARGET, delegateExpression] ?: return
66+
if (delegateTargetDescriptor is ValueParameterDescriptor &&
67+
delegateTargetDescriptor.containingDeclaration.let {
68+
it is ConstructorDescriptor &&
69+
it.isPrimary &&
70+
it.containingDeclaration == delegatedDescriptor.containingDeclaration
71+
}) {
72+
val delegateParameter = DescriptorToSourceUtils.descriptorToDeclaration(
73+
delegateTargetDescriptor) as? KtParameter
74+
if (delegateParameter != null && !delegateParameter.hasValOrVar()) {
75+
val factory = KtPsiFactory(project)
76+
delegateParameter.addModifier(KtTokens.PRIVATE_KEYWORD)
77+
delegateParameter.addAfter(factory.createValKeyword(), delegateParameter.modifierList)
78+
}
79+
}
80+
81+
val overrideMemberChooserObject = OverrideMemberChooserObject.create(
82+
project, delegatedDescriptor, overriddenDescriptor,
83+
OverrideMemberChooserObject.BodyType.Delegate(delegateTargetDescriptor.name.asString())
84+
)
85+
val member = overrideMemberChooserObject.generateMember(project, copyDoc = false)
86+
val insertedMember = element.addDeclaration(member)
87+
ShortenReferences.DEFAULT.process(insertedMember)
88+
return
89+
}
90+
}
91+
92+
}
93+
94+
companion object : KotlinSingleIntentionActionFactory() {
95+
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
96+
val hidesOverrideError = Errors.DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE.cast(diagnostic)
97+
val klass = hidesOverrideError.psiElement
98+
if (klass.superTypeListEntries.any {
99+
it is KtDelegatedSuperTypeEntry && it.delegateExpression !is KtNameReferenceExpression
100+
}) {
101+
return null
102+
}
103+
val properOverride = hidesOverrideError.a
104+
return SpecifyOverrideExplicitlyFix(klass, DescriptorRenderer.ONLY_NAMES_WITH_SHORT_TYPES.render(properOverride))
105+
}
106+
}
107+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// "Specify override for 'foo(): Unit' explicitly" "true"
2+
3+
interface A {
4+
fun foo()
5+
}
6+
7+
open class B : A {
8+
override fun foo() {}
9+
}
10+
11+
class C<caret>(a: A) : B(), A by a
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// "Specify override for 'foo(): Unit' explicitly" "true"
2+
3+
interface A {
4+
fun foo()
5+
}
6+
7+
open class B : A {
8+
override fun foo() {}
9+
}
10+
11+
class C(private val a: A) : B(), A by a {
12+
override fun foo() {
13+
a.foo()
14+
}
15+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// "Specify override for 'foo(): Unit' explicitly" "true"
2+
3+
interface A {
4+
fun foo()
5+
}
6+
7+
open class B : A {
8+
override fun foo() {}
9+
}
10+
11+
fun bar(): A = null!!
12+
13+
val a: A = bar()
14+
15+
class C<caret>() : B(), A by a
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// "Specify override for 'foo(): Unit' explicitly" "true"
2+
3+
interface A {
4+
fun foo()
5+
}
6+
7+
open class B : A {
8+
override fun foo() {}
9+
}
10+
11+
fun bar(): A = null!!
12+
13+
val a: A = bar()
14+
15+
class C() : B(), A by a {
16+
override fun foo() {
17+
a.foo()
18+
}
19+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// "Specify override for 'isEmpty(): Boolean' explicitly" "true"
2+
// WITH_RUNTIME
3+
4+
import java.util.*
5+
6+
class <caret>B(f: MutableList<String>): ArrayList<String>(), MutableList<String> by f
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// "Specify override for 'isEmpty(): Boolean' explicitly" "true"
2+
// WITH_RUNTIME
3+
4+
import java.util.*
5+
6+
class B(private val f: MutableList<String>): ArrayList<String>(), MutableList<String> by f {
7+
override fun isEmpty(): Boolean {
8+
return f.isEmpty()
9+
}
10+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// "Specify override for 'size: Int' explicitly" "true"
2+
// WITH_RUNTIME
3+
4+
import java.util.*
5+
6+
class <caret>B(private val f: MutableList<String>): ArrayList<String>(), MutableList<String> by f {
7+
override fun isEmpty(): Boolean {
8+
return f.isEmpty()
9+
}
10+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// "Specify override for 'size: Int' explicitly" "true"
2+
// WITH_RUNTIME
3+
4+
import java.util.*
5+
6+
class B(private val f: MutableList<String>): ArrayList<String>(), MutableList<String> by f {
7+
override fun isEmpty(): Boolean {
8+
return f.isEmpty()
9+
}
10+
11+
override val size: Int
12+
get() = f.size
13+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// "Specify override for 'foo(): Unit' explicitly" "false"
2+
// ACTION: Convert to secondary constructor
3+
// ACTION: Create test
4+
// ACTION: Make primary constructor internal
5+
// ACTION: Make primary constructor private
6+
// ACTION: Move 'C' to separate file
7+
// ACTION: Rename file to C.kt
8+
9+
interface A {
10+
fun foo()
11+
}
12+
13+
class W(val a: A)
14+
15+
open class B : A {
16+
override fun foo() {}
17+
}
18+
19+
class C<caret>(w: W) : B(), A by w.a
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// "Specify override for 'foo(): Unit' explicitly" "true"
2+
3+
interface A {
4+
fun foo()
5+
}
6+
7+
open class B : A {
8+
override fun foo() {}
9+
}
10+
11+
fun bar(a: A) {
12+
class C<caret> : B(), A by a
13+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// "Specify override for 'foo(): Unit' explicitly" "true"
2+
3+
interface A {
4+
fun foo()
5+
}
6+
7+
open class B : A {
8+
override fun foo() {}
9+
}
10+
11+
fun bar(a: A) {
12+
class C : B(), A by a {
13+
override fun foo() {
14+
a.foo()
15+
}
16+
}
17+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// "Specify override for 'foo(): Unit' explicitly" "true"
2+
3+
interface A {
4+
fun foo()
5+
}
6+
7+
open class B : A {
8+
override fun foo() {}
9+
}
10+
11+
class C<caret>(val a: A) : B(), A by a
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// "Specify override for 'foo(): Unit' explicitly" "true"
2+
3+
interface A {
4+
fun foo()
5+
}
6+
7+
open class B : A {
8+
override fun foo() {}
9+
}
10+
11+
class C(val a: A) : B(), A by a {
12+
override fun foo() {
13+
a.foo()
14+
}
15+
}

0 commit comments

Comments
 (0)