Supported inline function for expression body case

This commit is contained in:
Valentin Kipyatkov
2016-10-19 22:16:59 +03:00
parent 67e5ed802f
commit 57411b4d5e
16 changed files with 202 additions and 3 deletions
@@ -44,7 +44,8 @@ private val LOG = Logger.getInstance(UsageReplacementStrategy::class.java)
fun UsageReplacementStrategy.replaceUsagesInWholeProject(
targetPsiElement: PsiElement,
progressTitle: String,
commandName: String
commandName: String,
postAction: () -> Unit = {}
) {
val project = targetPsiElement.project
ProgressManager.getInstance().run(
@@ -56,7 +57,7 @@ fun UsageReplacementStrategy.replaceUsagesInWholeProject(
.filterIsInstance<KtSimpleNameReference>()
.map { ref -> ref.expression }
}
this@replaceUsagesInWholeProject.replaceUsages(usages, project, commandName)
this@replaceUsagesInWholeProject.replaceUsages(usages, project, commandName, postAction)
}
})
}
@@ -64,7 +65,8 @@ fun UsageReplacementStrategy.replaceUsagesInWholeProject(
private fun UsageReplacementStrategy.replaceUsages(
usages: Collection<KtSimpleNameExpression>,
project: Project,
commandName: String
commandName: String,
postAction: () -> Unit
) {
UIUtil.invokeLaterIfNeeded {
project.executeWriteCommand(commandName) {
@@ -92,6 +94,8 @@ private fun UsageReplacementStrategy.replaceUsages(
}
importsToDelete.forEach { it.delete() }
postAction()
}
}
}
+1
View File
@@ -372,6 +372,7 @@
<refactoring.introduceParameterMethodUsagesProcessor
implementation="org.jetbrains.kotlin.idea.refactoring.introduce.introduceParameter.KotlinIntroduceParameterMethodUsageProcessor"/>
<inlineActionHandler implementation="org.jetbrains.kotlin.idea.refactoring.inline.KotlinInlineValHandler"/>
<inlineActionHandler implementation="org.jetbrains.kotlin.idea.refactoring.inline.KotlinInlineFunctionHandler"/>
<inlineActionHandler implementation="org.jetbrains.kotlin.idea.refactoring.inline.KotlinInlineTypeAliasHandler"/>
<treeStructureProvider implementation="org.jetbrains.kotlin.idea.projectView.KotlinSelectInProjectViewProvider"/>
<treeStructureProvider implementation="org.jetbrains.kotlin.idea.projectView.KotlinExpandNodeProjectViewProvider" order="last"/>
@@ -0,0 +1,58 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.refactoring.inline
import com.intellij.lang.Language
import com.intellij.lang.refactoring.InlineActionHandler
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.refactoring.RefactoringBundle
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
import org.jetbrains.kotlin.idea.replacement.CallableUsageReplacementStrategy
import org.jetbrains.kotlin.idea.replacement.ReplacementBuilder
import org.jetbrains.kotlin.idea.replacement.replaceUsagesInWholeProject
import org.jetbrains.kotlin.idea.util.getResolutionScope
import org.jetbrains.kotlin.psi.KtNamedFunction
class KotlinInlineFunctionHandler: InlineActionHandler() {
override fun isEnabledForLanguage(language: Language) = language == KotlinLanguage.INSTANCE
override fun canInlineElement(element: PsiElement): Boolean {
return element is KtNamedFunction
&& element.hasBody() && !element.hasBlockBody() // TODO support multiline functions
&& element.getUseScope() is GlobalSearchScope // TODO support local functions
}
override fun inlineElement(project: Project, editor: Editor?, element: PsiElement) {
element as KtNamedFunction
val descriptor = element.resolveToDescriptor() as SimpleFunctionDescriptor
val bodyExpression = element.bodyExpression!!
val replacement = ReplacementBuilder(descriptor, element.getResolutionFacade())
.buildReplacementExpression(bodyExpression, bodyExpression.getResolutionScope())
val commandName = RefactoringBundle.message("inline.command", element.name)
CallableUsageReplacementStrategy(replacement)
.replaceUsagesInWholeProject(element, commandName, commandName, postAction = { element.delete() })
}
}
@@ -0,0 +1,11 @@
fun <caret>f(p: Int) = g()
fun g() {
}
fun complexFun(): Int {
}
fun main(args: Array<String>) {
f(complexFun())
}
@@ -0,0 +1,10 @@
fun g() {
}
fun complexFun(): Int {
}
fun main(args: Array<String>) {
complexFun()
g()
}
@@ -0,0 +1,8 @@
fun <caret>f(p: Int) = p + p
fun complexFun(): Int {
}
fun main(args: Array<String>) {
f(complexFun())
}
@@ -0,0 +1,7 @@
fun complexFun(): Int {
}
fun main(args: Array<String>) {
val p = complexFun()
p + p
}
@@ -0,0 +1,5 @@
fun <caret>f() = "foo"
fun main(args: Array<String>) {
println(f() + f())
}
@@ -0,0 +1,3 @@
fun main(args: Array<String>) {
println("foo" + "foo")
}
@@ -0,0 +1,7 @@
fun f(p1: Int, p2: Int) = p1 + p2
fun main(args: Array<String>) {
println(f(1, 2))
println(<caret>f(3, 4))
println(f(5, 6))
}
@@ -0,0 +1,5 @@
fun main(args: Array<String>) {
println(1 + 2)
println(3 + 4)
println(5 + 6)
}
@@ -0,0 +1,10 @@
fun <caret>foo(p1: String, p2: () -> Boolean) = bar(p1, null, p2)
fun bar(p1: String, p2: String?, p3: () -> Boolean)
fun foo(i: I) {
foo("foo") {
println("bar")
println("baz")
}
}
@@ -0,0 +1,8 @@
fun bar(p1: String, p2: String?, p3: () -> Boolean)
fun foo(i: I) {
bar("foo", null) {
println("bar")
println("baz")
}
}
@@ -0,0 +1,5 @@
fun <caret>f(p1: Int, p2: Int) = p1 + p2
fun main(args: Array<String>) {
println(f(3, 5))
}
@@ -0,0 +1,3 @@
fun main(args: Array<String>) {
println(3 + 5)
}
@@ -35,6 +35,60 @@ public class InlineTestGenerated extends AbstractInlineTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/refactoring/inline"), Pattern.compile("^(\\w+)\\.kt$"), true);
}
@TestMetadata("idea/testData/refactoring/inline/function")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Function extends AbstractInlineTest {
public void testAllFilesPresentInFunction() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/refactoring/inline/function"), Pattern.compile("^(\\w+)\\.kt$"), true);
}
@TestMetadata("idea/testData/refactoring/inline/function/expressionBody")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class ExpressionBody extends AbstractInlineTest {
public void testAllFilesPresentInExpressionBody() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/refactoring/inline/function/expressionBody"), Pattern.compile("^(\\w+)\\.kt$"), true);
}
@TestMetadata("ComplexArgumentNotUsed.kt")
public void testComplexArgumentNotUsed() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/function/expressionBody/ComplexArgumentNotUsed.kt");
doTest(fileName);
}
@TestMetadata("ComplexArgumentUsedTwice.kt")
public void testComplexArgumentUsedTwice() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/function/expressionBody/ComplexArgumentUsedTwice.kt");
doTest(fileName);
}
@TestMetadata("Constant.kt")
public void testConstant() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/function/expressionBody/Constant.kt");
doTest(fileName);
}
@TestMetadata("FromUsage.kt")
public void testFromUsage() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/function/expressionBody/FromUsage.kt");
doTest(fileName);
}
@TestMetadata("FunctionalParameterPassed.kt")
public void testFunctionalParameterPassed() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/function/expressionBody/FunctionalParameterPassed.kt");
doTest(fileName);
}
@TestMetadata("Simple.kt")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/function/expressionBody/Simple.kt");
doTest(fileName);
}
}
}
@TestMetadata("idea/testData/refactoring/inline/inlineTypeAlias")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)