From 02342fce5d5d516d79edc2310a593648fcb481fe Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Fri, 27 Jun 2014 14:55:57 +0400 Subject: [PATCH] Pseudocode: Store lazily computed value usage map in the pseudocode --- .../jet/lang/cfg/pseudocode/Pseudocode.java | 3 ++ .../lang/cfg/pseudocode/PseudocodeImpl.java | 17 ++++++++++ .../jet/lang/cfg/pseudocode/pseudocodeUtil.kt | 33 +++++++++---------- .../jet/cfg/AbstractPseudoValueTest.kt | 4 +-- .../extractFunction/extractFunctionUtils.kt | 4 +-- 5 files changed, 37 insertions(+), 24 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/Pseudocode.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/Pseudocode.java index 91044d06959..9f87c4b64fc 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/Pseudocode.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/Pseudocode.java @@ -58,4 +58,7 @@ public interface Pseudocode { @Nullable PseudoValue getElementValue(@Nullable JetElement element); + + @NotNull + List getUsages(@Nullable PseudoValue value); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/PseudocodeImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/PseudocodeImpl.java index 7452157936e..f98fb32b326 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/PseudocodeImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/PseudocodeImpl.java @@ -17,6 +17,7 @@ package org.jetbrains.jet.lang.cfg.pseudocode; import com.google.common.collect.*; +import com.intellij.openapi.util.NotNullLazyValue; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.cfg.Label; @@ -89,6 +90,15 @@ public class PseudocodeImpl implements Pseudocode { private final Map elementsToValues = new HashMap(); + private final NotNullLazyValue>> valueUsages = + new NotNullLazyValue>>() { + @NotNull + @Override + protected Map> compute() { + return PseudocodePackage.collectValueUsages(PseudocodeImpl.this); + } + }; + private Pseudocode parent = null; private Set localDeclarations = null; //todo getters @@ -251,6 +261,13 @@ public class PseudocodeImpl implements Pseudocode { return elementsToValues.get(element); } + @NotNull + @Override + public List getUsages(@Nullable PseudoValue value) { + List result = valueUsages.getValue().get(value); + return result != null ? result : Collections.emptyList(); + } + /*package*/ void bindElementToValue(@NotNull JetElement element, @NotNull PseudoValue value) { elementsToValues.put(element, value); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/pseudocodeUtil.kt b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/pseudocodeUtil.kt index 41e3886f47b..a080bfe25f3 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/pseudocodeUtil.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/pseudocodeUtil.kt @@ -64,18 +64,6 @@ val PseudoValue.implicitReturnValue: Boolean return false } -fun Pseudocode.collectValueUsages(): Map> { - val map = HashMap>() - 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? { val callableDescriptor = resolvedCall.getResultingDescriptor() if (callableDescriptor == null) return null @@ -96,11 +84,8 @@ fun getReceiverTypePredicate(resolvedCall: ResolvedCall<*>, receiverValue: Recei return null } -fun getExpectedTypePredicate( - value: PseudoValue, - valueUsageMap: Map>, - bindingContext: BindingContext -): TypePredicate { +fun getExpectedTypePredicate(value: PseudoValue, bindingContext: BindingContext): TypePredicate { + val pseudocode = value.createdAt.owner val typePredicates = HashSet() fun addSubtypesOf(jetType: JetType?) = typePredicates.add(jetType?.getSubtypesPredicate()) @@ -112,7 +97,7 @@ fun getExpectedTypePredicate( addSubtypesOf(functionDescriptor?.getReturnType()) } - valueUsageMap[value]?.forEach { + pseudocode.getUsages(value).forEach { when (it) { is ReturnValueInstruction -> { val functionDescriptor = (it.element as JetReturnExpression).getTargetFunctionDescriptor(bindingContext) @@ -173,4 +158,16 @@ fun getExpectedTypePredicate( addTypePredicates(value) return and(typePredicates.filterNotNull()) +} + +private fun Pseudocode.collectValueUsages(): Map> { + val map = HashMap>() + traverseFollowingInstructions(getEnterInstruction(), HashSet(), TraversalOrder.FORWARD) { + for (value in it.inputValues) { + map.getOrPut(value){ ArrayList() }.add(it) + } + true + } + + return map } \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/cfg/AbstractPseudoValueTest.kt b/compiler/tests/org/jetbrains/jet/cfg/AbstractPseudoValueTest.kt index d3d20554597..c78d6642cc2 100644 --- a/compiler/tests/org/jetbrains/jet/cfg/AbstractPseudoValueTest.kt +++ b/compiler/tests/org/jetbrains/jet/cfg/AbstractPseudoValueTest.kt @@ -22,14 +22,12 @@ import org.jetbrains.jet.lang.psi.JetElement import org.jetbrains.jet.lang.psi.JetTreeVisitorVoid import org.jetbrains.jet.lang.resolve.BindingContext 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.getExpectedTypePredicate import org.jetbrains.jet.lang.cfg.pseudocode.instructions.eval.InstructionWithValue public abstract class AbstractPseudoValueTest : AbstractPseudocodeTest() { override fun dumpInstructions(pseudocode: PseudocodeImpl, out: StringBuilder, bindingContext: BindingContext) { - val valueUsageMap = pseudocode.collectValueUsages() val expectedTypePredicateMap = HashMap() fun getElementToValueMap(pseudocode: PseudocodeImpl): Map { @@ -51,7 +49,7 @@ public abstract class AbstractPseudoValueTest : AbstractPseudocodeTest() { element?.getText()?.replaceAll("\\s+", " ") ?: "" 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" } diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/extractFunctionUtils.kt b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/extractFunctionUtils.kt index 6c07ef3114e..b69f076d462 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/extractFunctionUtils.kt +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/extractFunction/extractFunctionUtils.kt @@ -373,8 +373,6 @@ private fun ExtractionData.inferParametersInfo( val extractedDescriptorToParameter = HashMap() - val valueUsageMap = pseudocode.collectValueUsages() - for (refInfo in getBrokenReferencesInfo(createTemporaryCodeBlock())) { val (originalRef, originalDeclaration, originalDescriptor, resolvedCall) = refInfo.resolveResult val ref = refInfo.refExpr @@ -437,7 +435,7 @@ private fun ExtractionData.inferParametersInfo( if (!parameterType.processTypeIfExtractable(typeParameters, nonDenotableTypes)) continue 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 parameterName =