lazy computing of pseudocode variables data

no need in special 'data' classes
This commit is contained in:
Svetlana Isakova
2012-05-26 16:30:50 +04:00
parent cdcedbe6ed
commit 8acfa20a02
9 changed files with 289 additions and 516 deletions
@@ -23,8 +23,10 @@ import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTreeUtil;
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.data.*;
import org.jetbrains.jet.lang.cfg.pseudocode.*; 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.descriptors.*;
import org.jetbrains.jet.lang.diagnostics.Errors; import org.jetbrains.jet.lang.diagnostics.Errors;
import org.jetbrains.jet.lang.psi.*; 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.lexer.JetTokens;
import org.jetbrains.jet.plugin.JetMainDetector; import org.jetbrains.jet.plugin.JetMainDetector;
import java.util.Collection; import java.util.*;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import static org.jetbrains.jet.lang.diagnostics.Errors.*; import static org.jetbrains.jet.lang.diagnostics.Errors.*;
import static org.jetbrains.jet.lang.resolve.BindingContext.CAPTURED_IN_CLOSURE; import static org.jetbrains.jet.lang.resolve.BindingContext.CAPTURED_IN_CLOSURE;
@@ -53,7 +52,7 @@ public class JetFlowInformationProvider {
private final JetDeclaration subroutine; private final JetDeclaration subroutine;
private final Pseudocode pseudocode; private final Pseudocode pseudocode;
private final PseudocodeData pseudocodeData; private final PseudocodeVariablesData pseudocodeData;
private BindingTrace trace; private BindingTrace trace;
public JetFlowInformationProvider( public JetFlowInformationProvider(
@@ -63,7 +62,7 @@ public class JetFlowInformationProvider {
subroutine = declaration; subroutine = declaration;
this.trace = trace; this.trace = trace;
pseudocode = new JetControlFlowProcessor(trace).generatePseudocode(declaration); pseudocode = new JetControlFlowProcessor(trace).generatePseudocode(declaration);
pseudocodeData = new PseudocodeData(pseudocode, trace.getBindingContext()); pseudocodeData = new PseudocodeVariablesData(pseudocode, trace.getBindingContext());
} }
private void collectReturnExpressions(@NotNull final Collection<JetElement> returnedExpressions) { private void collectReturnExpressions(@NotNull final Collection<JetElement> returnedExpressions) {
@@ -124,7 +123,6 @@ public class JetFlowInformationProvider {
public void checkDefiniteReturn(final @NotNull JetType expectedReturnType) { public void checkDefiniteReturn(final @NotNull JetType expectedReturnType) {
assert subroutine instanceof JetDeclarationWithBody; assert subroutine instanceof JetDeclarationWithBody;
JetDeclarationWithBody function = (JetDeclarationWithBody) subroutine; JetDeclarationWithBody function = (JetDeclarationWithBody) subroutine;
assert function instanceof JetDeclaration;
JetExpression bodyExpression = function.getBodyExpression(); JetExpression bodyExpression = function.getBodyExpression();
if (bodyExpression == null) return; if (bodyExpression == null) return;
@@ -189,43 +187,47 @@ public class JetFlowInformationProvider {
final Collection<VariableDescriptor> varWithValReassignErrorGenerated = Sets.newHashSet(); final Collection<VariableDescriptor> varWithValReassignErrorGenerated = Sets.newHashSet();
final boolean processClassOrObject = subroutine instanceof JetClassOrObject; final boolean processClassOrObject = subroutine instanceof JetClassOrObject;
pseudocodeData.traverseInstructionsGraph(true, true, new PseudocodeData.TraverseInstructionGraphStrategy() { Map<Instruction, Edges<Map<VariableDescriptor,VariableInitializers>>> initializers = pseudocodeData.getVariableInitializers();
final Set<VariableDescriptor> declaredVariables = pseudocodeData.getDeclaredVariables(pseudocode);
PseudocodeTraverser.traverseAndAnalyzeInstructionGraph(true, pseudocode, initializers, true, new PseudocodeTraverser.InstructionDataAnalyzeStrategy<Map<VariableDescriptor, VariableInitializers>>() {
@Override @Override
public void execute(@NotNull Instruction instruction, @NotNull DeclarationData declarationData, @NotNull InstructionData instructionData) { public void execute(@NotNull Instruction instruction,
//todo move to util @Nullable Map<VariableDescriptor, VariableInitializers> in,
VariableDescriptor variableDescriptor = pseudocodeData.extractVariableDescriptorIfAny(instruction, true); @Nullable Map<VariableDescriptor, VariableInitializers> out) {
assert in != null && out != null;
VariableDescriptor variableDescriptor = PseudocodeUtil.extractVariableDescriptorIfAny(instruction, true,
trace.getBindingContext());
if (variableDescriptor == null) return; if (variableDescriptor == null) return;
if (!(instruction instanceof ReadValueInstruction) && !(instruction instanceof WriteValueInstruction)) return; if (!(instruction instanceof ReadValueInstruction) && !(instruction instanceof WriteValueInstruction)) return;
Edges<VariableInitializers> variableInitializers = instructionData.getInitializersMap().get( VariableInitializers outInitializers = out.get(variableDescriptor);
variableDescriptor);
if (variableInitializers == null) return;
if (instruction instanceof ReadValueInstruction) { if (instruction instanceof ReadValueInstruction) {
JetElement element = ((ReadValueInstruction) instruction).getElement(); JetElement element = ((ReadValueInstruction) instruction).getElement();
boolean error = checkBackingField(variableDescriptor, element); boolean error = checkBackingField(variableDescriptor, element);
if (!error && declarationData.declaredVariables.contains(variableDescriptor)) { if (!error && declaredVariables.contains(variableDescriptor)) {
checkIsInitialized(variableDescriptor, element, variableInitializers.getOut(), varWithUninitializedErrorGenerated); checkIsInitialized(variableDescriptor, element, outInitializers, varWithUninitializedErrorGenerated);
} }
return; return;
} }
JetElement element = ((WriteValueInstruction) instruction).getlValue(); JetElement element = ((WriteValueInstruction) instruction).getlValue();
boolean error = checkBackingField(variableDescriptor, element); boolean error = checkBackingField(variableDescriptor, element);
if (!(element instanceof JetExpression)) return; 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 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) { if (!error && processClassOrObject) {
error = checkAssignmentBeforeDeclaration(variableDescriptor, (JetExpression) element, variableInitializers.getIn(), variableInitializers.getOut()); error = checkAssignmentBeforeDeclaration(variableDescriptor, (JetExpression) element, inInitializers, outInitializers);
} }
if (!error && processClassOrObject) { if (!error && processClassOrObject) {
checkInitializationUsingBackingField(variableDescriptor, (JetExpression) element, variableInitializers.getIn(), variableInitializers.getOut()); checkInitializationUsingBackingField(variableDescriptor, (JetExpression) element, inInitializers, outInitializers);
} }
} }
}); });
Pseudocode pseudocode = pseudocodeData.getPseudocode(); Pseudocode pseudocode = pseudocodeData.getPseudocode();
recordInitializedVariables(pseudocodeData.getDeclarationData(pseudocode), pseudocodeData.getResultInfo(pseudocode)); recordInitializedVariables(pseudocode, initializers);
for (LocalDeclarationInstruction instruction : pseudocode.getLocalDeclarations()) { for (LocalDeclarationInstruction instruction : pseudocode.getLocalDeclarations()) {
recordInitializedVariables(pseudocodeData.getDeclarationData(instruction.getBody()), pseudocodeData.getResultInfo(instruction.getBody())); recordInitializedVariables(instruction.getBody(), initializers);
} }
} }
@@ -244,7 +246,8 @@ public class JetFlowInformationProvider {
if (!isInitialized && !varWithUninitializedErrorGenerated.contains(variableDescriptor)) { if (!isInitialized && !varWithUninitializedErrorGenerated.contains(variableDescriptor)) {
varWithUninitializedErrorGenerated.add(variableDescriptor); varWithUninitializedErrorGenerated.add(variableDescriptor);
if (variableDescriptor instanceof ValueParameterDescriptor) { 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 { else {
trace.report(Errors.UNINITIALIZED_VARIABLE.on((JetSimpleNameExpression) element, variableDescriptor)); trace.report(Errors.UNINITIALIZED_VARIABLE.on((JetSimpleNameExpression) element, variableDescriptor));
@@ -392,12 +395,15 @@ public class JetFlowInformationProvider {
return false; return false;
} }
private void recordInitializedVariables(DeclarationData declarationData, InstructionData instructionData) { private void recordInitializedVariables(@NotNull Pseudocode pseudocode, @NotNull Map<Instruction, Edges<Map<VariableDescriptor,VariableInitializers>>> initializersMap) {
for (VariableDescriptor variable : declarationData.usedVariables) { Edges<Map<VariableDescriptor, VariableInitializers>> initializers = initializersMap.get(pseudocode.getExitInstruction());
if (variable instanceof PropertyDescriptor && declarationData.declaredVariables.contains(variable)) { Set<VariableDescriptor> usedVariables = pseudocodeData.getUsedVariables(pseudocode);
Edges<VariableInitializers> variableInitializers = instructionData.getInitializersMap().get(variable); Set<VariableDescriptor> 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; 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 // "Unused variable" & "unused value" analyses
public void markUnusedVariables() { public void markUnusedVariables() {
pseudocodeData.traverseInstructionsGraph(true, false, new PseudocodeData.TraverseInstructionGraphStrategy() { Map<Instruction, Edges<Map<VariableDescriptor, VariableUseStatus>>> variableStatusData = pseudocodeData.getVariableStatusData();
PseudocodeTraverser.traverseAndAnalyzeInstructionGraph(true, pseudocode, variableStatusData, false, new PseudocodeTraverser.InstructionDataAnalyzeStrategy<Map<VariableDescriptor, VariableUseStatus>>() {
@Override @Override
public void execute(@NotNull Instruction instruction, @NotNull DeclarationData declarationData, @NotNull InstructionData instructionData) { public void execute(@NotNull Instruction instruction,
VariableDescriptor variableDescriptor = pseudocodeData.extractVariableDescriptorIfAny(instruction, false); @Nullable Map<VariableDescriptor, VariableUseStatus> in,
if (variableDescriptor == null || !declarationData.declaredVariables.contains(variableDescriptor) || @Nullable Map<VariableDescriptor, VariableUseStatus> out) {
assert in != null && out != null;
Set<VariableDescriptor> 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; !DescriptorUtils.isLocal(variableDescriptor.getContainingDeclaration(), variableDescriptor)) return;
Edges<VariableUseStatus> statusEdgesData = instructionData.getUseStatusMap().get(variableDescriptor); VariableUseStatus variableUseStatus = in.get(variableDescriptor);
VariableUseStatus variableUseStatus = statusEdgesData != null ? statusEdgesData.getIn() : null;
if (instruction instanceof WriteValueInstruction) { if (instruction instanceof WriteValueInstruction) {
if (trace.get(CAPTURED_IN_CLOSURE, variableDescriptor)) return; if (trace.get(CAPTURED_IN_CLOSURE, variableDescriptor)) return;
JetElement element = ((WriteValueInstruction) instruction).getElement(); JetElement element = ((WriteValueInstruction) instruction).getElement();
@@ -480,7 +492,6 @@ public class JetFlowInformationProvider {
} }
}); });
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -488,11 +499,13 @@ public class JetFlowInformationProvider {
public void markUnusedLiteralsInBlock() { public void markUnusedLiteralsInBlock() {
assert pseudocode != null; assert pseudocode != null;
PseudocodeTraverser.traverseAndAnalyzeInstructionGraph(pseudocode, true, new PseudocodeTraverser.SimpleInstructionDataAnalyzeStrategy() { PseudocodeTraverser.traverseAndAnalyzeInstructionGraph(
pseudocode, true, new PseudocodeTraverser.SimpleInstructionDataAnalyzeStrategy() {
@Override @Override
public void execute(@NotNull Instruction instruction) { public void execute(@NotNull Instruction instruction) {
if (!(instruction instanceof ReadValueInstruction)) return; if (!(instruction instanceof ReadValueInstruction)) return;
JetElement element = ((ReadValueInstruction) instruction).getElement(); JetElement element =
((ReadValueInstruction) instruction).getElement();
if (!(element instanceof JetFunctionLiteralExpression if (!(element instanceof JetFunctionLiteralExpression
|| element instanceof JetConstantExpression || element instanceof JetConstantExpression
|| element instanceof JetStringTemplateExpression || element instanceof JetStringTemplateExpression
@@ -503,7 +516,8 @@ public class JetFlowInformationProvider {
if (parent instanceof JetBlockExpression) { if (parent instanceof JetBlockExpression) {
if (!JetPsiUtil.isImplicitlyUsed(element)) { if (!JetPsiUtil.isImplicitlyUsed(element)) {
if (element instanceof JetFunctionLiteralExpression) { if (element instanceof JetFunctionLiteralExpression) {
trace.report(Errors.UNUSED_FUNCTION_LITERAL.on((JetFunctionLiteralExpression) element)); trace.report(Errors.UNUSED_FUNCTION_LITERAL
.on((JetFunctionLiteralExpression) element));
} }
else { else {
trace.report(Errors.UNUSED_EXPRESSION.on(element)); trace.report(Errors.UNUSED_EXPRESSION.on(element));
@@ -21,7 +21,6 @@ import com.google.common.collect.Maps;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
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.data.Edges;
import org.jetbrains.jet.lang.cfg.pseudocode.*; import org.jetbrains.jet.lang.cfg.pseudocode.*;
import java.util.Collection; import java.util.Collection;
@@ -134,11 +133,7 @@ public class PseudocodeTraverser {
@NotNull Pseudocode pseudocode, @NotNull Pseudocode pseudocode,
boolean directOrder, boolean directOrder,
SimpleInstructionDataAnalyzeStrategy instructionDataAnalyzeStrategy) { SimpleInstructionDataAnalyzeStrategy instructionDataAnalyzeStrategy) {
List<Instruction> instructions = pseudocode.getInstructions(); List<Instruction> instructions = directOrder ? pseudocode.getInstructions() : pseudocode.getReversedInstructions();
if (!directOrder) {
instructions = Lists.newArrayList(instructions);
Collections.reverse(instructions);
}
for (Instruction instruction : instructions) { for (Instruction instruction : instructions) {
if (instruction instanceof LocalDeclarationInstruction) { if (instruction instanceof LocalDeclarationInstruction) {
traverseAndAnalyzeInstructionGraph(((LocalDeclarationInstruction) instruction).getBody(), directOrder, instructionDataAnalyzeStrategy); traverseAndAnalyzeInstructionGraph(((LocalDeclarationInstruction) instruction).getBody(), directOrder, instructionDataAnalyzeStrategy);
@@ -153,11 +148,7 @@ public class PseudocodeTraverser {
@NotNull Map<Instruction, Edges<D>> dataMap, @NotNull Map<Instruction, Edges<D>> dataMap,
boolean directOrder, boolean directOrder,
@NotNull InstructionDataAnalyzeStrategy<D> instructionDataAnalyzeStrategy) { @NotNull InstructionDataAnalyzeStrategy<D> instructionDataAnalyzeStrategy) {
List<Instruction> instructions = pseudocode.getInstructions(); List<Instruction> instructions = directOrder ? pseudocode.getInstructions() : pseudocode.getReversedInstructions();
if (!directOrder) {
instructions = Lists.newArrayList(instructions);
Collections.reverse(instructions);
}
for (Instruction instruction : instructions) { for (Instruction instruction : instructions) {
if (lookInside && instruction instanceof LocalDeclarationInstruction) { if (lookInside && instruction instanceof LocalDeclarationInstruction) {
traverseAndAnalyzeInstructionGraph(lookInside, ((LocalDeclarationInstruction) instruction).getBody(), dataMap, directOrder, instructionDataAnalyzeStrategy); traverseAndAnalyzeInstructionGraph(lookInside, ((LocalDeclarationInstruction) instruction).getBody(), dataMap, directOrder, instructionDataAnalyzeStrategy);
@@ -178,4 +169,48 @@ public class PseudocodeTraverser {
public interface SimpleInstructionDataAnalyzeStrategy { public interface SimpleInstructionDataAnalyzeStrategy {
void execute(@NotNull Instruction instruction); void execute(@NotNull Instruction instruction);
} }
public static class Edges<T> {
public final T in;
public final T out;
Edges(@NotNull T in, @NotNull T out) {
this.in = in;
this.out = out;
}
public static <T> Edges<T> create(@NotNull T in, @NotNull T out) {
return new Edges<T>(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;
}
}
} }
@@ -14,14 +14,13 @@
* limitations under the License. * 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.Maps;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
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.PseudocodeTraverser; import org.jetbrains.jet.lang.cfg.PseudocodeTraverser.Edges;
import org.jetbrains.jet.lang.cfg.pseudocode.*; import org.jetbrains.jet.lang.cfg.pseudocode.*;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor; 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.JetElement;
import org.jetbrains.jet.lang.psi.JetProperty; import org.jetbrains.jet.lang.psi.JetProperty;
import org.jetbrains.jet.lang.resolve.BindingContext; 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 * @author svtk
*/ */
public class PseudocodeData { public class PseudocodeVariablesData {
private final Pseudocode pseudocode; private final Pseudocode pseudocode;
private final Map<Instruction, InstructionData> instructionDataMap = Maps.newLinkedHashMap();
private final Map<Pseudocode, DeclarationData> declarationDataMap = Maps.newLinkedHashMap();
//private final Map<Pseudocode, Set<VariableDescriptor>> declaredVariablesInEachDeclaration;
//private final Map<Pseudocode, Set<VariableDescriptor>> usedVariablesInEachDeclaration;
private final BindingContext bindingContext; private final BindingContext bindingContext;
public PseudocodeData(@NotNull Pseudocode pseudocode, @NotNull BindingContext bindingContext) { private final Map<Pseudocode, Set<VariableDescriptor>> declaredVariablesInEachDeclaration = Maps.newHashMap();
private final Map<Pseudocode, Set<VariableDescriptor>> usedVariablesInEachDeclaration = Maps.newHashMap();
private Map<Instruction, Edges<Map<VariableDescriptor, VariableInitializers>>> variableInitializersMap;
private Map<Instruction, Edges<Map<VariableDescriptor, VariableUseStatus>>> variableStatusMap;
public PseudocodeVariablesData(@NotNull Pseudocode pseudocode, @NotNull BindingContext bindingContext) {
this.pseudocode = pseudocode; this.pseudocode = pseudocode;
this.bindingContext = bindingContext; this.bindingContext = bindingContext;
collectDeclarationData(pseudocode);
DeclarationData declarationData = declarationDataMap.get(pseudocode);
final Map<Instruction, Edges<Map<VariableDescriptor, VariableInitializers>>> variableInitializersMap =
collectVariableInitializers(pseudocode, declarationData);
final Map<Instruction, Edges<Map<VariableDescriptor, VariableUseStatus>>> 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 @NotNull
@@ -79,98 +57,66 @@ public class PseudocodeData {
return pseudocode; return pseudocode;
} }
@NotNull public Set<VariableDescriptor> getUsedVariables(@NotNull Pseudocode pseudocode) {
public Map<Instruction, InstructionData> getInstructionDataMap() { Set<VariableDescriptor> usedVariables = usedVariablesInEachDeclaration.get(pseudocode);
return instructionDataMap; if (usedVariables == null) {
} final Set<VariableDescriptor> result = Sets.newHashSet();
PseudocodeTraverser.traverseAndAnalyzeInstructionGraph(pseudocode, true, new PseudocodeTraverser.SimpleInstructionDataAnalyzeStrategy() {
@NotNull @Override
public DeclarationData getDeclarationData(Pseudocode pseudocode) { public void execute(@NotNull Instruction instruction) {
return declarationDataMap.get(pseudocode); VariableDescriptor variableDescriptor = PseudocodeUtil.extractVariableDescriptorIfAny(instruction, false,
} bindingContext);
if (variableDescriptor != null) {
@NotNull result.add(variableDescriptor);
public InstructionData getResultInfo(Pseudocode pseudocode) { }
return instructionDataMap.get(pseudocode.getExitInstruction()); }
} });
usedVariables = Collections.unmodifiableSet(result);
public void traverseInstructionsGraph(boolean lookInside, boolean straightDirection, usedVariablesInEachDeclaration.put(pseudocode, usedVariables);
@NotNull TraverseInstructionGraphStrategy traverseInstructionGraphStrategy) {
traverseInstructionsGraph(pseudocode, lookInside, straightDirection, traverseInstructionGraphStrategy);
}
private void traverseInstructionsGraph(@NotNull Pseudocode pseudocode,
boolean lookInside,
boolean straightDirection,
@NotNull TraverseInstructionGraphStrategy traverseInstructionGraphStrategy) {
List<Instruction> instructions = pseudocode.getInstructions();
if (!straightDirection) {
instructions = Lists.newArrayList(instructions);
Collections.reverse(instructions);
} }
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<VariableDescriptor> collectUsedVariables(@NotNull Pseudocode pseudocode) {
final Set<VariableDescriptor> 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; return usedVariables;
} }
private Set<VariableDescriptor> collectDeclaredVariables(@NotNull Pseudocode pseudocode) { public Set<VariableDescriptor> getDeclaredVariables(@NotNull Pseudocode pseudocode) {
final Set<VariableDescriptor> declaredVariables = Sets.newHashSet(); Set<VariableDescriptor> declaredVariables = declaredVariablesInEachDeclaration.get(pseudocode);
for (Instruction instruction : pseudocode.getInstructions()) { if (declaredVariables == null) {
if (instruction instanceof VariableDeclarationInstruction) { declaredVariables = Sets.newHashSet();
JetDeclaration variableDeclarationElement = ((VariableDeclarationInstruction) instruction).getVariableDeclarationElement(); for (Instruction instruction : pseudocode.getInstructions()) {
DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, variableDeclarationElement); if (instruction instanceof VariableDeclarationInstruction) {
if (descriptor != null) { JetDeclaration variableDeclarationElement = ((VariableDeclarationInstruction) instruction).getVariableDeclarationElement();
assert descriptor instanceof VariableDescriptor; DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, variableDeclarationElement);
declaredVariables.add((VariableDescriptor) descriptor); if (descriptor != null) {
assert descriptor instanceof VariableDescriptor;
declaredVariables.add((VariableDescriptor) descriptor);
}
} }
} }
declaredVariables = Collections.unmodifiableSet(declaredVariables);
declaredVariablesInEachDeclaration.put(pseudocode, declaredVariables);
} }
return declaredVariables; return declaredVariables;
} }
// variable initializers // variable initializers
private Map<Instruction, Edges<Map<VariableDescriptor, VariableInitializers>>> collectVariableInitializers( @NotNull
Pseudocode pseudocode, DeclarationData data) { public Map<Instruction, Edges<Map<VariableDescriptor, VariableInitializers>>> getVariableInitializers() {
final Map<VariableDescriptor, VariableInitializers> initialMapForStartInstruction = prepareInitialMapForStartInstruction(data.usedVariables, data.declaredVariables); if (variableInitializersMap == null) {
variableInitializersMap = getVariableInitializers(pseudocode);
}
return variableInitializersMap;
}
Map<Instruction, Edges<Map<VariableDescriptor, VariableInitializers>>> result = @NotNull
PseudocodeTraverser.collectInformationFromInstructionGraph(false, true, pseudocode, Collections.<VariableDescriptor, VariableInitializers>emptyMap(), initialMapForStartInstruction, private Map<Instruction, Edges<Map<VariableDescriptor, VariableInitializers>>> getVariableInitializers(Pseudocode pseudocode) {
new PseudocodeTraverser.InstructionDataMergeStrategy<Map<VariableDescriptor, VariableInitializers>>() {
Set<VariableDescriptor> usedVariables = getUsedVariables(pseudocode);
Set<VariableDescriptor> declaredVariables = getDeclaredVariables(pseudocode);
final Map<VariableDescriptor, VariableInitializers> initialMapForStartInstruction = prepareInitialMapForStartInstruction(usedVariables, declaredVariables);
Map<Instruction, Edges<Map<VariableDescriptor, VariableInitializers>>> variableInitializersMap = PseudocodeTraverser.collectInformationFromInstructionGraph(false, true, pseudocode,
Collections.<VariableDescriptor, VariableInitializers>emptyMap(), initialMapForStartInstruction,
new PseudocodeTraverser.InstructionDataMergeStrategy<Map<VariableDescriptor, VariableInitializers>>() {
@Override @Override
public Edges<Map<VariableDescriptor, VariableInitializers>> execute( public Edges<Map<VariableDescriptor, VariableInitializers>> execute(
@NotNull Instruction instruction, @NotNull Instruction instruction,
@@ -185,19 +131,17 @@ public class PseudocodeData {
for (LocalDeclarationInstruction localDeclarationInstruction : pseudocode.getLocalDeclarations()) { for (LocalDeclarationInstruction localDeclarationInstruction : pseudocode.getLocalDeclarations()) {
Pseudocode localPseudocode = localDeclarationInstruction.getBody(); Pseudocode localPseudocode = localDeclarationInstruction.getBody();
Map<Instruction, Edges<Map<VariableDescriptor, VariableInitializers>>> initializersForLocalDeclaration = Map<Instruction, Edges<Map<VariableDescriptor, VariableInitializers>>> initializersForLocalDeclaration = getVariableInitializers(localPseudocode);
collectVariableInitializers(localPseudocode, declarationDataMap.get(localPseudocode));
for (Instruction instruction : initializersForLocalDeclaration.keySet()) { for (Instruction instruction : initializersForLocalDeclaration.keySet()) {
//todo //todo
if (!result.containsKey(instruction)) { if (!variableInitializersMap.containsKey(instruction)) {
result.put(instruction, initializersForLocalDeclaration.get(instruction)); variableInitializersMap.put(instruction, initializersForLocalDeclaration.get(instruction));
} }
} }
result.putAll(initializersForLocalDeclaration); variableInitializersMap.putAll(initializersForLocalDeclaration);
} }
return variableInitializersMap;
return result;
} }
private Map<VariableDescriptor, VariableInitializers> prepareInitialMapForStartInstruction(Collection<VariableDescriptor> usedVariables, Collection<VariableDescriptor> declaredVariables) { private Map<VariableDescriptor, VariableInitializers> prepareInitialMapForStartInstruction(Collection<VariableDescriptor> usedVariables, Collection<VariableDescriptor> declaredVariables) {
@@ -240,7 +184,7 @@ public class PseudocodeData {
if (!(instruction instanceof WriteValueInstruction) && !(instruction instanceof VariableDeclarationInstruction)) { if (!(instruction instanceof WriteValueInstruction) && !(instruction instanceof VariableDeclarationInstruction)) {
return enterInstructionData; return enterInstructionData;
} }
VariableDescriptor variable = extractVariableDescriptorIfAny(instruction, false); VariableDescriptor variable = PseudocodeUtil.extractVariableDescriptorIfAny(instruction, false, bindingContext);
if (variable == null) { if (variable == null) {
return enterInstructionData; return enterInstructionData;
} }
@@ -269,13 +213,16 @@ public class PseudocodeData {
// variable use // variable use
private Map<Instruction, Edges<Map<VariableDescriptor, VariableUseStatus>>> collectVariableStatusData() { @NotNull
public Map<Instruction, Edges<Map<VariableDescriptor, VariableUseStatus>>> getVariableStatusData() {
if (variableStatusMap == null) {
Map<VariableDescriptor, VariableUseStatus> sinkInstructionData = Maps.newHashMap(); Map<VariableDescriptor, VariableUseStatus> sinkInstructionData = Maps.newHashMap();
for (VariableDescriptor usedVariable : declarationDataMap.get(pseudocode).usedVariables) { for (VariableDescriptor usedVariable : usedVariablesInEachDeclaration.get(pseudocode)) {
sinkInstructionData.put(usedVariable, VariableUseStatus.UNUSED); sinkInstructionData.put(usedVariable, VariableUseStatus.UNUSED);
} }
return PseudocodeTraverser.collectInformationFromInstructionGraph(true, false, pseudocode, Collections.<VariableDescriptor, VariableUseStatus>emptyMap(), sinkInstructionData, variableStatusMap = PseudocodeTraverser.collectInformationFromInstructionGraph(true, false, pseudocode,
new PseudocodeTraverser.InstructionDataMergeStrategy<Map<VariableDescriptor, VariableUseStatus>>() { Collections.<VariableDescriptor, VariableUseStatus>emptyMap(), sinkInstructionData,
new PseudocodeTraverser.InstructionDataMergeStrategy<Map<VariableDescriptor, VariableUseStatus>>() {
@Override @Override
public Edges<Map<VariableDescriptor, VariableUseStatus>> execute(@NotNull Instruction instruction, @NotNull Collection<Map<VariableDescriptor, VariableUseStatus>> incomingEdgesData) { public Edges<Map<VariableDescriptor, VariableUseStatus>> execute(@NotNull Instruction instruction, @NotNull Collection<Map<VariableDescriptor, VariableUseStatus>> incomingEdgesData) {
Map<VariableDescriptor, VariableUseStatus> enterResult = Maps.newHashMap(); Map<VariableDescriptor, VariableUseStatus> enterResult = Maps.newHashMap();
@@ -286,7 +233,7 @@ public class PseudocodeData {
enterResult.put(variableDescriptor, variableUseStatus.merge(enterResult.get(variableDescriptor))); 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))) { if (variableDescriptor == null || (!(instruction instanceof ReadValueInstruction) && !(instruction instanceof WriteValueInstruction))) {
return Edges.create(enterResult, enterResult); return Edges.create(enterResult, enterResult);
} }
@@ -310,23 +257,98 @@ public class PseudocodeData {
return Edges.create(enterResult, exitResult); return Edges.create(enterResult, exitResult);
} }
}); });
}
return variableStatusMap;
} }
// Util methods public static class VariableInitializers {
private final Set<JetElement> possibleLocalInitializers = Sets.newHashSet();
private boolean isInitialized;
private boolean isDeclared;
@Nullable public VariableInitializers(boolean isInitialized) {
public VariableDescriptor extractVariableDescriptorIfAny(@NotNull Instruction instruction, boolean onlyReference) { this(isInitialized, false);
JetElement element = null;
if (instruction instanceof ReadValueInstruction) {
element = ((ReadValueInstruction) instruction).getElement();
} }
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<VariableInitializers> 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<JetElement> 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;
}
}
} }
@@ -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<VariableDescriptor> declaredVariables;
public final Set<VariableDescriptor> usedVariables;
public DeclarationData(JetElement element,
PseudocodeData data,
Set<VariableDescriptor> declaredVariables,
Set<VariableDescriptor> usedVariables) {
this.element = element;
pseudocodeData = data;
this.declaredVariables = declaredVariables;
this.usedVariables = usedVariables;
}
}
@@ -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<T> {
public final T in;
public final T out;
Edges(@NotNull T in, @NotNull T out) {
this.in = in;
this.out = out;
}
public static <T> Edges<T> create(@NotNull T in, @NotNull T out) {
return new Edges<T>(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;
}
}
@@ -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<VariableDescriptor, Edges<VariableInitializers>> initializersMap = Maps.newHashMap();
private final Map<VariableDescriptor, Edges<VariableUseStatus>> useStatusMap = Maps.newHashMap();
public InstructionData(@NotNull PseudocodeData data, @NotNull Instruction instruction,
@NotNull Edges<Map<VariableDescriptor, VariableInitializers>> pairOfVariableInitializersMap,
@NotNull Edges<Map<VariableDescriptor, VariableUseStatus>> pairOfVariableStatusMap) {
pseudocodeData = data;
this.instruction = instruction;
for (Map.Entry<VariableDescriptor, VariableInitializers> 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<VariableDescriptor, VariableUseStatus> 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<VariableDescriptor, Edges<VariableInitializers>> getInitializersMap() {
return initializersMap;
}
@NotNull
public Map<VariableDescriptor, Edges<VariableUseStatus>> getUseStatusMap() {
return useStatusMap;
}
}
@@ -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<JetElement> 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<VariableInitializers> 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<JetElement> 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;
}
}
@@ -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;
}
}
@@ -17,10 +17,14 @@
package org.jetbrains.jet.lang.cfg.pseudocode; package org.jetbrains.jet.lang.cfg.pseudocode;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.cfg.JetControlFlowProcessor; 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.diagnostics.Diagnostic;
import org.jetbrains.jet.lang.psi.JetDeclaration; 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.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
import org.jetbrains.jet.lang.resolve.BindingTrace; import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.util.slicedmap.ReadOnlySlice; import org.jetbrains.jet.util.slicedmap.ReadOnlySlice;
import org.jetbrains.jet.util.slicedmap.WritableSlice; import org.jetbrains.jet.util.slicedmap.WritableSlice;
@@ -65,4 +69,18 @@ public class PseudocodeUtil {
return new JetControlFlowProcessor(mockTrace).generatePseudocode(declaration); 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);
}
} }