Added 'Uninitialized variable' error

This commit is contained in:
svtk
2011-10-18 16:53:04 +04:00
parent 5a9c23e8de
commit 101b836a71
3 changed files with 118 additions and 4 deletions
@@ -1,23 +1,29 @@
package org.jetbrains.jet.lang.cfg;
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.pseudocode.*;
import org.jetbrains.jet.lang.psi.JetElement;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.LocalVariableDescriptor;
import org.jetbrains.jet.lang.diagnostics.Errors;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingTrace;
import java.util.*;
/**
* @author svtk
*/
* @author svtk
*/
public class JetFlowInformationProvider {
private final Map<JetElement, Pseudocode> pseudocodeMap;
private BindingTrace trace;
public JetFlowInformationProvider(@NotNull JetElement declaration, @NotNull final JetExpression bodyExpression, @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory, @NotNull BindingTrace trace) {
this.trace = trace;
final JetPseudocodeTrace pseudocodeTrace = flowDataTraceFactory.createTrace(declaration);
pseudocodeMap = new HashMap<JetElement, Pseudocode>();
final Map<JetElement, Instruction> representativeInstructions = new HashMap<JetElement, Instruction>();
@@ -86,6 +92,13 @@ public class JetFlowInformationProvider {
// Nothing
}
@Override
public void visitUnconditionalJump(UnconditionalJumpInstruction instruction) {
for (Instruction previousInstruction : instruction.getPreviousInstructions()) {
previousInstruction.accept(this);
}
}
@Override
public void visitInstruction(Instruction instruction) {
if (instruction instanceof JetElementInstruction) {
@@ -233,4 +246,100 @@ public class JetFlowInformationProvider {
// previousInstruction.accept(visitor);
// }
// }
private <D> Map<Instruction, D> traverseInstructionGraphUntilFactsStabilization(Collection<Instruction> instructions, InstructionsMergeHandler<D> instructionsMergeHandler, D initialDataValue, boolean straightDirection) {
Map<Instruction, D> dataMap = Maps.newHashMap();
for (Instruction instruction : instructions) {
dataMap.put(instruction, initialDataValue);
}
boolean changed = true;
while (changed) {
changed = false;
for (Instruction instruction : instructions) {
D previousDataValue = dataMap.get(instruction);
Collection<Instruction> previousInstructions = straightDirection
? instruction.getPreviousInstructions()
: instruction.getNextInstructions();
Collection<D> incomingEdgesData = Sets.newHashSet();
for (Instruction previousInstruction : previousInstructions) {
incomingEdgesData.add(dataMap.get(previousInstruction));
}
D mergedData = instructionsMergeHandler.merge(instruction, previousDataValue, incomingEdgesData);
if (!mergedData.equals(previousDataValue)) {
changed = true;
dataMap.put(instruction, mergedData);
}
}
}
return dataMap;
}
public void markUninitializedVariables(@NotNull JetElement subroutine) {
Pseudocode pseudocode = pseudocodeMap.get(subroutine);
assert pseudocode != null;
Collection<Instruction> instructions = pseudocode.getInstructions();
InstructionsMergeHandler<Set<LocalVariableDescriptor>> instructionsMergeHandler = new InstructionsMergeHandler<Set<LocalVariableDescriptor>>() {
@Override
public Set<LocalVariableDescriptor> merge(Instruction instruction, Set<LocalVariableDescriptor> previousDataValue, Collection<Set<LocalVariableDescriptor>> incomingEdgesData) {
Set<LocalVariableDescriptor> initializedVariables = Sets.newHashSet();
initializedVariables.addAll(previousDataValue);
for (Set<LocalVariableDescriptor> edgeDataValue : incomingEdgesData) {
initializedVariables.addAll(edgeDataValue);
}
if (instruction instanceof WriteValueInstruction) {
JetElement element = ((WriteValueInstruction) instruction).getElement();
DeclarationDescriptor descriptor = null;
if (element instanceof JetBinaryExpression) {
JetExpression left = ((JetBinaryExpression) element).getLeft();
if (left instanceof JetSimpleNameExpression) {
descriptor = trace.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) left);
}
}
else if (element instanceof JetProperty) {
descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element);
}
if (descriptor instanceof LocalVariableDescriptor) {
initializedVariables.add((LocalVariableDescriptor) descriptor);
}
}
return initializedVariables;
}
};
Map<Instruction, Set<LocalVariableDescriptor>> dataMap = traverseInstructionGraphUntilFactsStabilization(instructions, instructionsMergeHandler, Collections.<LocalVariableDescriptor>emptySet(), true);
for (Instruction instruction : instructions) {
Set<LocalVariableDescriptor> initializedVariables = dataMap.get(instruction);
if (instruction instanceof ReadValueInstruction) {
JetElement element = ((ReadValueInstruction) instruction).getElement();
if (element instanceof JetSimpleNameExpression) {
DeclarationDescriptor descriptor = trace.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) element);
if (descriptor instanceof LocalVariableDescriptor) {
if (!initializedVariables.contains(descriptor)) {
trace.report(Errors.UNINITIALIZED_VARIABLE.on((JetSimpleNameExpression) element, descriptor));
}
}
}
}
else if (instruction instanceof WriteValueInstruction) {
JetElement element = ((WriteValueInstruction) instruction).getElement();
if (element instanceof JetSimpleNameExpression) {
DeclarationDescriptor descriptor = trace.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) element);
if (descriptor instanceof LocalVariableDescriptor) {
if (initializedVariables.contains(descriptor) && ((LocalVariableDescriptor) descriptor).isVar()) {
trace.report(Errors.VAL_REASSIGNMENT.on((JetSimpleNameExpression) element, descriptor));
}
}
}
}
}
}
interface InstructionsMergeHandler<D> {
D merge(Instruction instruction, D previousDataValue, Collection<D> incomingEdgesData);
}
}
@@ -142,6 +142,9 @@ public interface Errors {
};
PsiElementOnlyDiagnosticFactory3<JetModifierListOwner, CallableMemberDescriptor, CallableMemberDescriptor, DeclarationDescriptor> VIRTUAL_MEMBER_HIDDEN = PsiElementOnlyDiagnosticFactory3.create(ERROR, "''{0}'' hides ''{1}'' in class {2} and needs 'override' modifier", DescriptorRenderer.TEXT);
PsiElementOnlyDiagnosticFactory1<JetSimpleNameExpression, DeclarationDescriptor> UNINITIALIZED_VARIABLE = PsiElementOnlyDiagnosticFactory1.create(ERROR, "Variable ''{0}'' must be initialized", NAME);
PsiElementOnlyDiagnosticFactory1<JetSimpleNameExpression, DeclarationDescriptor> VAL_REASSIGNMENT = PsiElementOnlyDiagnosticFactory1.create(ERROR, "Val can not be reassigned", NAME);
SimpleDiagnosticFactory UNREACHABLE_CODE = SimpleDiagnosticFactory.create(ERROR, "Unreachable code");
SimpleDiagnosticFactory MANY_CLASS_OBJECTS = SimpleDiagnosticFactory.create(ERROR, "Only one class object is allowed per class");
@@ -108,6 +108,8 @@ public class ControlFlowAnalyzer {
}
});
}
//flowInformationProvider.markUninitializedVariables(function.asElement());
}
private void checkProperty(JetProperty property) {