From 8acfa20a0271c1a2e32aba68b8541f54f742abda Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Sat, 26 May 2012 16:30:50 +0400 Subject: [PATCH] lazy computing of pseudocode variables data no need in special 'data' classes --- .../lang/cfg/JetFlowInformationProvider.java | 114 ++++--- .../jet/lang/cfg/PseudocodeTraverser.java | 57 +++- ...Data.java => PseudocodeVariablesData.java} | 300 ++++++++++-------- .../jet/lang/cfg/data/DeclarationData.java | 42 --- .../jetbrains/jet/lang/cfg/data/Edges.java | 66 ---- .../jet/lang/cfg/data/InstructionData.java | 68 ---- .../lang/cfg/data/VariableInitializers.java | 100 ------ .../jet/lang/cfg/data/VariableUseStatus.java | 40 --- .../lang/cfg/pseudocode/PseudocodeUtil.java | 18 ++ 9 files changed, 289 insertions(+), 516 deletions(-) rename compiler/frontend/src/org/jetbrains/jet/lang/cfg/{data/PseudocodeData.java => PseudocodeVariablesData.java} (50%) delete mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/cfg/data/DeclarationData.java delete mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/cfg/data/Edges.java delete mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/cfg/data/InstructionData.java delete mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/cfg/data/VariableInitializers.java delete mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/cfg/data/VariableUseStatus.java diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java index 71ddd8e3e44..a271bf70c6f 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java @@ -23,8 +23,10 @@ import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.cfg.data.*; import org.jetbrains.jet.lang.cfg.pseudocode.*; +import org.jetbrains.jet.lang.cfg.PseudocodeTraverser.Edges; +import org.jetbrains.jet.lang.cfg.PseudocodeVariablesData.VariableInitializers; +import org.jetbrains.jet.lang.cfg.PseudocodeVariablesData.VariableUseStatus; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.diagnostics.Errors; import org.jetbrains.jet.lang.psi.*; @@ -37,10 +39,7 @@ import org.jetbrains.jet.lang.types.lang.JetStandardClasses; import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.plugin.JetMainDetector; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Set; +import java.util.*; import static org.jetbrains.jet.lang.diagnostics.Errors.*; import static org.jetbrains.jet.lang.resolve.BindingContext.CAPTURED_IN_CLOSURE; @@ -53,7 +52,7 @@ public class JetFlowInformationProvider { private final JetDeclaration subroutine; private final Pseudocode pseudocode; - private final PseudocodeData pseudocodeData; + private final PseudocodeVariablesData pseudocodeData; private BindingTrace trace; public JetFlowInformationProvider( @@ -63,7 +62,7 @@ public class JetFlowInformationProvider { subroutine = declaration; this.trace = trace; pseudocode = new JetControlFlowProcessor(trace).generatePseudocode(declaration); - pseudocodeData = new PseudocodeData(pseudocode, trace.getBindingContext()); + pseudocodeData = new PseudocodeVariablesData(pseudocode, trace.getBindingContext()); } private void collectReturnExpressions(@NotNull final Collection returnedExpressions) { @@ -120,15 +119,14 @@ public class JetFlowInformationProvider { }); } } - + public void checkDefiniteReturn(final @NotNull JetType expectedReturnType) { assert subroutine instanceof JetDeclarationWithBody; JetDeclarationWithBody function = (JetDeclarationWithBody) subroutine; - assert function instanceof JetDeclaration; JetExpression bodyExpression = function.getBodyExpression(); if (bodyExpression == null) return; - + List returnedExpressions = Lists.newArrayList(); collectReturnExpressions(returnedExpressions); @@ -140,7 +138,7 @@ public class JetFlowInformationProvider { trace.report(RETURN_TYPE_MISMATCH.on(bodyExpression, expectedReturnType)); } final boolean blockBody = function.hasBlockBody(); - + final Set rootUnreachableElements = collectUnreachableCode(); for (JetElement element : rootUnreachableElements) { trace.report(UNREACHABLE_CODE.on(element)); @@ -189,49 +187,53 @@ public class JetFlowInformationProvider { final Collection varWithValReassignErrorGenerated = Sets.newHashSet(); final boolean processClassOrObject = subroutine instanceof JetClassOrObject; - pseudocodeData.traverseInstructionsGraph(true, true, new PseudocodeData.TraverseInstructionGraphStrategy() { + Map>> initializers = pseudocodeData.getVariableInitializers(); + final Set declaredVariables = pseudocodeData.getDeclaredVariables(pseudocode); + PseudocodeTraverser.traverseAndAnalyzeInstructionGraph(true, pseudocode, initializers, true, new PseudocodeTraverser.InstructionDataAnalyzeStrategy>() { @Override - public void execute(@NotNull Instruction instruction, @NotNull DeclarationData declarationData, @NotNull InstructionData instructionData) { - //todo move to util - VariableDescriptor variableDescriptor = pseudocodeData.extractVariableDescriptorIfAny(instruction, true); + public void execute(@NotNull Instruction instruction, + @Nullable Map in, + @Nullable Map out) { + assert in != null && out != null; + VariableDescriptor variableDescriptor = PseudocodeUtil.extractVariableDescriptorIfAny(instruction, true, + trace.getBindingContext()); if (variableDescriptor == null) return; if (!(instruction instanceof ReadValueInstruction) && !(instruction instanceof WriteValueInstruction)) return; - Edges variableInitializers = instructionData.getInitializersMap().get( - variableDescriptor); - if (variableInitializers == null) return; + VariableInitializers outInitializers = out.get(variableDescriptor); if (instruction instanceof ReadValueInstruction) { JetElement element = ((ReadValueInstruction) instruction).getElement(); boolean error = checkBackingField(variableDescriptor, element); - if (!error && declarationData.declaredVariables.contains(variableDescriptor)) { - checkIsInitialized(variableDescriptor, element, variableInitializers.getOut(), varWithUninitializedErrorGenerated); + if (!error && declaredVariables.contains(variableDescriptor)) { + checkIsInitialized(variableDescriptor, element, outInitializers, varWithUninitializedErrorGenerated); } return; } JetElement element = ((WriteValueInstruction) instruction).getlValue(); boolean error = checkBackingField(variableDescriptor, element); if (!(element instanceof JetExpression)) return; + VariableInitializers inInitializers = in.get(variableDescriptor); if (!error && !processLocalDeclaration) { // error has been generated before, while processing outer function of this local declaration - error = checkValReassignment(variableDescriptor, (JetExpression) element, variableInitializers.getIn(), varWithValReassignErrorGenerated); + error = checkValReassignment(variableDescriptor, (JetExpression) element, inInitializers, varWithValReassignErrorGenerated); } if (!error && processClassOrObject) { - error = checkAssignmentBeforeDeclaration(variableDescriptor, (JetExpression) element, variableInitializers.getIn(), variableInitializers.getOut()); + error = checkAssignmentBeforeDeclaration(variableDescriptor, (JetExpression) element, inInitializers, outInitializers); } if (!error && processClassOrObject) { - checkInitializationUsingBackingField(variableDescriptor, (JetExpression) element, variableInitializers.getIn(), variableInitializers.getOut()); + checkInitializationUsingBackingField(variableDescriptor, (JetExpression) element, inInitializers, outInitializers); } } }); Pseudocode pseudocode = pseudocodeData.getPseudocode(); - recordInitializedVariables(pseudocodeData.getDeclarationData(pseudocode), pseudocodeData.getResultInfo(pseudocode)); + recordInitializedVariables(pseudocode, initializers); for (LocalDeclarationInstruction instruction : pseudocode.getLocalDeclarations()) { - recordInitializedVariables(pseudocodeData.getDeclarationData(instruction.getBody()), pseudocodeData.getResultInfo(instruction.getBody())); + recordInitializedVariables(instruction.getBody(), initializers); } } - private void checkIsInitialized(@NotNull VariableDescriptor variableDescriptor, - @NotNull JetElement element, - @NotNull VariableInitializers variableInitializers, + private void checkIsInitialized(@NotNull VariableDescriptor variableDescriptor, + @NotNull JetElement element, + @NotNull VariableInitializers variableInitializers, @NotNull Collection varWithUninitializedErrorGenerated) { if (!(element instanceof JetSimpleNameExpression)) return; @@ -244,7 +246,8 @@ public class JetFlowInformationProvider { if (!isInitialized && !varWithUninitializedErrorGenerated.contains(variableDescriptor)) { varWithUninitializedErrorGenerated.add(variableDescriptor); if (variableDescriptor instanceof ValueParameterDescriptor) { - trace.report(Errors.UNINITIALIZED_PARAMETER.on((JetSimpleNameExpression) element, (ValueParameterDescriptor) variableDescriptor)); + trace.report(Errors.UNINITIALIZED_PARAMETER.on((JetSimpleNameExpression) element, + (ValueParameterDescriptor) variableDescriptor)); } else { trace.report(Errors.UNINITIALIZED_VARIABLE.on((JetSimpleNameExpression) element, variableDescriptor)); @@ -252,9 +255,9 @@ public class JetFlowInformationProvider { } } - private boolean checkValReassignment(@NotNull VariableDescriptor variableDescriptor, - @NotNull JetExpression expression, - @NotNull VariableInitializers enterInitializers, + private boolean checkValReassignment(@NotNull VariableDescriptor variableDescriptor, + @NotNull JetExpression expression, + @NotNull VariableInitializers enterInitializers, @NotNull Collection varWithValReassignErrorGenerated) { boolean isInitializedNotHere = enterInitializers.isInitialized(); Set possibleLocalInitializers = enterInitializers.getPossibleLocalInitializers(); @@ -304,7 +307,7 @@ public class JetFlowInformationProvider { } return false; } - + private boolean checkAssignmentBeforeDeclaration(@NotNull VariableDescriptor variableDescriptor, @NotNull JetExpression expression, @NotNull VariableInitializers enterInitializers, @NotNull VariableInitializers exitInitializers) { if (!enterInitializers.isDeclared() && !exitInitializers.isDeclared() && !enterInitializers.isInitialized() && exitInitializers.isInitialized()) { trace.report(Errors.INITIALIZATION_BEFORE_DECLARATION.on(expression, variableDescriptor)); @@ -312,7 +315,7 @@ public class JetFlowInformationProvider { } return false; } - + private boolean checkInitializationUsingBackingField(@NotNull VariableDescriptor variableDescriptor, @NotNull JetExpression expression, @NotNull VariableInitializers enterInitializers, @NotNull VariableInitializers exitInitializers) { if (variableDescriptor instanceof PropertyDescriptor && !enterInitializers.isInitialized() && exitInitializers.isInitialized()) { if (!variableDescriptor.isVar()) return false; @@ -392,12 +395,15 @@ public class JetFlowInformationProvider { return false; } - private void recordInitializedVariables(DeclarationData declarationData, InstructionData instructionData) { - for (VariableDescriptor variable : declarationData.usedVariables) { - if (variable instanceof PropertyDescriptor && declarationData.declaredVariables.contains(variable)) { - Edges variableInitializers = instructionData.getInitializersMap().get(variable); + private void recordInitializedVariables(@NotNull Pseudocode pseudocode, @NotNull Map>> initializersMap) { + Edges> initializers = initializersMap.get(pseudocode.getExitInstruction()); + Set usedVariables = pseudocodeData.getUsedVariables(pseudocode); + Set declaredVariables = pseudocodeData.getDeclaredVariables(pseudocode); + for (VariableDescriptor variable : usedVariables) { + if (variable instanceof PropertyDescriptor && declaredVariables.contains(variable)) { + VariableInitializers variableInitializers = initializers.in.get(variable); if (variableInitializers == null) return; - trace.record(BindingContext.IS_INITIALIZED, (PropertyDescriptor) variable, variableInitializers.getIn().isInitialized()); + trace.record(BindingContext.IS_INITIALIZED, (PropertyDescriptor) variable, variableInitializers.isInitialized()); } } } @@ -406,14 +412,20 @@ public class JetFlowInformationProvider { // "Unused variable" & "unused value" analyses public void markUnusedVariables() { - pseudocodeData.traverseInstructionsGraph(true, false, new PseudocodeData.TraverseInstructionGraphStrategy() { + Map>> variableStatusData = pseudocodeData.getVariableStatusData(); + PseudocodeTraverser.traverseAndAnalyzeInstructionGraph(true, pseudocode, variableStatusData, false, new PseudocodeTraverser.InstructionDataAnalyzeStrategy>() { @Override - public void execute(@NotNull Instruction instruction, @NotNull DeclarationData declarationData, @NotNull InstructionData instructionData) { - VariableDescriptor variableDescriptor = pseudocodeData.extractVariableDescriptorIfAny(instruction, false); - if (variableDescriptor == null || !declarationData.declaredVariables.contains(variableDescriptor) || + public void execute(@NotNull Instruction instruction, + @Nullable Map in, + @Nullable Map out) { + + assert in != null && out != null; + Set declaredVariables = pseudocodeData.getDeclaredVariables(instruction.getOwner()); + VariableDescriptor variableDescriptor = PseudocodeUtil.extractVariableDescriptorIfAny(instruction, false, + trace.getBindingContext()); + if (variableDescriptor == null || !declaredVariables.contains(variableDescriptor) || !DescriptorUtils.isLocal(variableDescriptor.getContainingDeclaration(), variableDescriptor)) return; - Edges statusEdgesData = instructionData.getUseStatusMap().get(variableDescriptor); - VariableUseStatus variableUseStatus = statusEdgesData != null ? statusEdgesData.getIn() : null; + VariableUseStatus variableUseStatus = in.get(variableDescriptor); if (instruction instanceof WriteValueInstruction) { if (trace.get(CAPTURED_IN_CLOSURE, variableDescriptor)) return; JetElement element = ((WriteValueInstruction) instruction).getElement(); @@ -480,19 +492,20 @@ public class JetFlowInformationProvider { } }); - } //////////////////////////////////////////////////////////////////////////////// // "Unused literals" in block - + public void markUnusedLiteralsInBlock() { assert pseudocode != null; - PseudocodeTraverser.traverseAndAnalyzeInstructionGraph(pseudocode, true, new PseudocodeTraverser.SimpleInstructionDataAnalyzeStrategy() { + PseudocodeTraverser.traverseAndAnalyzeInstructionGraph( + pseudocode, true, new PseudocodeTraverser.SimpleInstructionDataAnalyzeStrategy() { @Override public void execute(@NotNull Instruction instruction) { if (!(instruction instanceof ReadValueInstruction)) return; - JetElement element = ((ReadValueInstruction) instruction).getElement(); + JetElement element = + ((ReadValueInstruction) instruction).getElement(); if (!(element instanceof JetFunctionLiteralExpression || element instanceof JetConstantExpression || element instanceof JetStringTemplateExpression @@ -503,7 +516,8 @@ public class JetFlowInformationProvider { if (parent instanceof JetBlockExpression) { if (!JetPsiUtil.isImplicitlyUsed(element)) { if (element instanceof JetFunctionLiteralExpression) { - trace.report(Errors.UNUSED_FUNCTION_LITERAL.on((JetFunctionLiteralExpression) element)); + trace.report(Errors.UNUSED_FUNCTION_LITERAL + .on((JetFunctionLiteralExpression) element)); } else { trace.report(Errors.UNUSED_EXPRESSION.on(element)); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/PseudocodeTraverser.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/PseudocodeTraverser.java index 54ce272fa1f..e8010b4d31a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/PseudocodeTraverser.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/PseudocodeTraverser.java @@ -21,7 +21,6 @@ import com.google.common.collect.Maps; import com.google.common.collect.Sets; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.cfg.data.Edges; import org.jetbrains.jet.lang.cfg.pseudocode.*; import java.util.Collection; @@ -134,11 +133,7 @@ public class PseudocodeTraverser { @NotNull Pseudocode pseudocode, boolean directOrder, SimpleInstructionDataAnalyzeStrategy instructionDataAnalyzeStrategy) { - List instructions = pseudocode.getInstructions(); - if (!directOrder) { - instructions = Lists.newArrayList(instructions); - Collections.reverse(instructions); - } + List instructions = directOrder ? pseudocode.getInstructions() : pseudocode.getReversedInstructions(); for (Instruction instruction : instructions) { if (instruction instanceof LocalDeclarationInstruction) { traverseAndAnalyzeInstructionGraph(((LocalDeclarationInstruction) instruction).getBody(), directOrder, instructionDataAnalyzeStrategy); @@ -153,11 +148,7 @@ public class PseudocodeTraverser { @NotNull Map> dataMap, boolean directOrder, @NotNull InstructionDataAnalyzeStrategy instructionDataAnalyzeStrategy) { - List instructions = pseudocode.getInstructions(); - if (!directOrder) { - instructions = Lists.newArrayList(instructions); - Collections.reverse(instructions); - } + List instructions = directOrder ? pseudocode.getInstructions() : pseudocode.getReversedInstructions(); for (Instruction instruction : instructions) { if (lookInside && instruction instanceof LocalDeclarationInstruction) { traverseAndAnalyzeInstructionGraph(lookInside, ((LocalDeclarationInstruction) instruction).getBody(), dataMap, directOrder, instructionDataAnalyzeStrategy); @@ -178,4 +169,48 @@ public class PseudocodeTraverser { public interface SimpleInstructionDataAnalyzeStrategy { void execute(@NotNull Instruction instruction); } + + public static class Edges { + public final T in; + public final T out; + + Edges(@NotNull T in, @NotNull T out) { + this.in = in; + this.out = out; + } + + public static Edges create(@NotNull T in, @NotNull T out) { + return new Edges(in, out); + } + + @NotNull + public T getIn() { + return in; + } + + @NotNull + public T getOut() { + return out; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Edges)) return false; + + Edges edges = (Edges) o; + + if (in != null ? !in.equals(edges.in) : edges.in != null) return false; + if (out != null ? !out.equals(edges.out) : edges.out != null) return false; + + return true; + } + + @Override + public int hashCode() { + int result = in != null ? in.hashCode() : 0; + result = 31 * result + (out != null ? out.hashCode() : 0); + return result; + } + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/data/PseudocodeData.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/PseudocodeVariablesData.java similarity index 50% rename from compiler/frontend/src/org/jetbrains/jet/lang/cfg/data/PseudocodeData.java rename to compiler/frontend/src/org/jetbrains/jet/lang/cfg/PseudocodeVariablesData.java index 38d7a54a0d0..9247f6d1189 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/data/PseudocodeData.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/PseudocodeVariablesData.java @@ -14,14 +14,13 @@ * limitations under the License. */ -package org.jetbrains.jet.lang.cfg.data; +package org.jetbrains.jet.lang.cfg; -import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.cfg.PseudocodeTraverser; +import org.jetbrains.jet.lang.cfg.PseudocodeTraverser.Edges; import org.jetbrains.jet.lang.cfg.pseudocode.*; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.VariableDescriptor; @@ -29,49 +28,28 @@ import org.jetbrains.jet.lang.psi.JetDeclaration; import org.jetbrains.jet.lang.psi.JetElement; import org.jetbrains.jet.lang.psi.JetProperty; import org.jetbrains.jet.lang.resolve.BindingContext; -import org.jetbrains.jet.lang.resolve.BindingContextUtils; -import java.util.*; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.Set; /** * @author svtk */ -public class PseudocodeData { +public class PseudocodeVariablesData { private final Pseudocode pseudocode; - private final Map instructionDataMap = Maps.newLinkedHashMap(); - private final Map declarationDataMap = Maps.newLinkedHashMap(); - - //private final Map> declaredVariablesInEachDeclaration; - //private final Map> usedVariablesInEachDeclaration; - private final BindingContext bindingContext; - public PseudocodeData(@NotNull Pseudocode pseudocode, @NotNull BindingContext bindingContext) { + private final Map> declaredVariablesInEachDeclaration = Maps.newHashMap(); + private final Map> usedVariablesInEachDeclaration = Maps.newHashMap(); + + private Map>> variableInitializersMap; + private Map>> variableStatusMap; + + public PseudocodeVariablesData(@NotNull Pseudocode pseudocode, @NotNull BindingContext bindingContext) { this.pseudocode = pseudocode; this.bindingContext = bindingContext; - collectDeclarationData(pseudocode); - - DeclarationData declarationData = declarationDataMap.get(pseudocode); - - final Map>> variableInitializersMap = - collectVariableInitializers(pseudocode, declarationData); - final Map>> variableStatusMap = - collectVariableStatusData(); - - - PseudocodeTraverser.traverseAndAnalyzeInstructionGraph(pseudocode, true, - new PseudocodeTraverser.SimpleInstructionDataAnalyzeStrategy() { - @Override - public void execute(@NotNull Instruction instruction) { - instructionDataMap.put(instruction, - new InstructionData(PseudocodeData.this, - instruction, - variableInitializersMap - .get(instruction), - variableStatusMap - .get(instruction))); - } - }); } @NotNull @@ -79,98 +57,66 @@ public class PseudocodeData { return pseudocode; } - @NotNull - public Map getInstructionDataMap() { - return instructionDataMap; - } - - @NotNull - public DeclarationData getDeclarationData(Pseudocode pseudocode) { - return declarationDataMap.get(pseudocode); - } - - @NotNull - public InstructionData getResultInfo(Pseudocode pseudocode) { - return instructionDataMap.get(pseudocode.getExitInstruction()); - } - - public void traverseInstructionsGraph(boolean lookInside, boolean straightDirection, - @NotNull TraverseInstructionGraphStrategy traverseInstructionGraphStrategy) { - traverseInstructionsGraph(pseudocode, lookInside, straightDirection, traverseInstructionGraphStrategy); - } - - private void traverseInstructionsGraph(@NotNull Pseudocode pseudocode, - boolean lookInside, - boolean straightDirection, - @NotNull TraverseInstructionGraphStrategy traverseInstructionGraphStrategy) { - List instructions = pseudocode.getInstructions(); - if (!straightDirection) { - instructions = Lists.newArrayList(instructions); - Collections.reverse(instructions); + public Set getUsedVariables(@NotNull Pseudocode pseudocode) { + Set usedVariables = usedVariablesInEachDeclaration.get(pseudocode); + if (usedVariables == null) { + final Set result = Sets.newHashSet(); + PseudocodeTraverser.traverseAndAnalyzeInstructionGraph(pseudocode, true, new PseudocodeTraverser.SimpleInstructionDataAnalyzeStrategy() { + @Override + public void execute(@NotNull Instruction instruction) { + VariableDescriptor variableDescriptor = PseudocodeUtil.extractVariableDescriptorIfAny(instruction, false, + bindingContext); + if (variableDescriptor != null) { + result.add(variableDescriptor); + } + } + }); + usedVariables = Collections.unmodifiableSet(result); + usedVariablesInEachDeclaration.put(pseudocode, usedVariables); } - for (Instruction instruction : instructions) { - if (lookInside && instruction instanceof LocalDeclarationInstruction) { - traverseInstructionsGraph(((LocalDeclarationInstruction) instruction).getBody(), lookInside, straightDirection, - traverseInstructionGraphStrategy - ); - } - traverseInstructionGraphStrategy.execute(instruction, declarationDataMap.get(pseudocode), instructionDataMap.get(instruction)); - } - } - - public interface TraverseInstructionGraphStrategy { - void execute(@NotNull Instruction instruction, @NotNull DeclarationData declarationData, @NotNull InstructionData instructionData); - } - - private void collectDeclarationData(Pseudocode pseudocode) { - DeclarationData declarationData = new DeclarationData(pseudocode.getCorrespondingElement(), this, collectDeclaredVariables(pseudocode), collectUsedVariables(pseudocode)); - declarationDataMap.put(pseudocode, declarationData); - - for (LocalDeclarationInstruction localDeclarationInstruction : pseudocode.getLocalDeclarations()) { - collectDeclarationData(localDeclarationInstruction.getBody()); - } - } - - private Set collectUsedVariables(@NotNull Pseudocode pseudocode) { - final Set usedVariables = Sets.newHashSet(); - PseudocodeTraverser.traverseAndAnalyzeInstructionGraph(pseudocode, true, - new PseudocodeTraverser.SimpleInstructionDataAnalyzeStrategy() { - @Override - public void execute(@NotNull Instruction instruction) { - VariableDescriptor variableDescriptor = - extractVariableDescriptorIfAny(instruction, false); - if (variableDescriptor != null) { - usedVariables.add(variableDescriptor); - } - } - }); return usedVariables; } - private Set collectDeclaredVariables(@NotNull Pseudocode pseudocode) { - final Set declaredVariables = Sets.newHashSet(); - for (Instruction instruction : pseudocode.getInstructions()) { - if (instruction instanceof VariableDeclarationInstruction) { - JetDeclaration variableDeclarationElement = ((VariableDeclarationInstruction) instruction).getVariableDeclarationElement(); - DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, variableDeclarationElement); - if (descriptor != null) { - assert descriptor instanceof VariableDescriptor; - declaredVariables.add((VariableDescriptor) descriptor); + public Set getDeclaredVariables(@NotNull Pseudocode pseudocode) { + Set declaredVariables = declaredVariablesInEachDeclaration.get(pseudocode); + if (declaredVariables == null) { + declaredVariables = Sets.newHashSet(); + for (Instruction instruction : pseudocode.getInstructions()) { + if (instruction instanceof VariableDeclarationInstruction) { + JetDeclaration variableDeclarationElement = ((VariableDeclarationInstruction) instruction).getVariableDeclarationElement(); + DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, variableDeclarationElement); + if (descriptor != null) { + assert descriptor instanceof VariableDescriptor; + declaredVariables.add((VariableDescriptor) descriptor); + } } } + declaredVariables = Collections.unmodifiableSet(declaredVariables); + declaredVariablesInEachDeclaration.put(pseudocode, declaredVariables); } return declaredVariables; } // variable initializers - private Map>> collectVariableInitializers( - Pseudocode pseudocode, DeclarationData data) { - final Map initialMapForStartInstruction = prepareInitialMapForStartInstruction(data.usedVariables, data.declaredVariables); + @NotNull + public Map>> getVariableInitializers() { + if (variableInitializersMap == null) { + variableInitializersMap = getVariableInitializers(pseudocode); + } + return variableInitializersMap; + } - Map>> result = - PseudocodeTraverser.collectInformationFromInstructionGraph(false, true, pseudocode, Collections.emptyMap(), initialMapForStartInstruction, - new PseudocodeTraverser.InstructionDataMergeStrategy>() { + @NotNull + private Map>> getVariableInitializers(Pseudocode pseudocode) { + + Set usedVariables = getUsedVariables(pseudocode); + Set declaredVariables = getDeclaredVariables(pseudocode); + final Map initialMapForStartInstruction = prepareInitialMapForStartInstruction(usedVariables, declaredVariables); + + Map>> variableInitializersMap = PseudocodeTraverser.collectInformationFromInstructionGraph(false, true, pseudocode, + Collections.emptyMap(), initialMapForStartInstruction, + new PseudocodeTraverser.InstructionDataMergeStrategy>() { @Override public Edges> execute( @NotNull Instruction instruction, @@ -185,19 +131,17 @@ public class PseudocodeData { for (LocalDeclarationInstruction localDeclarationInstruction : pseudocode.getLocalDeclarations()) { Pseudocode localPseudocode = localDeclarationInstruction.getBody(); - Map>> initializersForLocalDeclaration = - collectVariableInitializers(localPseudocode, declarationDataMap.get(localPseudocode)); + Map>> initializersForLocalDeclaration = getVariableInitializers(localPseudocode); for (Instruction instruction : initializersForLocalDeclaration.keySet()) { //todo - if (!result.containsKey(instruction)) { - result.put(instruction, initializersForLocalDeclaration.get(instruction)); + if (!variableInitializersMap.containsKey(instruction)) { + variableInitializersMap.put(instruction, initializersForLocalDeclaration.get(instruction)); } } - result.putAll(initializersForLocalDeclaration); + variableInitializersMap.putAll(initializersForLocalDeclaration); } - - return result; + return variableInitializersMap; } private Map prepareInitialMapForStartInstruction(Collection usedVariables, Collection declaredVariables) { @@ -240,7 +184,7 @@ public class PseudocodeData { if (!(instruction instanceof WriteValueInstruction) && !(instruction instanceof VariableDeclarationInstruction)) { return enterInstructionData; } - VariableDescriptor variable = extractVariableDescriptorIfAny(instruction, false); + VariableDescriptor variable = PseudocodeUtil.extractVariableDescriptorIfAny(instruction, false, bindingContext); if (variable == null) { return enterInstructionData; } @@ -269,13 +213,16 @@ public class PseudocodeData { // variable use - private Map>> collectVariableStatusData() { + @NotNull + public Map>> getVariableStatusData() { + if (variableStatusMap == null) { Map sinkInstructionData = Maps.newHashMap(); - for (VariableDescriptor usedVariable : declarationDataMap.get(pseudocode).usedVariables) { + for (VariableDescriptor usedVariable : usedVariablesInEachDeclaration.get(pseudocode)) { sinkInstructionData.put(usedVariable, VariableUseStatus.UNUSED); } - return PseudocodeTraverser.collectInformationFromInstructionGraph(true, false, pseudocode, Collections.emptyMap(), sinkInstructionData, - new PseudocodeTraverser.InstructionDataMergeStrategy>() { + variableStatusMap = PseudocodeTraverser.collectInformationFromInstructionGraph(true, false, pseudocode, + Collections.emptyMap(), sinkInstructionData, + new PseudocodeTraverser.InstructionDataMergeStrategy>() { @Override public Edges> execute(@NotNull Instruction instruction, @NotNull Collection> incomingEdgesData) { Map enterResult = Maps.newHashMap(); @@ -286,7 +233,7 @@ public class PseudocodeData { enterResult.put(variableDescriptor, variableUseStatus.merge(enterResult.get(variableDescriptor))); } } - VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction, true); + VariableDescriptor variableDescriptor = PseudocodeUtil.extractVariableDescriptorIfAny(instruction, true, bindingContext); if (variableDescriptor == null || (!(instruction instanceof ReadValueInstruction) && !(instruction instanceof WriteValueInstruction))) { return Edges.create(enterResult, enterResult); } @@ -310,23 +257,98 @@ public class PseudocodeData { return Edges.create(enterResult, exitResult); } }); + } + return variableStatusMap; } -// Util methods + public static class VariableInitializers { + private final Set possibleLocalInitializers = Sets.newHashSet(); + private boolean isInitialized; + private boolean isDeclared; - @Nullable - public VariableDescriptor extractVariableDescriptorIfAny(@NotNull Instruction instruction, boolean onlyReference) { - JetElement element = null; - if (instruction instanceof ReadValueInstruction) { - element = ((ReadValueInstruction) instruction).getElement(); + public VariableInitializers(boolean isInitialized) { + this(isInitialized, false); } - else if (instruction instanceof WriteValueInstruction) { - element = ((WriteValueInstruction) instruction).getlValue(); + + public VariableInitializers(boolean isInitialized, boolean isDeclared) { + this.isInitialized = isInitialized; + this.isDeclared = isDeclared; } - else if (instruction instanceof VariableDeclarationInstruction) { - element = ((VariableDeclarationInstruction) instruction).getVariableDeclarationElement(); + + public VariableInitializers(JetElement element, @Nullable VariableInitializers previous) { + isInitialized = true; + isDeclared = element instanceof JetProperty || (previous != null && previous.isDeclared()); + possibleLocalInitializers.add(element); + } + + public VariableInitializers(Set edgesData) { + isInitialized = true; + isDeclared = true; + for (VariableInitializers edgeData : edgesData) { + if (!edgeData.isInitialized) { + isInitialized = false; + } + if (!edgeData.isDeclared) { + isDeclared = false; + } + possibleLocalInitializers.addAll(edgeData.possibleLocalInitializers); + } + } + + public Set getPossibleLocalInitializers() { + return possibleLocalInitializers; + } + + public boolean isInitialized() { + return isInitialized; + } + + public boolean isDeclared() { + return isDeclared; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof VariableInitializers)) return false; + + VariableInitializers that = (VariableInitializers) o; + + if (isDeclared != that.isDeclared) return false; + if (isInitialized != that.isInitialized) return false; + if (possibleLocalInitializers != null + ? !possibleLocalInitializers.equals(that.possibleLocalInitializers) + : that.possibleLocalInitializers != null) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + int result = possibleLocalInitializers != null ? possibleLocalInitializers.hashCode() : 0; + result = 31 * result + (isInitialized ? 1 : 0); + result = 31 * result + (isDeclared ? 1 : 0); + return result; } - return BindingContextUtils.extractVariableDescriptorIfAny(bindingContext, element, onlyReference); } + public static enum VariableUseStatus { + LAST_READ(3), + LAST_WRITTEN(2), + ONLY_WRITTEN_NEVER_READ(1), + UNUSED(0); + + private final int importance; + + VariableUseStatus(int importance) { + this.importance = importance; + } + + public VariableUseStatus merge(@Nullable VariableUseStatus variableUseStatus) { + if (variableUseStatus == null || importance > variableUseStatus.importance) return this; + return variableUseStatus; + } + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/data/DeclarationData.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/data/DeclarationData.java deleted file mode 100644 index f22d47136bc..00000000000 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/data/DeclarationData.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2010-2012 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.jet.lang.cfg.data; - -import org.jetbrains.jet.lang.descriptors.VariableDescriptor; -import org.jetbrains.jet.lang.psi.JetElement; - -import java.util.Set; - -/** - * @author svtk - */ -public class DeclarationData { - public final JetElement element; - public final PseudocodeData pseudocodeData; - public final Set declaredVariables; - public final Set usedVariables; - - public DeclarationData(JetElement element, - PseudocodeData data, - Set declaredVariables, - Set usedVariables) { - this.element = element; - pseudocodeData = data; - this.declaredVariables = declaredVariables; - this.usedVariables = usedVariables; - } -} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/data/Edges.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/data/Edges.java deleted file mode 100644 index 519a491743e..00000000000 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/data/Edges.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2010-2012 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.jet.lang.cfg.data; - -import org.jetbrains.annotations.NotNull; - -/** -* @author svtk -*/ -public class Edges { - public final T in; - public final T out; - - Edges(@NotNull T in, @NotNull T out) { - this.in = in; - this.out = out; - } - - public static Edges create(@NotNull T in, @NotNull T out) { - return new Edges(in, out); - } - - @NotNull - public T getIn() { - return in; - } - - @NotNull - public T getOut() { - return out; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof Edges)) return false; - - Edges edges = (Edges) o; - - if (in != null ? !in.equals(edges.in) : edges.in != null) return false; - if (out != null ? !out.equals(edges.out) : edges.out != null) return false; - - return true; - } - - @Override - public int hashCode() { - int result = in != null ? in.hashCode() : 0; - result = 31 * result + (out != null ? out.hashCode() : 0); - return result; - } -} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/data/InstructionData.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/data/InstructionData.java deleted file mode 100644 index 2a0df4cd178..00000000000 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/data/InstructionData.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2010-2012 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.jet.lang.cfg.data; - -import com.google.common.collect.Maps; -import com.intellij.openapi.util.Pair; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.cfg.pseudocode.Instruction; -import org.jetbrains.jet.lang.descriptors.VariableDescriptor; - -import java.util.Map; - -/** - * @author svtk - */ -public class InstructionData { - public final Instruction instruction; - public final PseudocodeData pseudocodeData; - - private final Map> initializersMap = Maps.newHashMap(); - private final Map> useStatusMap = Maps.newHashMap(); - - public InstructionData(@NotNull PseudocodeData data, @NotNull Instruction instruction, - @NotNull Edges> pairOfVariableInitializersMap, - @NotNull Edges> pairOfVariableStatusMap) { - pseudocodeData = data; - this.instruction = instruction; - - for (Map.Entry entry : pairOfVariableInitializersMap.out.entrySet()) { - VariableDescriptor variableDescriptor = entry.getKey(); - VariableInitializers in = pairOfVariableInitializersMap.in.get(variableDescriptor); - VariableInitializers out = entry.getValue(); - initializersMap.put(variableDescriptor, Edges.create(in, out)); - } - - for (Map.Entry entry : pairOfVariableStatusMap.out.entrySet()) { - VariableDescriptor variableDescriptor = entry.getKey(); - VariableUseStatus in = pairOfVariableStatusMap.in.get(variableDescriptor); - VariableUseStatus out = entry.getValue(); - if (in == null || out == null) continue; - useStatusMap.put(variableDescriptor, Edges.create(in, out)); - } - } - - @NotNull - public Map> getInitializersMap() { - return initializersMap; - } - - @NotNull - public Map> getUseStatusMap() { - return useStatusMap; - } -} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/data/VariableInitializers.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/data/VariableInitializers.java deleted file mode 100644 index c30cef1a60f..00000000000 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/data/VariableInitializers.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2010-2012 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.jet.lang.cfg.data; - -import com.google.common.collect.Sets; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.psi.JetElement; -import org.jetbrains.jet.lang.psi.JetProperty; - -import java.util.Set; - -/** -* @author svtk -*/ -public class VariableInitializers { - private final Set possibleLocalInitializers = Sets.newHashSet(); - private boolean isInitialized; - private boolean isDeclared; - - public VariableInitializers(boolean isInitialized) { - this(isInitialized, false); - } - - public VariableInitializers(boolean isInitialized, boolean isDeclared) { - this.isInitialized = isInitialized; - this.isDeclared = isDeclared; - } - - public VariableInitializers(JetElement element, @Nullable VariableInitializers previous) { - isInitialized = true; - isDeclared = element instanceof JetProperty || (previous != null && previous.isDeclared()); - possibleLocalInitializers.add(element); - } - - public VariableInitializers(Set edgesData) { - isInitialized = true; - isDeclared = true; - for (VariableInitializers edgeData : edgesData) { - if (!edgeData.isInitialized) { - isInitialized = false; - } - if (!edgeData.isDeclared) { - isDeclared = false; - } - possibleLocalInitializers.addAll(edgeData.possibleLocalInitializers); - } - } - - public Set getPossibleLocalInitializers() { - return possibleLocalInitializers; - } - - public boolean isInitialized() { - return isInitialized; - } - - public boolean isDeclared() { - return isDeclared; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof VariableInitializers)) return false; - - VariableInitializers that = (VariableInitializers) o; - - if (isDeclared != that.isDeclared) return false; - if (isInitialized != that.isInitialized) return false; - if (possibleLocalInitializers != null - ? !possibleLocalInitializers.equals(that.possibleLocalInitializers) - : that.possibleLocalInitializers != null) { - return false; - } - - return true; - } - - @Override - public int hashCode() { - int result = possibleLocalInitializers != null ? possibleLocalInitializers.hashCode() : 0; - result = 31 * result + (isInitialized ? 1 : 0); - result = 31 * result + (isDeclared ? 1 : 0); - return result; - } -} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/data/VariableUseStatus.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/data/VariableUseStatus.java deleted file mode 100644 index 0d1b6bb7a9e..00000000000 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/data/VariableUseStatus.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2010-2012 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.jet.lang.cfg.data; - -import org.jetbrains.annotations.Nullable; - -/** -* @author svtk -*/ -public enum VariableUseStatus { - LAST_READ(3), - LAST_WRITTEN(2), - ONLY_WRITTEN_NEVER_READ(1), - UNUSED(0); - - private final int importance; - - VariableUseStatus(int importance) { - this.importance = importance; - } - - public VariableUseStatus merge(@Nullable VariableUseStatus variableUseStatus) { - if (variableUseStatus == null || importance > variableUseStatus.importance) return this; - return variableUseStatus; - } -} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/PseudocodeUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/PseudocodeUtil.java index f82ce6c46d6..cffada00275 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/PseudocodeUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/PseudocodeUtil.java @@ -17,10 +17,14 @@ package org.jetbrains.jet.lang.cfg.pseudocode; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.cfg.JetControlFlowProcessor; +import org.jetbrains.jet.lang.descriptors.VariableDescriptor; import org.jetbrains.jet.lang.diagnostics.Diagnostic; import org.jetbrains.jet.lang.psi.JetDeclaration; +import org.jetbrains.jet.lang.psi.JetElement; import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.BindingContextUtils; import org.jetbrains.jet.lang.resolve.BindingTrace; import org.jetbrains.jet.util.slicedmap.ReadOnlySlice; import org.jetbrains.jet.util.slicedmap.WritableSlice; @@ -65,4 +69,18 @@ public class PseudocodeUtil { return new JetControlFlowProcessor(mockTrace).generatePseudocode(declaration); } + @Nullable + public static VariableDescriptor extractVariableDescriptorIfAny(@NotNull Instruction instruction, boolean onlyReference, @NotNull BindingContext bindingContext) { + JetElement element = null; + if (instruction instanceof ReadValueInstruction) { + element = ((ReadValueInstruction) instruction).getElement(); + } + else if (instruction instanceof WriteValueInstruction) { + element = ((WriteValueInstruction) instruction).getlValue(); + } + else if (instruction instanceof VariableDeclarationInstruction) { + element = ((VariableDeclarationInstruction) instruction).getVariableDeclarationElement(); + } + return BindingContextUtils.extractVariableDescriptorIfAny(bindingContext, element, onlyReference); + } }