Added 'Uninitialized variable' error
This commit is contained in:
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user