[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.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
|
||||
@@ -31,26 +30,18 @@ import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
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.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.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.VarargValueArgument
|
||||
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.calls.util.isSafeCall
|
||||
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.*
|
||||
import java.util.ArrayList
|
||||
import java.util.LinkedHashSet
|
||||
|
||||
fun getReceiverTypePredicate(resolvedCall: ResolvedCall<*>, receiverValue: ReceiverValue): TypePredicate? {
|
||||
val callableDescriptor = resolvedCall.resultingDescriptor ?: return null
|
||||
@@ -87,60 +78,6 @@ fun getExpectedTypePredicate(
|
||||
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) {
|
||||
@@ -148,7 +85,7 @@ fun getExpectedTypePredicate(
|
||||
val returnElement = it.element
|
||||
val functionDescriptor = when (returnElement) {
|
||||
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)
|
||||
}
|
||||
@@ -198,30 +135,25 @@ fun getExpectedTypePredicate(
|
||||
}
|
||||
|
||||
is MagicInstruction -> when (it.kind) {
|
||||
AND, OR ->
|
||||
MagicKind.AND, MagicKind.OR ->
|
||||
addSubtypesOf(builtIns.booleanType)
|
||||
|
||||
LOOP_RANGE_ITERATION ->
|
||||
addByExplicitReceiver(bindingContext[LOOP_RANGE_ITERATOR_RESOLVED_CALL, value.element as? KtExpression])
|
||||
MagicKind.LOOP_RANGE_ITERATION ->
|
||||
addByExplicitReceiver(bindingContext[BindingContext.LOOP_RANGE_ITERATOR_RESOLVED_CALL, value.element as? KtExpression])
|
||||
|
||||
VALUE_CONSUMER -> {
|
||||
MagicKind.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
|
||||
val propertyDescriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, element] as? PropertyDescriptor
|
||||
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 -> {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ import org.jetbrains.kotlin.builtins.DefaultBuiltIns
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.PseudoValue
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.PseudocodeImpl
|
||||
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.psi.KtElement
|
||||
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