Extract Function: Limit the set of allowed containers for the default action
This commit is contained in:
+31
-4
@@ -50,8 +50,11 @@ import javax.swing.event.HyperlinkEvent
|
|||||||
import com.intellij.refactoring.BaseRefactoringProcessor.ConflictsInTestsException
|
import com.intellij.refactoring.BaseRefactoringProcessor.ConflictsInTestsException
|
||||||
import com.intellij.ui.awt.RelativePoint
|
import com.intellij.ui.awt.RelativePoint
|
||||||
import com.intellij.openapi.ui.popup.Balloon.Position
|
import com.intellij.openapi.ui.popup.Balloon.Position
|
||||||
|
import org.jetbrains.jet.lang.psi.psiUtil.getParentByType
|
||||||
|
import org.jetbrains.jet.lang.psi.JetDeclaration
|
||||||
|
import java.util.Collections
|
||||||
|
|
||||||
public class ExtractKotlinFunctionHandler : RefactoringActionHandler {
|
public class ExtractKotlinFunctionHandler(public val allContainersEnabled: Boolean = false) : RefactoringActionHandler {
|
||||||
fun doInvoke(
|
fun doInvoke(
|
||||||
editor: Editor,
|
editor: Editor,
|
||||||
file: JetFile,
|
file: JetFile,
|
||||||
@@ -119,7 +122,7 @@ public class ExtractKotlinFunctionHandler : RefactoringActionHandler {
|
|||||||
override fun invoke(project: Project, editor: Editor, file: PsiFile, dataContext: DataContext?) {
|
override fun invoke(project: Project, editor: Editor, file: PsiFile, dataContext: DataContext?) {
|
||||||
if (file !is JetFile) return
|
if (file !is JetFile) return
|
||||||
|
|
||||||
selectElements(editor, file) { (elements, targetSibling) ->
|
selectElements(editor, file, allContainersEnabled) { (elements, targetSibling) ->
|
||||||
doInvoke(editor, file, elements, targetSibling)
|
doInvoke(editor, file, elements, targetSibling)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -142,6 +145,7 @@ private fun showErrorHintByKey(project: Project, editor: Editor, key: String) {
|
|||||||
fun selectElements(
|
fun selectElements(
|
||||||
editor: Editor,
|
editor: Editor,
|
||||||
file: PsiFile,
|
file: PsiFile,
|
||||||
|
allContainersEnabled: Boolean = false,
|
||||||
continuation: (elements: List<PsiElement>, targetSibling: PsiElement) -> Unit
|
continuation: (elements: List<PsiElement>, targetSibling: PsiElement) -> Unit
|
||||||
) {
|
) {
|
||||||
fun noExpressionError() {
|
fun noExpressionError() {
|
||||||
@@ -167,17 +171,40 @@ fun selectElements(
|
|||||||
continuation(elements, outermostParent)
|
continuation(elements, outermostParent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getContainers(element: PsiElement, strict: Boolean): List<JetElement> {
|
||||||
|
if (allContainersEnabled) return element.getAllExtractionContainers(strict)
|
||||||
|
|
||||||
|
val declaration = element.getParentByType(javaClass<JetDeclaration>(), strict)
|
||||||
|
if (declaration == null) return Collections.emptyList()
|
||||||
|
|
||||||
|
val parent = declaration.getParent()
|
||||||
|
return when (parent) {
|
||||||
|
is JetFile -> Collections.singletonList(parent)
|
||||||
|
is JetClassBody -> {
|
||||||
|
element.getAllExtractionContainers(strict)
|
||||||
|
.filter {
|
||||||
|
it is JetClassBody || (it is JetBlockExpression && it.getParent() is JetDeclarationWithBody)
|
||||||
|
}
|
||||||
|
.dropWhile { it !is JetClassBody }
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
val targetContainer = parent?.getParentByType(javaClass<JetDeclarationWithBody>())?.getBodyExpression()
|
||||||
|
if (targetContainer is JetBlockExpression) Collections.singletonList(targetContainer) else Collections.emptyList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun selectTargetContainer(elements: List<PsiElement>) {
|
fun selectTargetContainer(elements: List<PsiElement>) {
|
||||||
val parent = PsiTreeUtil.findCommonParent(elements)
|
val parent = PsiTreeUtil.findCommonParent(elements)
|
||||||
?: throw AssertionError("Should have at least one parent: ${elements.makeString("\n")}")
|
?: throw AssertionError("Should have at least one parent: ${elements.makeString("\n")}")
|
||||||
|
|
||||||
val containers = parent.getAllExtractionContainers(elements.size == 1)
|
val containers = getContainers(parent, elements.size == 1)
|
||||||
if (containers.empty) {
|
if (containers.empty) {
|
||||||
noContainerError()
|
noContainerError()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ApplicationManager.getApplication()!!.isUnitTestMode()) {
|
if (containers.size == 1 || ApplicationManager.getApplication()!!.isUnitTestMode()) {
|
||||||
onSelectionComplete(parent, elements, containers[0])
|
onSelectionComplete(parent, elements, containers[0])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
class A {
|
||||||
|
fun foo(a: Int, b: Int): Int {
|
||||||
|
return object: Function0<Int> {
|
||||||
|
override fun invoke(): Int {
|
||||||
|
return <selection>a + b - 1</selection>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
class A {
|
||||||
|
fun foo(a: Int, b: Int): Int {
|
||||||
|
return object: Function0<Int> {
|
||||||
|
override fun invoke(): Int {
|
||||||
|
return i()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun i(): Int {
|
||||||
|
return a + b - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
class A {
|
||||||
|
class B {
|
||||||
|
fun foo(a: Int, b: Int): Int {
|
||||||
|
return <selection>a + b - 1</selection>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
class A {
|
||||||
|
class B {
|
||||||
|
fun foo(a: Int, b: Int): Int {
|
||||||
|
return i(a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun i(a: Int, b: Int): Int {
|
||||||
|
return a + b - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
class A {
|
||||||
|
fun foo(a: Int, b: Int): Int {
|
||||||
|
return {
|
||||||
|
<selection>a + b - 1</selection>
|
||||||
|
}.invoke()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
class A {
|
||||||
|
fun foo(a: Int, b: Int): Int {
|
||||||
|
fun i(): Int {
|
||||||
|
return a + b - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
i()
|
||||||
|
}.invoke()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
class A {
|
||||||
|
fun foo(a: Int, b: Int): Int {
|
||||||
|
class L: Function0<Int> {
|
||||||
|
override fun invoke(): Int {
|
||||||
|
return <selection>a + b - 1</selection>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return L().invoke()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
class A {
|
||||||
|
fun foo(a: Int, b: Int): Int {
|
||||||
|
class L: Function0<Int> {
|
||||||
|
override fun invoke(): Int {
|
||||||
|
return i()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun i(): Int {
|
||||||
|
return a + b - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return L().invoke()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fun foo(a: Int, b: Int): Int {
|
||||||
|
fun bar() {
|
||||||
|
return <selection>a + b - 1</selection>
|
||||||
|
}
|
||||||
|
|
||||||
|
return bar()
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fun foo(a: Int, b: Int): Int {
|
||||||
|
fun i(): Int {
|
||||||
|
return a + b - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bar() {
|
||||||
|
return i()
|
||||||
|
}
|
||||||
|
|
||||||
|
return bar()
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fun foo(a: Int, b: Int): Int {
|
||||||
|
return <selection>a + b - 1</selection>
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fun foo(a: Int, b: Int): Int {
|
||||||
|
return i(a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun i(a: Int, b: Int): Int {
|
||||||
|
return a + b - 1
|
||||||
|
}
|
||||||
+40
-1
@@ -191,7 +191,7 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("idea/testData/refactoring/extractFunction")
|
@TestMetadata("idea/testData/refactoring/extractFunction")
|
||||||
@InnerTestClasses({ExtractFunction.Basic.class, ExtractFunction.ControlFlow.class, ExtractFunction.Parameters.class, ExtractFunction.TypeParameters.class})
|
@InnerTestClasses({ExtractFunction.Basic.class, ExtractFunction.ControlFlow.class, ExtractFunction.DefaultContainer.class, ExtractFunction.Parameters.class, ExtractFunction.TypeParameters.class})
|
||||||
public static class ExtractFunction extends AbstractJetExtractionTest {
|
public static class ExtractFunction extends AbstractJetExtractionTest {
|
||||||
public void testAllFilesPresentInExtractFunction() throws Exception {
|
public void testAllFilesPresentInExtractFunction() throws Exception {
|
||||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/refactoring/extractFunction"), Pattern.compile("^(.+)\\.kt$"), true);
|
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/refactoring/extractFunction"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||||
@@ -537,6 +537,44 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("idea/testData/refactoring/extractFunction/defaultContainer")
|
||||||
|
public static class DefaultContainer extends AbstractJetExtractionTest {
|
||||||
|
public void testAllFilesPresentInDefaultContainer() throws Exception {
|
||||||
|
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/refactoring/extractFunction/defaultContainer"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("anonymousObject.kt")
|
||||||
|
public void testAnonymousObject() throws Exception {
|
||||||
|
doExtractFunctionTest("idea/testData/refactoring/extractFunction/defaultContainer/anonymousObject.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("classFunction.kt")
|
||||||
|
public void testClassFunction() throws Exception {
|
||||||
|
doExtractFunctionTest("idea/testData/refactoring/extractFunction/defaultContainer/classFunction.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("lambda.kt")
|
||||||
|
public void testLambda() throws Exception {
|
||||||
|
doExtractFunctionTest("idea/testData/refactoring/extractFunction/defaultContainer/lambda.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("localClass.kt")
|
||||||
|
public void testLocalClass() throws Exception {
|
||||||
|
doExtractFunctionTest("idea/testData/refactoring/extractFunction/defaultContainer/localClass.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("localFunction.kt")
|
||||||
|
public void testLocalFunction() throws Exception {
|
||||||
|
doExtractFunctionTest("idea/testData/refactoring/extractFunction/defaultContainer/localFunction.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("topLevelFunction.kt")
|
||||||
|
public void testTopLevelFunction() throws Exception {
|
||||||
|
doExtractFunctionTest("idea/testData/refactoring/extractFunction/defaultContainer/topLevelFunction.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("idea/testData/refactoring/extractFunction/parameters")
|
@TestMetadata("idea/testData/refactoring/extractFunction/parameters")
|
||||||
@InnerTestClasses({Parameters.ExtractSuper.class, Parameters.ExtractThis.class, Parameters.Misc.class, Parameters.NonDenotableTypes.class})
|
@InnerTestClasses({Parameters.ExtractSuper.class, Parameters.ExtractThis.class, Parameters.Misc.class, Parameters.NonDenotableTypes.class})
|
||||||
public static class Parameters extends AbstractJetExtractionTest {
|
public static class Parameters extends AbstractJetExtractionTest {
|
||||||
@@ -745,6 +783,7 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest {
|
|||||||
suite.addTestSuite(ExtractFunction.class);
|
suite.addTestSuite(ExtractFunction.class);
|
||||||
suite.addTestSuite(Basic.class);
|
suite.addTestSuite(Basic.class);
|
||||||
suite.addTest(ControlFlow.innerSuite());
|
suite.addTest(ControlFlow.innerSuite());
|
||||||
|
suite.addTestSuite(DefaultContainer.class);
|
||||||
suite.addTest(Parameters.innerSuite());
|
suite.addTest(Parameters.innerSuite());
|
||||||
suite.addTestSuite(TypeParameters.class);
|
suite.addTestSuite(TypeParameters.class);
|
||||||
return suite;
|
return suite;
|
||||||
|
|||||||
Reference in New Issue
Block a user