Used ConvertMemberToExtensionIntention in MigrateExternalExtensionFix instead of manually creating extension method
This commit is contained in:
+22
-12
@@ -54,6 +54,27 @@ class ConvertMemberToExtensionIntention : SelfTargetingRangeIntention<KtCallable
|
|||||||
//TODO: local class
|
//TODO: local class
|
||||||
|
|
||||||
override fun applyTo(element: KtCallableDeclaration, editor: Editor?) {
|
override fun applyTo(element: KtCallableDeclaration, editor: Editor?) {
|
||||||
|
val (extension, bodyToSelect) = createExtensionCallableAndPrepareBodyToSelect(element)
|
||||||
|
|
||||||
|
editor?.apply {
|
||||||
|
unblockDocument()
|
||||||
|
|
||||||
|
if (bodyToSelect != null) {
|
||||||
|
val range = bodyToSelect!!.textRange
|
||||||
|
moveCaret(range.startOffset, ScrollType.CENTER)
|
||||||
|
selectionModel.setSelection(range.startOffset, range.endOffset)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
moveCaret(extension.textOffset, ScrollType.CENTER)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun convert(element: KtCallableDeclaration): KtCallableDeclaration {
|
||||||
|
return createExtensionCallableAndPrepareBodyToSelect(element).first
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createExtensionCallableAndPrepareBodyToSelect(element: KtCallableDeclaration): Pair<KtCallableDeclaration, KtExpression?> {
|
||||||
val descriptor = element.resolveToDescriptor()
|
val descriptor = element.resolveToDescriptor()
|
||||||
val containingClass = descriptor.containingDeclaration as ClassDescriptor
|
val containingClass = descriptor.containingDeclaration as ClassDescriptor
|
||||||
|
|
||||||
@@ -179,18 +200,7 @@ class ConvertMemberToExtensionIntention : SelfTargetingRangeIntention<KtCallable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
editor?.apply {
|
return extension to bodyToSelect
|
||||||
unblockDocument()
|
|
||||||
|
|
||||||
if (bodyToSelect != null) {
|
|
||||||
val range = bodyToSelect!!.textRange
|
|
||||||
moveCaret(range.startOffset, ScrollType.CENTER)
|
|
||||||
selectionModel.setSelection(range.startOffset, range.endOffset)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
moveCaret(extension.textOffset, ScrollType.CENTER)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun newTypeParameterList(member: KtCallableDeclaration): KtTypeParameterList? {
|
private fun newTypeParameterList(member: KtCallableDeclaration): KtTypeParameterList? {
|
||||||
|
|||||||
+5
-62
@@ -21,19 +21,16 @@ import com.intellij.openapi.editor.Editor
|
|||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.checkAnnotationName
|
import org.jetbrains.kotlin.descriptors.annotations.checkAnnotationName
|
||||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors
|
import org.jetbrains.kotlin.diagnostics.Errors
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
|
||||||
import org.jetbrains.kotlin.idea.core.setReceiverType
|
|
||||||
import org.jetbrains.kotlin.idea.intentions.SpecifyTypeExplicitlyIntention
|
import org.jetbrains.kotlin.idea.intentions.SpecifyTypeExplicitlyIntention
|
||||||
|
import org.jetbrains.kotlin.idea.intentions.declarations.ConvertMemberToExtensionIntention
|
||||||
import org.jetbrains.kotlin.idea.project.builtIns
|
import org.jetbrains.kotlin.idea.project.builtIns
|
||||||
import org.jetbrains.kotlin.idea.quickfix.CleanupFix
|
import org.jetbrains.kotlin.idea.quickfix.CleanupFix
|
||||||
import org.jetbrains.kotlin.idea.quickfix.KotlinQuickFixAction
|
import org.jetbrains.kotlin.idea.quickfix.KotlinQuickFixAction
|
||||||
import org.jetbrains.kotlin.idea.quickfix.KotlinSingleIntentionActionFactory
|
import org.jetbrains.kotlin.idea.quickfix.KotlinSingleIntentionActionFactory
|
||||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
|
|
||||||
import org.jetbrains.kotlin.idea.util.addAnnotation
|
import org.jetbrains.kotlin.idea.util.addAnnotation
|
||||||
import org.jetbrains.kotlin.js.PredefinedAnnotation
|
import org.jetbrains.kotlin.js.PredefinedAnnotation
|
||||||
import org.jetbrains.kotlin.js.resolve.diagnostics.ErrorsJs
|
import org.jetbrains.kotlin.js.resolve.diagnostics.ErrorsJs
|
||||||
@@ -67,24 +64,19 @@ class MigrateExternalExtensionFix(declaration: KtNamedDeclaration)
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun fixNativeClass(containingClass: KtClassOrObject, project: Project, editor: Editor?, file: KtFile) {
|
private fun fixNativeClass(containingClass: KtClassOrObject, project: Project, editor: Editor?, file: KtFile) {
|
||||||
val membersToFix = containingClass.declarations.filterIsInstance<KtNamedDeclaration>().filter { isMemberDeclaration(it) }. map {
|
val membersToFix = containingClass.declarations.filterIsInstance<KtCallableDeclaration>().filter { isMemberDeclaration(it) }. map {
|
||||||
it to fetchJsNativeAnnotations(it)
|
it to fetchJsNativeAnnotations(it)
|
||||||
}.filter {
|
}.filter {
|
||||||
it.second.annotations.isNotEmpty()
|
it.second.annotations.isNotEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
var anchor: PsiElement = containingClass
|
membersToFix.asReversed().forEach { (memberDeclaration, annotations) ->
|
||||||
membersToFix.forEach { (memberDeclaration, annotations) ->
|
|
||||||
if (annotations.nativeAnnotation != null && !annotations.isGetter && !annotations.isSetter && !annotations.isInvoke) {
|
if (annotations.nativeAnnotation != null && !annotations.isGetter && !annotations.isSetter && !annotations.isInvoke) {
|
||||||
convertNativeAnnotationToJsName(memberDeclaration, annotations)
|
convertNativeAnnotationToJsName(memberDeclaration, annotations)
|
||||||
annotations.nativeAnnotation.delete()
|
annotations.nativeAnnotation.delete()
|
||||||
} else {
|
} else {
|
||||||
// TODO: find references
|
val externalDeclaration = ConvertMemberToExtensionIntention().convert(memberDeclaration)
|
||||||
createExtensionDeclaration(memberDeclaration, project, anchor)?.let { externalDeclaration ->
|
fixExtensionMemberDeclaration(externalDeclaration, project, null, file)
|
||||||
memberDeclaration.delete()
|
|
||||||
fixExtensionMemberDeclaration(externalDeclaration, project, null, file)
|
|
||||||
anchor = externalDeclaration
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,55 +85,6 @@ class MigrateExternalExtensionFix(declaration: KtNamedDeclaration)
|
|||||||
fixAnnotations(containingClass, classAnnotations, null)
|
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<KtAnnotationEntry>, val nativeAnnotation: KtAnnotationEntry?, val isGetter: Boolean, val isSetter: Boolean, val isInvoke: Boolean)
|
private data class JsNativeAnnotations(val annotations: List<KtAnnotationEntry>, val nativeAnnotation: KtAnnotationEntry?, val isGetter: Boolean, val isSetter: Boolean, val isInvoke: Boolean)
|
||||||
|
|
||||||
private fun fetchJsNativeAnnotations(declaration: KtNamedDeclaration) : JsNativeAnnotations {
|
private fun fetchJsNativeAnnotations(declaration: KtNamedDeclaration) : JsNativeAnnotations {
|
||||||
|
|||||||
@@ -20,6 +20,6 @@ inline fun B.bar(a: B) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
inline fun <T> B.exp(t: T) {
|
inline fun<T> B.exp(t: T) {
|
||||||
asDynamic()(t)
|
asDynamic()(t)
|
||||||
}
|
}
|
||||||
@@ -20,6 +20,6 @@ inline fun B.bar(a: B) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
inline fun <T> B.exp(t: T) {
|
inline fun<T> B.exp(t: T) {
|
||||||
asDynamic()(t)
|
asDynamic()(t)
|
||||||
}
|
}
|
||||||
@@ -20,6 +20,6 @@ inline fun B.bar(a: B) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
inline fun <T> B.exp(t: T) {
|
inline fun<T> B.exp(t: T) {
|
||||||
asDynamic()(t)
|
asDynamic()(t)
|
||||||
}
|
}
|
||||||
+1
-1
@@ -5,6 +5,6 @@ external class B {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
inline fun <T> B.exp(t: T) {
|
inline fun<T> B.exp(t: T) {
|
||||||
asDynamic()(t)
|
asDynamic()(t)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user