Code cleanup: CFG (several inspections applied)

This commit is contained in:
Mikhail Glukhikh
2017-07-12 12:25:05 +03:00
committed by Mikhail Glukhikh
parent 43f9035d07
commit 9a5b5393f5
30 changed files with 160 additions and 339 deletions
@@ -33,63 +33,47 @@ abstract class ControlFlowBuilderAdapter : ControlFlowBuilder {
delegateBuilder.loadUnit(expression)
}
override fun loadConstant(expression: KtExpression, constant: CompileTimeConstant<*>?): InstructionWithValue {
return delegateBuilder.loadConstant(expression, constant)
}
override fun loadConstant(expression: KtExpression, constant: CompileTimeConstant<*>?): InstructionWithValue =
delegateBuilder.loadConstant(expression, constant)
override fun createAnonymousObject(expression: KtObjectLiteralExpression): InstructionWithValue {
return delegateBuilder.createAnonymousObject(expression)
}
override fun createAnonymousObject(expression: KtObjectLiteralExpression): InstructionWithValue =
delegateBuilder.createAnonymousObject(expression)
override fun createLambda(expression: KtFunction): InstructionWithValue {
return delegateBuilder.createLambda(expression)
}
override fun createLambda(expression: KtFunction): InstructionWithValue = delegateBuilder.createLambda(expression)
override fun loadStringTemplate(expression: KtStringTemplateExpression, inputValues: List<PseudoValue>): InstructionWithValue {
return delegateBuilder.loadStringTemplate(expression, inputValues)
}
override fun loadStringTemplate(expression: KtStringTemplateExpression, inputValues: List<PseudoValue>): InstructionWithValue =
delegateBuilder.loadStringTemplate(expression, inputValues)
override fun magic(
instructionElement: KtElement,
valueElement: KtElement?,
inputValues: List<PseudoValue>,
kind: MagicKind): MagicInstruction {
return delegateBuilder.magic(instructionElement, valueElement, inputValues, kind)
}
kind: MagicKind): MagicInstruction = delegateBuilder.magic(instructionElement, valueElement, inputValues, kind)
override fun merge(expression: KtExpression, inputValues: List<PseudoValue>): MergeInstruction {
return delegateBuilder.merge(expression, inputValues)
}
override fun merge(expression: KtExpression, inputValues: List<PseudoValue>): MergeInstruction =
delegateBuilder.merge(expression, inputValues)
override fun readVariable(
expression: KtExpression,
resolvedCall: ResolvedCall<*>,
receiverValues: Map<PseudoValue, ReceiverValue>): ReadValueInstruction {
return delegateBuilder.readVariable(expression, resolvedCall, receiverValues)
}
receiverValues: Map<PseudoValue, ReceiverValue>): ReadValueInstruction =
delegateBuilder.readVariable(expression, resolvedCall, receiverValues)
override fun call(
valueElement: KtElement,
resolvedCall: ResolvedCall<*>,
receiverValues: Map<PseudoValue, ReceiverValue>,
arguments: Map<PseudoValue, ValueParameterDescriptor>): CallInstruction {
return delegateBuilder.call(valueElement, resolvedCall, receiverValues, arguments)
}
arguments: Map<PseudoValue, ValueParameterDescriptor>): CallInstruction =
delegateBuilder.call(valueElement, resolvedCall, receiverValues, arguments)
override fun predefinedOperation(
expression: KtExpression,
operation: ControlFlowBuilder.PredefinedOperation,
inputValues: List<PseudoValue>): OperationInstruction {
return delegateBuilder.predefinedOperation(expression, operation, inputValues)
}
inputValues: List<PseudoValue>): OperationInstruction = delegateBuilder.predefinedOperation(expression, operation, inputValues)
override fun createUnboundLabel(): Label {
return delegateBuilder.createUnboundLabel()
}
override fun createUnboundLabel(): Label = delegateBuilder.createUnboundLabel()
override fun createUnboundLabel(name: String): Label {
return delegateBuilder.createUnboundLabel(name)
}
override fun createUnboundLabel(name: String): Label = delegateBuilder.createUnboundLabel(name)
override fun bindLabel(label: Label) {
delegateBuilder.bindLabel(label)
@@ -123,21 +107,13 @@ abstract class ControlFlowBuilderAdapter : ControlFlowBuilder {
delegateBuilder.throwException(throwExpression, thrownValue)
}
override fun getSubroutineExitPoint(labelElement: KtElement): Label? {
return delegateBuilder.getSubroutineExitPoint(labelElement)
}
override fun getSubroutineExitPoint(labelElement: KtElement): Label? = delegateBuilder.getSubroutineExitPoint(labelElement)
override fun getLoopConditionEntryPoint(loop: KtLoopExpression): Label? {
return delegateBuilder.getLoopConditionEntryPoint(loop)
}
override fun getLoopConditionEntryPoint(loop: KtLoopExpression): Label? = delegateBuilder.getLoopConditionEntryPoint(loop)
override fun getLoopExitPoint(loop: KtLoopExpression): Label? {
return delegateBuilder.getLoopExitPoint(loop)
}
override fun getLoopExitPoint(loop: KtLoopExpression): Label? = delegateBuilder.getLoopExitPoint(loop)
override fun enterLoop(expression: KtLoopExpression): LoopInfo {
return delegateBuilder.enterLoop(expression)
}
override fun enterLoop(expression: KtLoopExpression): LoopInfo = delegateBuilder.enterLoop(expression)
override fun enterLoopBody(expression: KtLoopExpression) {
delegateBuilder.enterLoopBody(expression)
@@ -162,9 +138,7 @@ abstract class ControlFlowBuilderAdapter : ControlFlowBuilder {
delegateBuilder.enterSubroutine(subroutine)
}
override fun exitSubroutine(subroutine: KtElement): Pseudocode {
return delegateBuilder.exitSubroutine(subroutine)
}
override fun exitSubroutine(subroutine: KtElement): Pseudocode = delegateBuilder.exitSubroutine(subroutine)
override val currentSubroutine: KtElement
get() = delegateBuilder.currentSubroutine
@@ -216,17 +190,13 @@ abstract class ControlFlowBuilderAdapter : ControlFlowBuilder {
delegateBuilder.mark(element)
}
override fun getBoundValue(element: KtElement?): PseudoValue? {
return delegateBuilder.getBoundValue(element)
}
override fun getBoundValue(element: KtElement?): PseudoValue? = delegateBuilder.getBoundValue(element)
override fun bindValue(value: PseudoValue, element: KtElement) {
delegateBuilder.bindValue(value, element)
}
override fun newValue(element: KtElement?): PseudoValue {
return delegateBuilder.newValue(element)
}
override fun newValue(element: KtElement?): PseudoValue = delegateBuilder.newValue(element)
override fun enterBlockScope(block: KtElement) {
delegateBuilder.enterBlockScope(block)
@@ -102,13 +102,9 @@ enum class InitState(private val s: String) {
class VariableControlFlowState private constructor(val initState: InitState, val isDeclared: Boolean) {
fun definitelyInitialized(): Boolean {
return initState == InitState.INITIALIZED
}
fun definitelyInitialized(): Boolean = initState == InitState.INITIALIZED
fun mayBeInitialized(): Boolean {
return initState != InitState.NOT_INITIALIZED
}
fun mayBeInitialized(): Boolean = initState != InitState.NOT_INITIALIZED
override fun toString(): String {
if (initState == InitState.NOT_INITIALIZED && !isDeclared) return "-"
@@ -134,17 +130,14 @@ class VariableControlFlowState private constructor(val initState: InitState, val
InitState.NOT_INITIALIZED -> if (isDeclared) VS_NT else VS_NF
}
fun createInitializedExhaustively(isDeclared: Boolean): VariableControlFlowState {
return create(InitState.INITIALIZED_EXHAUSTIVELY, isDeclared)
}
fun createInitializedExhaustively(isDeclared: Boolean): VariableControlFlowState =
create(InitState.INITIALIZED_EXHAUSTIVELY, isDeclared)
fun create(isInitialized: Boolean, isDeclared: Boolean = false): VariableControlFlowState {
return create(if (isInitialized) InitState.INITIALIZED else InitState.NOT_INITIALIZED, isDeclared)
}
fun create(isInitialized: Boolean, isDeclared: Boolean = false): VariableControlFlowState =
create(if (isInitialized) InitState.INITIALIZED else InitState.NOT_INITIALIZED, isDeclared)
fun create(isDeclaredHere: Boolean, mergedEdgesData: VariableControlFlowState?): VariableControlFlowState {
return create(true, isDeclaredHere || mergedEdgesData != null && mergedEdgesData.isDeclared)
}
fun create(isDeclaredHere: Boolean, mergedEdgesData: VariableControlFlowState?): VariableControlFlowState =
create(true, isDeclaredHere || mergedEdgesData != null && mergedEdgesData.isDeclared)
}
}
@@ -162,9 +155,7 @@ enum class VariableUseState(private val priority: Int) {
companion object {
@JvmStatic
fun isUsed(variableUseState: VariableUseState?): Boolean {
return variableUseState != null && variableUseState != UNUSED
}
fun isUsed(variableUseState: VariableUseState?): Boolean = variableUseState != null && variableUseState != UNUSED
}
}
@@ -59,7 +59,6 @@ import org.jetbrains.kotlin.types.TypeUtils.*
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils
import org.jetbrains.kotlin.types.isFlexible
import org.jetbrains.kotlin.util.OperatorNameConventions
import java.util.*
class ControlFlowInformationProvider private constructor(
private val subroutine: KtElement,
@@ -311,7 +310,7 @@ class ControlFlowInformationProvider private constructor(
}
private fun PropertyDescriptor.isDefinitelyInitialized(): Boolean {
if (trace.get(BACKING_FIELD_REQUIRED, this) ?: false) return false
if (trace.get(BACKING_FIELD_REQUIRED, this) == true) return false
val property = DescriptorToSourceUtils.descriptorToDeclaration(this)
if (property is KtProperty && property.hasDelegate()) return false
return true
@@ -432,14 +431,14 @@ class ControlFlowInformationProvider private constructor(
if (operationReference != null) {
val descriptor = trace.get(BindingContext.REFERENCE_TARGET, operationReference)
if (descriptor is FunctionDescriptor) {
if (descriptor.returnType?.let { KotlinBuiltIns.isUnit(it) } ?: false) {
if (descriptor.returnType?.let { KotlinBuiltIns.isUnit(it) } == true) {
hasReassignMethodReturningUnit = true
}
}
if (descriptor == null) {
val descriptors = trace.get(BindingContext.AMBIGUOUS_REFERENCE_TARGET, operationReference) ?: emptyList()
for (referenceDescriptor in descriptors) {
if ((referenceDescriptor as? FunctionDescriptor)?.returnType?.let { KotlinBuiltIns.isUnit(it) } ?: false) {
if ((referenceDescriptor as? FunctionDescriptor)?.returnType?.let { KotlinBuiltIns.isUnit(it) } == true) {
hasReassignMethodReturningUnit = true
}
}
@@ -476,10 +475,10 @@ class ControlFlowInformationProvider private constructor(
}
private fun checkAssignmentBeforeDeclaration(ctxt: VariableInitContext, expression: KtExpression) =
if (ctxt.enterInitState?.isDeclared ?: false
|| ctxt.exitInitState?.isDeclared ?: false
|| ctxt.enterInitState?.mayBeInitialized() ?: false
|| !(ctxt.exitInitState?.mayBeInitialized() ?: false)) {
if (ctxt.enterInitState?.isDeclared == true
|| ctxt.exitInitState?.isDeclared == true
|| ctxt.enterInitState?.mayBeInitialized() == true
|| ctxt.exitInitState?.mayBeInitialized() != true) {
false
}
else {
@@ -492,10 +491,10 @@ class ControlFlowInformationProvider private constructor(
private fun checkInitializationForCustomSetter(ctxt: VariableInitContext, expression: KtExpression): Boolean {
val variableDescriptor = ctxt.variableDescriptor
if (variableDescriptor !is PropertyDescriptor
|| ctxt.enterInitState?.mayBeInitialized() ?: false
|| !(ctxt.exitInitState?.mayBeInitialized() ?: false)
|| ctxt.enterInitState?.mayBeInitialized() == true
|| ctxt.exitInitState?.mayBeInitialized() != true
|| !variableDescriptor.isVar
|| !(trace.get(BindingContext.BACKING_FIELD_REQUIRED, variableDescriptor) ?: false)) {
|| trace.get(BindingContext.BACKING_FIELD_REQUIRED, variableDescriptor) != true) {
return false
}
@@ -528,7 +527,7 @@ class ControlFlowInformationProvider private constructor(
val declaredVariables = pseudocodeVariablesData.getDeclaredVariables(pseudocode, false)
for (variable in declaredVariables) {
if (variable is PropertyDescriptor) {
if (initializers.incoming.getOrNull(variable)?.definitelyInitialized() ?: false) continue
if (initializers.incoming.getOrNull(variable)?.definitelyInitialized() == true) continue
trace.record(BindingContext.IS_UNINITIALIZED, variable)
}
}
@@ -947,7 +946,7 @@ class ControlFlowInformationProvider private constructor(
val tailInstructionDetector = TailInstructionDetector(subroutine)
return traverseFollowingInstructions(
this,
HashSet<Instruction>(),
hashSetOf(),
TraversalOrder.FORWARD
) {
if (it == this@isTailCall || it.accept(tailInstructionDetector))
@@ -117,9 +117,8 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
private val conditionVisitor = object : KtVisitorVoid() {
private fun getSubjectExpression(condition: KtWhenCondition): KtExpression? {
return condition.getStrictParentOfType<KtWhenExpression>()?.subjectExpression
}
private fun getSubjectExpression(condition: KtWhenCondition): KtExpression? =
condition.getStrictParentOfType<KtWhenExpression>()?.subjectExpression
override fun visitWhenConditionInRange(condition: KtWhenConditionInRange) {
if (!generateCall(condition.operationReference)) {
@@ -181,17 +180,14 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
}
}
private fun createSyntheticValue(instructionElement: KtElement, kind: MagicKind, vararg from: KtElement): PseudoValue {
return builder.magic(instructionElement, null, elementsToValues(from.asList()), kind).outputValue
}
private fun createSyntheticValue(instructionElement: KtElement, kind: MagicKind, vararg from: KtElement): PseudoValue =
builder.magic(instructionElement, null, elementsToValues(from.asList()), kind).outputValue
private fun createNonSyntheticValue(to: KtElement, from: List<KtElement?>, kind: MagicKind): PseudoValue {
return builder.magic(to, to, elementsToValues(from), kind).outputValue
}
private fun createNonSyntheticValue(to: KtElement, from: List<KtElement?>, kind: MagicKind): PseudoValue =
builder.magic(to, to, elementsToValues(from), kind).outputValue
private fun createNonSyntheticValue(to: KtElement, kind: MagicKind, vararg from: KtElement?): PseudoValue {
return createNonSyntheticValue(to, from.asList(), kind)
}
private fun createNonSyntheticValue(to: KtElement, kind: MagicKind, vararg from: KtElement?): PseudoValue =
createNonSyntheticValue(to, from.asList(), kind)
private fun mergeValues(from: List<KtExpression>, to: KtExpression) {
builder.merge(to, elementsToValues(from))
@@ -208,18 +204,16 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
return if (value != null || element is KtDeclaration) value else builder.newValue(element)
}
private fun elementsToValues(from: List<KtElement?>): List<PseudoValue> {
return from.mapNotNull { element -> getBoundOrUnreachableValue(element) }
}
private fun elementsToValues(from: List<KtElement?>): List<PseudoValue> =
from.mapNotNull { element -> getBoundOrUnreachableValue(element) }
private fun generateInitializer(declaration: KtDeclaration, initValue: PseudoValue) {
builder.write(declaration, declaration, initValue, getDeclarationAccessTarget(declaration), emptyMap())
}
private fun getResolvedCallAccessTarget(element: KtElement?): AccessTarget {
return element.getResolvedCall(trace.bindingContext)?.let { AccessTarget.Call(it) }
?: AccessTarget.BlackBox
}
private fun getResolvedCallAccessTarget(element: KtElement?): AccessTarget =
element.getResolvedCall(trace.bindingContext)?.let { AccessTarget.Call(it) }
?: AccessTarget.BlackBox
private fun getDeclarationAccessTarget(element: KtElement): AccessTarget {
val descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element)
@@ -533,9 +527,8 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
}
}
private fun isIncrementOrDecrement(operationType: IElementType): Boolean {
return operationType === KtTokens.PLUSPLUS || operationType === KtTokens.MINUSMINUS
}
private fun isIncrementOrDecrement(operationType: IElementType): Boolean =
operationType === KtTokens.PLUSPLUS || operationType === KtTokens.MINUSMINUS
override fun visitIfExpression(expression: KtIfExpression) {
mark(expression)
@@ -668,7 +661,7 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
builder.bindLabel(onException)
val catchLabels = LinkedList<Label>()
val catchClausesSize = catchClauses.size
for (i in 0..catchClausesSize - 1 - 1) {
for (i in 0 until catchClausesSize - 1) {
catchLabels.add(builder.createUnboundLabel("catch " + i))
}
if (!catchLabels.isEmpty()) {
@@ -1148,7 +1141,7 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
entry,
resolvedCall,
getReceiverValues(resolvedCall),
emptyMap<PseudoValue, ValueParameterDescriptor>()).outputValue
emptyMap()).outputValue
}
else {
initializer?.let { createSyntheticValue(entry, MagicKind.UNRESOLVED_CALL, it) }
@@ -1273,7 +1266,7 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
// For the last entry of exhaustive when,
// attempt to jump further should lead to error, not to "done"
if (!iterator.hasNext() && WhenChecker.isWhenExhaustive(expression, trace)) {
builder.magic(expression, null, emptyList<PseudoValue>(), MagicKind.EXHAUSTIVE_WHEN_ELSE)
builder.magic(expression, null, emptyList(), MagicKind.EXHAUSTIVE_WHEN_ELSE)
}
}
}
@@ -48,7 +48,7 @@ fun <D> Pseudocode.traverse(
if (instruction is LocalFunctionDeclarationInstruction) {
instruction.body.traverse(traversalOrder, edgesMap, analyzeInstruction)
}
val edges = edgesMap.get(instruction)
val edges = edgesMap[instruction]
if (edges != null) {
analyzeInstruction(instruction, edges.incoming, edges.outgoing)
}
@@ -27,7 +27,6 @@ import org.jetbrains.kotlin.cfg.pseudocodeTraverser.traverse
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingContextUtils
import java.util.*
class PseudocodeVariableDataCollector(
private val bindingContext: BindingContext,
@@ -68,7 +67,7 @@ class PseudocodeVariableDataCollector(
} as I
}
fun computeBlockScopeVariableInfo(pseudocode: Pseudocode): BlockScopeVariableInfo {
private fun computeBlockScopeVariableInfo(pseudocode: Pseudocode): BlockScopeVariableInfo {
val blockScopeVariableInfo = BlockScopeVariableInfoImpl()
pseudocode.traverse(TraversalOrder.FORWARD, { instruction ->
if (instruction is VariableDeclarationInstruction) {
@@ -96,7 +95,7 @@ class BlockScopeVariableInfoImpl : BlockScopeVariableInfo {
fun registerVariableDeclaredInScope(variable: VariableDescriptor, blockScope: BlockScope) {
declaredIn[variable] = blockScope
val variablesInScope = scopeVariables.getOrPut(blockScope, { ArrayList<VariableDescriptor>() })
val variablesInScope = scopeVariables.getOrPut(blockScope, { arrayListOf() })
variablesInScope.add(variable)
}
}
@@ -38,7 +38,7 @@ class UnreachableCodeImpl(
) : UnreachableCode {
// This is needed in order to highlight only '1 < 2' and not '1', '<' and '2' as well
override val elements = KtPsiUtil.findRootExpressions(unreachableElements)
override val elements: Set<KtElement> = KtPsiUtil.findRootExpressions(unreachableElements)
override fun getUnreachableTextRanges(element: KtElement): List<TextRange> {
return if (element.hasChildrenInSet(reachableElements)) {
@@ -54,9 +54,8 @@ class UnreachableCodeImpl(
}
}
private fun KtElement.hasChildrenInSet(set: Set<KtElement>): Boolean {
return PsiTreeUtil.collectElements(this) { it != this }.any { it in set }
}
private fun KtElement.hasChildrenInSet(set: Set<KtElement>): Boolean =
PsiTreeUtil.collectElements(this) { it != this }.any { it in set }
private fun KtElement.getLeavesOrReachableChildren(): List<PsiElement> {
val children = ArrayList<PsiElement>()
@@ -74,7 +73,7 @@ class UnreachableCodeImpl(
return children
}
fun List<PsiElement>.removeReachableElementsWithMeaninglessSiblings(): List<PsiElement> {
private fun List<PsiElement>.removeReachableElementsWithMeaninglessSiblings(): List<PsiElement> {
fun PsiElement.isMeaningless() = this is PsiWhiteSpace
|| this.node?.elementType == KtTokens.COMMA
|| this is PsiComment
@@ -90,9 +90,9 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
private inner class ControlFlowInstructionsGeneratorWorker(scopingElement: KtElement, override val returnSubroutine: KtElement) : ControlFlowBuilder {
val pseudocode: PseudocodeImpl
private val error: Label
private val sink: Label
val pseudocode: PseudocodeImpl = PseudocodeImpl(scopingElement)
private val error: Label = pseudocode.createLabel("error", null)
private val sink: Label = pseudocode.createLabel("sink", null)
private val valueFactory = object : PseudoValueFactoryImpl() {
override fun newValue(element: KtElement?, instruction: InstructionWithValue?): PseudoValue {
@@ -104,23 +104,13 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
}
}
init {
this.pseudocode = PseudocodeImpl(scopingElement)
this.error = pseudocode.createLabel("error", null)
this.sink = pseudocode.createLabel("sink", null)
}
private fun add(instruction: Instruction) {
pseudocode.addInstruction(instruction)
}
override fun createUnboundLabel(): Label {
return pseudocode.createLabel("L" + labelCount++, null)
}
override fun createUnboundLabel(): Label = pseudocode.createLabel("L" + labelCount++, null)
override fun createUnboundLabel(name: String): Label {
return pseudocode.createLabel("L" + labelCount++, name)
}
override fun createUnboundLabel(name: String): Label = pseudocode.createLabel("L" + labelCount++, name)
override fun enterLoop(expression: KtLoopExpression): LoopInfo {
val info = LoopInfo(
@@ -166,19 +156,13 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
override val currentSubroutine: KtElement
get() = pseudocode.correspondingElement
override fun getLoopConditionEntryPoint(loop: KtLoopExpression): Label? {
return elementToLoopInfo[loop]?.conditionEntryPoint
}
override fun getLoopConditionEntryPoint(loop: KtLoopExpression): Label? = elementToLoopInfo[loop]?.conditionEntryPoint
override fun getLoopExitPoint(loop: KtLoopExpression): Label? {
// It's quite possible to have null here, see testBreakInsideLocal
return elementToLoopInfo[loop]?.exitPoint
}
override fun getLoopExitPoint(loop: KtLoopExpression): Label? =// It's quite possible to have null here, see testBreakInsideLocal
elementToLoopInfo[loop]?.exitPoint
override fun getSubroutineExitPoint(labelElement: KtElement): Label? {
// It's quite possible to have null here, e.g. for non-local returns (see KT-10823)
return elementToSubroutineInfo[labelElement]?.exitPoint
}
override fun getSubroutineExitPoint(labelElement: KtElement): Label? =// It's quite possible to have null here, e.g. for non-local returns (see KT-10823)
elementToSubroutineInfo[labelElement]?.exitPoint
private val currentScope: BlockScope
get() = blockScopes.peek()
@@ -233,17 +217,13 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
add(MarkInstruction(element, currentScope))
}
override fun getBoundValue(element: KtElement?): PseudoValue? {
return pseudocode.getElementValue(element)
}
override fun getBoundValue(element: KtElement?): PseudoValue? = pseudocode.getElementValue(element)
override fun bindValue(value: PseudoValue, element: KtElement) {
pseudocode.bindElementToValue(element, value)
}
override fun newValue(element: KtElement?): PseudoValue {
return valueFactory.newValue(element, null)
}
override fun newValue(element: KtElement?): PseudoValue = valueFactory.newValue(element, null)
override fun returnValue(returnExpression: KtExpression, returnValue: PseudoValue, subroutine: KtElement) {
val exitPoint = getSubroutineExitPoint(subroutine) ?: return
@@ -396,9 +376,7 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
override fun predefinedOperation(
expression: KtExpression,
operation: ControlFlowBuilder.PredefinedOperation,
inputValues: List<PseudoValue>): OperationInstruction {
return magic(expression, expression, inputValues, getMagicKind(operation))
}
inputValues: List<PseudoValue>): OperationInstruction = magic(expression, expression, inputValues, getMagicKind(operation))
private fun getMagicKind(operation: ControlFlowBuilder.PredefinedOperation) = when (operation) {
ControlFlowBuilder.PredefinedOperation.AND -> MagicKind.AND
@@ -417,7 +395,7 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
private fun read(
expression: KtExpression,
resolvedCall: ResolvedCall<*>? = null,
receiverValues: Map<PseudoValue, ReceiverValue> = emptyMap<PseudoValue, ReceiverValue>()
receiverValues: Map<PseudoValue, ReceiverValue> = emptyMap()
) = read(expression, if (resolvedCall != null) AccessTarget.Call(resolvedCall) else AccessTarget.BlackBox, receiverValues)
}
@@ -123,9 +123,7 @@ class PseudocodeImpl(override val correspondingElement: KtElement) : Pseudocode
get() = mutableInstructionList
//for tests only
fun getLabels(): List<PseudocodeLabel> {
return labels
}
fun getLabels(): List<PseudocodeLabel> = labels
fun addExitInstruction(exitInstruction: SubroutineExitInstruction) {
addInstruction(exitInstruction)
@@ -215,7 +213,7 @@ class PseudocodeImpl(override val correspondingElement: KtElement) : Pseudocode
if (usage is MergeInstruction) return
valueUsages.getOrPut(
value
) { arrayListOf<Instruction>() }.add(usage)
) { arrayListOf() }.add(usage)
}
fun postProcess() {
@@ -333,9 +331,7 @@ class PseudocodeImpl(override val correspondingElement: KtElement) : Pseudocode
}
}
private fun getJumpTarget(targetLabel: Label): Instruction {
return targetLabel.resolveToInstruction()
}
private fun getJumpTarget(targetLabel: Label): Instruction = targetLabel.resolveToInstruction()
private fun getNextPosition(currentPosition: Int): Instruction {
val targetPosition = currentPosition + 1
@@ -349,18 +345,15 @@ class PseudocodeImpl(override val correspondingElement: KtElement) : Pseudocode
return result
}
override fun instructionForElement(element: KtElement): KtElementInstruction? {
return representativeInstructions[element]
}
override fun instructionForElement(element: KtElement): KtElementInstruction? = representativeInstructions[element]
private fun repeatWhole(originalPseudocode: PseudocodeImpl) {
repeatInternal(originalPseudocode, null, null, 0)
parent = originalPseudocode.parent
}
fun repeatPart(startLabel: Label, finishLabel: Label, labelCount: Int): Int {
return repeatInternal(startLabel.pseudocode as PseudocodeImpl, startLabel, finishLabel, labelCount)
}
fun repeatPart(startLabel: Label, finishLabel: Label, labelCount: Int): Int =
repeatInternal(startLabel.pseudocode as PseudocodeImpl, startLabel, finishLabel, labelCount)
private fun repeatInternal(
originalPseudocode: PseudocodeImpl,
@@ -387,7 +380,7 @@ class PseudocodeImpl(override val correspondingElement: KtElement) : Pseudocode
for (label in originalToCopy.values) {
labels.add(label)
}
for (index in startIndex..finishIndex - 1) {
for (index in startIndex until finishIndex) {
val originalInstruction = originalPseudocode.mutableInstructionList[index]
repeatLabelsBindingForInstruction(originalInstruction, originalToCopy, originalLabelsForInstruction)
val copy = copyInstruction(originalInstruction, originalToCopy)
@@ -30,9 +30,7 @@ class PseudocodeLabel internal constructor(
override var targetInstructionIndex = -1
override fun toString(): String {
return if (comment == null) name else "$name [$comment]"
}
override fun toString(): String = if (comment == null) name else "$name [$comment]"
override fun resolveToInstruction(): Instruction {
val index = targetInstructionIndex
@@ -43,7 +41,6 @@ class PseudocodeLabel internal constructor(
return instructionList[index]
}
fun copy(newPseudocode: PseudocodeImpl, newLabelIndex: Int): PseudocodeLabel {
return PseudocodeLabel(newPseudocode, "L" + newLabelIndex, "copy of $name, $comment")
}
fun copy(newPseudocode: PseudocodeImpl, newLabelIndex: Int): PseudocodeLabel =
PseudocodeLabel(newPseudocode, "L" + newLabelIndex, "copy of $name, $comment")
}
@@ -71,12 +71,10 @@ fun or(predicates: Collection<TypePredicate>): TypePredicate? =
else -> ForSomeType(predicates.toList())
}
fun KotlinType.getSubtypesPredicate(): TypePredicate {
return when {
KotlinBuiltIns.isAnyOrNullableAny(this) && isMarkedNullable -> AllTypes
TypeUtils.canHaveSubtypes(KotlinTypeChecker.DEFAULT, this) -> AllSubtypes(this)
else -> SingleType(this)
}
fun KotlinType.getSubtypesPredicate(): TypePredicate = when {
KotlinBuiltIns.isAnyOrNullableAny(this) && isMarkedNullable -> AllTypes
TypeUtils.canHaveSubtypes(KotlinTypeChecker.DEFAULT, this) -> AllSubtypes(this)
else -> SingleType(this)
}
@@ -26,7 +26,7 @@ abstract class InstructionImpl(override val blockScope: BlockScope): Instruction
override var owner: Pseudocode
get() = _owner!!
set(value: Pseudocode) {
set(value) {
assert(_owner == null || _owner == value)
_owner = value
}
@@ -16,7 +16,6 @@
package org.jetbrains.kotlin.cfg.pseudocode.instructions
import org.jetbrains.kotlin.cfg.pseudocode.instructions.*
import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.*
import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.*
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.*
@@ -16,7 +16,6 @@
package org.jetbrains.kotlin.cfg.pseudocode.instructions
import org.jetbrains.kotlin.cfg.pseudocode.instructions.*
import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.*
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.*
import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.*
@@ -24,91 +23,48 @@ import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.*
abstract class InstructionVisitorWithResult<out R> {
abstract fun visitInstruction(instruction: Instruction): R
open fun visitAccessInstruction(instruction: AccessValueInstruction): R {
return visitInstructionWithNext(instruction)
}
open fun visitAccessInstruction(instruction: AccessValueInstruction): R = visitInstructionWithNext(instruction)
open fun visitReadValue(instruction: ReadValueInstruction): R {
return visitAccessInstruction(instruction)
}
open fun visitReadValue(instruction: ReadValueInstruction): R = visitAccessInstruction(instruction)
open fun visitLocalFunctionDeclarationInstruction(instruction: LocalFunctionDeclarationInstruction): R {
return visitInstructionWithNext(instruction)
}
open fun visitLocalFunctionDeclarationInstruction(instruction: LocalFunctionDeclarationInstruction): R =
visitInstructionWithNext(instruction)
open fun visitVariableDeclarationInstruction(instruction: VariableDeclarationInstruction): R {
return visitInstructionWithNext(instruction)
}
open fun visitVariableDeclarationInstruction(instruction: VariableDeclarationInstruction): R = visitInstructionWithNext(instruction)
open fun visitUnconditionalJump(instruction: UnconditionalJumpInstruction): R {
return visitJump(instruction)
}
open fun visitUnconditionalJump(instruction: UnconditionalJumpInstruction): R = visitJump(instruction)
open fun visitConditionalJump(instruction: ConditionalJumpInstruction): R {
return visitJump(instruction)
}
open fun visitConditionalJump(instruction: ConditionalJumpInstruction): R = visitJump(instruction)
open fun visitReturnValue(instruction: ReturnValueInstruction): R {
return visitJump(instruction)
}
open fun visitReturnValue(instruction: ReturnValueInstruction): R = visitJump(instruction)
open fun visitReturnNoValue(instruction: ReturnNoValueInstruction): R {
return visitJump(instruction)
}
open fun visitReturnNoValue(instruction: ReturnNoValueInstruction): R = visitJump(instruction)
open fun visitThrowExceptionInstruction(instruction: ThrowExceptionInstruction): R {
return visitJump(instruction)
}
open fun visitThrowExceptionInstruction(instruction: ThrowExceptionInstruction): R = visitJump(instruction)
open fun visitNondeterministicJump(instruction: NondeterministicJumpInstruction): R {
return visitInstruction(instruction)
}
open fun visitNondeterministicJump(instruction: NondeterministicJumpInstruction): R = visitInstruction(instruction)
open fun visitSubroutineExit(instruction: SubroutineExitInstruction): R {
return visitInstruction(instruction)
}
open fun visitSubroutineExit(instruction: SubroutineExitInstruction): R = visitInstruction(instruction)
open fun visitSubroutineSink(instruction: SubroutineSinkInstruction): R {
return visitInstruction(instruction)
}
open fun visitSubroutineSink(instruction: SubroutineSinkInstruction): R = visitInstruction(instruction)
open fun visitJump(instruction: AbstractJumpInstruction): R {
return visitInstruction(instruction)
}
open fun visitJump(instruction: AbstractJumpInstruction): R = visitInstruction(instruction)
open fun visitInstructionWithNext(instruction: InstructionWithNext): R {
return visitInstruction(instruction)
}
open fun visitInstructionWithNext(instruction: InstructionWithNext): R = visitInstruction(instruction)
open fun visitSubroutineEnter(instruction: SubroutineEnterInstruction): R {
return visitInstructionWithNext(instruction)
}
open fun visitSubroutineEnter(instruction: SubroutineEnterInstruction): R = visitInstructionWithNext(instruction)
open fun visitWriteValue(instruction: WriteValueInstruction): R {
return visitAccessInstruction(instruction)
}
open fun visitWriteValue(instruction: WriteValueInstruction): R = visitAccessInstruction(instruction)
open fun visitLoadUnitValue(instruction: LoadUnitValueInstruction): R {
return visitInstructionWithNext(instruction)
}
open fun visitLoadUnitValue(instruction: LoadUnitValueInstruction): R = visitInstructionWithNext(instruction)
open fun visitOperation(instruction: OperationInstruction): R {
return visitInstructionWithNext(instruction)
}
open fun visitOperation(instruction: OperationInstruction): R = visitInstructionWithNext(instruction)
open fun visitCallInstruction(instruction: CallInstruction): R {
return visitOperation(instruction)
}
open fun visitCallInstruction(instruction: CallInstruction): R = visitOperation(instruction)
open fun visitMerge(instruction: MergeInstruction): R {
return visitOperation(instruction)
}
open fun visitMerge(instruction: MergeInstruction): R = visitOperation(instruction)
open fun visitMarkInstruction(instruction: MarkInstruction): R {
return visitInstructionWithNext(instruction)
}
open fun visitMarkInstruction(instruction: MarkInstruction): R = visitInstructionWithNext(instruction)
open fun visitMagic(instruction: MagicInstruction): R {
return visitOperation(instruction)
}
open fun visitMagic(instruction: MagicInstruction): R = visitOperation(instruction)
}
@@ -20,7 +20,6 @@ import org.jetbrains.kotlin.cfg.pseudocode.PseudoValue
import org.jetbrains.kotlin.cfg.pseudocode.PseudoValueFactory
import org.jetbrains.kotlin.cfg.pseudocode.instructions.*
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtNamedDeclaration
@@ -82,9 +81,7 @@ class ReadValueInstruction private constructor(
visitor.visitReadValue(this)
}
override fun <R> accept(visitor: InstructionVisitorWithResult<R>): R {
return visitor.visitReadValue(this)
}
override fun <R> accept(visitor: InstructionVisitorWithResult<R>): R = visitor.visitReadValue(this)
override fun toString(): String {
val inVal = if (receiverValues.isEmpty()) "" else "|${receiverValues.keys.joinToString()}"
@@ -109,7 +106,7 @@ class WriteValueInstruction(
target: AccessTarget,
receiverValues: Map<PseudoValue, ReceiverValue>,
val lValue: KtElement,
val rValue: PseudoValue
private val rValue: PseudoValue
) : AccessValueInstruction(assignment, blockScope, target, receiverValues) {
override val inputValues: List<PseudoValue>
get() = (receiverValues.keys as Collection<PseudoValue>) + rValue
@@ -118,9 +115,7 @@ class WriteValueInstruction(
visitor.visitWriteValue(this)
}
override fun <R> accept(visitor: InstructionVisitorWithResult<R>): R {
return visitor.visitWriteValue(this)
}
override fun <R> accept(visitor: InstructionVisitorWithResult<R>): R = visitor.visitWriteValue(this)
override fun toString(): String {
val lhs = (lValue as? KtNamedDeclaration)?.name ?: render(lValue)
@@ -18,7 +18,6 @@ package org.jetbrains.kotlin.cfg.pseudocode.instructions.eval
import org.jetbrains.kotlin.cfg.pseudocode.PseudoValue
import org.jetbrains.kotlin.cfg.pseudocode.PseudoValueFactory
import org.jetbrains.kotlin.cfg.pseudocode.TypePredicate
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionVisitor
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionVisitorWithResult
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionWithNext
@@ -48,9 +47,8 @@ abstract class OperationInstruction protected constructor(
return this
}
protected fun setResult(factory: PseudoValueFactory?, valueElement: KtElement? = element): OperationInstruction {
return setResult(factory?.newValue(valueElement, this))
}
protected fun setResult(factory: PseudoValueFactory?, valueElement: KtElement? = element): OperationInstruction =
setResult(factory?.newValue(valueElement, this))
}
class CallInstruction private constructor(
@@ -76,9 +74,7 @@ class CallInstruction private constructor(
visitor.visitCallInstruction(this)
}
override fun <R> accept(visitor: InstructionVisitorWithResult<R>): R {
return visitor.visitCallInstruction(this)
}
override fun <R> accept(visitor: InstructionVisitorWithResult<R>): R = visitor.visitCallInstruction(this)
override fun createCopy() =
CallInstruction(element, blockScope, resolvedCall, receiverValues, arguments).setResult(resultValue)
@@ -35,13 +35,9 @@ abstract class AbstractJumpInstruction(
protected abstract fun createCopy(newLabel: Label, blockScope: BlockScope): AbstractJumpInstruction
fun copy(newLabel: Label): Instruction {
return updateCopyInfo(createCopy(newLabel, blockScope))
}
fun copy(newLabel: Label): Instruction = updateCopyInfo(createCopy(newLabel, blockScope))
override fun createCopy(): InstructionImpl {
return createCopy(targetLabel, blockScope)
}
override fun createCopy(): InstructionImpl = createCopy(targetLabel, blockScope)
override val nextInstructions: Collection<Instruction>
get() = listOfNotNull(resolvedTarget)
@@ -30,7 +30,7 @@ class ConditionalJumpInstruction(
val onTrue: Boolean,
blockScope: BlockScope,
targetLabel: Label,
val conditionValue: PseudoValue?) : AbstractJumpInstruction(element, targetLabel, blockScope) {
private val conditionValue: PseudoValue?) : AbstractJumpInstruction(element, targetLabel, blockScope) {
private var _nextOnTrue: Instruction? = null
private var _nextOnFalse: Instruction? = null
@@ -30,7 +30,7 @@ class NondeterministicJumpInstruction(
element: KtElement,
targetLabels: List<Label>,
blockScope: BlockScope,
val inputValue: PseudoValue?
private val inputValue: PseudoValue?
) : KtElementInstructionImpl(element, blockScope), JumpInstruction {
private var _next: Instruction? = null
private val _resolvedTargets: MutableMap<Label, Instruction> = linkedMapOf()
@@ -63,9 +63,7 @@ class NondeterministicJumpInstruction(
visitor.visitNondeterministicJump(this)
}
override fun <R> accept(visitor: InstructionVisitorWithResult<R>): R {
return visitor.visitNondeterministicJump(this)
}
override fun <R> accept(visitor: InstructionVisitorWithResult<R>): R = visitor.visitNondeterministicJump(this)
override fun toString(): String {
val inVal = if (inputValue != null) "|$inputValue" else ""
@@ -73,15 +71,10 @@ class NondeterministicJumpInstruction(
return "jmp?($labels$inVal)"
}
override fun createCopy(): InstructionImpl {
return createCopy(targetLabels)
}
override fun createCopy(): InstructionImpl = createCopy(targetLabels)
fun copy(newTargetLabels: MutableList<Label>): Instruction {
return updateCopyInfo(createCopy(newTargetLabels))
}
fun copy(newTargetLabels: MutableList<Label>): Instruction = updateCopyInfo(createCopy(newTargetLabels))
private fun createCopy(newTargetLabels: List<Label>): InstructionImpl {
return NondeterministicJumpInstruction(element, newTargetLabels, blockScope, inputValue)
}
private fun createCopy(newTargetLabels: List<Label>): InstructionImpl =
NondeterministicJumpInstruction(element, newTargetLabels, blockScope, inputValue)
}
@@ -32,9 +32,7 @@ class ReturnNoValueInstruction(
visitor.visitReturnNoValue(this)
}
override fun <R> accept(visitor: InstructionVisitorWithResult<R>): R {
return visitor.visitReturnNoValue(this)
}
override fun <R> accept(visitor: InstructionVisitorWithResult<R>): R = visitor.visitReturnNoValue(this)
override fun toString(): String = "ret $targetLabel"
@@ -39,17 +39,12 @@ class ReturnValueInstruction(
visitor.visitReturnValue(this)
}
override fun <R> accept(visitor: InstructionVisitorWithResult<R>): R {
return visitor.visitReturnValue(this)
}
override fun <R> accept(visitor: InstructionVisitorWithResult<R>): R = visitor.visitReturnValue(this)
override fun toString(): String {
return "ret(*|$returnedValue) $targetLabel"
}
override fun toString(): String = "ret(*|$returnedValue) $targetLabel"
override fun createCopy(newLabel: Label, blockScope: BlockScope): AbstractJumpInstruction {
return ReturnValueInstruction((element as KtExpression), blockScope, newLabel, returnedValue, subroutine)
}
override fun createCopy(newLabel: Label, blockScope: BlockScope): AbstractJumpInstruction =
ReturnValueInstruction((element as KtExpression), blockScope, newLabel, returnedValue, subroutine)
val returnExpressionIfAny: KtReturnExpression? = element as? KtReturnExpression
}
@@ -36,15 +36,10 @@ class ThrowExceptionInstruction(
visitor.visitThrowExceptionInstruction(this)
}
override fun <R> accept(visitor: InstructionVisitorWithResult<R>): R {
return visitor.visitThrowExceptionInstruction(this)
}
override fun <R> accept(visitor: InstructionVisitorWithResult<R>): R = visitor.visitThrowExceptionInstruction(this)
override fun toString(): String {
return "throw (${element.text}|$thrownValue)"
}
override fun toString(): String = "throw (${element.text}|$thrownValue)"
override fun createCopy(newLabel: Label, blockScope: BlockScope): AbstractJumpInstruction {
return ThrowExceptionInstruction((element as KtThrowExpression), blockScope, newLabel, thrownValue)
}
override fun createCopy(newLabel: Label, blockScope: BlockScope): AbstractJumpInstruction =
ThrowExceptionInstruction((element as KtThrowExpression), blockScope, newLabel, thrownValue)
}
@@ -29,9 +29,7 @@ class UnconditionalJumpInstruction(
visitor.visitUnconditionalJump(this)
}
override fun <R> accept(visitor: InstructionVisitorWithResult<R>): R {
return visitor.visitUnconditionalJump(this)
}
override fun <R> accept(visitor: InstructionVisitorWithResult<R>): R = visitor.visitUnconditionalJump(this)
override fun toString(): String = "jmp(${targetLabel.name})"
@@ -49,9 +49,7 @@ class LocalFunctionDeclarationInstruction(
visitor.visitLocalFunctionDeclarationInstruction(this)
}
override fun <R> accept(visitor: InstructionVisitorWithResult<R>): R {
return visitor.visitLocalFunctionDeclarationInstruction(this)
}
override fun <R> accept(visitor: InstructionVisitorWithResult<R>): R = visitor.visitLocalFunctionDeclarationInstruction(this)
override fun toString(): String = "d(${render(element)})"
@@ -31,9 +31,7 @@ class MarkInstruction(
visitor.visitMarkInstruction(this)
}
override fun <R> accept(visitor: InstructionVisitorWithResult<R>): R {
return visitor.visitMarkInstruction(this)
}
override fun <R> accept(visitor: InstructionVisitorWithResult<R>): R = visitor.visitMarkInstruction(this)
override fun createCopy() = MarkInstruction(element, blockScope)
@@ -31,9 +31,7 @@ class SubroutineEnterInstruction(
visitor.visitSubroutineEnter(this)
}
override fun <R> accept(visitor: InstructionVisitorWithResult<R>): R {
return visitor.visitSubroutineEnter(this)
}
override fun <R> accept(visitor: InstructionVisitorWithResult<R>): R = visitor.visitSubroutineEnter(this)
override fun toString(): String = "<START>"
@@ -40,9 +40,7 @@ class SubroutineExitInstruction(
visitor.visitSubroutineExit(this)
}
override fun <R> accept(visitor: InstructionVisitorWithResult<R>): R {
return visitor.visitSubroutineExit(this)
}
override fun <R> accept(visitor: InstructionVisitorWithResult<R>): R = visitor.visitSubroutineExit(this)
override fun toString(): String = if (isError) "<ERROR>" else "<END>"
@@ -35,9 +35,7 @@ class SubroutineSinkInstruction(
visitor.visitSubroutineSink(this)
}
override fun <R> accept(visitor: InstructionVisitorWithResult<R>): R {
return visitor.visitSubroutineSink(this)
}
override fun <R> accept(visitor: InstructionVisitorWithResult<R>): R = visitor.visitSubroutineSink(this)
override fun toString(): String = debugLabel
@@ -40,9 +40,7 @@ class VariableDeclarationInstruction(
visitor.visitVariableDeclarationInstruction(this)
}
override fun <R> accept(visitor: InstructionVisitorWithResult<R>): R {
return visitor.visitVariableDeclarationInstruction(this)
}
override fun <R> accept(visitor: InstructionVisitorWithResult<R>): R = visitor.visitVariableDeclarationInstruction(this)
override fun toString(): String = "v(${render(element)})"
@@ -123,11 +123,10 @@ fun getExpectedTypePredicate(
val i = inputValueIndex - argValueOffset
if (i < 0 || i >= callArguments.size) continue
val mapping = candidateCall.getArgumentMapping(callArguments.get(i))
if (mapping !is ArgumentMatch) continue
val mapping = candidateCall.getArgumentMapping(callArguments[i]) as? ArgumentMatch ?: continue
val candidateParameter = mapping.valueParameter
val resolvedArgument = candidateArgumentMap.get(candidateParameter)
val resolvedArgument = candidateArgumentMap[candidateParameter]
val expectedType = if (resolvedArgument is VarargValueArgument)
candidateParameter.varargElementType
else
@@ -206,19 +205,15 @@ fun getExpectedTypePredicate(
VALUE_CONSUMER -> {
val element = it.element
when {
element.getStrictParentOfType<KtWhileExpression>()?.condition == element ->
addSubtypesOf(builtIns.booleanType)
element is KtProperty -> {
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])
}
}
element is KtDelegatedSuperTypeEntry ->
addSubtypesOf(bindingContext[TYPE, element.typeReference])
is KtDelegatedSuperTypeEntry -> addSubtypesOf(bindingContext[TYPE, element.typeReference])
}
}
@@ -247,7 +242,7 @@ val Instruction.sideEffectFree: Boolean
fun Instruction.calcSideEffectFree(): Boolean {
if (this !is InstructionWithValue) return false
if (!inputValues.all { it.createdAt?.sideEffectFree ?: false }) return false
if (!inputValues.all { it.createdAt?.sideEffectFree == true }) return false
return when (this) {
is ReadValueInstruction -> target.let {