Extract Function: Ignore internal smartcasts
#KT-8458 Fixed
This commit is contained in:
@@ -74,4 +74,13 @@ public fun ResolvedCall<*>.getExplicitReceiverValue(): ReceiverValue {
|
|||||||
ExplicitReceiverKind.EXTENSION_RECEIVER, ExplicitReceiverKind.BOTH_RECEIVERS -> getExtensionReceiver()
|
ExplicitReceiverKind.EXTENSION_RECEIVER, ExplicitReceiverKind.BOTH_RECEIVERS -> getExtensionReceiver()
|
||||||
else -> ReceiverValue.NO_RECEIVER
|
else -> ReceiverValue.NO_RECEIVER
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun ResolvedCall<*>.getImplicitReceiverValue(): ReceiverValue {
|
||||||
|
return when (getExplicitReceiverKind()) {
|
||||||
|
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER -> if (extensionReceiver.exists()) extensionReceiver else dispatchReceiver
|
||||||
|
ExplicitReceiverKind.DISPATCH_RECEIVER -> extensionReceiver
|
||||||
|
ExplicitReceiverKind.EXTENSION_RECEIVER -> dispatchReceiver
|
||||||
|
else -> ReceiverValue.NO_RECEIVER
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+26
-8
@@ -38,13 +38,13 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
|
|||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.getImplicitReceiverValue
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.isSynthesizedInvoke
|
import org.jetbrains.kotlin.resolve.calls.tasks.isSynthesizedInvoke
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver
|
||||||
import org.jetbrains.kotlin.types.JetType
|
import org.jetbrains.kotlin.types.JetType
|
||||||
import java.util.ArrayList
|
import java.util.*
|
||||||
import java.util.Collections
|
|
||||||
import java.util.HashMap
|
|
||||||
|
|
||||||
data class ExtractionOptions(
|
data class ExtractionOptions(
|
||||||
val inferUnitTypeForUnusedValues: Boolean = true,
|
val inferUnitTypeForUnusedValues: Boolean = true,
|
||||||
@@ -69,7 +69,8 @@ data class ResolvedReferenceInfo(
|
|||||||
val refExpr: JetSimpleNameExpression,
|
val refExpr: JetSimpleNameExpression,
|
||||||
val offsetInBody: Int,
|
val offsetInBody: Int,
|
||||||
val resolveResult: ResolveResult,
|
val resolveResult: ResolveResult,
|
||||||
val smartCast: JetType?
|
val smartCast: JetType?,
|
||||||
|
val possibleTypes: Set<JetType>
|
||||||
)
|
)
|
||||||
|
|
||||||
data class ExtractionData(
|
data class ExtractionData(
|
||||||
@@ -160,6 +161,19 @@ data class ExtractionData(
|
|||||||
else Collections.emptyMap<Int, ResolveResult>()
|
else Collections.emptyMap<Int, ResolveResult>()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getPossibleTypes(expression: JetExpression, resolvedCall: ResolvedCall<*>?, context: BindingContext): Set<JetType> {
|
||||||
|
val typeInfo = context[BindingContext.EXPRESSION_TYPE_INFO, expression] ?: return emptySet()
|
||||||
|
|
||||||
|
(resolvedCall?.getImplicitReceiverValue() as? ThisReceiver)?.let {
|
||||||
|
return typeInfo.dataFlowInfo.getPossibleTypes(DataFlowValueFactory.createDataFlowValue(it))
|
||||||
|
}
|
||||||
|
|
||||||
|
val type = resolvedCall?.resultingDescriptor?.returnType ?: return emptySet()
|
||||||
|
val containingDescriptor = context[BindingContext.LEXICAL_SCOPE, expression]?.ownerDescriptor ?: return emptySet()
|
||||||
|
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(expression, type, context, containingDescriptor)
|
||||||
|
return typeInfo.dataFlowInfo.getPossibleTypes(dataFlowValue)
|
||||||
|
}
|
||||||
|
|
||||||
fun getBrokenReferencesInfo(body: JetBlockExpression): List<ResolvedReferenceInfo> {
|
fun getBrokenReferencesInfo(body: JetBlockExpression): List<ResolvedReferenceInfo> {
|
||||||
val originalContext = bindingContext ?: return listOf()
|
val originalContext = bindingContext ?: return listOf()
|
||||||
|
|
||||||
@@ -174,11 +188,14 @@ data class ExtractionData(
|
|||||||
val originalResolveResult = refOffsetToDeclaration[offset] ?: continue
|
val originalResolveResult = refOffsetToDeclaration[offset] ?: continue
|
||||||
|
|
||||||
val smartCast: JetType?
|
val smartCast: JetType?
|
||||||
|
val possibleTypes: Set<JetType>
|
||||||
|
|
||||||
// Qualified property reference: a.b
|
// Qualified property reference: a.b
|
||||||
val qualifiedExpression = ref.getQualifiedExpressionForSelector()
|
val qualifiedExpression = ref.getQualifiedExpressionForSelector()
|
||||||
if (qualifiedExpression != null) {
|
if (qualifiedExpression != null) {
|
||||||
smartCast = originalContext[BindingContext.SMARTCAST, originalResolveResult.originalRefExpr.getParent() as JetExpression]
|
val smartCastTarget = originalResolveResult.originalRefExpr.getParent() as JetExpression
|
||||||
|
smartCast = originalContext[BindingContext.SMARTCAST, smartCastTarget]
|
||||||
|
possibleTypes = getPossibleTypes(smartCastTarget, originalResolveResult.resolvedCall, originalContext)
|
||||||
val receiverDescriptor =
|
val receiverDescriptor =
|
||||||
(originalResolveResult.resolvedCall?.getDispatchReceiver() as? ThisReceiver)?.getDeclarationDescriptor()
|
(originalResolveResult.resolvedCall?.getDispatchReceiver() as? ThisReceiver)?.getDeclarationDescriptor()
|
||||||
if (smartCast == null
|
if (smartCast == null
|
||||||
@@ -187,6 +204,7 @@ data class ExtractionData(
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
smartCast = originalContext[BindingContext.SMARTCAST, originalResolveResult.originalRefExpr]
|
smartCast = originalContext[BindingContext.SMARTCAST, originalResolveResult.originalRefExpr]
|
||||||
|
possibleTypes = getPossibleTypes(originalResolveResult.originalRefExpr, originalResolveResult.resolvedCall, originalContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
val parent = ref.getParent()
|
val parent = ref.getParent()
|
||||||
@@ -207,11 +225,11 @@ data class ExtractionData(
|
|||||||
val functionResolveResult = originalResolveResult.copy(resolvedCall = originalFunctionCall!!,
|
val functionResolveResult = originalResolveResult.copy(resolvedCall = originalFunctionCall!!,
|
||||||
descriptor = originalFunctionCall.getResultingDescriptor(),
|
descriptor = originalFunctionCall.getResultingDescriptor(),
|
||||||
declaration = synthesizedInvokeDeclaration)
|
declaration = synthesizedInvokeDeclaration)
|
||||||
referencesInfo.add(ResolvedReferenceInfo(ref, offset, variableResolveResult, smartCast))
|
referencesInfo.add(ResolvedReferenceInfo(ref, offset, variableResolveResult, smartCast, possibleTypes))
|
||||||
referencesInfo.add(ResolvedReferenceInfo(ref, offset, functionResolveResult, smartCast))
|
referencesInfo.add(ResolvedReferenceInfo(ref, offset, functionResolveResult, smartCast, possibleTypes))
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
referencesInfo.add(ResolvedReferenceInfo(ref, offset, originalResolveResult, smartCast))
|
referencesInfo.add(ResolvedReferenceInfo(ref, offset, originalResolveResult, smartCast, possibleTypes))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+56
-31
@@ -59,8 +59,8 @@ import org.jetbrains.kotlin.idea.references.mainReference
|
|||||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||||
import org.jetbrains.kotlin.idea.util.approximateWithResolvableType
|
import org.jetbrains.kotlin.idea.util.approximateWithResolvableType
|
||||||
import org.jetbrains.kotlin.idea.util.isResolvableInScope
|
import org.jetbrains.kotlin.idea.util.isResolvableInScope
|
||||||
import org.jetbrains.kotlin.lexer.JetToken
|
|
||||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||||
|
import org.jetbrains.kotlin.lexer.JetToken
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||||
@@ -68,6 +68,7 @@ import org.jetbrains.kotlin.resolve.BindingContext
|
|||||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsStatement
|
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsStatement
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.isSynthesizedInvoke
|
import org.jetbrains.kotlin.resolve.calls.tasks.isSynthesizedInvoke
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||||
@@ -498,18 +499,23 @@ private class MutableParameter(
|
|||||||
override val argumentText: String,
|
override val argumentText: String,
|
||||||
override val originalDescriptor: DeclarationDescriptor,
|
override val originalDescriptor: DeclarationDescriptor,
|
||||||
override val receiverCandidate: Boolean,
|
override val receiverCandidate: Boolean,
|
||||||
private val targetScope: LexicalScope?
|
private val targetScope: LexicalScope?,
|
||||||
|
private val originalType: JetType,
|
||||||
|
private val possibleTypes: Set<JetType>
|
||||||
): Parameter {
|
): Parameter {
|
||||||
// All modifications happen in the same thread
|
// All modifications happen in the same thread
|
||||||
private var writable: Boolean = true
|
private var writable: Boolean = true
|
||||||
private val defaultTypes = HashSet<JetType>()
|
private val defaultTypes = LinkedHashSet<JetType>()
|
||||||
private val typePredicates = HashSet<TypePredicate>()
|
private val typePredicates = HashSet<TypePredicate>()
|
||||||
|
|
||||||
var refCount: Int = 0
|
var refCount: Int = 0
|
||||||
|
|
||||||
fun addDefaultType(jetType: JetType) {
|
fun addDefaultType(jetType: JetType) {
|
||||||
assert(writable) { "Can't add type to non-writable parameter $currentName" }
|
assert(writable) { "Can't add type to non-writable parameter $currentName" }
|
||||||
defaultTypes.add(jetType)
|
|
||||||
|
if (jetType in possibleTypes) {
|
||||||
|
defaultTypes.add(jetType)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addTypePredicate(predicate: TypePredicate) {
|
fun addTypePredicate(predicate: TypePredicate) {
|
||||||
@@ -524,7 +530,10 @@ private class MutableParameter(
|
|||||||
|
|
||||||
private val defaultType: JetType by lazy {
|
private val defaultType: JetType by lazy {
|
||||||
writable = false
|
writable = false
|
||||||
TypeIntersector.intersectTypes(originalDescriptor.builtIns, JetTypeChecker.DEFAULT, defaultTypes)!!
|
if (defaultTypes.isNotEmpty()) {
|
||||||
|
TypeIntersector.intersectTypes(originalDescriptor.builtIns, JetTypeChecker.DEFAULT, defaultTypes)!!
|
||||||
|
}
|
||||||
|
else originalType
|
||||||
}
|
}
|
||||||
|
|
||||||
private val parameterTypeCandidates: List<JetType> by lazy {
|
private val parameterTypeCandidates: List<JetType> by lazy {
|
||||||
@@ -595,6 +604,44 @@ private fun ExtractionData.inferParametersInfo(
|
|||||||
|
|
||||||
val extractedDescriptorToParameter = HashMap<DeclarationDescriptor, MutableParameter>()
|
val extractedDescriptorToParameter = HashMap<DeclarationDescriptor, MutableParameter>()
|
||||||
|
|
||||||
|
fun suggestParameterType(
|
||||||
|
extractFunctionRef: Boolean,
|
||||||
|
originalDescriptor: DeclarationDescriptor,
|
||||||
|
parameterExpression: JetExpression?,
|
||||||
|
receiverToExtract: ReceiverValue,
|
||||||
|
resolvedCall: ResolvedCall<*>?,
|
||||||
|
useSmartCastsIfPossible: Boolean
|
||||||
|
): JetType {
|
||||||
|
return when {
|
||||||
|
extractFunctionRef -> {
|
||||||
|
originalDescriptor as FunctionDescriptor
|
||||||
|
KotlinBuiltIns.getInstance().getFunctionType(Annotations.EMPTY,
|
||||||
|
originalDescriptor.getExtensionReceiverParameter()?.getType(),
|
||||||
|
originalDescriptor.getValueParameters().map { it.getType() },
|
||||||
|
originalDescriptor.getReturnType() ?: DEFAULT_RETURN_TYPE)
|
||||||
|
}
|
||||||
|
parameterExpression != null ->
|
||||||
|
(if (useSmartCastsIfPossible) bindingContext[BindingContext.SMARTCAST, parameterExpression] else null)
|
||||||
|
?: bindingContext.getType(parameterExpression)
|
||||||
|
?: (parameterExpression as? JetReferenceExpression)?.let {
|
||||||
|
(bindingContext[BindingContext.REFERENCE_TARGET, it] as? CallableDescriptor)?.getReturnType()
|
||||||
|
}
|
||||||
|
?: if (receiverToExtract.exists()) receiverToExtract.getType() else null
|
||||||
|
receiverToExtract is ThisReceiver -> {
|
||||||
|
val calleeExpression = resolvedCall!!.getCall().getCalleeExpression()
|
||||||
|
val typeByDataFlowInfo = if (useSmartCastsIfPossible) {
|
||||||
|
bindingContext[BindingContext.EXPRESSION_TYPE_INFO, calleeExpression]?.dataFlowInfo?.let { dataFlowInfo ->
|
||||||
|
val possibleTypes = dataFlowInfo.getPossibleTypes(DataFlowValueFactory.createDataFlowValue(receiverToExtract))
|
||||||
|
if (possibleTypes.isNotEmpty()) CommonSupertypes.commonSupertype(possibleTypes) else null
|
||||||
|
}
|
||||||
|
} else null
|
||||||
|
typeByDataFlowInfo ?: receiverToExtract.getType()
|
||||||
|
}
|
||||||
|
receiverToExtract.exists() -> receiverToExtract.getType()
|
||||||
|
else -> null
|
||||||
|
} ?: DEFAULT_PARAMETER_TYPE
|
||||||
|
}
|
||||||
|
|
||||||
for (refInfo in getBrokenReferencesInfo(createTemporaryCodeBlock())) {
|
for (refInfo in getBrokenReferencesInfo(createTemporaryCodeBlock())) {
|
||||||
val (originalRef, originalDeclaration, originalDescriptor, resolvedCall) = refInfo.resolveResult
|
val (originalRef, originalDeclaration, originalDescriptor, resolvedCall) = refInfo.resolveResult
|
||||||
val ref = refInfo.refExpr
|
val ref = refInfo.refExpr
|
||||||
@@ -671,31 +718,7 @@ private fun ExtractionData.inferParametersInfo(
|
|||||||
else -> (originalRef.getParent() as? JetThisExpression) ?: originalRef
|
else -> (originalRef.getParent() as? JetThisExpression) ?: originalRef
|
||||||
}
|
}
|
||||||
|
|
||||||
val parameterType = when {
|
val parameterType = suggestParameterType(extractFunctionRef, originalDescriptor, parameterExpression, receiverToExtract, resolvedCall, true)
|
||||||
extractFunctionRef -> {
|
|
||||||
originalDescriptor as FunctionDescriptor
|
|
||||||
KotlinBuiltIns.getInstance().getFunctionType(Annotations.EMPTY,
|
|
||||||
originalDescriptor.getExtensionReceiverParameter()?.getType(),
|
|
||||||
originalDescriptor.getValueParameters().map { it.getType() },
|
|
||||||
originalDescriptor.getReturnType() ?: DEFAULT_RETURN_TYPE)
|
|
||||||
}
|
|
||||||
parameterExpression != null ->
|
|
||||||
bindingContext[BindingContext.SMARTCAST, parameterExpression]
|
|
||||||
?: bindingContext.getType(parameterExpression)
|
|
||||||
?: (parameterExpression as? JetReferenceExpression)?.let {
|
|
||||||
(bindingContext[BindingContext.REFERENCE_TARGET, it] as? CallableDescriptor)?.getReturnType()
|
|
||||||
}
|
|
||||||
?: if (receiverToExtract.exists()) receiverToExtract.getType() else null
|
|
||||||
receiverToExtract is ThisReceiver -> {
|
|
||||||
val calleeExpression = resolvedCall!!.getCall().getCalleeExpression()
|
|
||||||
bindingContext[BindingContext.EXPRESSION_TYPE_INFO, calleeExpression]?.dataFlowInfo?.let { dataFlowInfo ->
|
|
||||||
val possibleTypes = dataFlowInfo.getPossibleTypes(DataFlowValueFactory.createDataFlowValue(receiverToExtract))
|
|
||||||
if (possibleTypes.isNotEmpty()) CommonSupertypes.commonSupertype(possibleTypes) else null
|
|
||||||
} ?: receiverToExtract.getType()
|
|
||||||
}
|
|
||||||
receiverToExtract.exists() -> receiverToExtract.getType()
|
|
||||||
else -> null
|
|
||||||
} ?: DEFAULT_PARAMETER_TYPE
|
|
||||||
|
|
||||||
val parameter = extractedDescriptorToParameter.getOrPut(descriptorToExtract) {
|
val parameter = extractedDescriptorToParameter.getOrPut(descriptorToExtract) {
|
||||||
var argumentText =
|
var argumentText =
|
||||||
@@ -720,7 +743,9 @@ private fun ExtractionData.inferParametersInfo(
|
|||||||
argumentText = "$receiverTypeText::$argumentText"
|
argumentText = "$receiverTypeText::$argumentText"
|
||||||
}
|
}
|
||||||
|
|
||||||
MutableParameter(argumentText, descriptorToExtract, extractThis, targetScope)
|
val originalType = suggestParameterType(extractFunctionRef, originalDescriptor, parameterExpression, receiverToExtract, resolvedCall, false)
|
||||||
|
|
||||||
|
MutableParameter(argumentText, descriptorToExtract, extractThis, targetScope, originalType, refInfo.possibleTypes)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!extractThis) {
|
if (!extractThis) {
|
||||||
|
|||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
// SUGGESTED_NAMES: i, getX
|
||||||
|
// PARAM_TYPES: kotlin.Any
|
||||||
|
// PARAM_DESCRIPTOR: value-parameter val o: kotlin.Any defined in foo
|
||||||
|
|
||||||
|
open class A {
|
||||||
|
val a = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
interface T {
|
||||||
|
val t: Int
|
||||||
|
}
|
||||||
|
|
||||||
|
class B : A(), T {
|
||||||
|
override val t: Int = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo(o: Any) {
|
||||||
|
val x = <selection>when (o) {
|
||||||
|
is A -> {
|
||||||
|
if (o is T) o.a + o.t else o.a
|
||||||
|
}
|
||||||
|
else -> o.hashCode()
|
||||||
|
}</selection>
|
||||||
|
}
|
||||||
Vendored
+28
@@ -0,0 +1,28 @@
|
|||||||
|
// SUGGESTED_NAMES: i, getX
|
||||||
|
// PARAM_TYPES: kotlin.Any
|
||||||
|
// PARAM_DESCRIPTOR: value-parameter val o: kotlin.Any defined in foo
|
||||||
|
|
||||||
|
open class A {
|
||||||
|
val a = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
interface T {
|
||||||
|
val t: Int
|
||||||
|
}
|
||||||
|
|
||||||
|
class B : A(), T {
|
||||||
|
override val t: Int = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo(o: Any) {
|
||||||
|
val x = i(o)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun i(o: Any): Int {
|
||||||
|
return when (o) {
|
||||||
|
is A -> {
|
||||||
|
if (o is T) o.a + o.t else o.a
|
||||||
|
}
|
||||||
|
else -> o.hashCode()
|
||||||
|
}
|
||||||
|
}
|
||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
// PARAM_TYPES: A
|
||||||
|
// PARAM_DESCRIPTOR: value-parameter val o: kotlin.Any defined in foo
|
||||||
|
|
||||||
|
open class A {
|
||||||
|
val a = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
interface T {
|
||||||
|
val t: Int
|
||||||
|
}
|
||||||
|
|
||||||
|
class B : A(), T {
|
||||||
|
override val t: Int = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo(o: Any) {
|
||||||
|
val x = when (o) {
|
||||||
|
is A -> {
|
||||||
|
<selection>if (o is T) o.a + o.t else o.a</selection>
|
||||||
|
}
|
||||||
|
else -> o.hashCode()
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
+25
@@ -0,0 +1,25 @@
|
|||||||
|
// PARAM_TYPES: A
|
||||||
|
// PARAM_DESCRIPTOR: value-parameter val o: kotlin.Any defined in foo
|
||||||
|
|
||||||
|
open class A {
|
||||||
|
val a = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
interface T {
|
||||||
|
val t: Int
|
||||||
|
}
|
||||||
|
|
||||||
|
class B : A(), T {
|
||||||
|
override val t: Int = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo(o: Any) {
|
||||||
|
val x = when (o) {
|
||||||
|
is A -> {
|
||||||
|
i(o)
|
||||||
|
}
|
||||||
|
else -> o.hashCode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun i(o: A) = if (o is T) o.a + o.t else o.a
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
open class A {
|
||||||
|
val a = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
interface T {
|
||||||
|
val t: Int
|
||||||
|
}
|
||||||
|
|
||||||
|
class B : A(), T {
|
||||||
|
override val t: Int = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo(o: Any) {
|
||||||
|
val x = when (o) {
|
||||||
|
is A -> {
|
||||||
|
if (o is T) <selection>o.a + o.t</selection> else o.a
|
||||||
|
}
|
||||||
|
else -> o.hashCode()
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
Cannot extract method since following types are not denotable in the target scope: {A & T}
|
||||||
+18
@@ -1784,6 +1784,24 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest {
|
|||||||
doExtractFunctionTest(fileName);
|
doExtractFunctionTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("multipleTypes2.kt")
|
||||||
|
public void testMultipleTypes2() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/parameters/candidateTypes/multipleTypes2.kt");
|
||||||
|
doExtractFunctionTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("multipleTypes3.kt")
|
||||||
|
public void testMultipleTypes3() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/parameters/candidateTypes/multipleTypes3.kt");
|
||||||
|
doExtractFunctionTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("multipleTypes4.kt")
|
||||||
|
public void testMultipleTypes4() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/parameters/candidateTypes/multipleTypes4.kt");
|
||||||
|
doExtractFunctionTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("nonNullableTypes.kt")
|
@TestMetadata("nonNullableTypes.kt")
|
||||||
public void testNonNullableTypes() throws Exception {
|
public void testNonNullableTypes() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/parameters/candidateTypes/nonNullableTypes.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/parameters/candidateTypes/nonNullableTypes.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user