From ab5a69161236f78b746602fd4e3b394f6481d1d1 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Fri, 6 Mar 2015 18:08:36 +0300 Subject: [PATCH] Create From Usage: Place generated declarations next to original element container if they have common parent #KT-6687 Fixed --- .../callableBuilder/CallableBuilder.kt | 47 ++++++++++++------- .../afterCallWithThisReceiverInClass.kt | 4 +- ...afterCallWithThisReceiverInNestedClass1.kt | 4 +- ...afterCallWithThisReceiverInNestedClass2.kt | 8 ++-- .../afterObjectWithSuperclass.kt | 8 ++-- .../afterObjectWithSupertrait.kt | 8 ++-- .../createFunction/call/afterFunPlacement.kt | 18 +++++++ .../call/afterTopLevelFunPlacement.kt | 16 +++++++ .../createFunction/call/beforeFunPlacement.kt | 14 ++++++ .../call/beforeTopLevelFunPlacement.kt | 12 +++++ .../afterRefInStringTemplateRuntime.kt | 6 +-- .../property/afterTopLevelValNoReceiver.kt | 4 +- .../afterTopLevelValWithPackageName.kt | 4 +- .../property/afterValOnLibObject.kt | 4 +- .../property/afterValOnLibType.kt | 4 +- .../property/afterVarOnLibType.kt | 4 +- .../extensionValOnGroovyType.after.kt | 6 +-- .../property/extensionValOnJavaType.after.kt | 6 +-- .../idea/quickfix/QuickFixTestGenerated.java | 12 +++++ 19 files changed, 136 insertions(+), 53 deletions(-) create mode 100644 idea/testData/quickfix/createFromUsage/createFunction/call/afterFunPlacement.kt create mode 100644 idea/testData/quickfix/createFromUsage/createFunction/call/afterTopLevelFunPlacement.kt create mode 100644 idea/testData/quickfix/createFromUsage/createFunction/call/beforeFunPlacement.kt create mode 100644 idea/testData/quickfix/createFromUsage/createFunction/call/beforeTopLevelFunPlacement.kt 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 109a159a7cc..773023a536d 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 @@ -529,12 +529,37 @@ class CallableBuilder(val config: CallableBuilderConfiguration) { return Math.max(lineBreaksNeeded - lineBreaksPresent, 0) } - val declarationInPlace = when (containingElement) { - is JetFile -> containingElement.add(declaration) as JetNamedDeclaration + fun addNextToOriginalElementContainer(addBefore: Boolean): JetNamedDeclaration { + val actualContainer = (containingElement as? JetClassOrObject)?.getBody() ?: containingElement + val sibling = config.originalElement.parents().first { it.getParent() == actualContainer } + return if (addBefore) { + actualContainer.addBefore(declaration, sibling) + } + else { + actualContainer.addAfter(declaration, sibling) + } as JetNamedDeclaration + } - is PsiClass -> jetFileToEdit.add(declaration) as JetNamedDeclaration + val declarationInPlace = when { + containingElement.isAncestor(config.originalElement, true) -> { + val insertToBlock = containingElement is JetBlockExpression + if (insertToBlock) { + val parent = containingElement.getParent() + if (parent is JetFunctionLiteral) { + if (!parent.isMultiLine()) { + parent.addBefore(newLine, containingElement) + parent.addAfter(newLine, containingElement) + } + } + } + addNextToOriginalElementContainer(insertToBlock || declaration is JetProperty) + } - is JetClassOrObject -> { + containingElement is JetFile -> containingElement.add(declaration) as JetNamedDeclaration + + containingElement is PsiClass -> jetFileToEdit.add(declaration) as JetNamedDeclaration + + containingElement is JetClassOrObject -> { var classBody = containingElement.getBody() if (classBody == null) { classBody = containingElement.add(psiFactory.createEmptyClassBody()) as JetClassBody @@ -550,20 +575,6 @@ class CallableBuilder(val config: CallableBuilderConfiguration) { } else classBody.addAfter(declaration, classBody!!.getLBrace()!!) as JetNamedDeclaration } - - is JetBlockExpression -> { - val parent = containingElement.getParent() - if (parent is JetFunctionLiteral) { - if (!parent.isMultiLine()) { - parent.addBefore(newLine, containingElement) - parent.addAfter(newLine, containingElement) - } - } - - val sibling = config.originalElement.parents().first { it.getParent() == containingElement } - containingElement.addBefore(declaration, sibling) as JetNamedDeclaration - } - else -> throw AssertionError("Invalid containing element: ${containingElement.getText()}") } diff --git a/idea/testData/quickfix/createFromUsage/createClass/callExpression/afterCallWithThisReceiverInClass.kt b/idea/testData/quickfix/createFromUsage/createClass/callExpression/afterCallWithThisReceiverInClass.kt index 6deab77cda1..395cd5927ad 100644 --- a/idea/testData/quickfix/createFromUsage/createClass/callExpression/afterCallWithThisReceiverInClass.kt +++ b/idea/testData/quickfix/createFromUsage/createClass/callExpression/afterCallWithThisReceiverInClass.kt @@ -1,9 +1,9 @@ // "Create class 'Foo'" "true" class A(val n: T) { + fun test() = this.Foo(2, "2") + inner class Foo(i: Int, s: String) { } - - fun test() = this.Foo(2, "2") } \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createClass/callExpression/afterCallWithThisReceiverInNestedClass1.kt b/idea/testData/quickfix/createFromUsage/createClass/callExpression/afterCallWithThisReceiverInNestedClass1.kt index 7deebb1a224..9988a1dc616 100644 --- a/idea/testData/quickfix/createFromUsage/createClass/callExpression/afterCallWithThisReceiverInNestedClass1.kt +++ b/idea/testData/quickfix/createFromUsage/createClass/callExpression/afterCallWithThisReceiverInNestedClass1.kt @@ -2,10 +2,10 @@ class A(val n: T) { inner class B(val m: U) { + fun test() = this.Foo(2, "2") + inner class Foo(i: Int, s: String) { } - - fun test() = this.Foo(2, "2") } } \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createClass/callExpression/afterCallWithThisReceiverInNestedClass2.kt b/idea/testData/quickfix/createFromUsage/createClass/callExpression/afterCallWithThisReceiverInNestedClass2.kt index 90734173d93..d0b09858207 100644 --- a/idea/testData/quickfix/createFromUsage/createClass/callExpression/afterCallWithThisReceiverInNestedClass2.kt +++ b/idea/testData/quickfix/createFromUsage/createClass/callExpression/afterCallWithThisReceiverInNestedClass2.kt @@ -1,11 +1,11 @@ // "Create class 'Foo'" "true" class A(val n: T) { - inner class Foo(i: Int, s: String) { - - } - inner class B(val m: U) { fun test() = this@A.Foo(2, "2") } + + inner class Foo(i: Int, s: String) { + + } } \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createClass/referenceExpression/afterObjectWithSuperclass.kt b/idea/testData/quickfix/createFromUsage/createClass/referenceExpression/afterObjectWithSuperclass.kt index 9df73821295..e8612debf48 100644 --- a/idea/testData/quickfix/createFromUsage/createClass/referenceExpression/afterObjectWithSuperclass.kt +++ b/idea/testData/quickfix/createFromUsage/createClass/referenceExpression/afterObjectWithSuperclass.kt @@ -3,10 +3,10 @@ package p fun foo(): X = A -open class X { - -} - object A : X() { } + +open class X { + +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createClass/referenceExpression/afterObjectWithSupertrait.kt b/idea/testData/quickfix/createFromUsage/createClass/referenceExpression/afterObjectWithSupertrait.kt index b5d24016c8c..544241d5126 100644 --- a/idea/testData/quickfix/createFromUsage/createClass/referenceExpression/afterObjectWithSupertrait.kt +++ b/idea/testData/quickfix/createFromUsage/createClass/referenceExpression/afterObjectWithSupertrait.kt @@ -3,10 +3,10 @@ package p fun foo(): X = A -trait X { - -} - object A : X { } + +trait X { + +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createFunction/call/afterFunPlacement.kt b/idea/testData/quickfix/createFromUsage/createFunction/call/afterFunPlacement.kt new file mode 100644 index 00000000000..0596e7a1c13 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/afterFunPlacement.kt @@ -0,0 +1,18 @@ +// "Create function 'foo'" "true" + +class A { + val baz = 1 + + fun test() { + val a: A = foo() + } + + private fun foo(): A { + throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + fun bar() { + + } +} + diff --git a/idea/testData/quickfix/createFromUsage/createFunction/call/afterTopLevelFunPlacement.kt b/idea/testData/quickfix/createFromUsage/createFunction/call/afterTopLevelFunPlacement.kt new file mode 100644 index 00000000000..cdd74c4c564 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/afterTopLevelFunPlacement.kt @@ -0,0 +1,16 @@ +// "Create function 'foo'" "true" + +val baz = 1 + +fun test() { + val a: Int = foo() +} + +fun foo(): Int { + throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates. +} + +fun bar() { + +} + diff --git a/idea/testData/quickfix/createFromUsage/createFunction/call/beforeFunPlacement.kt b/idea/testData/quickfix/createFromUsage/createFunction/call/beforeFunPlacement.kt new file mode 100644 index 00000000000..59e5b0d55ef --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/beforeFunPlacement.kt @@ -0,0 +1,14 @@ +// "Create function 'foo'" "true" + +class A { + val baz = 1 + + fun test() { + val a: A = foo() + } + + fun bar() { + + } +} + diff --git a/idea/testData/quickfix/createFromUsage/createFunction/call/beforeTopLevelFunPlacement.kt b/idea/testData/quickfix/createFromUsage/createFunction/call/beforeTopLevelFunPlacement.kt new file mode 100644 index 00000000000..3bea7e02dbd --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createFunction/call/beforeTopLevelFunPlacement.kt @@ -0,0 +1,12 @@ +// "Create function 'foo'" "true" + +val baz = 1 + +fun test() { + val a: Int = foo() +} + +fun bar() { + +} + diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/afterRefInStringTemplateRuntime.kt b/idea/testData/quickfix/createFromUsage/createVariable/property/afterRefInStringTemplateRuntime.kt index 1158b7fcb98..d339ab9ba6b 100644 --- a/idea/testData/quickfix/createFromUsage/createVariable/property/afterRefInStringTemplateRuntime.kt +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/afterRefInStringTemplateRuntime.kt @@ -1,8 +1,8 @@ // "Create property 'foo'" "true" // ERROR: Property must be initialized +val foo: String + fun test() { println("a = $foo") -} - -val foo: String +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/afterTopLevelValNoReceiver.kt b/idea/testData/quickfix/createFromUsage/createVariable/property/afterTopLevelValNoReceiver.kt index 6c67f61adda..3248ce2cf73 100644 --- a/idea/testData/quickfix/createFromUsage/createVariable/property/afterTopLevelValNoReceiver.kt +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/afterTopLevelValNoReceiver.kt @@ -1,8 +1,8 @@ // "Create property 'foo'" "true" // ERROR: Property must be initialized +val foo: Int + fun test(): Int { return foo } - -val foo: Int diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/afterTopLevelValWithPackageName.kt b/idea/testData/quickfix/createFromUsage/createVariable/property/afterTopLevelValWithPackageName.kt index 544eab913e5..879ff8eaf38 100644 --- a/idea/testData/quickfix/createFromUsage/createVariable/property/afterTopLevelValWithPackageName.kt +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/afterTopLevelValWithPackageName.kt @@ -3,8 +3,8 @@ package foo +val foo: Int + fun test(): Int { return foo } - -val foo: Int diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/afterValOnLibObject.kt b/idea/testData/quickfix/createFromUsage/createVariable/property/afterValOnLibObject.kt index c6a6870aa05..d84c592e297 100644 --- a/idea/testData/quickfix/createFromUsage/createVariable/property/afterValOnLibObject.kt +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/afterValOnLibObject.kt @@ -1,8 +1,8 @@ // "Create extension property 'foo'" "true" // ERROR: Property must be initialized +val Unit.foo: Int + fun test() { val a: Int = Unit.foo } - -val Unit.foo: Int diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/afterValOnLibType.kt b/idea/testData/quickfix/createFromUsage/createVariable/property/afterValOnLibType.kt index fd09cffdd5f..2cd1ad44a64 100644 --- a/idea/testData/quickfix/createFromUsage/createVariable/property/afterValOnLibType.kt +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/afterValOnLibType.kt @@ -3,8 +3,8 @@ class A(val n: T) +val Int.foo: A + fun test() { val a: A = 2.foo } - -val Int.foo: A diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/afterVarOnLibType.kt b/idea/testData/quickfix/createFromUsage/createVariable/property/afterVarOnLibType.kt index bb6fcf30edd..448726f1efb 100644 --- a/idea/testData/quickfix/createFromUsage/createVariable/property/afterVarOnLibType.kt +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/afterVarOnLibType.kt @@ -3,8 +3,8 @@ class A(val n: T) +var Int.foo: A + fun test() { 2.foo = A("2") } - -var Int.foo: A diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/extensionValOnGroovyType.after.kt b/idea/testData/quickfix/createFromUsage/createVariable/property/extensionValOnGroovyType.after.kt index 7f994d2b30d..af0dab01d05 100644 --- a/idea/testData/quickfix/createFromUsage/createVariable/property/extensionValOnGroovyType.after.kt +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/extensionValOnGroovyType.after.kt @@ -1,8 +1,8 @@ // "Create extension property 'foo'" "true" // ERROR: Unresolved reference: foo +val A.foo: String? + fun test(): String? { return A().foo -} - -val A.foo: String? +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createVariable/property/extensionValOnJavaType.after.kt b/idea/testData/quickfix/createFromUsage/createVariable/property/extensionValOnJavaType.after.kt index 7f994d2b30d..af0dab01d05 100644 --- a/idea/testData/quickfix/createFromUsage/createVariable/property/extensionValOnJavaType.after.kt +++ b/idea/testData/quickfix/createFromUsage/createVariable/property/extensionValOnJavaType.after.kt @@ -1,8 +1,8 @@ // "Create extension property 'foo'" "true" // ERROR: Unresolved reference: foo +val A.foo: String? + fun test(): String? { return A().foo -} - -val A.foo: String? +} \ 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 e0ecd4b8a2b..33a87c36192 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -1680,6 +1680,12 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { doTest(fileName); } + @TestMetadata("beforeFunPlacement.kt") + public void testFunPlacement() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createFunction/call/beforeFunPlacement.kt"); + doTest(fileName); + } + @TestMetadata("beforeFunWithExplicitParamNamesOnUserType.kt") public void testFunWithExplicitParamNamesOnUserType() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createFunction/call/beforeFunWithExplicitParamNamesOnUserType.kt"); @@ -1806,6 +1812,12 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { doTest(fileName); } + @TestMetadata("beforeTopLevelFunPlacement.kt") + public void testTopLevelFunPlacement() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createFunction/call/beforeTopLevelFunPlacement.kt"); + doTest(fileName); + } + @TestMetadata("beforeUnitFun.kt") public void testUnitFun() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createFunction/call/beforeUnitFun.kt");