Create from Usage: Use function form when rendering FunctionN types

#KT-7522 Fixed
This commit is contained in:
Alexey Sedunov
2015-09-29 18:42:44 +03:00
parent 605802847a
commit 1d83d75a82
8 changed files with 55 additions and 20 deletions
@@ -19,18 +19,18 @@ package org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder
import com.intellij.refactoring.psi.SearchUtils
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.cfg.pseudocode.*
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.idea.references.JetSimpleNameReference
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getAssignmentByLHS
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsStatement
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.descriptorUtil.resolveTopLevelClass
@@ -44,21 +44,36 @@ internal fun JetType.contains(inner: JetType): Boolean {
return JetTypeChecker.DEFAULT.equalTypes(this, inner) || getArguments().any { inner in it.getType() }
}
private fun DeclarationDescriptor.render(
typeParameterNameMap: Map<TypeParameterDescriptor, String>,
fq: Boolean
): String = when {
this is TypeParameterDescriptor -> typeParameterNameMap[this] ?: getName().asString()
fq -> DescriptorUtils.getFqName(this).asString()
else -> getName().asString()
}
private fun JetType.render(typeParameterNameMap: Map<TypeParameterDescriptor, String>, fq: Boolean): String {
val arguments = getArguments().map { if (it.isStarProjection) "*" else it.getType().render(typeParameterNameMap, fq) }
val typeString = getConstructor().getDeclarationDescriptor()!!.render(typeParameterNameMap, fq)
val typeArgumentString = if (arguments.isNotEmpty()) arguments.joinToString(", ", "<", ">") else ""
val nullifier = if (isMarkedNullable()) "?" else ""
return "$typeString$typeArgumentString$nullifier"
val substitution = typeParameterNameMap
.mapValues {
val name = Name.identifier(it.value)
val typeParameter = it.key
var wrappingTypeParameter: TypeParameterDescriptor
var wrappingTypeConstructor: TypeConstructor
wrappingTypeParameter = object : TypeParameterDescriptor by typeParameter {
override fun getName() = name
override fun getTypeConstructor() = wrappingTypeConstructor
}
wrappingTypeConstructor = object : TypeConstructor by typeParameter.typeConstructor {
override fun getDeclarationDescriptor() = wrappingTypeParameter
}
val wrappingType = object : JetType by typeParameter.defaultType {
override fun getConstructor() = wrappingTypeConstructor
}
TypeProjectionImpl(wrappingType)
}
.mapKeys { it.key.typeConstructor }
val typeToRender = TypeSubstitutor.create(substitution).substitute(this, Variance.INVARIANT)!!
val renderer = if (fq) IdeDescriptorRenderers.SOURCE_CODE else IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES
return renderer.renderType(typeToRender)
}
internal fun JetType.renderShort(typeParameterNameMap: Map<TypeParameterDescriptor, String>) = render(typeParameterNameMap, false)
@@ -4,6 +4,6 @@ fun test() {
val a = Foo(2, "2") { p: Int -> p + 1 }
}
class Foo(i: Int, s: String, function: Function1<Int, Int>) {
class Foo(i: Int, s: String, function: (Int) -> Int) {
}
@@ -4,6 +4,6 @@ fun test() {
val a = Foo { p: Int -> p + 1 }
}
class Foo(function: Function1<Int, Int>) {
class Foo(function: (Int) -> Int) {
}
@@ -1,7 +1,7 @@
// "Create member function 'foo'" "true"
class A<T>(val n: T) {
fun foo(t: T, s: String, function: Function1<T, T>): A<T> {
fun foo(t: T, s: String, function: (T) -> T): A<T> {
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
}
@@ -1,7 +1,7 @@
// "Create member function 'foo'" "true"
class A<T>(val n: T) {
fun foo(function: Function1<T, T>): A<T> {
fun foo(function: (T) -> T): A<T> {
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
}
@@ -0,0 +1,5 @@
// "Create function 'bar'" "true"
fun foo(block: (Int) -> String) {
<caret>bar(block)
}
@@ -0,0 +1,9 @@
// "Create function 'bar'" "true"
fun foo(block: (Int) -> String) {
bar(block)
}
fun bar(block: (Int) -> String) {
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
}
@@ -1784,6 +1784,12 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
doTest(fileName);
}
@TestMetadata("functionalType.kt")
public void testFunctionalType() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createFunction/call/functionalType.kt");
doTest(fileName);
}
@TestMetadata("inLambda.kt")
public void testInLambda() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createFunction/call/inLambda.kt");