no need in possible local initializers

for each variable for each instruction
rename
This commit is contained in:
Svetlana Isakova
2012-05-28 13:48:49 +04:00
parent 468052c3a5
commit de67cae571
3 changed files with 120 additions and 151 deletions
@@ -25,8 +25,8 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.cfg.pseudocode.*; import org.jetbrains.jet.lang.cfg.pseudocode.*;
import org.jetbrains.jet.lang.cfg.PseudocodeTraverser.*; import org.jetbrains.jet.lang.cfg.PseudocodeTraverser.*;
import org.jetbrains.jet.lang.cfg.PseudocodeVariablesData.VariableInitializers; import org.jetbrains.jet.lang.cfg.PseudocodeVariablesData.VariableInitState;
import org.jetbrains.jet.lang.cfg.PseudocodeVariablesData.VariableUseStatus; import org.jetbrains.jet.lang.cfg.PseudocodeVariablesData.VariableUseState;
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.*;
@@ -41,6 +41,7 @@ import org.jetbrains.jet.plugin.JetMainDetector;
import java.util.*; import java.util.*;
import static org.jetbrains.jet.lang.cfg.PseudocodeVariablesData.VariableUseState.*;
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;
import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE; import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
@@ -187,38 +188,38 @@ 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;
Map<Instruction, Edges<Map<VariableDescriptor,VariableInitializers>>> initializers = pseudocodeVariablesData.getVariableInitializers(); Map<Instruction, Edges<Map<VariableDescriptor,VariableInitState>>> initializers = pseudocodeVariablesData.getVariableInitializers();
final Set<VariableDescriptor> declaredVariables = pseudocodeVariablesData.getDeclaredVariables(pseudocode); final Set<VariableDescriptor> declaredVariables = pseudocodeVariablesData.getDeclaredVariables(pseudocode);
PseudocodeTraverser.traverse(pseudocode, true, true, initializers, new InstructionDataAnalyzeStrategy<Map<VariableDescriptor, VariableInitializers>>() { PseudocodeTraverser.traverse(pseudocode, true, true, initializers, new InstructionDataAnalyzeStrategy<Map<VariableDescriptor, PseudocodeVariablesData.VariableInitState>>() {
@Override @Override
public void execute(@NotNull Instruction instruction, public void execute(@NotNull Instruction instruction,
@Nullable Map<VariableDescriptor, VariableInitializers> in, @Nullable Map<VariableDescriptor, VariableInitState> in,
@Nullable Map<VariableDescriptor, VariableInitializers> out) { @Nullable Map<VariableDescriptor, PseudocodeVariablesData.VariableInitState> out) {
assert in != null && out != null; assert in != null && out != null;
VariableDescriptor variableDescriptor = PseudocodeUtil.extractVariableDescriptorIfAny(instruction, true, trace.getBindingContext()); 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;
VariableInitializers outInitializers = out.get(variableDescriptor); VariableInitState outInitState = out.get(variableDescriptor);
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 && declaredVariables.contains(variableDescriptor)) { if (!error && declaredVariables.contains(variableDescriptor)) {
checkIsInitialized(variableDescriptor, element, outInitializers, varWithUninitializedErrorGenerated); checkIsInitialized(variableDescriptor, element, outInitState, 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); PseudocodeVariablesData.VariableInitState inInitState = 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, inInitializers, varWithValReassignErrorGenerated); error = checkValReassignment(variableDescriptor, (JetExpression) element, inInitState, varWithValReassignErrorGenerated);
} }
if (!error && processClassOrObject) { if (!error && processClassOrObject) {
error = checkAssignmentBeforeDeclaration(variableDescriptor, (JetExpression) element, inInitializers, outInitializers); error = checkAssignmentBeforeDeclaration(variableDescriptor, (JetExpression) element, inInitState, outInitState);
} }
if (!error && processClassOrObject) { if (!error && processClassOrObject) {
checkInitializationUsingBackingField(variableDescriptor, (JetExpression) element, inInitializers, outInitializers); checkInitializationUsingBackingField(variableDescriptor, (JetExpression) element, inInitState, outInitState);
} }
} }
}); });
@@ -232,11 +233,11 @@ public class JetFlowInformationProvider {
private void checkIsInitialized(@NotNull VariableDescriptor variableDescriptor, private void checkIsInitialized(@NotNull VariableDescriptor variableDescriptor,
@NotNull JetElement element, @NotNull JetElement element,
@NotNull VariableInitializers variableInitializers, @NotNull PseudocodeVariablesData.VariableInitState variableInitState,
@NotNull Collection<VariableDescriptor> varWithUninitializedErrorGenerated) { @NotNull Collection<VariableDescriptor> varWithUninitializedErrorGenerated) {
if (!(element instanceof JetSimpleNameExpression)) return; if (!(element instanceof JetSimpleNameExpression)) return;
boolean isInitialized = variableInitializers.isInitialized(); boolean isInitialized = variableInitState.isInitialized;
if (variableDescriptor instanceof PropertyDescriptor) { if (variableDescriptor instanceof PropertyDescriptor) {
if (!trace.get(BindingContext.BACKING_FIELD_REQUIRED, (PropertyDescriptor) variableDescriptor)) { if (!trace.get(BindingContext.BACKING_FIELD_REQUIRED, (PropertyDescriptor) variableDescriptor)) {
isInitialized = true; isInitialized = true;
@@ -256,15 +257,11 @@ public class JetFlowInformationProvider {
private boolean checkValReassignment(@NotNull VariableDescriptor variableDescriptor, private boolean checkValReassignment(@NotNull VariableDescriptor variableDescriptor,
@NotNull JetExpression expression, @NotNull JetExpression expression,
@NotNull VariableInitializers enterInitializers, @NotNull VariableInitState enterInitState,
@NotNull Collection<VariableDescriptor> varWithValReassignErrorGenerated) { @NotNull Collection<VariableDescriptor> varWithValReassignErrorGenerated) {
boolean isInitializedNotHere = enterInitializers.isInitialized(); boolean isInitializedNotHere = enterInitState.isInitialized;
Set<JetElement> possibleLocalInitializers = enterInitializers.getPossibleLocalInitializers(); if (expression.getParent() instanceof JetProperty && ((JetProperty)expression).getInitializer() != null) {
if (possibleLocalInitializers.size() == 1) { isInitializedNotHere = false;
JetElement initializer = possibleLocalInitializers.iterator().next();
if (initializer instanceof JetProperty && initializer == expression.getParent()) {
isInitializedNotHere = false;
}
} }
boolean hasBackingField = true; boolean hasBackingField = true;
if (variableDescriptor instanceof PropertyDescriptor) { if (variableDescriptor instanceof PropertyDescriptor) {
@@ -307,16 +304,16 @@ public class JetFlowInformationProvider {
return false; return false;
} }
private boolean checkAssignmentBeforeDeclaration(@NotNull VariableDescriptor variableDescriptor, @NotNull JetExpression expression, @NotNull VariableInitializers enterInitializers, @NotNull VariableInitializers exitInitializers) { private boolean checkAssignmentBeforeDeclaration(@NotNull VariableDescriptor variableDescriptor, @NotNull JetExpression expression, @NotNull VariableInitState enterInitState, @NotNull VariableInitState exitInitState) {
if (!enterInitializers.isDeclared() && !exitInitializers.isDeclared() && !enterInitializers.isInitialized() && exitInitializers.isInitialized()) { if (!enterInitState.isDeclared && !exitInitState.isDeclared && !enterInitState.isInitialized && exitInitState.isInitialized) {
trace.report(Errors.INITIALIZATION_BEFORE_DECLARATION.on(expression, variableDescriptor)); trace.report(Errors.INITIALIZATION_BEFORE_DECLARATION.on(expression, variableDescriptor));
return true; return true;
} }
return false; return false;
} }
private boolean checkInitializationUsingBackingField(@NotNull VariableDescriptor variableDescriptor, @NotNull JetExpression expression, @NotNull VariableInitializers enterInitializers, @NotNull VariableInitializers exitInitializers) { private boolean checkInitializationUsingBackingField(@NotNull VariableDescriptor variableDescriptor, @NotNull JetExpression expression, @NotNull VariableInitState enterInitState, @NotNull VariableInitState exitInitState) {
if (variableDescriptor instanceof PropertyDescriptor && !enterInitializers.isInitialized() && exitInitializers.isInitialized()) { if (variableDescriptor instanceof PropertyDescriptor && !enterInitState.isInitialized && exitInitState.isInitialized) {
if (!variableDescriptor.isVar()) return false; if (!variableDescriptor.isVar()) return false;
if (!trace.get(BindingContext.BACKING_FIELD_REQUIRED, (PropertyDescriptor) variableDescriptor)) return false; if (!trace.get(BindingContext.BACKING_FIELD_REQUIRED, (PropertyDescriptor) variableDescriptor)) return false;
PsiElement property = BindingContextUtils.descriptorToDeclaration(trace.getBindingContext(), variableDescriptor); PsiElement property = BindingContextUtils.descriptorToDeclaration(trace.getBindingContext(), variableDescriptor);
@@ -396,15 +393,15 @@ public class JetFlowInformationProvider {
return false; return false;
} }
private void recordInitializedVariables(@NotNull Pseudocode pseudocode, @NotNull Map<Instruction, Edges<Map<VariableDescriptor,VariableInitializers>>> initializersMap) { private void recordInitializedVariables(@NotNull Pseudocode pseudocode, @NotNull Map<Instruction, Edges<Map<VariableDescriptor,PseudocodeVariablesData.VariableInitState>>> initializersMap) {
Edges<Map<VariableDescriptor, VariableInitializers>> initializers = initializersMap.get(pseudocode.getExitInstruction()); Edges<Map<VariableDescriptor, VariableInitState>> initializers = initializersMap.get(pseudocode.getExitInstruction());
Set<VariableDescriptor> usedVariables = pseudocodeVariablesData.getUsedVariables(pseudocode); Set<VariableDescriptor> usedVariables = pseudocodeVariablesData.getUsedVariables(pseudocode);
Set<VariableDescriptor> declaredVariables = pseudocodeVariablesData.getDeclaredVariables(pseudocode); Set<VariableDescriptor> declaredVariables = pseudocodeVariablesData.getDeclaredVariables(pseudocode);
for (VariableDescriptor variable : usedVariables) { for (VariableDescriptor variable : usedVariables) {
if (variable instanceof PropertyDescriptor && declaredVariables.contains(variable)) { if (variable instanceof PropertyDescriptor && declaredVariables.contains(variable)) {
VariableInitializers variableInitializers = initializers.in.get(variable); PseudocodeVariablesData.VariableInitState variableInitState = initializers.in.get(variable);
if (variableInitializers == null) return; if (variableInitState == null) return;
trace.record(BindingContext.IS_INITIALIZED, (PropertyDescriptor) variable, variableInitializers.isInitialized()); trace.record(BindingContext.IS_INITIALIZED, (PropertyDescriptor) variable, variableInitState.isInitialized);
} }
} }
} }
@@ -413,13 +410,13 @@ public class JetFlowInformationProvider {
// "Unused variable" & "unused value" analyses // "Unused variable" & "unused value" analyses
public void markUnusedVariables() { public void markUnusedVariables() {
Map<Instruction, Edges<Map<VariableDescriptor, VariableUseStatus>>> variableStatusData = pseudocodeVariablesData.getVariableUseStatusData(); Map<Instruction, Edges<Map<VariableDescriptor, VariableUseState>>> variableStatusData = pseudocodeVariablesData.getVariableUseStatusData();
InstructionDataAnalyzeStrategy<Map<VariableDescriptor, VariableUseStatus>> variableStatusAnalyzeStrategy = InstructionDataAnalyzeStrategy<Map<VariableDescriptor, VariableUseState>> variableStatusAnalyzeStrategy =
new InstructionDataAnalyzeStrategy<Map<VariableDescriptor, VariableUseStatus>>() { new InstructionDataAnalyzeStrategy<Map<VariableDescriptor, PseudocodeVariablesData.VariableUseState>>() {
@Override @Override
public void execute(@NotNull Instruction instruction, public void execute(@NotNull Instruction instruction,
@Nullable Map<VariableDescriptor, VariableUseStatus> in, @Nullable Map<VariableDescriptor, PseudocodeVariablesData.VariableUseState> in,
@Nullable Map<VariableDescriptor, VariableUseStatus> out) { @Nullable Map<VariableDescriptor, VariableUseState> out) {
assert in != null && out != null; assert in != null && out != null;
Set<VariableDescriptor> declaredVariables = pseudocodeVariablesData.getDeclaredVariables(instruction.getOwner()); Set<VariableDescriptor> declaredVariables = pseudocodeVariablesData.getDeclaredVariables(instruction.getOwner());
@@ -427,11 +424,11 @@ public class JetFlowInformationProvider {
trace.getBindingContext()); trace.getBindingContext());
if (variableDescriptor == null || !declaredVariables.contains(variableDescriptor) || if (variableDescriptor == null || !declaredVariables.contains(variableDescriptor) ||
!DescriptorUtils.isLocal(variableDescriptor.getContainingDeclaration(), variableDescriptor)) return; !DescriptorUtils.isLocal(variableDescriptor.getContainingDeclaration(), variableDescriptor)) return;
VariableUseStatus variableUseStatus = in.get(variableDescriptor); PseudocodeVariablesData.VariableUseState variableUseState = in.get(variableDescriptor);
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();
if (variableUseStatus != VariableUseStatus.LAST_READ) { if (variableUseState != LAST_READ) {
if (element instanceof JetBinaryExpression && if (element instanceof JetBinaryExpression &&
((JetBinaryExpression) element).getOperationToken() == JetTokens.EQ) { ((JetBinaryExpression) element).getOperationToken() == JetTokens.EQ) {
JetExpression right = ((JetBinaryExpression) element).getRight(); JetExpression right = ((JetBinaryExpression) element).getRight();
@@ -452,7 +449,7 @@ public class JetFlowInformationProvider {
if (element instanceof JetNamedDeclaration) { if (element instanceof JetNamedDeclaration) {
PsiElement nameIdentifier = ((JetNamedDeclaration) element).getNameIdentifier(); PsiElement nameIdentifier = ((JetNamedDeclaration) element).getNameIdentifier();
if (nameIdentifier == null) return; if (nameIdentifier == null) return;
if (variableUseStatus == null || variableUseStatus == VariableUseStatus.UNUSED) { if (variableUseState == null || variableUseState == UNUSED) {
if (element instanceof JetProperty) { if (element instanceof JetProperty) {
trace.report(Errors.UNUSED_VARIABLE.on((JetProperty) element, variableDescriptor)); trace.report(Errors.UNUSED_VARIABLE.on((JetProperty) element, variableDescriptor));
} }
@@ -470,10 +467,10 @@ public class JetFlowInformationProvider {
} }
} }
} }
else if (variableUseStatus == VariableUseStatus.ONLY_WRITTEN_NEVER_READ &&element instanceof JetProperty) { else if (variableUseState == ONLY_WRITTEN_NEVER_READ &&element instanceof JetProperty) {
trace.report(Errors.ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE.on((JetNamedDeclaration) element, variableDescriptor)); trace.report(Errors.ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE.on((JetNamedDeclaration) element, variableDescriptor));
} }
else if (variableUseStatus == VariableUseStatus.LAST_WRITTEN && element instanceof JetProperty) { else if (variableUseState == LAST_WRITTEN && element instanceof JetProperty) {
JetExpression initializer = ((JetProperty) element).getInitializer(); JetExpression initializer = ((JetProperty) element).getInitializer();
if (initializer != null) { if (initializer != null) {
trace.report(Errors.VARIABLE_WITH_REDUNDANT_INITIALIZER.on(initializer, variableDescriptor)); trace.report(Errors.VARIABLE_WITH_REDUNDANT_INITIALIZER.on(initializer, variableDescriptor));
@@ -181,16 +181,6 @@ public class PseudocodeTraverser {
return new Edges<T>(in, out); return new Edges<T>(in, out);
} }
@NotNull
public T getIn() {
return in;
}
@NotNull
public T getOut() {
return out;
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
@@ -44,8 +44,8 @@ public class PseudocodeVariablesData {
private final Map<Pseudocode, Set<VariableDescriptor>> declaredVariablesInEachDeclaration = Maps.newHashMap(); private final Map<Pseudocode, Set<VariableDescriptor>> declaredVariablesInEachDeclaration = Maps.newHashMap();
private final Map<Pseudocode, Set<VariableDescriptor>> usedVariablesInEachDeclaration = 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, VariableInitState>>> variableInitializersMap;
private Map<Instruction, Edges<Map<VariableDescriptor, VariableUseStatus>>> variableStatusMap; private Map<Instruction, Edges<Map<VariableDescriptor, VariableUseState>>> variableStatusMap;
public PseudocodeVariablesData(@NotNull Pseudocode pseudocode, @NotNull BindingContext bindingContext) { public PseudocodeVariablesData(@NotNull Pseudocode pseudocode, @NotNull BindingContext bindingContext) {
this.pseudocode = pseudocode; this.pseudocode = pseudocode;
@@ -102,7 +102,7 @@ public class PseudocodeVariablesData {
// variable initializers // variable initializers
@NotNull @NotNull
public Map<Instruction, Edges<Map<VariableDescriptor, VariableInitializers>>> getVariableInitializers() { public Map<Instruction, Edges<Map<VariableDescriptor, VariableInitState>>> getVariableInitializers() {
if (variableInitializersMap == null) { if (variableInitializersMap == null) {
variableInitializersMap = getVariableInitializers(pseudocode); variableInitializersMap = getVariableInitializers(pseudocode);
} }
@@ -110,23 +110,23 @@ public class PseudocodeVariablesData {
} }
@NotNull @NotNull
private Map<Instruction, Edges<Map<VariableDescriptor, VariableInitializers>>> getVariableInitializers(@NotNull Pseudocode pseudocode) { private Map<Instruction, Edges<Map<VariableDescriptor, VariableInitState>>> getVariableInitializers(@NotNull Pseudocode pseudocode) {
Set<VariableDescriptor> usedVariables = getUsedVariables(pseudocode); Set<VariableDescriptor> usedVariables = getUsedVariables(pseudocode);
Set<VariableDescriptor> declaredVariables = getDeclaredVariables(pseudocode); Set<VariableDescriptor> declaredVariables = getDeclaredVariables(pseudocode);
Map<VariableDescriptor, VariableInitializers> initialMap = Collections.emptyMap(); Map<VariableDescriptor, VariableInitState> initialMap = Collections.emptyMap();
final Map<VariableDescriptor, VariableInitializers> initialMapForStartInstruction = prepareInitializersMapForStartInstruction( final Map<VariableDescriptor, VariableInitState> initialMapForStartInstruction = prepareInitializersMapForStartInstruction(
usedVariables, declaredVariables); usedVariables, declaredVariables);
Map<Instruction, Edges<Map<VariableDescriptor, VariableInitializers>>> variableInitializersMap = PseudocodeTraverser.collectData( Map<Instruction, Edges<Map<VariableDescriptor, VariableInitState>>> variableInitializersMap = PseudocodeTraverser.collectData(
pseudocode, /* directOrder = */ true, /* lookInside = */ false, pseudocode, /* directOrder = */ true, /* lookInside = */ false,
initialMap, initialMapForStartInstruction, new PseudocodeTraverser.InstructionDataMergeStrategy<Map<VariableDescriptor, VariableInitializers>>() { initialMap, initialMapForStartInstruction, new PseudocodeTraverser.InstructionDataMergeStrategy<Map<VariableDescriptor, VariableInitState>>() {
@Override @Override
public Edges<Map<VariableDescriptor, VariableInitializers>> execute( public Edges<Map<VariableDescriptor, VariableInitState>> execute(
@NotNull Instruction instruction, @NotNull Collection<Map<VariableDescriptor, VariableInitializers>> incomingEdgesData) { @NotNull Instruction instruction, @NotNull Collection<Map<VariableDescriptor, VariableInitState>> incomingEdgesData) {
Map<VariableDescriptor, VariableInitializers> enterInstructionData = mergeIncomingEdgesDataForInitializers(incomingEdgesData); Map<VariableDescriptor, VariableInitState> enterInstructionData = mergeIncomingEdgesDataForInitializers(incomingEdgesData);
Map<VariableDescriptor, VariableInitializers> exitInstructionData = Map<VariableDescriptor, VariableInitState> exitInstructionData =
addVariableInitializerFromCurrentInstructionIfAny(instruction, enterInstructionData); addVariableInitializerFromCurrentInstructionIfAny(instruction, enterInstructionData);
return Edges.create(enterInstructionData, exitInstructionData); return Edges.create(enterInstructionData, exitInstructionData);
} }
@@ -135,7 +135,7 @@ public class PseudocodeVariablesData {
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 = getVariableInitializers(localPseudocode); Map<Instruction, Edges<Map<VariableDescriptor, VariableInitState>>> initializersForLocalDeclaration = getVariableInitializers(localPseudocode);
for (Instruction instruction : initializersForLocalDeclaration.keySet()) { for (Instruction instruction : initializersForLocalDeclaration.keySet()) {
//todo //todo
@@ -149,51 +149,51 @@ public class PseudocodeVariablesData {
} }
@NotNull @NotNull
private Map<VariableDescriptor, VariableInitializers> prepareInitializersMapForStartInstruction( private Map<VariableDescriptor, VariableInitState> prepareInitializersMapForStartInstruction(
@NotNull Collection<VariableDescriptor> usedVariables, @NotNull Collection<VariableDescriptor> usedVariables,
@NotNull Collection<VariableDescriptor> declaredVariables) { @NotNull Collection<VariableDescriptor> declaredVariables) {
Map<VariableDescriptor, VariableInitializers> initialMapForStartInstruction = Maps.newHashMap(); Map<VariableDescriptor, VariableInitState> initialMapForStartInstruction = Maps.newHashMap();
VariableInitializers isInitializedForExternalVariable = new VariableInitializers(true); VariableInitState initializedForExternalVariable = new VariableInitState(true);
VariableInitializers isNotInitializedForDeclaredVariable = new VariableInitializers(false); VariableInitState notInitializedForDeclaredVariable = new VariableInitState(false);
for (VariableDescriptor variable : usedVariables) { for (VariableDescriptor variable : usedVariables) {
if (declaredVariables.contains(variable)) { if (declaredVariables.contains(variable)) {
initialMapForStartInstruction.put(variable, isNotInitializedForDeclaredVariable); initialMapForStartInstruction.put(variable, notInitializedForDeclaredVariable);
} }
else { else {
initialMapForStartInstruction.put(variable, isInitializedForExternalVariable); initialMapForStartInstruction.put(variable, initializedForExternalVariable);
} }
} }
return initialMapForStartInstruction; return initialMapForStartInstruction;
} }
@NotNull @NotNull
private Map<VariableDescriptor, VariableInitializers> mergeIncomingEdgesDataForInitializers( private Map<VariableDescriptor, VariableInitState> mergeIncomingEdgesDataForInitializers(
@NotNull Collection<Map<VariableDescriptor, VariableInitializers>> incomingEdgesData) { @NotNull Collection<Map<VariableDescriptor, VariableInitState>> incomingEdgesData) {
Set<VariableDescriptor> variablesInScope = Sets.newHashSet(); Set<VariableDescriptor> variablesInScope = Sets.newHashSet();
for (Map<VariableDescriptor, VariableInitializers> edgeData : incomingEdgesData) { for (Map<VariableDescriptor, VariableInitState> edgeData : incomingEdgesData) {
variablesInScope.addAll(edgeData.keySet()); variablesInScope.addAll(edgeData.keySet());
} }
Map<VariableDescriptor, VariableInitializers> enterInstructionData = Maps.newHashMap(); Map<VariableDescriptor, VariableInitState> enterInstructionData = Maps.newHashMap();
for (VariableDescriptor variable : variablesInScope) { for (VariableDescriptor variable : variablesInScope) {
Set<VariableInitializers> edgesDataForVariable = Sets.newHashSet(); Set<VariableInitState> edgesDataForVariable = Sets.newHashSet();
for (Map<VariableDescriptor, VariableInitializers> edgeData : incomingEdgesData) { for (Map<VariableDescriptor, VariableInitState> edgeData : incomingEdgesData) {
VariableInitializers initializers = edgeData.get(variable); VariableInitState initState = edgeData.get(variable);
if (initializers != null) { if (initState != null) {
edgesDataForVariable.add(initializers); edgesDataForVariable.add(initState);
} }
} }
enterInstructionData.put(variable, new VariableInitializers(edgesDataForVariable)); enterInstructionData.put(variable, new VariableInitState(edgesDataForVariable));
} }
return enterInstructionData; return enterInstructionData;
} }
@NotNull @NotNull
private Map<VariableDescriptor, VariableInitializers> addVariableInitializerFromCurrentInstructionIfAny( private Map<VariableDescriptor, VariableInitState> addVariableInitializerFromCurrentInstructionIfAny(
@NotNull Instruction instruction, @NotNull Map<VariableDescriptor, VariableInitializers> enterInstructionData) { @NotNull Instruction instruction, @NotNull Map<VariableDescriptor, VariableInitState> enterInstructionData) {
if (!(instruction instanceof WriteValueInstruction) && !(instruction instanceof VariableDeclarationInstruction)) { if (!(instruction instanceof WriteValueInstruction) && !(instruction instanceof VariableDeclarationInstruction)) {
return enterInstructionData; return enterInstructionData;
@@ -202,21 +202,22 @@ public class PseudocodeVariablesData {
if (variable == null) { if (variable == null) {
return enterInstructionData; return enterInstructionData;
} }
Map<VariableDescriptor, VariableInitializers> exitInstructionData = Maps.newHashMap(enterInstructionData); Map<VariableDescriptor, VariableInitState> exitInstructionData = Maps.newHashMap(enterInstructionData);
if (instruction instanceof WriteValueInstruction) { if (instruction instanceof WriteValueInstruction) {
VariableInitializers enterInitializers = enterInstructionData.get(variable); VariableInitState enterInitState = enterInstructionData.get(variable);
VariableInitializers initializationAtThisElement = new VariableInitializers(((WriteValueInstruction) instruction).getElement(), enterInitializers); VariableInitState initializationAtThisElement =
new VariableInitState(((WriteValueInstruction) instruction).getElement() instanceof JetProperty, enterInitState);
exitInstructionData.put(variable, initializationAtThisElement); exitInstructionData.put(variable, initializationAtThisElement);
} }
else { else { // instruction instanceof VariableDeclarationInstruction
VariableInitializers enterInitializers = enterInstructionData.get(variable); VariableInitState enterInitState = enterInstructionData.get(variable);
if (enterInitializers == null || !enterInitializers.isInitialized() || !enterInitializers.isDeclared()) { if (enterInitState == null || !enterInitState.isInitialized || !enterInitState.isDeclared) {
JetElement element = ((VariableDeclarationInstruction) instruction).getElement(); JetElement element = ((VariableDeclarationInstruction) instruction).getElement();
if (element instanceof JetProperty) { if (element instanceof JetProperty) {
JetProperty property = (JetProperty) element; JetProperty property = (JetProperty) element;
if (property.getInitializer() == null) { if (property.getInitializer() == null) {
boolean isInitialized = enterInitializers != null && enterInitializers.isInitialized(); boolean isInitialized = enterInitState != null && enterInitState.isInitialized;
VariableInitializers variableDeclarationInfo = new VariableInitializers(isInitialized, true); VariableInitState variableDeclarationInfo = new VariableInitState(isInitialized, true);
exitInstructionData.put(variable, variableDeclarationInfo); exitInstructionData.put(variable, variableDeclarationInfo);
} }
} }
@@ -228,23 +229,23 @@ public class PseudocodeVariablesData {
// variable use // variable use
@NotNull @NotNull
public Map<Instruction, Edges<Map<VariableDescriptor, VariableUseStatus>>> getVariableUseStatusData() { public Map<Instruction, Edges<Map<VariableDescriptor, VariableUseState>>> getVariableUseStatusData() {
if (variableStatusMap == null) { if (variableStatusMap == null) {
Map<VariableDescriptor, VariableUseStatus> sinkInstructionData = Maps.newHashMap(); Map<VariableDescriptor, VariableUseState> sinkInstructionData = Maps.newHashMap();
for (VariableDescriptor usedVariable : usedVariablesInEachDeclaration.get(pseudocode)) { for (VariableDescriptor usedVariable : usedVariablesInEachDeclaration.get(pseudocode)) {
sinkInstructionData.put(usedVariable, VariableUseStatus.UNUSED); sinkInstructionData.put(usedVariable, VariableUseState.UNUSED);
} }
InstructionDataMergeStrategy<Map<VariableDescriptor, VariableUseStatus>> collectVariableUseStatusStrategy = new InstructionDataMergeStrategy<Map<VariableDescriptor, VariableUseStatus>>() { InstructionDataMergeStrategy<Map<VariableDescriptor, VariableUseState>> collectVariableUseStatusStrategy = new InstructionDataMergeStrategy<Map<VariableDescriptor, VariableUseState>>() {
@Override @Override
public Edges<Map<VariableDescriptor, VariableUseStatus>> execute(@NotNull Instruction instruction, public Edges<Map<VariableDescriptor, VariableUseState>> execute(@NotNull Instruction instruction,
@NotNull Collection<Map<VariableDescriptor, VariableUseStatus>> incomingEdgesData) { @NotNull Collection<Map<VariableDescriptor, VariableUseState>> incomingEdgesData) {
Map<VariableDescriptor, VariableUseStatus> enterResult = Maps.newHashMap(); Map<VariableDescriptor, VariableUseState> enterResult = Maps.newHashMap();
for (Map<VariableDescriptor, VariableUseStatus> edgeData : incomingEdgesData) { for (Map<VariableDescriptor, VariableUseState> edgeData : incomingEdgesData) {
for (Map.Entry<VariableDescriptor, VariableUseStatus> entry : edgeData.entrySet()) { for (Map.Entry<VariableDescriptor, VariableUseState> entry : edgeData.entrySet()) {
VariableDescriptor variableDescriptor = entry.getKey(); VariableDescriptor variableDescriptor = entry.getKey();
VariableUseStatus variableUseStatus = entry.getValue(); VariableUseState variableUseState = entry.getValue();
enterResult.put(variableDescriptor, variableUseStatus.merge(enterResult.get(variableDescriptor))); enterResult.put(variableDescriptor, variableUseState.merge(enterResult.get(variableDescriptor)));
} }
} }
VariableDescriptor variableDescriptor = PseudocodeUtil.extractVariableDescriptorIfAny(instruction, true, VariableDescriptor variableDescriptor = PseudocodeUtil.extractVariableDescriptorIfAny(instruction, true,
@@ -253,109 +254,90 @@ public class PseudocodeVariablesData {
(!(instruction instanceof ReadValueInstruction) && !(instruction instanceof WriteValueInstruction))) { (!(instruction instanceof ReadValueInstruction) && !(instruction instanceof WriteValueInstruction))) {
return Edges.create(enterResult, enterResult); return Edges.create(enterResult, enterResult);
} }
Map<VariableDescriptor, VariableUseStatus> exitResult = Maps.newHashMap(enterResult); Map<VariableDescriptor, VariableUseState> exitResult = Maps.newHashMap(enterResult);
if (instruction instanceof ReadValueInstruction) { if (instruction instanceof ReadValueInstruction) {
exitResult.put(variableDescriptor, VariableUseStatus.LAST_READ); exitResult.put(variableDescriptor, VariableUseState.LAST_READ);
} }
else { else { //instruction instanceof WriteValueInstruction
VariableUseStatus variableUseStatus = enterResult.get(variableDescriptor); VariableUseState variableUseState = enterResult.get(variableDescriptor);
if (variableUseStatus == null) { if (variableUseState == null) {
variableUseStatus = VariableUseStatus.UNUSED; variableUseState = VariableUseState.UNUSED;
} }
switch (variableUseStatus) { switch (variableUseState) {
case UNUSED: case UNUSED:
case ONLY_WRITTEN_NEVER_READ: case ONLY_WRITTEN_NEVER_READ:
exitResult.put(variableDescriptor, VariableUseStatus.ONLY_WRITTEN_NEVER_READ); exitResult.put(variableDescriptor, VariableUseState.ONLY_WRITTEN_NEVER_READ);
break; break;
case LAST_WRITTEN: case LAST_WRITTEN:
case LAST_READ: case LAST_READ:
exitResult.put(variableDescriptor, VariableUseStatus.LAST_WRITTEN); exitResult.put(variableDescriptor, VariableUseState.LAST_WRITTEN);
} }
} }
return Edges.create(enterResult, exitResult); return Edges.create(enterResult, exitResult);
} }
}; };
variableStatusMap = PseudocodeTraverser.collectData(pseudocode, false, true, variableStatusMap = PseudocodeTraverser.collectData(pseudocode, false, true,
Collections.<VariableDescriptor, VariableUseStatus>emptyMap(), Collections.<VariableDescriptor, VariableUseState>emptyMap(),
sinkInstructionData, collectVariableUseStatusStrategy); sinkInstructionData, collectVariableUseStatusStrategy);
} }
return variableStatusMap; return variableStatusMap;
} }
public static class VariableInitializers { public static class VariableInitState {
private final Set<JetElement> possibleLocalInitializers = Sets.newHashSet(); public final boolean isInitialized;
private boolean isInitialized; public final boolean isDeclared;
private boolean isDeclared;
public VariableInitializers(boolean isInitialized) { public VariableInitState(boolean isInitialized) {
this(isInitialized, false); this(isInitialized, false);
} }
public VariableInitializers(boolean isInitialized, boolean isDeclared) { public VariableInitState(boolean isInitialized, boolean isDeclared) {
this.isInitialized = isInitialized; this.isInitialized = isInitialized;
this.isDeclared = isDeclared; this.isDeclared = isDeclared;
} }
public VariableInitializers(JetElement element, @Nullable VariableInitializers previous) { public VariableInitState(boolean isDeclaredHere, @Nullable VariableInitState mergedEdgesData) {
isInitialized = true; isInitialized = true;
isDeclared = element instanceof JetProperty || (previous != null && previous.isDeclared()); isDeclared = isDeclaredHere || (mergedEdgesData != null && mergedEdgesData.isDeclared);
possibleLocalInitializers.add(element);
} }
public VariableInitializers(Set<VariableInitializers> edgesData) { public VariableInitState(@NotNull Set<VariableInitState> edgesData) {
isInitialized = true; boolean isInitialized = true;
isDeclared = true; boolean isDeclared = true;
for (VariableInitializers edgeData : edgesData) { for (VariableInitState edgeData : edgesData) {
if (!edgeData.isInitialized) { if (!edgeData.isInitialized) {
isInitialized = false; isInitialized = false;
} }
if (!edgeData.isDeclared) { if (!edgeData.isDeclared) {
isDeclared = false; isDeclared = false;
} }
possibleLocalInitializers.addAll(edgeData.possibleLocalInitializers);
} }
} this.isInitialized = isInitialized;
this.isDeclared = isDeclared;
public Set<JetElement> getPossibleLocalInitializers() {
return possibleLocalInitializers;
}
public boolean isInitialized() {
return isInitialized;
}
public boolean isDeclared() {
return isDeclared;
} }
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
if (!(o instanceof VariableInitializers)) return false; if (!(o instanceof VariableInitState)) return false;
VariableInitializers that = (VariableInitializers) o; VariableInitState that = (VariableInitState) o;
if (isDeclared != that.isDeclared) return false; if (isDeclared != that.isDeclared) return false;
if (isInitialized != that.isInitialized) return false; if (isInitialized != that.isInitialized) return false;
if (possibleLocalInitializers != null
? !possibleLocalInitializers.equals(that.possibleLocalInitializers)
: that.possibleLocalInitializers != null) {
return false;
}
return true; return true;
} }
@Override @Override
public int hashCode() { public int hashCode() {
int result = possibleLocalInitializers != null ? possibleLocalInitializers.hashCode() : 0; int result = (isInitialized ? 1 : 0);
result = 31 * result + (isInitialized ? 1 : 0);
result = 31 * result + (isDeclared ? 1 : 0); result = 31 * result + (isDeclared ? 1 : 0);
return result; return result;
} }
} }
public static enum VariableUseStatus { public static enum VariableUseState {
LAST_READ(3), LAST_READ(3),
LAST_WRITTEN(2), LAST_WRITTEN(2),
ONLY_WRITTEN_NEVER_READ(1), ONLY_WRITTEN_NEVER_READ(1),
@@ -363,13 +345,13 @@ public class PseudocodeVariablesData {
private final int importance; private final int importance;
VariableUseStatus(int importance) { VariableUseState(int importance) {
this.importance = importance; this.importance = importance;
} }
public VariableUseStatus merge(@Nullable VariableUseStatus variableUseStatus) { public VariableUseState merge(@Nullable VariableUseState variableUseState) {
if (variableUseStatus == null || importance > variableUseStatus.importance) return this; if (variableUseState == null || importance > variableUseState.importance) return this;
return variableUseStatus; return variableUseState;
} }
} }
} }