Create class quick fix: suggest on supertype entry
#KT-32511 Fixed
This commit is contained in:
committed by
Yan Zhulanow
parent
4973d3c359
commit
21d6d50241
+1
-1
@@ -542,7 +542,7 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
psiFactory.createEnumEntry("$safeName${if (hasParameters) "()" else " "}")
|
psiFactory.createEnumEntry("$safeName${if (hasParameters) "()" else " "}")
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
val openMod = if (open) "open " else ""
|
val openMod = if (open && kind != ClassKind.INTERFACE) "open " else ""
|
||||||
val innerMod = if (inner || isInsideInnerOrLocalClass()) "inner " else ""
|
val innerMod = if (inner || isInsideInnerOrLocalClass()) "inner " else ""
|
||||||
val typeParamList = when (kind) {
|
val typeParamList = when (kind) {
|
||||||
ClassKind.PLAIN_CLASS, ClassKind.INTERFACE -> "<>"
|
ClassKind.PLAIN_CLASS, ClassKind.INTERFACE -> "<>"
|
||||||
|
|||||||
+17
-5
@@ -9,8 +9,10 @@ import org.jetbrains.kotlin.diagnostics.Diagnostic
|
|||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeAndGetResult
|
import org.jetbrains.kotlin.idea.caches.resolve.analyzeAndGetResult
|
||||||
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
|
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
|
||||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
|
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
|
||||||
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypeAndBranch
|
import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypeAndBranch
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
@@ -28,16 +30,17 @@ object CreateClassFromTypeReferenceActionFactory : CreateClassFromUsageFactory<K
|
|||||||
val typeRefParent = element.parent.parent
|
val typeRefParent = element.parent.parent
|
||||||
if (typeRefParent is KtConstructorCalleeExpression) return Collections.emptyList()
|
if (typeRefParent is KtConstructorCalleeExpression) return Collections.emptyList()
|
||||||
|
|
||||||
val interfaceExpected = typeRefParent is KtSuperTypeEntry
|
|
||||||
|
|
||||||
val isQualifier = (element.parent as? KtUserType)?.let { it.qualifier == element } ?: false
|
val isQualifier = (element.parent as? KtUserType)?.let { it.qualifier == element } ?: false
|
||||||
|
|
||||||
val typeReference = element.parent as? KtTypeReference
|
val typeReference = element.parent as? KtTypeReference
|
||||||
val isUpperBound =
|
val isUpperBound =
|
||||||
typeReference?.getParentOfTypeAndBranch<KtTypeParameter> { extendsBound } != null || typeReference?.getParentOfTypeAndBranch<KtTypeConstraint> { boundTypeReference } != null
|
typeReference?.getParentOfTypeAndBranch<KtTypeParameter> { extendsBound } != null || typeReference?.getParentOfTypeAndBranch<KtTypeConstraint> { boundTypeReference } != null
|
||||||
|
|
||||||
return when {
|
return when (typeRefParent) {
|
||||||
interfaceExpected -> Collections.singletonList(ClassKind.INTERFACE)
|
is KtSuperTypeEntry -> listOfNotNull(
|
||||||
|
ClassKind.INTERFACE,
|
||||||
|
if (typeRefParent.classExpected()) ClassKind.PLAIN_CLASS else null
|
||||||
|
)
|
||||||
else -> ClassKind.values().filter {
|
else -> ClassKind.values().filter {
|
||||||
val noTypeArguments = element.typeArgumentsAsTypes.isEmpty()
|
val noTypeArguments = element.typeArgumentsAsTypes.isEmpty()
|
||||||
when (it) {
|
when (it) {
|
||||||
@@ -51,6 +54,13 @@ object CreateClassFromTypeReferenceActionFactory : CreateClassFromUsageFactory<K
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun KtSuperTypeEntry.classExpected(): Boolean {
|
||||||
|
val containingClass = getStrictParentOfType<KtClass>() ?: return false
|
||||||
|
return !containingClass.hasModifier(KtTokens.ANNOTATION_KEYWORD)
|
||||||
|
&& !containingClass.hasModifier(KtTokens.ENUM_KEYWORD)
|
||||||
|
&& !containingClass.hasModifier(KtTokens.INLINE_KEYWORD)
|
||||||
|
}
|
||||||
|
|
||||||
private fun getExpectedUpperBound(element: KtUserType, context: BindingContext): KotlinType? {
|
private fun getExpectedUpperBound(element: KtUserType, context: BindingContext): KotlinType? {
|
||||||
val projection = (element.parent as? KtTypeReference)?.parent as? KtTypeProjection ?: return null
|
val projection = (element.parent as? KtTypeReference)?.parent as? KtTypeProjection ?: return null
|
||||||
val argumentList = projection.parent as? KtTypeArgumentList ?: return null
|
val argumentList = projection.parent as? KtTypeArgumentList ?: return null
|
||||||
@@ -64,7 +74,8 @@ object CreateClassFromTypeReferenceActionFactory : CreateClassFromUsageFactory<K
|
|||||||
|
|
||||||
override fun extractFixData(element: KtUserType, diagnostic: Diagnostic): ClassInfo? {
|
override fun extractFixData(element: KtUserType, diagnostic: Diagnostic): ClassInfo? {
|
||||||
val name = element.referenceExpression?.getReferencedName() ?: return null
|
val name = element.referenceExpression?.getReferencedName() ?: return null
|
||||||
if (element.parent.parent is KtConstructorCalleeExpression) return null
|
val typeRefParent = element.parent.parent
|
||||||
|
if (typeRefParent is KtConstructorCalleeExpression) return null
|
||||||
|
|
||||||
val (context, module) = element.analyzeAndGetResult()
|
val (context, module) = element.analyzeAndGetResult()
|
||||||
val qualifier = element.qualifier?.referenceExpression
|
val qualifier = element.qualifier?.referenceExpression
|
||||||
@@ -79,6 +90,7 @@ object CreateClassFromTypeReferenceActionFactory : CreateClassFromUsageFactory<K
|
|||||||
name = name,
|
name = name,
|
||||||
targetParents = targetParents,
|
targetParents = targetParents,
|
||||||
expectedTypeInfo = expectedUpperBound?.let { TypeInfo.ByType(it, Variance.INVARIANT) } ?: TypeInfo.Empty,
|
expectedTypeInfo = expectedUpperBound?.let { TypeInfo.ByType(it, Variance.INVARIANT) } ?: TypeInfo.Empty,
|
||||||
|
open = typeRefParent is KtSuperTypeEntry && typeRefParent.classExpected(),
|
||||||
typeArguments = element.typeArgumentsAsTypes.map {
|
typeArguments = element.typeArgumentsAsTypes.map {
|
||||||
if (it != null) TypeInfo(it, Variance.INVARIANT) else TypeInfo(anyType, Variance.INVARIANT)
|
if (it != null) TypeInfo(it, Variance.INVARIANT) else TypeInfo(anyType, Variance.INVARIANT)
|
||||||
}
|
}
|
||||||
|
|||||||
idea/testData/quickfix/createFromUsage/createClass/delegationSpecifier/classDelegatorToSuperclass.kt
Vendored
-10
@@ -1,10 +0,0 @@
|
|||||||
// "Create class 'A'" "false"
|
|
||||||
// ACTION: Create interface 'A'
|
|
||||||
// ACTION: Create type parameter 'A' in class 'Foo'
|
|
||||||
// ACTION: Create test
|
|
||||||
// ERROR: Unresolved reference: A
|
|
||||||
package p
|
|
||||||
|
|
||||||
class Foo: <caret>A {
|
|
||||||
|
|
||||||
}
|
|
||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
// "Create class 'Unknown'" "true"
|
||||||
|
class A : Unknown<caret> {
|
||||||
|
constructor()
|
||||||
|
}
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
// "Create class 'Unknown'" "true"
|
||||||
|
class A : Unknown {
|
||||||
|
constructor()
|
||||||
|
}
|
||||||
|
|
||||||
|
open class Unknown {
|
||||||
|
|
||||||
|
}
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
// "Create class 'Unknown'" "true"
|
||||||
|
// ACTION: Create interface 'Unknown'
|
||||||
|
// ACTION: Create type parameter 'Unknown' in class 'A'
|
||||||
|
// DISABLE-ERRORS
|
||||||
|
class A : Unknown<caret> {
|
||||||
|
}
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
// "Create class 'Unknown'" "true"
|
||||||
|
// ACTION: Create interface 'Unknown'
|
||||||
|
// ACTION: Create type parameter 'Unknown' in class 'A'
|
||||||
|
// DISABLE-ERRORS
|
||||||
|
class A : Unknown {
|
||||||
|
}
|
||||||
|
|
||||||
|
open class Unknown {
|
||||||
|
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
// "Create class 'Unknown'" "true"
|
||||||
|
// ACTION: Create interface 'Unknown'
|
||||||
|
// ACTION: Create type parameter 'Unknown' in class 'A'
|
||||||
|
// DISABLE-ERRORS
|
||||||
|
class A() : Unknown<caret> {
|
||||||
|
constructor(i: Int)
|
||||||
|
}
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
// "Create class 'Unknown'" "true"
|
||||||
|
// ACTION: Create interface 'Unknown'
|
||||||
|
// ACTION: Create type parameter 'Unknown' in class 'A'
|
||||||
|
// DISABLE-ERRORS
|
||||||
|
class A() : Unknown {
|
||||||
|
constructor(i: Int)
|
||||||
|
}
|
||||||
|
|
||||||
|
open class Unknown {
|
||||||
|
|
||||||
|
}
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
// "Create class 'Unknown'" "false"
|
||||||
|
// ACTION: Create interface 'Unknown'
|
||||||
|
// ACTION: Create type parameter 'Unknown' in class 'A'
|
||||||
|
// DISABLE-ERRORS
|
||||||
|
annotation class A : Unknown<caret>
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
// "Create class 'Unknown'" "false"
|
||||||
|
// ACTION: Create interface 'Unknown'
|
||||||
|
// ACTION: Create type parameter 'Unknown' in class 'A'
|
||||||
|
// DISABLE-ERRORS
|
||||||
|
enum class A : Unknown<caret>
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
// "Create class 'Unknown'" "false"
|
||||||
|
// ACTION: Create interface 'Unknown'
|
||||||
|
// ACTION: Create type parameter 'Unknown' in class 'A'
|
||||||
|
// DISABLE-ERRORS
|
||||||
|
inline class A(val a: String) : Unknown<caret>
|
||||||
@@ -3277,9 +3277,34 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/quickfix/createFromUsage/createClass/delegationSpecifier"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), null, true);
|
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/quickfix/createFromUsage/createClass/delegationSpecifier"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), null, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("classDelegatorToSuperclass.kt")
|
@TestMetadata("createSuperClassFromSuperTypeEntry.kt")
|
||||||
public void testClassDelegatorToSuperclass() throws Exception {
|
public void testCreateSuperClassFromSuperTypeEntry() throws Exception {
|
||||||
runTest("idea/testData/quickfix/createFromUsage/createClass/delegationSpecifier/classDelegatorToSuperclass.kt");
|
runTest("idea/testData/quickfix/createFromUsage/createClass/delegationSpecifier/createSuperClassFromSuperTypeEntry.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("createSuperClassFromSuperTypeEntry2.kt")
|
||||||
|
public void testCreateSuperClassFromSuperTypeEntry2() throws Exception {
|
||||||
|
runTest("idea/testData/quickfix/createFromUsage/createClass/delegationSpecifier/createSuperClassFromSuperTypeEntry2.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("createSuperClassFromSuperTypeEntry3.kt")
|
||||||
|
public void testCreateSuperClassFromSuperTypeEntry3() throws Exception {
|
||||||
|
runTest("idea/testData/quickfix/createFromUsage/createClass/delegationSpecifier/createSuperClassFromSuperTypeEntry3.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("createSuperClassFromSuperTypeEntryForAnnotation.kt")
|
||||||
|
public void testCreateSuperClassFromSuperTypeEntryForAnnotation() throws Exception {
|
||||||
|
runTest("idea/testData/quickfix/createFromUsage/createClass/delegationSpecifier/createSuperClassFromSuperTypeEntryForAnnotation.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("createSuperClassFromSuperTypeEntryForEnum.kt")
|
||||||
|
public void testCreateSuperClassFromSuperTypeEntryForEnum() throws Exception {
|
||||||
|
runTest("idea/testData/quickfix/createFromUsage/createClass/delegationSpecifier/createSuperClassFromSuperTypeEntryForEnum.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("createSuperClassFromSuperTypeEntryForInline.kt")
|
||||||
|
public void testCreateSuperClassFromSuperTypeEntryForInline() throws Exception {
|
||||||
|
runTest("idea/testData/quickfix/createFromUsage/createClass/delegationSpecifier/createSuperClassFromSuperTypeEntryForInline.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("createSuperclassInsideSubclass.kt")
|
@TestMetadata("createSuperclassInsideSubclass.kt")
|
||||||
|
|||||||
Reference in New Issue
Block a user