From 97a3d343f77c4a997b502a67fd256cec4691c45f Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Fri, 21 Jul 2017 14:09:43 +0300 Subject: [PATCH] Create Class from Usage: Support nested classes This covers the case when original expression doesn't contains qualifier Also for local or inner containing classes: - forbid nested objects - add 'inner' to nested class declaration #KT-16404 Fixed --- .../callableBuilder/CallableBuilder.kt | 9 +- ...mCallWithConstructorCalleeActionFactory.kt | 3 +- ...teClassFromConstructorCallActionFactory.kt | 7 +- ...assFromReferenceExpressionActionFactory.kt | 22 +-- ...eateClassFromTypeReferenceActionFactory.kt | 4 +- .../createClass/CreateClassFromUsageFix.kt | 140 ++++++++++-------- .../createClass/createClassUtils.kt | 15 +- ...TypeAliasFromTypeReferenceActionFactory.kt | 2 +- .../callExpression/createNestedClass.kt | 7 + .../callExpression/createNestedClass.kt.after | 11 ++ .../createNestedClassInInner.kt | 7 + .../createNestedClassInInner.kt.after | 11 ++ .../referenceExpression/createNestedObject.kt | 7 + .../createNestedObject.kt.after | 11 ++ .../createNestedObjectInInner.kt | 7 + .../createNestedObjectInInner.kt.after | 11 ++ .../typeReference/createNestedClass.kt | 7 + .../typeReference/createNestedClass.kt.after | 11 ++ .../typeReference/createNestedClassInInner.kt | 7 + .../createNestedClassInInner.kt.after | 11 ++ .../idea/quickfix/QuickFixTestGenerated.java | 36 +++++ 21 files changed, 252 insertions(+), 94 deletions(-) create mode 100644 idea/testData/quickfix/createFromUsage/createClass/callExpression/createNestedClass.kt create mode 100644 idea/testData/quickfix/createFromUsage/createClass/callExpression/createNestedClass.kt.after create mode 100644 idea/testData/quickfix/createFromUsage/createClass/callExpression/createNestedClassInInner.kt create mode 100644 idea/testData/quickfix/createFromUsage/createClass/callExpression/createNestedClassInInner.kt.after create mode 100644 idea/testData/quickfix/createFromUsage/createClass/referenceExpression/createNestedObject.kt create mode 100644 idea/testData/quickfix/createFromUsage/createClass/referenceExpression/createNestedObject.kt.after create mode 100644 idea/testData/quickfix/createFromUsage/createClass/referenceExpression/createNestedObjectInInner.kt create mode 100644 idea/testData/quickfix/createFromUsage/createClass/referenceExpression/createNestedObjectInInner.kt.after create mode 100644 idea/testData/quickfix/createFromUsage/createClass/typeReference/createNestedClass.kt create mode 100644 idea/testData/quickfix/createFromUsage/createClass/typeReference/createNestedClass.kt.after create mode 100644 idea/testData/quickfix/createFromUsage/createClass/typeReference/createNestedClassInInner.kt create mode 100644 idea/testData/quickfix/createFromUsage/createClass/typeReference/createNestedClassInInner.kt.after diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableBuilder.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableBuilder.kt index 359d57fd70b..b97e5eb20d7 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableBuilder.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableBuilder.kt @@ -413,6 +413,11 @@ class CallableBuilder(val config: CallableBuilderConfiguration) { typeCandidates[typeInfo]?.forEach { it.render(typeParameterNameMap, fakeFunction) } } + private fun isInsideInnerOrLocalClass(): Boolean { + val classOrObject = containingElement.getNonStrictParentOfType() + return classOrObject is KtClass && (classOrObject.isInner() || classOrObject.isLocal) + } + private fun createDeclarationSkeleton(): KtNamedDeclaration { with (config) { val assignmentToReplace = @@ -490,14 +495,14 @@ class CallableBuilder(val config: CallableBuilderConfiguration) { val safeName = name.quoteIfNeeded() when (kind) { ClassKind.ENUM_ENTRY -> { - val targetParent = targetParents.singleOrNull() + val targetParent = applicableParents.singleOrNull() if (!(targetParent is KtClass && targetParent.isEnum())) throw AssertionError("Enum class expected: ${targetParent?.text}") val hasParameters = targetParent.primaryConstructorParameters.isNotEmpty() psiFactory.createEnumEntry("$safeName${if (hasParameters) "()" else " "}") } else -> { val openMod = if (open) "open " else "" - val innerMod = if (inner) "inner " else "" + val innerMod = if (inner || isInsideInnerOrLocalClass()) "inner " else "" val typeParamList = when (kind) { ClassKind.PLAIN_CLASS, ClassKind.INTERFACE -> "<>" else -> "" diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createClass/CreateClassFromCallWithConstructorCalleeActionFactory.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createClass/CreateClassFromCallWithConstructorCalleeActionFactory.kt index fa1aadfe0bb..b31862a90e5 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createClass/CreateClassFromCallWithConstructorCalleeActionFactory.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createClass/CreateClassFromCallWithConstructorCalleeActionFactory.kt @@ -53,7 +53,6 @@ object CreateClassFromCallWithConstructorCalleeActionFactory : CreateClassFromUs val isAnnotation = element is KtAnnotationEntry val callee = element.calleeExpression as? KtConstructorCalleeExpression ?: return null val calleeRef = callee.constructorReferenceExpression ?: return null - val file = element.containingFile as? KtFile ?: return null val typeRef = callee.typeReference ?: return null val userType = typeRef.typeElement as? KtUserType ?: return null @@ -62,7 +61,7 @@ object CreateClassFromCallWithConstructorCalleeActionFactory : CreateClassFromUs val qualifier = userType.qualifier?.referenceExpression val qualifierDescriptor = qualifier?.let { context[BindingContext.REFERENCE_TARGET, it] } - val targetParents = getTargetParentsByQualifier(file, qualifier != null, qualifierDescriptor).ifEmpty { return null } + val targetParents = getTargetParentsByQualifier(element, qualifier != null, qualifierDescriptor).ifEmpty { return null } val anyType = module.builtIns.nullableAnyType val valueArguments = element.valueArguments diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createClass/CreateClassFromConstructorCallActionFactory.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createClass/CreateClassFromConstructorCallActionFactory.kt index d27597eedff..caf954d7c56 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createClass/CreateClassFromConstructorCallActionFactory.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createClass/CreateClassFromConstructorCallActionFactory.kt @@ -42,9 +42,8 @@ object CreateClassFromConstructorCallActionFactory: CreateClassFromUsageFactory< val inAnnotationEntry = diagnostic.psiElement.getNonStrictParentOfType() != null val (context, moduleDescriptor) = element.analyzeFullyAndGetResult() - val file = element.containingFile as? KtFile ?: return emptyList() val call = element.getCall(context) ?: return emptyList() - val targetParents = getTargetParentsByCall(call, file, context).ifEmpty { return emptyList() } + val targetParents = getTargetParentsByCall(call, context).ifEmpty { return emptyList() } val classKind = if (inAnnotationEntry) ClassKind.ANNOTATION_CLASS else ClassKind.PLAIN_CLASS val fullCallExpr = element.getQualifiedExpressionForSelectorOrThis() @@ -72,12 +71,10 @@ object CreateClassFromConstructorCallActionFactory: CreateClassFromUsageFactory< val fullCallExpr = if (callParent is KtQualifiedExpression && callParent.selectorExpression == callExpr) callParent else callExpr - val file = fullCallExpr.containingFile as? KtFile ?: return null - val (context, moduleDescriptor) = callExpr.analyzeFullyAndGetResult() val call = callExpr.getCall(context) ?: return null - val targetParents = getTargetParentsByCall(call, file, context).ifEmpty { return null } + val targetParents = getTargetParentsByCall(call, context).ifEmpty { return null } val inner = isInnerClassExpected(call) val valueArguments = callExpr.valueArguments diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createClass/CreateClassFromReferenceExpressionActionFactory.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createClass/CreateClassFromReferenceExpressionActionFactory.kt index 9f6dddf1f43..89b80e55fb3 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createClass/CreateClassFromReferenceExpressionActionFactory.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createClass/CreateClassFromReferenceExpressionActionFactory.kt @@ -57,8 +57,6 @@ object CreateClassFromReferenceExpressionActionFactory : CreateClassFromUsageFac } } - val file = element.containingFile as? KtFile ?: return Collections.emptyList() - val name = element.getReferencedName() val (context, moduleDescriptor) = element.analyzeFullyAndGetResult() @@ -70,11 +68,8 @@ object CreateClassFromReferenceExpressionActionFactory : CreateClassFromUsageFac val receiverSelector = (fullCallExpr as? KtQualifiedExpression)?.receiverExpression?.getQualifiedElementSelector() as? KtReferenceExpression val qualifierDescriptor = receiverSelector?.let { context[BindingContext.REFERENCE_TARGET, it] } - val targetParents = getTargetParentsByQualifier( - element.containingKtFile, - receiverSelector != null, - qualifierDescriptor - ).ifEmpty { return emptyList() } + val targetParents = getTargetParentsByQualifier(element, receiverSelector != null, qualifierDescriptor) + .ifEmpty { return emptyList() } targetParents.forEach { if (element.getCreatePackageFixIfApplicable(it) != null) return emptyList() @@ -100,7 +95,7 @@ object CreateClassFromReferenceExpressionActionFactory : CreateClassFromUsageFac if (fullCallExpr.getAssignmentByLHS() != null) return Collections.emptyList() val call = element.getCall(context) ?: return Collections.emptyList() - val targetParents = getTargetParentsByCall(call, file, context).ifEmpty { return emptyList() } + val targetParents = getTargetParentsByCall(call, context).ifEmpty { return emptyList() } if (isInnerClassExpected(call)) return Collections.emptyList() val allKinds = Arrays.asList(ClassKind.OBJECT, ClassKind.ENUM_ENTRY) @@ -119,8 +114,6 @@ object CreateClassFromReferenceExpressionActionFactory : CreateClassFromUsageFac } override fun extractFixData(element: KtSimpleNameExpression, diagnostic: Diagnostic): ClassInfo? { - val file = element.containingFile as? KtFile ?: return null - val name = element.getReferencedName() val (context, moduleDescriptor) = element.analyzeFullyAndGetResult() @@ -131,11 +124,8 @@ object CreateClassFromReferenceExpressionActionFactory : CreateClassFromUsageFac val receiverSelector = (fullCallExpr as? KtQualifiedExpression)?.receiverExpression?.getQualifiedElementSelector() as? KtReferenceExpression val qualifierDescriptor = receiverSelector?.let { context[BindingContext.REFERENCE_TARGET, it] } - val targetParents = getTargetParentsByQualifier( - element.containingKtFile, - receiverSelector != null, - qualifierDescriptor - ).ifEmpty { return null } + val targetParents = getTargetParentsByQualifier(element, receiverSelector != null, qualifierDescriptor) + .ifEmpty { return null } return ClassInfo( name = name, @@ -145,7 +135,7 @@ object CreateClassFromReferenceExpressionActionFactory : CreateClassFromUsageFac } val call = element.getCall(context) ?: return null - val targetParents = getTargetParentsByCall(call, file, context).ifEmpty { return null } + val targetParents = getTargetParentsByCall(call, context).ifEmpty { return null } val expectedTypeInfo = fullCallExpr.guessTypeForClass(context, moduleDescriptor)?.toClassTypeInfo() ?: TypeInfo.Empty diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createClass/CreateClassFromTypeReferenceActionFactory.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createClass/CreateClassFromTypeReferenceActionFactory.kt index e58de1c9c0e..9002b4e0632 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createClass/CreateClassFromTypeReferenceActionFactory.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createClass/CreateClassFromTypeReferenceActionFactory.kt @@ -77,13 +77,11 @@ object CreateClassFromTypeReferenceActionFactory : CreateClassFromUsageFactory, + private val targetParents: List, val expectedTypeInfo: TypeInfo, val inner: Boolean = false, val open: Boolean = false, val typeArguments: List = Collections.emptyList(), val parameterInfos: List = Collections.emptyList() -) +) { + val applicableParents by lazy { + targetParents.filter { + if (kind == ClassKind.OBJECT && it is KtClass && (it.isInner() || it.isLocal)) return@filter false + true + } + } +} open class CreateClassFromUsageFix protected constructor ( element: E, @@ -76,7 +82,8 @@ open class CreateClassFromUsageFix protected constructor ( if (!super.isAvailable(project, editor, file)) return false with(classInfo) { if (kind == DEFAULT) return false - targetParents.forEach { + if (applicableParents.isEmpty()) return false + applicableParents.forEach { if (it is PsiClass) { if (kind == OBJECT || kind == ENUM_ENTRY) return false if (it.isInterface && inner) return false @@ -90,60 +97,75 @@ open class CreateClassFromUsageFix protected constructor ( override fun startInWriteAction() = false override fun invoke(project: Project, editor: Editor?, file: KtFile) { - fun createFileByPackage(psiPackage: PsiPackage): KtFile? { - val directories = psiPackage.directories.filter { it.canRefactor() } - assert (directories.isNotEmpty()) { "Package '${psiPackage.qualifiedName}' must be refactorable" } - - val currentModule = ModuleUtilCore.findModuleForPsiElement(file) - val preferredDirectory = - directories.firstOrNull { ModuleUtilCore.findModuleForPsiElement(it) == currentModule } - ?: directories.firstOrNull() - - val targetDirectory = if (directories.size > 1 && !ApplicationManager.getApplication().isUnitTestMode) { - DirectoryChooserUtil.chooseDirectory(directories.toTypedArray(), preferredDirectory, project, HashMap()) - } - else { - preferredDirectory - } ?: return null - - val fileName = "${classInfo.name}.${KotlinFileType.INSTANCE.defaultExtension}" - val targetFile = getOrCreateKotlinFile(fileName, targetDirectory) - if (targetFile == null) { - val filePath = "${targetDirectory.virtualFile.path}/$fileName" - CodeInsightUtils.showErrorHint( - targetDirectory.project, - editor!!, - "File $filePath already exists but does not correspond to Kotlin file", - "Create file", - null - ) - } - return targetFile - } - if (editor == null) return - with (classInfo) { - chooseContainerElementIfNecessary(targetParents, editor, "Choose class container", true, { it }) { - runWriteAction { - val targetParent = - when (it) { - is KtElement, is PsiClass -> it - is PsiPackage -> createFileByPackage(it) - else -> throw AssertionError("Unexpected element: " + it.text) - } ?: return@runWriteAction - val constructorInfo = PrimaryConstructorInfo(classInfo, expectedTypeInfo) - val builder = CallableBuilderConfiguration( - Collections.singletonList(constructorInfo), - element as KtElement, - file, - editor, - false, - kind == PLAIN_CLASS || kind == INTERFACE - ).createBuilder() - builder.placement = CallablePlacement.NoReceiver(targetParent) - project.executeCommand(text) { builder.build() } - } + if (ApplicationManager.getApplication().isUnitTestMode) { + val targetParent = classInfo.applicableParents.firstOrNull { + it.allChildren.any { it is PsiComment && it.text == "// TARGET_PARENT:" } + } ?: classInfo.applicableParents.last() + return doInvoke(targetParent, editor, file) + } + + chooseContainerElementIfNecessary(classInfo.applicableParents, editor, "Choose class container", true, { it }) { + doInvoke(it, editor, file) + } + } + + private fun createFileByPackage( + psiPackage: PsiPackage, + editor: Editor, + originalFile: KtFile + ): KtFile? { + val directories = psiPackage.directories.filter { it.canRefactor() } + assert (directories.isNotEmpty()) { "Package '${psiPackage.qualifiedName}' must be refactorable" } + + val currentModule = ModuleUtilCore.findModuleForPsiElement(originalFile) + val preferredDirectory = + directories.firstOrNull { ModuleUtilCore.findModuleForPsiElement(it) == currentModule } + ?: directories.firstOrNull() + + val targetDirectory = if (directories.size > 1 && !ApplicationManager.getApplication().isUnitTestMode) { + DirectoryChooserUtil.chooseDirectory(directories.toTypedArray(), preferredDirectory, originalFile.project, HashMap()) + } + else { + preferredDirectory + } ?: return null + + val fileName = "${classInfo.name}.${KotlinFileType.INSTANCE.defaultExtension}" + val targetFile = getOrCreateKotlinFile(fileName, targetDirectory) + if (targetFile == null) { + val filePath = "${targetDirectory.virtualFile.path}/$fileName" + CodeInsightUtils.showErrorHint( + targetDirectory.project, + editor, + "File $filePath already exists but does not correspond to Kotlin file", + "Create file", + null + ) + } + return targetFile + } + + private fun doInvoke(selectedParent: PsiElement, editor: Editor, file: KtFile) { + runWriteAction { + with(classInfo) { + val targetParent = + when (selectedParent) { + is KtElement, is PsiClass -> selectedParent + is PsiPackage -> createFileByPackage(selectedParent, editor, file) + else -> throw AssertionError("Unexpected element: " + selectedParent.text) + } ?: return@runWriteAction + val constructorInfo = PrimaryConstructorInfo(classInfo, expectedTypeInfo) + val builder = CallableBuilderConfiguration( + Collections.singletonList(constructorInfo), + element as KtElement, + file, + editor, + false, + kind == PLAIN_CLASS || kind == INTERFACE + ).createBuilder() + builder.placement = CallablePlacement.NoReceiver(targetParent) + file.project.executeCommand(text) { builder.build() } } } } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createClass/createClassUtils.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createClass/createClassUtils.kt index f7aeea266f3..1fd0744319d 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createClass/createClassUtils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createClass/createClassUtils.kt @@ -33,6 +33,7 @@ import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.guessT import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.noSubstitutions import org.jetbrains.kotlin.idea.refactoring.canRefactor import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.parents import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.DescriptorUtils @@ -51,14 +52,15 @@ internal fun String.checkClassName(): Boolean = isNotEmpty() && Character.isUppe private fun String.checkPackageName(): Boolean = isNotEmpty() && Character.isLowerCase(first()) internal fun getTargetParentsByQualifier( - file: KtFile, + element: KtElement, isQualified: Boolean, qualifierDescriptor: DeclarationDescriptor? ): List { + val file = element.containingKtFile val project = file.project val targetParents: List = when { !isQualified -> - listOf(file) + element.parents.filterIsInstance().toList() + file qualifierDescriptor is ClassDescriptor -> listOfNotNull(DescriptorToSourceUtilsIde.getAnyDeclaration(project, qualifierDescriptor)) qualifierDescriptor is PackageViewDescriptor -> @@ -72,12 +74,13 @@ internal fun getTargetParentsByQualifier( return targetParents.filter { it.canRefactor() } } -internal fun getTargetParentsByCall(call: Call, file: KtFile, context: BindingContext): List { +internal fun getTargetParentsByCall(call: Call, context: BindingContext): List { + val callElement = call.callElement val receiver = call.explicitReceiver return when (receiver) { - null -> getTargetParentsByQualifier(file, false, null) - is Qualifier -> getTargetParentsByQualifier(file, true, context[BindingContext.REFERENCE_TARGET, receiver.referenceExpression]) - is ReceiverValue -> getTargetParentsByQualifier(file, true, receiver.type.constructor.declarationDescriptor) + null -> getTargetParentsByQualifier(callElement, false, null) + is Qualifier -> getTargetParentsByQualifier(callElement, true, context[BindingContext.REFERENCE_TARGET, receiver.referenceExpression]) + is ReceiverValue -> getTargetParentsByQualifier(callElement, true, receiver.type.constructor.declarationDescriptor) else -> throw AssertionError("Unexpected receiver: $receiver") } } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createTypeAlias/CreateTypeAliasFromTypeReferenceActionFactory.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createTypeAlias/CreateTypeAliasFromTypeReferenceActionFactory.kt index c48625e2aac..beb2fd6fac8 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createTypeAlias/CreateTypeAliasFromTypeReferenceActionFactory.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createTypeAlias/CreateTypeAliasFromTypeReferenceActionFactory.kt @@ -40,7 +40,7 @@ object CreateTypeAliasFromTypeReferenceActionFactory : KotlinSingleIntentionActi if (!element.languageVersionSettings.supportsFeature(LanguageFeature.TypeAliases)) return null val classInfo = CreateClassFromTypeReferenceActionFactory.extractFixData(element, diagnostic) ?: return null - val targetParent = classInfo.targetParents.singleOrNull { it !is KtDeclaration && it !is PsiPackage } ?: return null + val targetParent = classInfo.applicableParents.singleOrNull { it !is KtDeclaration && it !is PsiPackage } ?: return null val expectedType = getTypeConstraintInfo(element)?.upperBound if (expectedType != null && expectedType.containsError()) return null diff --git a/idea/testData/quickfix/createFromUsage/createClass/callExpression/createNestedClass.kt b/idea/testData/quickfix/createFromUsage/createClass/callExpression/createNestedClass.kt new file mode 100644 index 00000000000..fad7bf26b8f --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createClass/callExpression/createNestedClass.kt @@ -0,0 +1,7 @@ +// "Create class 'Nested'" "true" +class A { + // TARGET_PARENT: + class B { + val a = Nested() + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createClass/callExpression/createNestedClass.kt.after b/idea/testData/quickfix/createFromUsage/createClass/callExpression/createNestedClass.kt.after new file mode 100644 index 00000000000..ffc533c74fc --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createClass/callExpression/createNestedClass.kt.after @@ -0,0 +1,11 @@ +// "Create class 'Nested'" "true" +class A { + // TARGET_PARENT: + class B { + val a = Nested() + + class Nested { + + } + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createClass/callExpression/createNestedClassInInner.kt b/idea/testData/quickfix/createFromUsage/createClass/callExpression/createNestedClassInInner.kt new file mode 100644 index 00000000000..fd9fa86d74c --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createClass/callExpression/createNestedClassInInner.kt @@ -0,0 +1,7 @@ +// "Create class 'Nested'" "true" +class A { + // TARGET_PARENT: + inner class B { + val a = Nested() + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createClass/callExpression/createNestedClassInInner.kt.after b/idea/testData/quickfix/createFromUsage/createClass/callExpression/createNestedClassInInner.kt.after new file mode 100644 index 00000000000..986a3d7c9b3 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createClass/callExpression/createNestedClassInInner.kt.after @@ -0,0 +1,11 @@ +// "Create class 'Nested'" "true" +class A { + // TARGET_PARENT: + inner class B { + val a = Nested() + + inner class Nested { + + } + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createClass/referenceExpression/createNestedObject.kt b/idea/testData/quickfix/createFromUsage/createClass/referenceExpression/createNestedObject.kt new file mode 100644 index 00000000000..9f0d5f3be21 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createClass/referenceExpression/createNestedObject.kt @@ -0,0 +1,7 @@ +// "Create object 'Nested'" "true" +class A { + // TARGET_PARENT: + class B { + val a = Nested + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createClass/referenceExpression/createNestedObject.kt.after b/idea/testData/quickfix/createFromUsage/createClass/referenceExpression/createNestedObject.kt.after new file mode 100644 index 00000000000..255be6f3a86 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createClass/referenceExpression/createNestedObject.kt.after @@ -0,0 +1,11 @@ +// "Create object 'Nested'" "true" +class A { + // TARGET_PARENT: + class B { + val a = Nested + + object Nested { + + } + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createClass/referenceExpression/createNestedObjectInInner.kt b/idea/testData/quickfix/createFromUsage/createClass/referenceExpression/createNestedObjectInInner.kt new file mode 100644 index 00000000000..c557a4e7552 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createClass/referenceExpression/createNestedObjectInInner.kt @@ -0,0 +1,7 @@ +// "Create object 'Nested'" "true" +class A { + // TARGET_PARENT: + inner class B { + val a = Nested + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createClass/referenceExpression/createNestedObjectInInner.kt.after b/idea/testData/quickfix/createFromUsage/createClass/referenceExpression/createNestedObjectInInner.kt.after new file mode 100644 index 00000000000..173f216a314 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createClass/referenceExpression/createNestedObjectInInner.kt.after @@ -0,0 +1,11 @@ +// "Create object 'Nested'" "true" +class A { + // TARGET_PARENT: + inner class B { + val a = Nested + } +} + +object Nested { + +} diff --git a/idea/testData/quickfix/createFromUsage/createClass/typeReference/createNestedClass.kt b/idea/testData/quickfix/createFromUsage/createClass/typeReference/createNestedClass.kt new file mode 100644 index 00000000000..25dcbda3561 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createClass/typeReference/createNestedClass.kt @@ -0,0 +1,7 @@ +// "Create class 'Nested'" "true" +class A { + // TARGET_PARENT: + class B { + val a: Nested = Nested() + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createClass/typeReference/createNestedClass.kt.after b/idea/testData/quickfix/createFromUsage/createClass/typeReference/createNestedClass.kt.after new file mode 100644 index 00000000000..08ebe7e46c7 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createClass/typeReference/createNestedClass.kt.after @@ -0,0 +1,11 @@ +// "Create class 'Nested'" "true" +class A { + // TARGET_PARENT: + class B { + val a: Nested = Nested() + + class Nested { + + } + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createClass/typeReference/createNestedClassInInner.kt b/idea/testData/quickfix/createFromUsage/createClass/typeReference/createNestedClassInInner.kt new file mode 100644 index 00000000000..65f1e904ec1 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createClass/typeReference/createNestedClassInInner.kt @@ -0,0 +1,7 @@ +// "Create class 'Nested'" "true" +class A { + // TARGET_PARENT: + inner class B { + val a: Nested = Nested() + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createClass/typeReference/createNestedClassInInner.kt.after b/idea/testData/quickfix/createFromUsage/createClass/typeReference/createNestedClassInInner.kt.after new file mode 100644 index 00000000000..dbc982f749f --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createClass/typeReference/createNestedClassInInner.kt.after @@ -0,0 +1,11 @@ +// "Create class 'Nested'" "true" +class A { + // TARGET_PARENT: + inner class B { + val a: Nested = Nested() + + inner class Nested { + + } + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index 011507b6be1..75ed6817de8 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -1647,6 +1647,18 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { doTest(fileName); } + @TestMetadata("createNestedClass.kt") + public void testCreateNestedClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createClass/callExpression/createNestedClass.kt"); + doTest(fileName); + } + + @TestMetadata("createNestedClassInInner.kt") + public void testCreateNestedClassInInner() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createClass/callExpression/createNestedClassInInner.kt"); + doTest(fileName); + } + @TestMetadata("expectedTypeBySuperFunction.kt") public void testExpectedTypeBySuperFunction() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createClass/callExpression/expectedTypeBySuperFunction.kt"); @@ -1959,6 +1971,18 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { doTest(fileName); } + @TestMetadata("createNestedObject.kt") + public void testCreateNestedObject() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createClass/referenceExpression/createNestedObject.kt"); + doTest(fileName); + } + + @TestMetadata("createNestedObjectInInner.kt") + public void testCreateNestedObjectInInner() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createClass/referenceExpression/createNestedObjectInInner.kt"); + doTest(fileName); + } + @TestMetadata("enumByClassLiteral.kt") public void testEnumByClassLiteral() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createClass/referenceExpression/enumByClassLiteral.kt"); @@ -2196,6 +2220,18 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { doTest(fileName); } + @TestMetadata("createNestedClass.kt") + public void testCreateNestedClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createClass/typeReference/createNestedClass.kt"); + doTest(fileName); + } + + @TestMetadata("createNestedClassInInner.kt") + public void testCreateNestedClassInInner() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createClass/typeReference/createNestedClassInInner.kt"); + doTest(fileName); + } + @TestMetadata("enumEntryNotQualifierNoTypeArgs.kt") public void testEnumEntryNotQualifierNoTypeArgs() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createClass/typeReference/enumEntryNotQualifierNoTypeArgs.kt");