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