diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/declarations/ConvertMemberToExtensionIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/declarations/ConvertMemberToExtensionIntention.kt index 71543503874..98afd97e129 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/declarations/ConvertMemberToExtensionIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/declarations/ConvertMemberToExtensionIntention.kt @@ -54,6 +54,27 @@ class ConvertMemberToExtensionIntention : SelfTargetingRangeIntention { val descriptor = element.resolveToDescriptor() val containingClass = descriptor.containingDeclaration as ClassDescriptor @@ -179,18 +200,7 @@ class ConvertMemberToExtensionIntention : SelfTargetingRangeIntention().filter { isMemberDeclaration(it) }. map { + val membersToFix = containingClass.declarations.filterIsInstance().filter { isMemberDeclaration(it) }. map { it to fetchJsNativeAnnotations(it) }.filter { it.second.annotations.isNotEmpty() } - var anchor: PsiElement = containingClass - membersToFix.forEach { (memberDeclaration, annotations) -> + membersToFix.asReversed().forEach { (memberDeclaration, annotations) -> if (annotations.nativeAnnotation != null && !annotations.isGetter && !annotations.isSetter && !annotations.isInvoke) { convertNativeAnnotationToJsName(memberDeclaration, annotations) annotations.nativeAnnotation.delete() } else { - // TODO: find references - createExtensionDeclaration(memberDeclaration, project, anchor)?.let { externalDeclaration -> - memberDeclaration.delete() - fixExtensionMemberDeclaration(externalDeclaration, project, null, file) - anchor = externalDeclaration - } + val externalDeclaration = ConvertMemberToExtensionIntention().convert(memberDeclaration) + fixExtensionMemberDeclaration(externalDeclaration, project, null, file) } } @@ -93,55 +85,6 @@ class MigrateExternalExtensionFix(declaration: KtNamedDeclaration) fixAnnotations(containingClass, classAnnotations, null) } - private fun createExtensionDeclaration(declaration: KtNamedDeclaration, project: Project, anchor: PsiElement): KtNamedDeclaration? { - val containingClass = declaration.containingClassOrObject ?: return null - val builder = KtPsiFactory.CallableBuilder(if (declaration is KtNamedFunction) KtPsiFactory.CallableBuilder.Target.FUNCTION else KtPsiFactory.CallableBuilder.Target.READ_ONLY_PROPERTY) - - // modifiers - declaration.annotationEntries.forEach { - builder.modifier(it.text) - } - - // type parameters - builder.typeParams(containingClass.typeParameters.union((declaration as? KtTypeParameterListOwner)?.typeParameters ?: emptyList()).map { it.text }) - - // receiver - builder.receiver(containingClass.name ?: "XXX") - - // name - builder.name(declaration.nameAsSafeName.identifier) - - // parameters - (declaration as? KtCallableDeclaration)?.valueParameters?.forEach { - builder.param(it.nameAsSafeName.identifier, it.typeReference?.text ?: "XXX", it.defaultValue?.text) - } - - // return type - val returnTypeReference = declaration.getReturnTypeReference() - if (returnTypeReference != null) - builder.returnType(returnTypeReference.text) - else - builder.noReturnType() - - // body - (declaration as? KtDeclarationWithBody)?.bodyExpression?.let { - builder.blockBody(it.text) - } - - // Create function etc - var newFunctionText = builder.asString() - val psiFactory = KtPsiFactory(project) - val newFunction = psiFactory.createFunction(newFunctionText) - - val parent = anchor.parent - val result = parent.addAfter(newFunction, anchor) as KtCallableDeclaration - parent.addBefore(psiFactory.createNewLine(2), result) - - // fix receiver type - result.setReceiverType((containingClass.resolveToDescriptor(BodyResolveMode.PARTIAL) as ClassDescriptor).defaultType) - return result - } - private data class JsNativeAnnotations(val annotations: List, val nativeAnnotation: KtAnnotationEntry?, val isGetter: Boolean, val isSetter: Boolean, val isInvoke: Boolean) private fun fetchJsNativeAnnotations(declaration: KtNamedDeclaration) : JsNativeAnnotations { diff --git a/idea/testData/quickfix/migration/jsExternal/nativeMemberAll01.kt.after b/idea/testData/quickfix/migration/jsExternal/nativeMemberAll01.kt.after index c68fec9b39b..2a043e3205e 100644 --- a/idea/testData/quickfix/migration/jsExternal/nativeMemberAll01.kt.after +++ b/idea/testData/quickfix/migration/jsExternal/nativeMemberAll01.kt.after @@ -20,6 +20,6 @@ inline fun B.bar(a: B) { } @Suppress("NOTHING_TO_INLINE") -inline fun B.exp(t: T) { +inline fun B.exp(t: T) { asDynamic()(t) } \ No newline at end of file diff --git a/idea/testData/quickfix/migration/jsExternal/nativeMemberAll02.kt.after b/idea/testData/quickfix/migration/jsExternal/nativeMemberAll02.kt.after index c68fec9b39b..2a043e3205e 100644 --- a/idea/testData/quickfix/migration/jsExternal/nativeMemberAll02.kt.after +++ b/idea/testData/quickfix/migration/jsExternal/nativeMemberAll02.kt.after @@ -20,6 +20,6 @@ inline fun B.bar(a: B) { } @Suppress("NOTHING_TO_INLINE") -inline fun B.exp(t: T) { +inline fun B.exp(t: T) { asDynamic()(t) } \ No newline at end of file diff --git a/idea/testData/quickfix/migration/jsExternal/nativeMemberAll03.kt.after b/idea/testData/quickfix/migration/jsExternal/nativeMemberAll03.kt.after index c68fec9b39b..2a043e3205e 100644 --- a/idea/testData/quickfix/migration/jsExternal/nativeMemberAll03.kt.after +++ b/idea/testData/quickfix/migration/jsExternal/nativeMemberAll03.kt.after @@ -20,6 +20,6 @@ inline fun B.bar(a: B) { } @Suppress("NOTHING_TO_INLINE") -inline fun B.exp(t: T) { +inline fun B.exp(t: T) { asDynamic()(t) } \ No newline at end of file diff --git a/idea/testData/quickfix/migration/jsExternal/nativeMemberInvokeGenericFun.kt.after b/idea/testData/quickfix/migration/jsExternal/nativeMemberInvokeGenericFun.kt.after index 97e13daee40..3613e03ec70 100644 --- a/idea/testData/quickfix/migration/jsExternal/nativeMemberInvokeGenericFun.kt.after +++ b/idea/testData/quickfix/migration/jsExternal/nativeMemberInvokeGenericFun.kt.after @@ -5,6 +5,6 @@ external class B { } @Suppress("NOTHING_TO_INLINE") -inline fun B.exp(t: T) { +inline fun B.exp(t: T) { asDynamic()(t) }