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 " "}")
|
||||
}
|
||||
else -> {
|
||||
val openMod = if (open) "open " else ""
|
||||
val openMod = if (open && kind != ClassKind.INTERFACE) "open " else ""
|
||||
val innerMod = if (inner || isInsideInnerOrLocalClass()) "inner " else ""
|
||||
val typeParamList = when (kind) {
|
||||
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.core.quickfix.QuickFixUtil
|
||||
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.psiUtil.getParentOfTypeAndBranch
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
@@ -28,16 +30,17 @@ object CreateClassFromTypeReferenceActionFactory : CreateClassFromUsageFactory<K
|
||||
val typeRefParent = element.parent.parent
|
||||
if (typeRefParent is KtConstructorCalleeExpression) return Collections.emptyList()
|
||||
|
||||
val interfaceExpected = typeRefParent is KtSuperTypeEntry
|
||||
|
||||
val isQualifier = (element.parent as? KtUserType)?.let { it.qualifier == element } ?: false
|
||||
|
||||
val typeReference = element.parent as? KtTypeReference
|
||||
val isUpperBound =
|
||||
typeReference?.getParentOfTypeAndBranch<KtTypeParameter> { extendsBound } != null || typeReference?.getParentOfTypeAndBranch<KtTypeConstraint> { boundTypeReference } != null
|
||||
|
||||
return when {
|
||||
interfaceExpected -> Collections.singletonList(ClassKind.INTERFACE)
|
||||
return when (typeRefParent) {
|
||||
is KtSuperTypeEntry -> listOfNotNull(
|
||||
ClassKind.INTERFACE,
|
||||
if (typeRefParent.classExpected()) ClassKind.PLAIN_CLASS else null
|
||||
)
|
||||
else -> ClassKind.values().filter {
|
||||
val noTypeArguments = element.typeArgumentsAsTypes.isEmpty()
|
||||
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? {
|
||||
val projection = (element.parent as? KtTypeReference)?.parent as? KtTypeProjection ?: 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? {
|
||||
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 qualifier = element.qualifier?.referenceExpression
|
||||
@@ -79,6 +90,7 @@ object CreateClassFromTypeReferenceActionFactory : CreateClassFromUsageFactory<K
|
||||
name = name,
|
||||
targetParents = targetParents,
|
||||
expectedTypeInfo = expectedUpperBound?.let { TypeInfo.ByType(it, Variance.INVARIANT) } ?: TypeInfo.Empty,
|
||||
open = typeRefParent is KtSuperTypeEntry && typeRefParent.classExpected(),
|
||||
typeArguments = element.typeArgumentsAsTypes.map {
|
||||
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);
|
||||
}
|
||||
|
||||
@TestMetadata("classDelegatorToSuperclass.kt")
|
||||
public void testClassDelegatorToSuperclass() throws Exception {
|
||||
runTest("idea/testData/quickfix/createFromUsage/createClass/delegationSpecifier/classDelegatorToSuperclass.kt");
|
||||
@TestMetadata("createSuperClassFromSuperTypeEntry.kt")
|
||||
public void testCreateSuperClassFromSuperTypeEntry() throws Exception {
|
||||
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")
|
||||
|
||||
Reference in New Issue
Block a user