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() =
hasModifier(KtTokens.HEADER_KEYWORD) || (containingClassOrObject?.hasModifier(KtTokens.HEADER_KEYWORD) ?: false)
private fun DeclarationDescriptor.liftToHeader(): DeclarationDescriptor? {
internal fun DeclarationDescriptor.liftToHeader(): DeclarationDescriptor? {
if (this is MemberDescriptor) {
return when {
isHeader -> this
@@ -19,15 +19,14 @@ package org.jetbrains.kotlin.idea.intentions
import com.intellij.openapi.editor.Editor
import com.intellij.psi.PsiElement
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.KotlinMethodDescriptor
import org.jetbrains.kotlin.idea.refactoring.changeSignature.modify
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.KtParameter
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.resolve.BindingContext
class ConvertParameterToReceiverIntention : SelfTargetingIntention<KtParameter>(KtParameter::class.java, "Convert parameter to receiver") {
override fun isApplicableTo(element: KtParameter, caretOffset: Int): Boolean {
@@ -53,8 +52,7 @@ class ConvertParameterToReceiverIntention : SelfTargetingIntention<KtParameter>(
override fun applyTo(element: KtParameter, editor: Editor?) {
val function = element.getStrictParentOfType<KtNamedFunction>() ?: return
val parameterIndex = function.valueParameters.indexOf(element)
val context = function.analyze()
val descriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, function] as? FunctionDescriptor ?: return
val descriptor = function.resolveToHeaderDescriptorIfPossible() as? FunctionDescriptor ?: return
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.PsiElement
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.refactoring.changeSignature.*
import org.jetbrains.kotlin.idea.refactoring.resolveToHeaderDescriptorIfPossible
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.psi.KtNamedFunction
@@ -61,7 +61,7 @@ class ConvertReceiverToParameterIntention : SelfTargetingOffsetIndependentIntent
override fun applyTo(element: KtTypeReference, editor: Editor?) {
val function = element.parent as? KtNamedFunction ?: return
val descriptor = function.resolveToDescriptor() as FunctionDescriptor
val descriptor = function.resolveToHeaderDescriptorIfPossible() as FunctionDescriptor
val project = function.project
@@ -102,7 +102,7 @@ class ConvertReceiverToParameterIntention : SelfTargetingOffsetIndependentIntent
if (!brokenOff) {
runChangeSignature(
element.project,
function.resolveToDescriptor() as FunctionDescriptor,
function.resolveToHeaderDescriptorIfPossible() as FunctionDescriptor,
configureChangeSignature(newName),
function.receiverTypeReference!!,
text
@@ -970,4 +970,9 @@ internal fun KtDeclaration.withHeaderImplementations(): List<KtDeclaration> {
val header = liftToHeader() ?: return listOf(this)
val implementations = header.headerImplementations() ?: emptySet()
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
fun testAddOperatorByImpl() = doTestHeaderWithJvmAndJs()
@Test
fun testMemberFunReceiverToParameterByHeader() = doTestHeaderWithJvmAndJs()
@Test
fun testMemberFunReceiverToParameterByImpl() = doTestHeaderWithJvmAndJs()
@Test
fun testMemberFunParameterToReceiverByHeader() = doTestHeaderWithJvmAndJs()
@Test
fun testMemberFunParameterToReceiverByImpl() = doTestHeaderWithJvmAndJs()
}