Parameter <-> Receiver Conversion: Support header/impl declarations

#KT-18907 Fixed
This commit is contained in:
Alexey Sedunov
2017-08-09 15:19:12 +03:00
parent d3a9d122e6
commit f80fcc7146
29 changed files with 239 additions and 8 deletions
@@ -68,7 +68,7 @@ internal fun KtDeclaration.headerDeclarationIfAny(): KtDeclaration? {
internal fun KtDeclaration.isHeaderOrHeaderClassMember() = internal fun KtDeclaration.isHeaderOrHeaderClassMember() =
hasModifier(KtTokens.HEADER_KEYWORD) || (containingClassOrObject?.hasModifier(KtTokens.HEADER_KEYWORD) ?: false) hasModifier(KtTokens.HEADER_KEYWORD) || (containingClassOrObject?.hasModifier(KtTokens.HEADER_KEYWORD) ?: false)
private fun DeclarationDescriptor.liftToHeader(): DeclarationDescriptor? { internal fun DeclarationDescriptor.liftToHeader(): DeclarationDescriptor? {
if (this is MemberDescriptor) { if (this is MemberDescriptor) {
return when { return when {
isHeader -> this isHeader -> this
@@ -19,15 +19,14 @@ package org.jetbrains.kotlin.idea.intentions
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.refactoring.changeSignature.KotlinChangeSignatureConfiguration import org.jetbrains.kotlin.idea.refactoring.changeSignature.KotlinChangeSignatureConfiguration
import org.jetbrains.kotlin.idea.refactoring.changeSignature.KotlinMethodDescriptor import org.jetbrains.kotlin.idea.refactoring.changeSignature.KotlinMethodDescriptor
import org.jetbrains.kotlin.idea.refactoring.changeSignature.modify import org.jetbrains.kotlin.idea.refactoring.changeSignature.modify
import org.jetbrains.kotlin.idea.refactoring.changeSignature.runChangeSignature import org.jetbrains.kotlin.idea.refactoring.changeSignature.runChangeSignature
import org.jetbrains.kotlin.idea.refactoring.resolveToHeaderDescriptorIfPossible
import org.jetbrains.kotlin.psi.KtNamedFunction import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtParameter import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.resolve.BindingContext
class ConvertParameterToReceiverIntention : SelfTargetingIntention<KtParameter>(KtParameter::class.java, "Convert parameter to receiver") { class ConvertParameterToReceiverIntention : SelfTargetingIntention<KtParameter>(KtParameter::class.java, "Convert parameter to receiver") {
override fun isApplicableTo(element: KtParameter, caretOffset: Int): Boolean { override fun isApplicableTo(element: KtParameter, caretOffset: Int): Boolean {
@@ -53,8 +52,7 @@ class ConvertParameterToReceiverIntention : SelfTargetingIntention<KtParameter>(
override fun applyTo(element: KtParameter, editor: Editor?) { override fun applyTo(element: KtParameter, editor: Editor?) {
val function = element.getStrictParentOfType<KtNamedFunction>() ?: return val function = element.getStrictParentOfType<KtNamedFunction>() ?: return
val parameterIndex = function.valueParameters.indexOf(element) val parameterIndex = function.valueParameters.indexOf(element)
val context = function.analyze() val descriptor = function.resolveToHeaderDescriptorIfPossible() as? FunctionDescriptor ?: return
val descriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, function] as? FunctionDescriptor ?: return
runChangeSignature(element.project, descriptor, configureChangeSignature(parameterIndex), element, text) runChangeSignature(element.project, descriptor, configureChangeSignature(parameterIndex), element, text)
} }
} }
@@ -26,9 +26,9 @@ import com.intellij.openapi.editor.Editor
import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
import org.jetbrains.kotlin.idea.core.getOrCreateValueParameterList import org.jetbrains.kotlin.idea.core.getOrCreateValueParameterList
import org.jetbrains.kotlin.idea.refactoring.changeSignature.* import org.jetbrains.kotlin.idea.refactoring.changeSignature.*
import org.jetbrains.kotlin.idea.refactoring.resolveToHeaderDescriptorIfPossible
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
import org.jetbrains.kotlin.idea.util.application.runWriteAction import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.psi.KtNamedFunction import org.jetbrains.kotlin.psi.KtNamedFunction
@@ -61,7 +61,7 @@ class ConvertReceiverToParameterIntention : SelfTargetingOffsetIndependentIntent
override fun applyTo(element: KtTypeReference, editor: Editor?) { override fun applyTo(element: KtTypeReference, editor: Editor?) {
val function = element.parent as? KtNamedFunction ?: return val function = element.parent as? KtNamedFunction ?: return
val descriptor = function.resolveToDescriptor() as FunctionDescriptor val descriptor = function.resolveToHeaderDescriptorIfPossible() as FunctionDescriptor
val project = function.project val project = function.project
@@ -102,7 +102,7 @@ class ConvertReceiverToParameterIntention : SelfTargetingOffsetIndependentIntent
if (!brokenOff) { if (!brokenOff) {
runChangeSignature( runChangeSignature(
element.project, element.project,
function.resolveToDescriptor() as FunctionDescriptor, function.resolveToHeaderDescriptorIfPossible() as FunctionDescriptor,
configureChangeSignature(newName), configureChangeSignature(newName),
function.receiverTypeReference!!, function.receiverTypeReference!!,
text text
@@ -970,4 +970,9 @@ internal fun KtDeclaration.withHeaderImplementations(): List<KtDeclaration> {
val header = liftToHeader() ?: return listOf(this) val header = liftToHeader() ?: return listOf(this)
val implementations = header.headerImplementations() ?: emptySet() val implementations = header.headerImplementations() ?: emptySet()
return listOf(header) + implementations return listOf(header) + implementations
}
internal fun KtDeclaration.resolveToHeaderDescriptorIfPossible(): DeclarationDescriptor {
val descriptor = resolveToDescriptor()
return descriptor.liftToHeader() ?: descriptor
} }
@@ -0,0 +1,9 @@
// "Convert parameter to receiver" "true"
header class Foo {
fun foo(n: Int, <caret>s: String)
}
fun Foo.test() {
foo(1, "2")
}
@@ -0,0 +1,9 @@
// "Convert parameter to receiver" "true"
header class Foo {
fun String.foo(n: Int)
}
fun Foo.test() {
"2".foo(1)
}
@@ -0,0 +1,9 @@
impl class Foo {
impl fun foo(n: Int, s: String) {
}
}
fun Foo.test() {
foo(1, "2")
}
@@ -0,0 +1,9 @@
impl class Foo {
impl fun String.foo(n: Int) {
}
}
fun Foo.test() {
"2".foo(1)
}
@@ -0,0 +1,9 @@
impl class Foo {
impl fun foo(n: Int, s: String) {
}
}
fun Foo.test() {
foo(1, "2")
}
@@ -0,0 +1,9 @@
impl class Foo {
impl fun String.foo(n: Int) {
}
}
fun Foo.test() {
"2".foo(1)
}
@@ -0,0 +1,7 @@
header class Foo {
fun foo(n: Int, s: String)
}
fun Foo.test() {
foo(1, "2")
}
@@ -0,0 +1,7 @@
header class Foo {
fun String.foo(n: Int)
}
fun Foo.test() {
"2".foo(1)
}
@@ -0,0 +1,11 @@
// "Convert parameter to receiver" "true"
impl class Foo {
impl fun foo(n: Int, <caret>s: String) {
}
}
fun Foo.test() {
foo(1, "2")
}
@@ -0,0 +1,11 @@
// "Convert parameter to receiver" "true"
impl class Foo {
impl fun String.foo(n: Int) {
}
}
fun Foo.test() {
"2".foo(1)
}
@@ -0,0 +1,9 @@
impl class Foo {
impl fun foo(n: Int, s: String) {
}
}
fun Foo.test() {
foo(1, "2")
}
@@ -0,0 +1,9 @@
impl class Foo {
impl fun String.foo(n: Int) {
}
}
fun Foo.test() {
"2".foo(1)
}
@@ -0,0 +1,9 @@
// "Convert receiver to parameter" "true"
header class Foo {
fun <caret>String.foo(n: Int)
}
fun Foo.test() {
"1".foo(2)
}
@@ -0,0 +1,9 @@
// "Convert receiver to parameter" "true"
header class Foo {
fun foo(s: String, n: Int)
}
fun Foo.test() {
foo("1", 2)
}
@@ -0,0 +1,9 @@
impl class Foo {
impl fun String.foo(n: Int) {
}
}
fun Foo.test() {
"1".foo(2)
}
@@ -0,0 +1,9 @@
impl class Foo {
impl fun foo(s: String, n: Int) {
}
}
fun Foo.test() {
foo("1", 2)
}
@@ -0,0 +1,9 @@
impl class Foo {
impl fun String.foo(n: Int) {
}
}
fun Foo.test() {
"1".foo(2)
}
@@ -0,0 +1,9 @@
impl class Foo {
impl fun foo(s: String, n: Int) {
}
}
fun Foo.test() {
foo("1", 2)
}
@@ -0,0 +1,7 @@
header class Foo {
fun String.foo(n: Int)
}
fun Foo.test() {
"1".foo(2)
}
@@ -0,0 +1,7 @@
header class Foo {
fun foo(s: String, n: Int)
}
fun Foo.test() {
foo("1", 2)
}
@@ -0,0 +1,11 @@
// "Convert receiver to parameter" "true"
impl class Foo {
impl fun <caret>String.foo(n: Int) {
}
}
fun Foo.test() {
"1".foo(2)
}
@@ -0,0 +1,11 @@
// "Convert receiver to parameter" "true"
impl class Foo {
impl fun foo(s: String, n: Int) {
}
}
fun Foo.test() {
foo("1", 2)
}
@@ -0,0 +1,9 @@
impl class Foo {
impl fun String.foo(n: Int) {
}
}
fun Foo.test() {
"1".foo(2)
}
@@ -0,0 +1,9 @@
impl class Foo {
impl fun foo(s: String, n: Int) {
}
}
fun Foo.test() {
foo("1", 2)
}
@@ -129,4 +129,16 @@ class QuickFixMultiModuleTest : AbstractQuickFixMultiModuleTest() {
@Test @Test
fun testAddOperatorByImpl() = doTestHeaderWithJvmAndJs() fun testAddOperatorByImpl() = doTestHeaderWithJvmAndJs()
@Test
fun testMemberFunReceiverToParameterByHeader() = doTestHeaderWithJvmAndJs()
@Test
fun testMemberFunReceiverToParameterByImpl() = doTestHeaderWithJvmAndJs()
@Test
fun testMemberFunParameterToReceiverByHeader() = doTestHeaderWithJvmAndJs()
@Test
fun testMemberFunParameterToReceiverByImpl() = doTestHeaderWithJvmAndJs()
} }