Pseudocode: Store lazily computed value usage map in the pseudocode
This commit is contained in:
@@ -58,4 +58,7 @@ public interface Pseudocode {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
PseudoValue getElementValue(@Nullable JetElement element);
|
PseudoValue getElementValue(@Nullable JetElement element);
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
List<? extends Instruction> getUsages(@Nullable PseudoValue value);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package org.jetbrains.jet.lang.cfg.pseudocode;
|
package org.jetbrains.jet.lang.cfg.pseudocode;
|
||||||
|
|
||||||
import com.google.common.collect.*;
|
import com.google.common.collect.*;
|
||||||
|
import com.intellij.openapi.util.NotNullLazyValue;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.lang.cfg.Label;
|
import org.jetbrains.jet.lang.cfg.Label;
|
||||||
@@ -89,6 +90,15 @@ public class PseudocodeImpl implements Pseudocode {
|
|||||||
|
|
||||||
private final Map<JetElement, PseudoValue> elementsToValues = new HashMap<JetElement, PseudoValue>();
|
private final Map<JetElement, PseudoValue> elementsToValues = new HashMap<JetElement, PseudoValue>();
|
||||||
|
|
||||||
|
private final NotNullLazyValue<Map<PseudoValue, List<? extends Instruction>>> valueUsages =
|
||||||
|
new NotNullLazyValue<Map<PseudoValue, List<? extends Instruction>>>() {
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
protected Map<PseudoValue, List<? extends Instruction>> compute() {
|
||||||
|
return PseudocodePackage.collectValueUsages(PseudocodeImpl.this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private Pseudocode parent = null;
|
private Pseudocode parent = null;
|
||||||
private Set<LocalFunctionDeclarationInstruction> localDeclarations = null;
|
private Set<LocalFunctionDeclarationInstruction> localDeclarations = null;
|
||||||
//todo getters
|
//todo getters
|
||||||
@@ -251,6 +261,13 @@ public class PseudocodeImpl implements Pseudocode {
|
|||||||
return elementsToValues.get(element);
|
return elementsToValues.get(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public List<? extends Instruction> getUsages(@Nullable PseudoValue value) {
|
||||||
|
List<? extends Instruction> result = valueUsages.getValue().get(value);
|
||||||
|
return result != null ? result : Collections.<Instruction>emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
/*package*/ void bindElementToValue(@NotNull JetElement element, @NotNull PseudoValue value) {
|
/*package*/ void bindElementToValue(@NotNull JetElement element, @NotNull PseudoValue value) {
|
||||||
elementsToValues.put(element, value);
|
elementsToValues.put(element, value);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,18 +64,6 @@ val PseudoValue.implicitReturnValue: Boolean
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Pseudocode.collectValueUsages(): Map<PseudoValue, List<Instruction>> {
|
|
||||||
val map = HashMap<PseudoValue, MutableList<Instruction>>()
|
|
||||||
traverseFollowingInstructions(getEnterInstruction(), HashSet(), TraversalOrder.FORWARD) {
|
|
||||||
for (value in it.inputValues) {
|
|
||||||
map.getOrPut(value){ ArrayList() }.add(it)
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
return map
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getReceiverTypePredicate(resolvedCall: ResolvedCall<*>, receiverValue: ReceiverValue): TypePredicate? {
|
fun getReceiverTypePredicate(resolvedCall: ResolvedCall<*>, receiverValue: ReceiverValue): TypePredicate? {
|
||||||
val callableDescriptor = resolvedCall.getResultingDescriptor()
|
val callableDescriptor = resolvedCall.getResultingDescriptor()
|
||||||
if (callableDescriptor == null) return null
|
if (callableDescriptor == null) return null
|
||||||
@@ -96,11 +84,8 @@ fun getReceiverTypePredicate(resolvedCall: ResolvedCall<*>, receiverValue: Recei
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getExpectedTypePredicate(
|
fun getExpectedTypePredicate(value: PseudoValue, bindingContext: BindingContext): TypePredicate {
|
||||||
value: PseudoValue,
|
val pseudocode = value.createdAt.owner
|
||||||
valueUsageMap: Map<PseudoValue, List<Instruction>>,
|
|
||||||
bindingContext: BindingContext
|
|
||||||
): TypePredicate {
|
|
||||||
val typePredicates = HashSet<TypePredicate?>()
|
val typePredicates = HashSet<TypePredicate?>()
|
||||||
|
|
||||||
fun addSubtypesOf(jetType: JetType?) = typePredicates.add(jetType?.getSubtypesPredicate())
|
fun addSubtypesOf(jetType: JetType?) = typePredicates.add(jetType?.getSubtypesPredicate())
|
||||||
@@ -112,7 +97,7 @@ fun getExpectedTypePredicate(
|
|||||||
addSubtypesOf(functionDescriptor?.getReturnType())
|
addSubtypesOf(functionDescriptor?.getReturnType())
|
||||||
}
|
}
|
||||||
|
|
||||||
valueUsageMap[value]?.forEach {
|
pseudocode.getUsages(value).forEach {
|
||||||
when (it) {
|
when (it) {
|
||||||
is ReturnValueInstruction -> {
|
is ReturnValueInstruction -> {
|
||||||
val functionDescriptor = (it.element as JetReturnExpression).getTargetFunctionDescriptor(bindingContext)
|
val functionDescriptor = (it.element as JetReturnExpression).getTargetFunctionDescriptor(bindingContext)
|
||||||
@@ -173,4 +158,16 @@ fun getExpectedTypePredicate(
|
|||||||
|
|
||||||
addTypePredicates(value)
|
addTypePredicates(value)
|
||||||
return and(typePredicates.filterNotNull())
|
return and(typePredicates.filterNotNull())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Pseudocode.collectValueUsages(): Map<PseudoValue, List<Instruction>> {
|
||||||
|
val map = HashMap<PseudoValue, MutableList<Instruction>>()
|
||||||
|
traverseFollowingInstructions(getEnterInstruction(), HashSet(), TraversalOrder.FORWARD) {
|
||||||
|
for (value in it.inputValues) {
|
||||||
|
map.getOrPut(value){ ArrayList() }.add(it)
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
return map
|
||||||
}
|
}
|
||||||
@@ -22,14 +22,12 @@ import org.jetbrains.jet.lang.psi.JetElement
|
|||||||
import org.jetbrains.jet.lang.psi.JetTreeVisitorVoid
|
import org.jetbrains.jet.lang.psi.JetTreeVisitorVoid
|
||||||
import org.jetbrains.jet.lang.resolve.BindingContext
|
import org.jetbrains.jet.lang.resolve.BindingContext
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import org.jetbrains.jet.lang.cfg.pseudocode.collectValueUsages
|
|
||||||
import org.jetbrains.jet.lang.cfg.pseudocode.TypePredicate
|
import org.jetbrains.jet.lang.cfg.pseudocode.TypePredicate
|
||||||
import org.jetbrains.jet.lang.cfg.pseudocode.getExpectedTypePredicate
|
import org.jetbrains.jet.lang.cfg.pseudocode.getExpectedTypePredicate
|
||||||
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.eval.InstructionWithValue
|
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.eval.InstructionWithValue
|
||||||
|
|
||||||
public abstract class AbstractPseudoValueTest : AbstractPseudocodeTest() {
|
public abstract class AbstractPseudoValueTest : AbstractPseudocodeTest() {
|
||||||
override fun dumpInstructions(pseudocode: PseudocodeImpl, out: StringBuilder, bindingContext: BindingContext) {
|
override fun dumpInstructions(pseudocode: PseudocodeImpl, out: StringBuilder, bindingContext: BindingContext) {
|
||||||
val valueUsageMap = pseudocode.collectValueUsages()
|
|
||||||
val expectedTypePredicateMap = HashMap<PseudoValue, TypePredicate>()
|
val expectedTypePredicateMap = HashMap<PseudoValue, TypePredicate>()
|
||||||
|
|
||||||
fun getElementToValueMap(pseudocode: PseudocodeImpl): Map<JetElement, PseudoValue> {
|
fun getElementToValueMap(pseudocode: PseudocodeImpl): Map<JetElement, PseudoValue> {
|
||||||
@@ -51,7 +49,7 @@ public abstract class AbstractPseudoValueTest : AbstractPseudocodeTest() {
|
|||||||
element?.getText()?.replaceAll("\\s+", " ") ?: ""
|
element?.getText()?.replaceAll("\\s+", " ") ?: ""
|
||||||
|
|
||||||
fun valueDecl(value: PseudoValue): String {
|
fun valueDecl(value: PseudoValue): String {
|
||||||
val typePredicate = expectedTypePredicateMap.getOrPut(value) { getExpectedTypePredicate(value, valueUsageMap, bindingContext) }
|
val typePredicate = expectedTypePredicateMap.getOrPut(value) { getExpectedTypePredicate(value, bindingContext) }
|
||||||
return "${value.debugName}: $typePredicate"
|
return "${value.debugName}: $typePredicate"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-3
@@ -373,8 +373,6 @@ private fun ExtractionData.inferParametersInfo(
|
|||||||
|
|
||||||
val extractedDescriptorToParameter = HashMap<DeclarationDescriptor, MutableParameter>()
|
val extractedDescriptorToParameter = HashMap<DeclarationDescriptor, MutableParameter>()
|
||||||
|
|
||||||
val valueUsageMap = pseudocode.collectValueUsages()
|
|
||||||
|
|
||||||
for (refInfo in getBrokenReferencesInfo(createTemporaryCodeBlock())) {
|
for (refInfo in getBrokenReferencesInfo(createTemporaryCodeBlock())) {
|
||||||
val (originalRef, originalDeclaration, originalDescriptor, resolvedCall) = refInfo.resolveResult
|
val (originalRef, originalDeclaration, originalDescriptor, resolvedCall) = refInfo.resolveResult
|
||||||
val ref = refInfo.refExpr
|
val ref = refInfo.refExpr
|
||||||
@@ -437,7 +435,7 @@ private fun ExtractionData.inferParametersInfo(
|
|||||||
if (!parameterType.processTypeIfExtractable(typeParameters, nonDenotableTypes)) continue
|
if (!parameterType.processTypeIfExtractable(typeParameters, nonDenotableTypes)) continue
|
||||||
|
|
||||||
val parameterTypePredicate =
|
val parameterTypePredicate =
|
||||||
pseudocode.getElementValue(originalRef)?.let { getExpectedTypePredicate(it, valueUsageMap, bindingContext) } ?: AllTypes
|
pseudocode.getElementValue(originalRef)?.let { getExpectedTypePredicate(it, bindingContext) } ?: AllTypes
|
||||||
|
|
||||||
val parameter = extractedDescriptorToParameter.getOrPut(descriptorToExtract) {
|
val parameter = extractedDescriptorToParameter.getOrPut(descriptorToExtract) {
|
||||||
val parameterName =
|
val parameterName =
|
||||||
|
|||||||
Reference in New Issue
Block a user