Create from Usage: Implement "Create function" on callable references
#KT-10283 Fixed
This commit is contained in:
@@ -252,6 +252,7 @@ public class QuickFixRegistrar : QuickFixContributor {
|
||||
|
||||
UNRESOLVED_REFERENCE_WRONG_RECEIVER.registerFactory(*CreateCallableFromCallActionFactory.INSTANCES)
|
||||
UNRESOLVED_REFERENCE.registerFactory(*CreateCallableFromCallActionFactory.INSTANCES)
|
||||
UNRESOLVED_REFERENCE.registerFactory(CreateFunctionFromCallableReferenceActionFactory)
|
||||
NO_VALUE_FOR_PARAMETER.registerFactory(*CreateCallableFromCallActionFactory.INSTANCES)
|
||||
TOO_MANY_ARGUMENTS.registerFactory(*CreateCallableFromCallActionFactory.INSTANCES)
|
||||
EXPRESSION_EXPECTED_PACKAGE_FOUND.registerFactory(*CreateCallableFromCallActionFactory.INSTANCES)
|
||||
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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.quickfix.createFromUsage.createCallable
|
||||
|
||||
import com.intellij.util.SmartList
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.core.refactoring.getExtractionContainers
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
|
||||
import org.jetbrains.kotlin.psi.KtCallableReferenceExpression
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.utils.ifEmpty
|
||||
|
||||
object CreateFunctionFromCallableReferenceActionFactory : CreateCallableMemberFromUsageFactory<KtCallableReferenceExpression>() {
|
||||
override fun getElementOfInterest(diagnostic: Diagnostic): KtCallableReferenceExpression? {
|
||||
return diagnostic.psiElement.getStrictParentOfType<KtCallableReferenceExpression>()
|
||||
}
|
||||
|
||||
override fun extractFixData(element: KtCallableReferenceExpression, diagnostic: Diagnostic): List<CallableInfo> {
|
||||
val name = element.callableReference.getReferencedName()
|
||||
val resolutionFacade = element.getResolutionFacade()
|
||||
val context = resolutionFacade.analyze(element, BodyResolveMode.PARTIAL)
|
||||
return element
|
||||
.guessTypes(context, resolutionFacade.moduleDescriptor)
|
||||
.filter { KotlinBuiltIns.isExactFunctionType(it) || KotlinBuiltIns.isExactExtensionFunctionType(it) }
|
||||
.mapNotNull {
|
||||
val receiverTypeInfo = element.typeReference?.let { TypeInfo(it, Variance.IN_VARIANCE) } ?: TypeInfo.Empty
|
||||
val returnTypeInfo = TypeInfo(KotlinBuiltIns.getReturnTypeFromFunctionType(it), Variance.OUT_VARIANCE)
|
||||
val containers = element.getExtractionContainers(includeAll = true).ifEmpty { return@mapNotNull null }
|
||||
val parameterInfos = SmartList<ParameterInfo>().apply {
|
||||
if (element.typeReference == null) {
|
||||
KotlinBuiltIns.getReceiverType(it)?.let { add(ParameterInfo(TypeInfo(it, Variance.IN_VARIANCE))) }
|
||||
}
|
||||
KotlinBuiltIns
|
||||
.getParameterTypeProjectionsFromFunctionType(it)
|
||||
.mapTo(this) { ParameterInfo(TypeInfo(it.type, it.projectionKind)) }
|
||||
}
|
||||
|
||||
FunctionInfo(name, receiverTypeInfo, returnTypeInfo, containers, parameterInfos)
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// "Create function 'foo'" "true"
|
||||
fun <T, U> T.map(f: T.() -> U) = f()
|
||||
|
||||
fun consume(s: String) {}
|
||||
|
||||
fun test() {
|
||||
consume(1.map(::<caret>foo))
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// "Create function 'foo'" "true"
|
||||
fun <T, U> T.map(f: T.() -> U) = f()
|
||||
|
||||
fun consume(s: String) {}
|
||||
|
||||
fun test() {
|
||||
fun foo(i: Int): String {
|
||||
<selection>throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.</selection>
|
||||
}
|
||||
consume(1.map(::foo))
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// "Create extension function 'foo'" "true"
|
||||
fun <T, U> T.map(f: T.() -> U) = f()
|
||||
|
||||
fun consume(s: String) {}
|
||||
|
||||
fun test() {
|
||||
consume(1.map(Int::<caret>foo))
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// "Create extension function 'foo'" "true"
|
||||
fun <T, U> T.map(f: T.() -> U) = f()
|
||||
|
||||
fun consume(s: String) {}
|
||||
|
||||
fun test() {
|
||||
consume(1.map(Int::foo))
|
||||
}
|
||||
|
||||
fun Int.foo(): String {
|
||||
<selection>throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.</selection>
|
||||
}
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
// "Create function 'foo'" "true"
|
||||
fun <T, U> T.map(f: (T) -> U) = f(this)
|
||||
|
||||
fun test() {
|
||||
1.map(::<caret>foo)
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// "Create function 'foo'" "true"
|
||||
fun <T, U> T.map(f: (T) -> U) = f(this)
|
||||
|
||||
fun test() {
|
||||
fun foo(i: Int): Any {
|
||||
<selection>throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.</selection>
|
||||
}
|
||||
1.map(::foo)
|
||||
}
|
||||
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
// "Create function 'foo'" "false"
|
||||
// ACTION: Convert to expression body
|
||||
// ACTION: Rename reference
|
||||
// ERROR: Unresolved reference: foo
|
||||
fun bar(n: Int) = "$n"
|
||||
|
||||
fun consume(s: String) {}
|
||||
|
||||
fun test() {
|
||||
consume(bar(::<caret>foo))
|
||||
}
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
// "Create function 'foo'" "true"
|
||||
fun <T, U> T.map(f: (T) -> U) = f(this)
|
||||
|
||||
fun consume(s: String) {}
|
||||
|
||||
fun test() {
|
||||
consume(1.map(::<caret>foo))
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// "Create function 'foo'" "true"
|
||||
fun <T, U> T.map(f: (T) -> U) = f(this)
|
||||
|
||||
fun consume(s: String) {}
|
||||
|
||||
fun test() {
|
||||
fun foo(i: Int): String {
|
||||
<selection>throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.</selection>
|
||||
}
|
||||
consume(1.map(::foo))
|
||||
}
|
||||
+1
@@ -1,6 +1,7 @@
|
||||
// "Create local variable 'foo'" "false"
|
||||
// ACTION: Rename reference
|
||||
// ACTION: Add 'f =' to argument
|
||||
// ACTION: Create function 'foo'
|
||||
// ERROR: Unresolved reference: foo
|
||||
fun test(f: (Int) -> Int) {}
|
||||
|
||||
|
||||
+1
@@ -1,6 +1,7 @@
|
||||
// "Create parameter 'foo'" "false"
|
||||
// ACTION: Rename reference
|
||||
// ACTION: Add 'f =' to argument
|
||||
// ACTION: Create function 'foo'
|
||||
// ERROR: Unresolved reference: foo
|
||||
fun test(f: (Int) -> Int) {}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// "Create property 'foo'" "false"
|
||||
// ACTION: Rename reference
|
||||
// ACTION: Add 'f =' to argument
|
||||
// ACTION: Create function 'foo'
|
||||
// ERROR: Unresolved reference: foo
|
||||
fun test(f: (Int) -> Int) {}
|
||||
|
||||
|
||||
@@ -2157,6 +2157,45 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/quickfix/createFromUsage/createFunction/callableReferences")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class CallableReferences extends AbstractQuickFixTest {
|
||||
public void testAllFilesPresentInCallableReferences() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/createFromUsage/createFunction/callableReferences"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("extensionNoReceiverInCallableRef.kt")
|
||||
public void testExtensionNoReceiverInCallableRef() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createFunction/callableReferences/extensionNoReceiverInCallableRef.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("extensionWithReceiverInCallableRef.kt")
|
||||
public void testExtensionWithReceiverInCallableRef() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createFunction/callableReferences/extensionWithReceiverInCallableRef.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("noExpectedReturnType.kt")
|
||||
public void testNoExpectedReturnType() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createFunction/callableReferences/noExpectedReturnType.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("noFunctionalType.kt")
|
||||
public void testNoFunctionalType() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createFunction/callableReferences/noFunctionalType.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("withExpectedReturnType.kt")
|
||||
public void testWithExpectedReturnType() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createFunction/callableReferences/withExpectedReturnType.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/quickfix/createFromUsage/createFunction/component")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
Reference in New Issue
Block a user