Create From Usage: Add support of property delegates
This commit is contained in:
+1
-1
@@ -29,7 +29,7 @@ abstract class TypeInfo(val variance: Variance) {
|
||||
}
|
||||
|
||||
override fun getPossibleTypes(builder: CallableBuilder): List<JetType> =
|
||||
expression.guessTypes(builder.currentFileContext).flatMap { it.getPossibleSupertypes(variance) }
|
||||
expression.guessTypes(builder.currentFileContext, builder.currentFileModule).flatMap { it.getPossibleSupertypes(variance) }
|
||||
}
|
||||
|
||||
class ByType(val theType: JetType, variance: Variance, val keepUnsubstituted: Boolean = false): TypeInfo(variance) {
|
||||
|
||||
+27
-6
@@ -26,6 +26,13 @@ import org.jetbrains.jet.lang.psi.psiUtil.getAssignmentByLHS
|
||||
import org.jetbrains.jet.lang.resolve.bindingContextUtil.isUsedAsStatement
|
||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns
|
||||
import org.jetbrains.jet.lang.psi.JetDeclaration
|
||||
import org.jetbrains.jet.lang.psi.JetPropertyDelegate
|
||||
import org.jetbrains.jet.lang.psi.JetProperty
|
||||
import org.jetbrains.jet.lang.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.jet.lang.resolve.lazy.ResolveSessionUtils
|
||||
import org.jetbrains.jet.lang.resolve.name.FqName
|
||||
import kotlin.properties.Delegates
|
||||
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor
|
||||
|
||||
private fun JetType.contains(inner: JetType): Boolean {
|
||||
return JetTypeChecker.DEFAULT.equalTypes(this, inner) || getArguments().any { inner in it.getType() }
|
||||
@@ -74,8 +81,10 @@ fun JetType.getTypeParameters(): Set<TypeParameterDescriptor> {
|
||||
return typeParameters
|
||||
}
|
||||
|
||||
fun JetExpression.guessTypes(context: BindingContext): Array<JetType> {
|
||||
if (this !is JetDeclaration && isUsedAsStatement(context)) return array(KotlinBuiltIns.getInstance().getUnitType())
|
||||
fun JetExpression.guessTypes(context: BindingContext, module: ModuleDescriptor?): Array<JetType> {
|
||||
val builtIns = KotlinBuiltIns.getInstance()
|
||||
|
||||
if (this !is JetDeclaration && isUsedAsStatement(context)) return array(builtIns.getUnitType())
|
||||
|
||||
// if we know the actual type of the expression
|
||||
val theType1 = context[BindingContext.EXPRESSION_TYPE, this]
|
||||
@@ -89,15 +98,16 @@ fun JetExpression.guessTypes(context: BindingContext): Array<JetType> {
|
||||
return array(theType2)
|
||||
}
|
||||
|
||||
val parent = getParent()
|
||||
return when {
|
||||
this is JetTypeConstraint -> {
|
||||
// expression itself is a type assertion
|
||||
val constraint = (this as JetTypeConstraint)
|
||||
array(context[BindingContext.TYPE, constraint.getBoundTypeReference()]!!)
|
||||
}
|
||||
getParent() is JetTypeConstraint -> {
|
||||
parent is JetTypeConstraint -> {
|
||||
// expression is on the left side of a type assertion
|
||||
val constraint = (getParent() as JetTypeConstraint)
|
||||
val constraint = (parent as JetTypeConstraint)
|
||||
array(context[BindingContext.TYPE, constraint.getBoundTypeReference()]!!)
|
||||
}
|
||||
this is JetMultiDeclarationEntry -> {
|
||||
@@ -124,9 +134,9 @@ fun JetExpression.guessTypes(context: BindingContext): Array<JetType> {
|
||||
guessType(context)
|
||||
}
|
||||
}
|
||||
getParent() is JetVariableDeclaration -> {
|
||||
parent is JetVariableDeclaration -> {
|
||||
// the expression is the RHS of a variable assignment with a specified type
|
||||
val variable = getParent() as JetVariableDeclaration
|
||||
val variable = parent as JetVariableDeclaration
|
||||
val typeRef = variable.getTypeReference()
|
||||
if (typeRef != null) {
|
||||
// and has a specified type
|
||||
@@ -137,6 +147,17 @@ fun JetExpression.guessTypes(context: BindingContext): Array<JetType> {
|
||||
variable.guessType(context)
|
||||
}
|
||||
}
|
||||
parent is JetPropertyDelegate && module != null -> {
|
||||
val property = context[BindingContext.DECLARATION_TO_DESCRIPTOR, parent.getParent() as JetProperty] as PropertyDescriptor
|
||||
val delegateClassName = if (property.isVar() ) "ReadWriteProperty" else "ReadOnlyProperty"
|
||||
val delegateClass =
|
||||
ResolveSessionUtils.getClassDescriptorsByFqName(module, FqName("kotlin.properties.$delegateClassName")).firstOrNull()
|
||||
?: return array(builtIns.getAnyType())
|
||||
val receiverType = (property.getExtensionReceiverParameter() ?: property.getDispatchReceiverParameter())?.getType()
|
||||
?: builtIns.getNullableNothingType()
|
||||
val typeArguments = listOf(TypeProjectionImpl(receiverType), TypeProjectionImpl(property.getType()))
|
||||
array(TypeUtils.substituteProjectionsForParameters(delegateClass, typeArguments))
|
||||
}
|
||||
else -> array() // can't infer anything
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ object CreateIteratorFunctionActionFactory : JetSingleIntentionActionFactory() {
|
||||
val returnJetType = KotlinBuiltIns.getInstance().getIterator().getDefaultType()
|
||||
|
||||
val context = file.getBindingContext()
|
||||
val returnJetTypeParameterTypes = variableExpr.guessTypes(context)
|
||||
val returnJetTypeParameterTypes = variableExpr.guessTypes(context, null)
|
||||
if (returnJetTypeParameterTypes.size != 1) return null
|
||||
|
||||
val returnJetTypeParameterType = TypeProjectionImpl(returnJetTypeParameterTypes[0])
|
||||
|
||||
+4
-2
@@ -40,6 +40,7 @@ import org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils
|
||||
import org.jetbrains.jet.lang.psi.JetNamedFunction
|
||||
import org.jetbrains.jet.lang.psi.psiUtil.getAssignmentByLHS
|
||||
import org.jetbrains.jet.plugin.quickfix.createFromUsage.callableBuilder.getExpressionForTypeGuess
|
||||
import org.jetbrains.jet.plugin.caches.resolve.getAnalysisResults
|
||||
|
||||
object CreateParameterActionFactory: JetSingleIntentionActionFactory() {
|
||||
private fun JetType.hasTypeParametersToAdd(functionDescriptor: FunctionDescriptor, context: BindingContext): Boolean {
|
||||
@@ -65,14 +66,15 @@ object CreateParameterActionFactory: JetSingleIntentionActionFactory() {
|
||||
}
|
||||
|
||||
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
|
||||
val context = (diagnostic.getPsiFile() as? JetFile)?.getBindingContext() ?: return null
|
||||
val exhaust = (diagnostic.getPsiFile() as? JetFile)?.getAnalysisResults() ?: return null
|
||||
val context = exhaust.getBindingContext()
|
||||
|
||||
val refExpr = QuickFixUtil.getParentElementOfType(diagnostic, javaClass<JetSimpleNameExpression>()) ?: return null
|
||||
if (refExpr.getQualifiedElement() != refExpr) return null
|
||||
|
||||
val varExpected = refExpr.getAssignmentByLHS() != null
|
||||
|
||||
val paramType = refExpr.getExpressionForTypeGuess().guessTypes(context).let {
|
||||
val paramType = refExpr.getExpressionForTypeGuess().guessTypes(context, exhaust.getModuleDescriptor()).let {
|
||||
when (it.size) {
|
||||
0 -> KotlinBuiltIns.getInstance().getAnyType()
|
||||
1 -> it.first()
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// "Create function 'foo' from usage" "true"
|
||||
|
||||
import kotlin.properties.ReadOnlyProperty
|
||||
|
||||
class A<T>(val t: T) {
|
||||
val x: A<Int> by foo(t, "")
|
||||
|
||||
fun <T> foo(t: T, s: String): ReadOnlyProperty<A<T>, A<Int>> {
|
||||
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// "Create function 'foo' from usage" "true"
|
||||
|
||||
import kotlin.properties.ReadWriteProperty
|
||||
|
||||
class A<T>(val t: T) {
|
||||
var x: A<Int> by foo(t, "")
|
||||
|
||||
fun <T> foo(t: T, s: String): ReadWriteProperty<A<T>, A<Int>> {
|
||||
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// "Create function 'foo' from usage" "true"
|
||||
|
||||
class A<T>(val t: T) {
|
||||
val x: A<Int> by <caret>foo(t, "")
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// "Create function 'foo' from usage" "true"
|
||||
|
||||
class A<T>(val t: T) {
|
||||
var x: A<Int> by <caret>foo(t, "")
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// "Create property 'foo' from usage" "true"
|
||||
// ERROR: Property must be initialized or be abstract
|
||||
// ERROR: Variable 'foo' must be initialized
|
||||
|
||||
import kotlin.properties.ReadOnlyProperty
|
||||
|
||||
class A<T> {
|
||||
val <T> foo: ReadOnlyProperty<A<T>, A<Int>>
|
||||
|
||||
val x: A<Int> by foo
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// "Create property 'foo' from usage" "true"
|
||||
// ERROR: Property must be initialized or be abstract
|
||||
// ERROR: Variable 'foo' must be initialized
|
||||
|
||||
import kotlin.properties.ReadWriteProperty
|
||||
|
||||
class A<T> {
|
||||
val <T> foo: ReadWriteProperty<A<T>, A<Int>>
|
||||
|
||||
var x: A<Int> by foo
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// "Create property 'foo' from usage" "true"
|
||||
// ERROR: Property must be initialized or be abstract
|
||||
// ERROR: Variable 'foo' must be initialized
|
||||
|
||||
class A<T> {
|
||||
val x: A<Int> by <caret>foo
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// "Create property 'foo' from usage" "true"
|
||||
// ERROR: Property must be initialized or be abstract
|
||||
// ERROR: Variable 'foo' must be initialized
|
||||
|
||||
class A<T> {
|
||||
var x: A<Int> by <caret>foo
|
||||
}
|
||||
@@ -844,6 +844,18 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("beforeMemberValDelegateRuntime.kt")
|
||||
public void testMemberValDelegateRuntime() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createFunction/call/beforeMemberValDelegateRuntime.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("beforeMemberVarDelegateRuntime.kt")
|
||||
public void testMemberVarDelegateRuntime() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createFunction/call/beforeMemberVarDelegateRuntime.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("beforeObjectMemberFunNoReceiver.kt")
|
||||
public void testObjectMemberFunNoReceiver() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createFunction/call/beforeObjectMemberFunNoReceiver.kt");
|
||||
@@ -1541,12 +1553,24 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("beforeMemberValDelegateRuntime.kt")
|
||||
public void testMemberValDelegateRuntime() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createVariable/property/beforeMemberValDelegateRuntime.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("beforeMemberValNoReceiver.kt")
|
||||
public void testMemberValNoReceiver() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createVariable/property/beforeMemberValNoReceiver.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("beforeMemberVarDelegateRuntime.kt")
|
||||
public void testMemberVarDelegateRuntime() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createVariable/property/beforeMemberVarDelegateRuntime.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("beforeObjectMemberValNoReceiver.kt")
|
||||
public void testObjectMemberValNoReceiver() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createVariable/property/beforeObjectMemberValNoReceiver.kt");
|
||||
|
||||
Reference in New Issue
Block a user