[FE 1.0] Clean-up pseudocodeUtils.kt: remove unused methods, move test specific methods into test-common module
This commit is contained in:
committed by
teamcity
parent
6e191147b9
commit
5f5c3aa534
@@ -21,7 +21,6 @@ import org.jetbrains.kotlin.cfg.Label
|
|||||||
import org.jetbrains.kotlin.cfg.containingDeclarationForPseudocode
|
import org.jetbrains.kotlin.cfg.containingDeclarationForPseudocode
|
||||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.Instruction
|
import org.jetbrains.kotlin.cfg.pseudocode.instructions.Instruction
|
||||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.*
|
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.*
|
||||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.MagicKind.*
|
|
||||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.ConditionalJumpInstruction
|
import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.ConditionalJumpInstruction
|
||||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.ReturnValueInstruction
|
import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.ReturnValueInstruction
|
||||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.ThrowExceptionInstruction
|
import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.ThrowExceptionInstruction
|
||||||
@@ -31,26 +30,18 @@ import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
|||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.parents
|
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext.*
|
|
||||||
import org.jetbrains.kotlin.resolve.DelegatingBindingTrace
|
|
||||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.getReferenceTargets
|
|
||||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.getTargetFunctionDescriptor
|
import org.jetbrains.kotlin.resolve.bindingContextUtil.getTargetFunctionDescriptor
|
||||||
import org.jetbrains.kotlin.resolve.calls.ValueArgumentsToParametersMapper
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.util.getCall
|
import org.jetbrains.kotlin.resolve.calls.model.VarargValueArgument
|
||||||
import org.jetbrains.kotlin.resolve.calls.util.isSafeCall
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.util.getExplicitReceiverValue
|
import org.jetbrains.kotlin.resolve.calls.util.getExplicitReceiverValue
|
||||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
import org.jetbrains.kotlin.resolve.calls.util.isSafeCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.OldResolutionCandidate
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy
|
|
||||||
import org.jetbrains.kotlin.resolve.findTopMostOverriddenDescriptors
|
import org.jetbrains.kotlin.resolve.findTopMostOverriddenDescriptors
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.types.TypeUtils
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
import java.util.*
|
import java.util.ArrayList
|
||||||
|
import java.util.LinkedHashSet
|
||||||
|
|
||||||
fun getReceiverTypePredicate(resolvedCall: ResolvedCall<*>, receiverValue: ReceiverValue): TypePredicate? {
|
fun getReceiverTypePredicate(resolvedCall: ResolvedCall<*>, receiverValue: ReceiverValue): TypePredicate? {
|
||||||
val callableDescriptor = resolvedCall.resultingDescriptor ?: return null
|
val callableDescriptor = resolvedCall.resultingDescriptor ?: return null
|
||||||
@@ -87,60 +78,6 @@ fun getExpectedTypePredicate(
|
|||||||
if (receiverValue != null) typePredicates.add(getReceiverTypePredicate(resolvedCall, receiverValue))
|
if (receiverValue != null) typePredicates.add(getReceiverTypePredicate(resolvedCall, receiverValue))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getTypePredicateForUnresolvedCallArgument(to: KtElement, inputValueIndex: Int): TypePredicate? {
|
|
||||||
if (inputValueIndex < 0) return null
|
|
||||||
val call = to.getCall(bindingContext) ?: return null
|
|
||||||
val callee = call.calleeExpression ?: return null
|
|
||||||
|
|
||||||
val candidates = callee.getReferenceTargets(bindingContext)
|
|
||||||
.filterIsInstance<FunctionDescriptor>()
|
|
||||||
.sortedBy { DescriptorRenderer.FQ_NAMES_IN_TYPES.render(it) }
|
|
||||||
if (candidates.isEmpty()) return null
|
|
||||||
|
|
||||||
val explicitReceiver = call.explicitReceiver
|
|
||||||
val argValueOffset = if (explicitReceiver != null) 1 else 0
|
|
||||||
|
|
||||||
val predicates = ArrayList<TypePredicate>()
|
|
||||||
|
|
||||||
for (candidate in candidates) {
|
|
||||||
val resolutionCandidate = OldResolutionCandidate.create(
|
|
||||||
call,
|
|
||||||
candidate,
|
|
||||||
null,
|
|
||||||
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER,
|
|
||||||
null
|
|
||||||
)
|
|
||||||
val candidateCall = ResolvedCallImpl.create(
|
|
||||||
resolutionCandidate,
|
|
||||||
DelegatingBindingTrace(bindingContext, "Compute type predicates for unresolved call arguments"),
|
|
||||||
TracingStrategy.EMPTY,
|
|
||||||
DataFlowInfoForArgumentsImpl(DataFlowInfo.EMPTY, call)
|
|
||||||
)
|
|
||||||
val status = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters(
|
|
||||||
call, TracingStrategy.EMPTY, candidateCall, LanguageVersionSettingsImpl.DEFAULT
|
|
||||||
)
|
|
||||||
if (!status.isSuccess) continue
|
|
||||||
|
|
||||||
val candidateArgumentMap = candidateCall.valueArguments
|
|
||||||
val callArguments = call.valueArguments
|
|
||||||
val i = inputValueIndex - argValueOffset
|
|
||||||
if (i < 0 || i >= callArguments.size) continue
|
|
||||||
|
|
||||||
val mapping = candidateCall.getArgumentMapping(callArguments[i]) as? ArgumentMatch ?: continue
|
|
||||||
|
|
||||||
val candidateParameter = mapping.valueParameter
|
|
||||||
val resolvedArgument = candidateArgumentMap[candidateParameter]
|
|
||||||
val expectedType = if (resolvedArgument is VarargValueArgument)
|
|
||||||
candidateParameter.varargElementType
|
|
||||||
else
|
|
||||||
candidateParameter.type
|
|
||||||
|
|
||||||
predicates.add(if (expectedType != null) AllSubtypes(expectedType) else AllTypes)
|
|
||||||
}
|
|
||||||
|
|
||||||
return or(predicates)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun addTypePredicates(value: PseudoValue) {
|
fun addTypePredicates(value: PseudoValue) {
|
||||||
pseudocode.getUsages(value).forEach {
|
pseudocode.getUsages(value).forEach {
|
||||||
when (it) {
|
when (it) {
|
||||||
@@ -148,7 +85,7 @@ fun getExpectedTypePredicate(
|
|||||||
val returnElement = it.element
|
val returnElement = it.element
|
||||||
val functionDescriptor = when (returnElement) {
|
val functionDescriptor = when (returnElement) {
|
||||||
is KtReturnExpression -> returnElement.getTargetFunctionDescriptor(bindingContext)
|
is KtReturnExpression -> returnElement.getTargetFunctionDescriptor(bindingContext)
|
||||||
else -> bindingContext[DECLARATION_TO_DESCRIPTOR, pseudocode.correspondingElement]
|
else -> bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, pseudocode.correspondingElement]
|
||||||
}
|
}
|
||||||
addSubtypesOf((functionDescriptor as? CallableDescriptor)?.returnType)
|
addSubtypesOf((functionDescriptor as? CallableDescriptor)?.returnType)
|
||||||
}
|
}
|
||||||
@@ -198,30 +135,25 @@ fun getExpectedTypePredicate(
|
|||||||
}
|
}
|
||||||
|
|
||||||
is MagicInstruction -> when (it.kind) {
|
is MagicInstruction -> when (it.kind) {
|
||||||
AND, OR ->
|
MagicKind.AND, MagicKind.OR ->
|
||||||
addSubtypesOf(builtIns.booleanType)
|
addSubtypesOf(builtIns.booleanType)
|
||||||
|
|
||||||
LOOP_RANGE_ITERATION ->
|
MagicKind.LOOP_RANGE_ITERATION ->
|
||||||
addByExplicitReceiver(bindingContext[LOOP_RANGE_ITERATOR_RESOLVED_CALL, value.element as? KtExpression])
|
addByExplicitReceiver(bindingContext[BindingContext.LOOP_RANGE_ITERATOR_RESOLVED_CALL, value.element as? KtExpression])
|
||||||
|
|
||||||
VALUE_CONSUMER -> {
|
MagicKind.VALUE_CONSUMER -> {
|
||||||
val element = it.element
|
val element = it.element
|
||||||
when (element) {
|
when (element) {
|
||||||
element.getStrictParentOfType<KtWhileExpression>()?.condition -> addSubtypesOf(builtIns.booleanType)
|
element.getStrictParentOfType<KtWhileExpression>()?.condition -> addSubtypesOf(builtIns.booleanType)
|
||||||
is KtProperty -> {
|
is KtProperty -> {
|
||||||
val propertyDescriptor = bindingContext[DECLARATION_TO_DESCRIPTOR, element] as? PropertyDescriptor
|
val propertyDescriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, element] as? PropertyDescriptor
|
||||||
propertyDescriptor?.accessors?.map {
|
propertyDescriptor?.accessors?.map {
|
||||||
addByExplicitReceiver(bindingContext[DELEGATED_PROPERTY_RESOLVED_CALL, it])
|
addByExplicitReceiver(bindingContext[BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, it])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is KtDelegatedSuperTypeEntry -> addSubtypesOf(bindingContext[TYPE, element.typeReference])
|
is KtDelegatedSuperTypeEntry -> addSubtypesOf(bindingContext[BindingContext.TYPE, element.typeReference])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UNRESOLVED_CALL -> {
|
|
||||||
val typePredicate = getTypePredicateForUnresolvedCallArgument(it.element, it.inputValues.indexOf(value))
|
|
||||||
typePredicates.add(typePredicate)
|
|
||||||
}
|
|
||||||
else -> {}
|
else -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import org.jetbrains.kotlin.builtins.DefaultBuiltIns
|
|||||||
import org.jetbrains.kotlin.cfg.pseudocode.PseudoValue
|
import org.jetbrains.kotlin.cfg.pseudocode.PseudoValue
|
||||||
import org.jetbrains.kotlin.cfg.pseudocode.PseudocodeImpl
|
import org.jetbrains.kotlin.cfg.pseudocode.PseudocodeImpl
|
||||||
import org.jetbrains.kotlin.cfg.pseudocode.TypePredicate
|
import org.jetbrains.kotlin.cfg.pseudocode.TypePredicate
|
||||||
import org.jetbrains.kotlin.cfg.pseudocode.getExpectedTypePredicate
|
|
||||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.InstructionWithValue
|
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.InstructionWithValue
|
||||||
import org.jetbrains.kotlin.psi.KtElement
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
import org.jetbrains.kotlin.psi.KtTreeVisitorVoid
|
import org.jetbrains.kotlin.psi.KtTreeVisitorVoid
|
||||||
|
|||||||
@@ -0,0 +1,260 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 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.cfg
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
|
import org.jetbrains.kotlin.cfg.pseudocode.*
|
||||||
|
import org.jetbrains.kotlin.cfg.pseudocode.instructions.Instruction
|
||||||
|
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.*
|
||||||
|
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.MagicKind.*
|
||||||
|
import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.ConditionalJumpInstruction
|
||||||
|
import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.ReturnValueInstruction
|
||||||
|
import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.ThrowExceptionInstruction
|
||||||
|
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
|
||||||
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
||||||
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||||
|
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||||
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
|
import org.jetbrains.kotlin.resolve.BindingContext.*
|
||||||
|
import org.jetbrains.kotlin.resolve.DelegatingBindingTrace
|
||||||
|
import org.jetbrains.kotlin.resolve.bindingContextUtil.getReferenceTargets
|
||||||
|
import org.jetbrains.kotlin.resolve.bindingContextUtil.getTargetFunctionDescriptor
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.ValueArgumentsToParametersMapper
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.util.getCall
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.util.isSafeCall
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.util.getExplicitReceiverValue
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.tasks.OldResolutionCandidate
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy
|
||||||
|
import org.jetbrains.kotlin.resolve.findTopMostOverriddenDescriptors
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
fun getReceiverTypePredicate(resolvedCall: ResolvedCall<*>, receiverValue: ReceiverValue): TypePredicate? {
|
||||||
|
val callableDescriptor = resolvedCall.resultingDescriptor ?: return null
|
||||||
|
|
||||||
|
when (receiverValue) {
|
||||||
|
resolvedCall.extensionReceiver -> {
|
||||||
|
val receiverParameter = callableDescriptor.extensionReceiverParameter
|
||||||
|
if (receiverParameter != null) return receiverParameter.type.getSubtypesPredicate()
|
||||||
|
}
|
||||||
|
resolvedCall.dispatchReceiver -> {
|
||||||
|
val rootCallableDescriptors = callableDescriptor.findTopMostOverriddenDescriptors()
|
||||||
|
return or(rootCallableDescriptors.mapNotNull {
|
||||||
|
it.dispatchReceiverParameter?.type?.let { TypeUtils.makeNullableIfNeeded(it, resolvedCall.call.isSafeCall()) }
|
||||||
|
?.getSubtypesPredicate()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getExpectedTypePredicate(
|
||||||
|
value: PseudoValue,
|
||||||
|
bindingContext: BindingContext,
|
||||||
|
builtIns: KotlinBuiltIns
|
||||||
|
): TypePredicate {
|
||||||
|
val pseudocode = value.createdAt?.owner ?: return AllTypes
|
||||||
|
val typePredicates = LinkedHashSet<TypePredicate?>()
|
||||||
|
|
||||||
|
fun addSubtypesOf(jetType: KotlinType?) = typePredicates.add(jetType?.getSubtypesPredicate())
|
||||||
|
|
||||||
|
fun addByExplicitReceiver(resolvedCall: ResolvedCall<*>?) {
|
||||||
|
val receiverValue = (resolvedCall ?: return).getExplicitReceiverValue()
|
||||||
|
if (receiverValue != null) typePredicates.add(getReceiverTypePredicate(resolvedCall, receiverValue))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getTypePredicateForUnresolvedCallArgument(to: KtElement, inputValueIndex: Int): TypePredicate? {
|
||||||
|
if (inputValueIndex < 0) return null
|
||||||
|
val call = to.getCall(bindingContext) ?: return null
|
||||||
|
val callee = call.calleeExpression ?: return null
|
||||||
|
|
||||||
|
val candidates = callee.getReferenceTargets(bindingContext)
|
||||||
|
.filterIsInstance<FunctionDescriptor>()
|
||||||
|
.sortedBy { DescriptorRenderer.FQ_NAMES_IN_TYPES.render(it) }
|
||||||
|
if (candidates.isEmpty()) return null
|
||||||
|
|
||||||
|
val explicitReceiver = call.explicitReceiver
|
||||||
|
val argValueOffset = if (explicitReceiver != null) 1 else 0
|
||||||
|
|
||||||
|
val predicates = ArrayList<TypePredicate>()
|
||||||
|
|
||||||
|
for (candidate in candidates) {
|
||||||
|
val resolutionCandidate = OldResolutionCandidate.create(
|
||||||
|
call,
|
||||||
|
candidate,
|
||||||
|
null,
|
||||||
|
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER,
|
||||||
|
null
|
||||||
|
)
|
||||||
|
val candidateCall = ResolvedCallImpl.create(
|
||||||
|
resolutionCandidate,
|
||||||
|
DelegatingBindingTrace(bindingContext, "Compute type predicates for unresolved call arguments"),
|
||||||
|
TracingStrategy.EMPTY,
|
||||||
|
DataFlowInfoForArgumentsImpl(DataFlowInfo.EMPTY, call)
|
||||||
|
)
|
||||||
|
val status = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters(
|
||||||
|
call, TracingStrategy.EMPTY, candidateCall, LanguageVersionSettingsImpl.DEFAULT
|
||||||
|
)
|
||||||
|
if (!status.isSuccess) continue
|
||||||
|
|
||||||
|
val candidateArgumentMap = candidateCall.valueArguments
|
||||||
|
val callArguments = call.valueArguments
|
||||||
|
val i = inputValueIndex - argValueOffset
|
||||||
|
if (i < 0 || i >= callArguments.size) continue
|
||||||
|
|
||||||
|
val mapping = candidateCall.getArgumentMapping(callArguments[i]) as? ArgumentMatch ?: continue
|
||||||
|
|
||||||
|
val candidateParameter = mapping.valueParameter
|
||||||
|
val resolvedArgument = candidateArgumentMap[candidateParameter]
|
||||||
|
val expectedType = if (resolvedArgument is VarargValueArgument)
|
||||||
|
candidateParameter.varargElementType
|
||||||
|
else
|
||||||
|
candidateParameter.type
|
||||||
|
|
||||||
|
predicates.add(if (expectedType != null) AllSubtypes(expectedType) else AllTypes)
|
||||||
|
}
|
||||||
|
|
||||||
|
return or(predicates)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addTypePredicates(value: PseudoValue) {
|
||||||
|
pseudocode.getUsages(value).forEach {
|
||||||
|
when (it) {
|
||||||
|
is ReturnValueInstruction -> {
|
||||||
|
val returnElement = it.element
|
||||||
|
val functionDescriptor = when (returnElement) {
|
||||||
|
is KtReturnExpression -> returnElement.getTargetFunctionDescriptor(bindingContext)
|
||||||
|
else -> bindingContext[DECLARATION_TO_DESCRIPTOR, pseudocode.correspondingElement]
|
||||||
|
}
|
||||||
|
addSubtypesOf((functionDescriptor as? CallableDescriptor)?.returnType)
|
||||||
|
}
|
||||||
|
|
||||||
|
is ConditionalJumpInstruction ->
|
||||||
|
addSubtypesOf(builtIns.booleanType)
|
||||||
|
|
||||||
|
is ThrowExceptionInstruction ->
|
||||||
|
addSubtypesOf(builtIns.throwable.defaultType)
|
||||||
|
|
||||||
|
is MergeInstruction ->
|
||||||
|
addTypePredicates(it.outputValue)
|
||||||
|
|
||||||
|
is AccessValueInstruction -> {
|
||||||
|
val accessTarget = it.target
|
||||||
|
val receiverValue = it.receiverValues[value]
|
||||||
|
if (receiverValue != null) {
|
||||||
|
typePredicates.add(getReceiverTypePredicate((accessTarget as AccessTarget.Call).resolvedCall, receiverValue))
|
||||||
|
} else {
|
||||||
|
val expectedType = when (accessTarget) {
|
||||||
|
is AccessTarget.Call ->
|
||||||
|
(accessTarget.resolvedCall.resultingDescriptor as? VariableDescriptor)?.type
|
||||||
|
is AccessTarget.Declaration ->
|
||||||
|
accessTarget.descriptor.type
|
||||||
|
else ->
|
||||||
|
null
|
||||||
|
}
|
||||||
|
addSubtypesOf(expectedType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
is CallInstruction -> {
|
||||||
|
val receiverValue = it.receiverValues[value]
|
||||||
|
if (receiverValue != null) {
|
||||||
|
typePredicates.add(getReceiverTypePredicate(it.resolvedCall, receiverValue))
|
||||||
|
} else {
|
||||||
|
it.arguments[value]?.let { parameter ->
|
||||||
|
val expectedType = when (it.resolvedCall.valueArguments[parameter]) {
|
||||||
|
is VarargValueArgument ->
|
||||||
|
parameter.varargElementType
|
||||||
|
else ->
|
||||||
|
parameter.type
|
||||||
|
}
|
||||||
|
addSubtypesOf(expectedType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
is MagicInstruction -> when (it.kind) {
|
||||||
|
AND, OR ->
|
||||||
|
addSubtypesOf(builtIns.booleanType)
|
||||||
|
|
||||||
|
LOOP_RANGE_ITERATION ->
|
||||||
|
addByExplicitReceiver(bindingContext[LOOP_RANGE_ITERATOR_RESOLVED_CALL, value.element as? KtExpression])
|
||||||
|
|
||||||
|
VALUE_CONSUMER -> {
|
||||||
|
val element = it.element
|
||||||
|
when (element) {
|
||||||
|
element.getStrictParentOfType<KtWhileExpression>()?.condition -> addSubtypesOf(builtIns.booleanType)
|
||||||
|
is KtProperty -> {
|
||||||
|
val propertyDescriptor = bindingContext[DECLARATION_TO_DESCRIPTOR, element] as? PropertyDescriptor
|
||||||
|
propertyDescriptor?.accessors?.map {
|
||||||
|
addByExplicitReceiver(bindingContext[DELEGATED_PROPERTY_RESOLVED_CALL, it])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is KtDelegatedSuperTypeEntry -> addSubtypesOf(bindingContext[TYPE, element.typeReference])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UNRESOLVED_CALL -> {
|
||||||
|
val typePredicate = getTypePredicateForUnresolvedCallArgument(it.element, it.inputValues.indexOf(value))
|
||||||
|
typePredicates.add(typePredicate)
|
||||||
|
}
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addTypePredicates(value)
|
||||||
|
return and(typePredicates.filterNotNull())
|
||||||
|
}
|
||||||
|
|
||||||
|
val Instruction.sideEffectFree: Boolean
|
||||||
|
get() = owner.isSideEffectFree(this)
|
||||||
|
|
||||||
|
fun Instruction.calcSideEffectFree(): Boolean {
|
||||||
|
if (this !is InstructionWithValue) return false
|
||||||
|
if (!inputValues.all { it.createdAt?.sideEffectFree == true }) return false
|
||||||
|
|
||||||
|
return when (this) {
|
||||||
|
is ReadValueInstruction -> target.let {
|
||||||
|
when (it) {
|
||||||
|
is AccessTarget.Call -> when (it.resolvedCall.resultingDescriptor) {
|
||||||
|
is LocalVariableDescriptor, is ValueParameterDescriptor, is ReceiverParameterDescriptor -> true
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> when (element) {
|
||||||
|
is KtNamedFunction -> element.name == null
|
||||||
|
is KtConstantExpression, is KtLambdaExpression, is KtStringTemplateExpression -> true
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
is MagicInstruction -> kind.sideEffectFree
|
||||||
|
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user