Create from Usage: Support generation of abstract members for superclasses. Skip non-abstract superclasses when generating abstract member
#KT-14019 Fixed
This commit is contained in:
@@ -336,6 +336,7 @@ These artifacts include extensions for the types available in the latter JDKs, s
|
||||
- [`KT-14500`](https://youtrack.jetbrains.com/issue/KT-14500) Create from Usage: Suggest functional type based on the call with lambda argument and unresolved invoke()
|
||||
- [`KT-14459`](https://youtrack.jetbrains.com/issue/KT-14459) Initialize with Constructor Parameter: Fix IDE freeze on properties in generic class
|
||||
- [`KT-14044`](https://youtrack.jetbrains.com/issue/KT-14044) Fix exception on deleting unused declaration in IDEA 2016.3
|
||||
- [`KT-14019`](https://youtrack.jetbrains.com/issue/KT-14019) Create from Usage: Support generation of abstract members for superclasses
|
||||
|
||||
#### Refactorings
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
package org.jetbrains.kotlin.idea.util
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.idea.imports.canBeReferencedViaImport
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
@@ -30,7 +31,10 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.utils.findClassifier
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.typeUtil.*
|
||||
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||
import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes
|
||||
import org.jetbrains.kotlin.types.typeUtil.substitute
|
||||
import org.jetbrains.kotlin.types.typeUtil.supertypes
|
||||
import org.jetbrains.kotlin.utils.SmartSet
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.singletonList
|
||||
|
||||
@@ -141,4 +145,9 @@ fun KotlinType.getResolvableApproximations(scope: LexicalScope?, checkTypeParame
|
||||
|
||||
it.replace(newArguments)
|
||||
}
|
||||
}
|
||||
|
||||
fun KotlinType.isAbstract(): Boolean {
|
||||
val modality = (constructor.declarationDescriptor as? ClassDescriptor)?.modality
|
||||
return modality == Modality.ABSTRACT || modality == Modality.SEALED
|
||||
}
|
||||
+15
-5
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
|
||||
import org.jetbrains.kotlin.idea.refactoring.canRefactor
|
||||
import org.jetbrains.kotlin.idea.refactoring.getExtractionContainers
|
||||
import org.jetbrains.kotlin.idea.refactoring.isInterfaceClass
|
||||
import org.jetbrains.kotlin.idea.util.isAbstract
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
@@ -42,6 +43,8 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classValueType
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.*
|
||||
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
||||
import java.lang.AssertionError
|
||||
@@ -130,17 +133,24 @@ sealed class CreateCallableFromCallActionFactory<E : KtExpression>(
|
||||
}
|
||||
|
||||
protected fun getAbstractCallableInfo(mainCallable: CallableInfo, originalExpression: KtExpression): CallableInfo? {
|
||||
val containingClass = originalExpression.getStrictParentOfType<KtClassOrObject>() as? KtClass ?: return null
|
||||
if (!containingClass.isAbstract()) return null
|
||||
val containingClass: KtClass
|
||||
val receiverType: KotlinType
|
||||
|
||||
val receiverTypeInfo = mainCallable.receiverTypeInfo
|
||||
if (receiverTypeInfo != TypeInfo.Empty) {
|
||||
if (receiverTypeInfo !is TypeInfo.ByType) return null
|
||||
val containingDescriptor = containingClass.resolveToDescriptor() as ClassDescriptor
|
||||
if (receiverTypeInfo.theType.constructor.declarationDescriptor != containingDescriptor) return null
|
||||
receiverType = receiverTypeInfo.theType
|
||||
containingClass = receiverType.constructor.declarationDescriptor?.source?.getPsi() as? KtClass ?: return null
|
||||
}
|
||||
else {
|
||||
containingClass = originalExpression.getStrictParentOfType<KtClassOrObject>() as? KtClass ?: return null
|
||||
if (containingClass is KtEnumEntry) return null
|
||||
receiverType = (containingClass.resolveToDescriptor() as ClassDescriptor).defaultType
|
||||
}
|
||||
|
||||
return mainCallable.copy(receiverTypeInfo = TypeInfo.Empty, possibleContainers = listOf(containingClass), isAbstract = true)
|
||||
if (!receiverType.isAbstract() && TypeUtils.getAllSupertypes(receiverType).all { !it.isAbstract() }) return null
|
||||
|
||||
return mainCallable.copy(receiverTypeInfo = receiverTypeInfo, possibleContainers = listOf(containingClass), isAbstract = true)
|
||||
}
|
||||
|
||||
protected fun getCallableWithReceiverInsideExtension(
|
||||
|
||||
+14
-9
@@ -25,15 +25,16 @@ import com.intellij.psi.PsiFile
|
||||
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
||||
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
||||
import org.jetbrains.kotlin.idea.refactoring.canRefactor
|
||||
import org.jetbrains.kotlin.idea.refactoring.chooseContainerElementIfNecessary
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.CreateFromUsageFixBase
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
|
||||
import org.jetbrains.kotlin.idea.refactoring.canRefactor
|
||||
import org.jetbrains.kotlin.idea.refactoring.chooseContainerElementIfNecessary
|
||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||
import org.jetbrains.kotlin.idea.util.application.executeCommand
|
||||
import org.jetbrains.kotlin.idea.util.isAbstract
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
|
||||
import java.util.HashSet
|
||||
import java.util.*
|
||||
|
||||
class CreateCallableFromUsageFix<E : KtElement>(
|
||||
originalExpression: E,
|
||||
@@ -125,11 +126,13 @@ abstract class CreateCallableFromUsageFixBase<E : KtElement>(
|
||||
append("Create ")
|
||||
|
||||
val receiverInfo = callableInfos.first().receiverTypeInfo
|
||||
if (isExtension) {
|
||||
append("extension ")
|
||||
}
|
||||
else if (receiverInfo !is TypeInfo.Empty) {
|
||||
append("member ")
|
||||
if (!callableInfos.any { it.isAbstract }) {
|
||||
if (isExtension) {
|
||||
append("extension ")
|
||||
}
|
||||
else if (receiverInfo !is TypeInfo.Empty) {
|
||||
append("member ")
|
||||
}
|
||||
}
|
||||
|
||||
renderedCallables.joinTo(this)
|
||||
@@ -188,7 +191,9 @@ abstract class CreateCallableFromUsageFixBase<E : KtElement>(
|
||||
}
|
||||
|
||||
val popupTitle = "Choose target class or interface"
|
||||
val receiverTypeCandidates = callableBuilder.computeTypeCandidates(callableInfo.receiverTypeInfo)
|
||||
val receiverTypeCandidates = callableBuilder.computeTypeCandidates(callableInfo.receiverTypeInfo).let {
|
||||
if (callableInfo.isAbstract) it.filter { it.theType.isAbstract() } else it
|
||||
}
|
||||
if (receiverTypeCandidates.isNotEmpty()) {
|
||||
val containers = receiverTypeCandidates
|
||||
.mapNotNull { candidate -> getDeclarationIfApplicable(project, candidate)?.let { candidate to it } }
|
||||
|
||||
+1
@@ -69,6 +69,7 @@ abstract class CreateCallableMemberFromUsageFactory<E : KtElement>(
|
||||
|
||||
if (extensionsSupported) {
|
||||
newCallableQuickFix(originalElementPointer, IntentionActionPriority.LOW, quickFixDataFactory) { element, data ->
|
||||
if (data.any { it.isAbstract }) return@newCallableQuickFix null
|
||||
CreateExtensionCallableFromUsageFix(element, data)
|
||||
}.let { fixes.add(it) }
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// "Create abstract function 'foo'" "true"
|
||||
// "Create abstract function 'A.foo'" "true"
|
||||
abstract class A {
|
||||
fun bar(b: Boolean) {}
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// "Create abstract function 'foo'" "true"
|
||||
// "Create abstract function 'A.foo'" "true"
|
||||
abstract class A {
|
||||
fun bar(b: Boolean) {}
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// "Create abstract property 'foo'" "true"
|
||||
// "Create abstract property 'A.foo'" "true"
|
||||
abstract class A {
|
||||
fun bar(b: Boolean) {}
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// "Create abstract property 'foo'" "true"
|
||||
// "Create abstract property 'A.foo'" "true"
|
||||
abstract class A {
|
||||
fun bar(b: Boolean) {}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user