Added checks for an initialization of properties using backing fields, not using setters
This commit is contained in:
@@ -3,18 +3,18 @@ package org.jetbrains.jet.lang.cfg;
|
|||||||
import com.google.common.collect.Lists;
|
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 com.intellij.openapi.util.Pair;
|
||||||
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.pseudocode.*;
|
import org.jetbrains.jet.lang.cfg.pseudocode.*;
|
||||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
import org.jetbrains.jet.lang.descriptors.*;
|
||||||
import org.jetbrains.jet.lang.descriptors.LocalVariableDescriptor;
|
|
||||||
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
|
|
||||||
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
|
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
|
||||||
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.*;
|
||||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
||||||
import org.jetbrains.jet.lang.types.JetStandardClasses;
|
import org.jetbrains.jet.lang.types.JetStandardClasses;
|
||||||
|
import org.jetbrains.jet.lexer.JetTokens;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@@ -259,13 +259,16 @@ public class JetFlowInformationProvider {
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
public void markUninitializedVariables(@NotNull JetElement subroutine, List<? extends VariableDescriptor> initializedVariables) {
|
public void markUninitializedVariables(
|
||||||
Pseudocode pseudocode = pseudocodeMap.get(subroutine);
|
@NotNull JetElement subroutine,
|
||||||
|
final boolean inAnonymousInitializers) {
|
||||||
|
final Pseudocode pseudocode = pseudocodeMap.get(subroutine);
|
||||||
assert pseudocode != null;
|
assert pseudocode != null;
|
||||||
|
|
||||||
JetControlFlowGraphTraverser.InstructionsMergeStrategy<Map<VariableDescriptor, InitializationPoints>> instructionsMergeStrategy = new JetControlFlowGraphTraverser.InstructionsMergeStrategy<Map<VariableDescriptor, InitializationPoints>>() {
|
JetControlFlowGraphTraverser.InstructionsMergeStrategy<Map<VariableDescriptor, InitializationPoints>> instructionsMergeStrategy =
|
||||||
|
new JetControlFlowGraphTraverser.InstructionsMergeStrategy<Map<VariableDescriptor, InitializationPoints>>() {
|
||||||
@Override
|
@Override
|
||||||
public Map<VariableDescriptor, InitializationPoints> execute(
|
public Pair<Map<VariableDescriptor, InitializationPoints>, Map<VariableDescriptor, InitializationPoints>> execute(
|
||||||
Instruction instruction,
|
Instruction instruction,
|
||||||
Collection<Map<VariableDescriptor, InitializationPoints>> incomingEdgesData) {
|
Collection<Map<VariableDescriptor, InitializationPoints>> incomingEdgesData) {
|
||||||
|
|
||||||
@@ -274,7 +277,7 @@ public class JetFlowInformationProvider {
|
|||||||
variablesInScope.addAll(edgePointsMap.keySet());
|
variablesInScope.addAll(edgePointsMap.keySet());
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<VariableDescriptor, InitializationPoints> pointsMap = Maps.newHashMap();
|
Map<VariableDescriptor, InitializationPoints> enterInstructionPointsMap = Maps.newHashMap();
|
||||||
for (VariableDescriptor variable : variablesInScope) {
|
for (VariableDescriptor variable : variablesInScope) {
|
||||||
Set<InitializationPoints> edgesDataForVariable = Sets.newHashSet();
|
Set<InitializationPoints> edgesDataForVariable = Sets.newHashSet();
|
||||||
for (Map<VariableDescriptor, InitializationPoints> edgePointsMap : incomingEdgesData) {
|
for (Map<VariableDescriptor, InitializationPoints> edgePointsMap : incomingEdgesData) {
|
||||||
@@ -283,43 +286,64 @@ public class JetFlowInformationProvider {
|
|||||||
edgesDataForVariable.add(points);
|
edgesDataForVariable.add(points);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pointsMap.put(variable, new InitializationPoints(edgesDataForVariable));
|
enterInstructionPointsMap.put(variable, new InitializationPoints(edgesDataForVariable));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Map<VariableDescriptor, InitializationPoints> exitInstructionPointsMap = Maps.newHashMap(enterInstructionPointsMap);
|
||||||
if (instruction instanceof WriteValueInstruction) {
|
if (instruction instanceof WriteValueInstruction) {
|
||||||
VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction);
|
VariableDescriptor variable = extractVariableDescriptorIfAny(instruction);
|
||||||
InitializationPoints initializationAtThisPoint = new InitializationPoints(((WriteValueInstruction) instruction).getElement());
|
InitializationPoints initializationAtThisPoint = new InitializationPoints(((WriteValueInstruction) instruction).getElement());
|
||||||
pointsMap.put(variableDescriptor, initializationAtThisPoint);
|
exitInstructionPointsMap.put(variable, initializationAtThisPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
return pointsMap;
|
return Pair.create(enterInstructionPointsMap, exitInstructionPointsMap);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Set<VariableDescriptor> localVariables = collectAllLocalVariables(pseudocode);
|
Collection<VariableDescriptor> usedVariables = collectUsedVariables(pseudocode);
|
||||||
|
Collection<VariableDescriptor> declaredVariables = collectDeclaredVariables(subroutine);
|
||||||
|
|
||||||
Map<VariableDescriptor, InitializationPoints> initialMapForStartInstruction = Maps.newHashMap();
|
Map<VariableDescriptor, InitializationPoints> initialMapForStartInstruction = Maps.newHashMap();
|
||||||
InitializationPoints initialPointsForLocalVariable = new InitializationPoints(true);
|
InitializationPoints initialPointsForDeclaredVariable = new InitializationPoints(true);
|
||||||
for (VariableDescriptor variable : localVariables) {
|
InitializationPoints initialPointsForExternalVariable = new InitializationPoints(false);
|
||||||
initialMapForStartInstruction.put(variable, initialPointsForLocalVariable);
|
|
||||||
|
for (VariableDescriptor variable : usedVariables) {
|
||||||
|
if (declaredVariables.contains(variable)) {
|
||||||
|
initialMapForStartInstruction.put(variable, initialPointsForDeclaredVariable);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
initialMapForStartInstruction.put(variable, initialPointsForExternalVariable);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
InitializationPoints initialPointsForParameter = new InitializationPoints(false);
|
final Map<Instruction, Pair<Map<VariableDescriptor, InitializationPoints>, Map<VariableDescriptor, InitializationPoints>>> dataMap =
|
||||||
for (VariableDescriptor initializedVariable : initializedVariables) {
|
JetControlFlowGraphTraverser.traverseInstructionGraphUntilFactsStabilization(pseudocode,
|
||||||
initialMapForStartInstruction.put(initializedVariable, initialPointsForParameter);
|
instructionsMergeStrategy,
|
||||||
}
|
Collections.<VariableDescriptor, InitializationPoints>emptyMap(),
|
||||||
final Map<Instruction, Map<VariableDescriptor, InitializationPoints>> dataMap =
|
initialMapForStartInstruction,
|
||||||
JetControlFlowGraphTraverser.traverseInstructionGraphUntilFactsStabilization(pseudocode, instructionsMergeStrategy, Collections.<VariableDescriptor, InitializationPoints>emptyMap(), initialMapForStartInstruction, true);
|
true);
|
||||||
|
|
||||||
JetControlFlowGraphTraverser.traverseAndAnalyzeInstructionGraph(pseudocode, new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy() {
|
JetControlFlowGraphTraverser.traverseAndAnalyzeInstructionGraph(pseudocode, new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy() {
|
||||||
@Override
|
@Override
|
||||||
public void execute(Instruction instruction) {
|
public void execute(Instruction instruction) {
|
||||||
Map<VariableDescriptor, InitializationPoints> variablesData = dataMap.get(instruction);
|
Pair<Map<VariableDescriptor, InitializationPoints>, Map<VariableDescriptor, InitializationPoints>> variablesData = dataMap.get(instruction);
|
||||||
|
Map<VariableDescriptor, InitializationPoints> enterData = variablesData.getFirst();
|
||||||
|
Map<VariableDescriptor, InitializationPoints> exitData = variablesData.getSecond();
|
||||||
if (instruction instanceof ReadValueInstruction) {
|
if (instruction instanceof ReadValueInstruction) {
|
||||||
VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction);
|
VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction);
|
||||||
JetElement element = ((ReadValueInstruction) instruction).getElement();
|
JetElement element = ((ReadValueInstruction) instruction).getElement();
|
||||||
if (element instanceof JetSimpleNameExpression && variableDescriptor instanceof LocalVariableDescriptor) {
|
if (element instanceof JetSimpleNameExpression && variableDescriptor != null &&
|
||||||
InitializationPoints initializationPoints = variablesData.get(variableDescriptor);
|
(inAnonymousInitializers || variableDescriptor instanceof LocalVariableDescriptor)) {
|
||||||
assert initializationPoints != null;
|
|
||||||
if (initializationPoints.canBeUninitialized) {
|
InitializationPoints exitInitializationPoints = exitData.get(variableDescriptor);
|
||||||
|
assert exitInitializationPoints != null;
|
||||||
|
|
||||||
|
boolean canBeUnitialized = exitInitializationPoints.canBeUninitialized();
|
||||||
|
if (variableDescriptor instanceof PropertyDescriptor) {
|
||||||
|
if (!trace.get(BindingContext.BACKING_FIELD_REQUIRED, (PropertyDescriptor) variableDescriptor)) {
|
||||||
|
canBeUnitialized = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (canBeUnitialized) {
|
||||||
trace.report(Errors.UNINITIALIZED_VARIABLE.on((JetSimpleNameExpression) element, variableDescriptor));
|
trace.report(Errors.UNINITIALIZED_VARIABLE.on((JetSimpleNameExpression) element, variableDescriptor));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -328,15 +352,43 @@ public class JetFlowInformationProvider {
|
|||||||
JetElement element = ((WriteValueInstruction) instruction).getlValue();
|
JetElement element = ((WriteValueInstruction) instruction).getlValue();
|
||||||
VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction);
|
VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction);
|
||||||
if (element instanceof JetSimpleNameExpression && variableDescriptor != null) {
|
if (element instanceof JetSimpleNameExpression && variableDescriptor != null) {
|
||||||
InitializationPoints initializationPoints = variablesData.get(variableDescriptor);
|
InitializationPoints enterInitializationPoints = enterData.get(variableDescriptor);
|
||||||
assert initializationPoints != null;
|
assert enterInitializationPoints != null;
|
||||||
if (initializationPoints.hasPossibleInitializers() && !variableDescriptor.isVar()) {
|
InitializationPoints exitInitializationPoints = exitData.get(variableDescriptor);
|
||||||
trace.report(Errors.VAL_REASSIGNMENT.on((JetSimpleNameExpression) element, variableDescriptor));
|
assert exitInitializationPoints != null;
|
||||||
|
Set<JetElement> possiblePoints = enterInitializationPoints.getPossiblePoints();
|
||||||
|
boolean hasAnotherInitializer = !possiblePoints.isEmpty() || !enterInitializationPoints.canBeUninitialized;
|
||||||
|
if (possiblePoints.size() == 1) {
|
||||||
|
JetElement initializer = possiblePoints.iterator().next();
|
||||||
|
if (initializer == element.getParent()) {
|
||||||
|
hasAnotherInitializer = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
JetSimpleNameExpression expression = (JetSimpleNameExpression) element;
|
||||||
|
if (hasAnotherInitializer && !variableDescriptor.isVar()) {
|
||||||
|
trace.report(Errors.VAL_REASSIGNMENT.on(expression, variableDescriptor));
|
||||||
|
}
|
||||||
|
if (inAnonymousInitializers && variableDescriptor instanceof PropertyDescriptor &&
|
||||||
|
enterInitializationPoints.canBeUninitialized && !exitInitializationPoints.canBeUninitialized) {
|
||||||
|
if (expression.getReferencedNameElementType() != JetTokens.FIELD_IDENTIFIER) {
|
||||||
|
trace.report(Errors.INITIALIZATION_USING_BACKING_FIELD.on(expression, variableDescriptor));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (inAnonymousInitializers) {
|
||||||
|
Map<VariableDescriptor, InitializationPoints> lastInfo = dataMap.get(pseudocode.getExitInstruction()).getFirst();
|
||||||
|
for (Map.Entry<VariableDescriptor, InitializationPoints> entry : lastInfo.entrySet()) {
|
||||||
|
VariableDescriptor variable = entry.getKey();
|
||||||
|
if (variable instanceof PropertyDescriptor) {
|
||||||
|
InitializationPoints initializationPoints = entry.getValue();
|
||||||
|
trace.record(BindingContext.IS_INITIALIZED, (PropertyDescriptor) variable, !initializationPoints.canBeUninitialized);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void markNotOnlyInvokedFunctionVariables(@NotNull JetElement subroutine, List<? extends VariableDescriptor> variables) {
|
public void markNotOnlyInvokedFunctionVariables(@NotNull JetElement subroutine, List<? extends VariableDescriptor> variables) {
|
||||||
@@ -395,19 +447,43 @@ public class JetFlowInformationProvider {
|
|||||||
return variableDescriptor;
|
return variableDescriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<VariableDescriptor> collectAllLocalVariables(Pseudocode pseudocode) {
|
private Collection<VariableDescriptor> collectUsedVariables(Pseudocode pseudocode) {
|
||||||
final Set<VariableDescriptor> localVariables = Sets.newHashSet();
|
final Set<VariableDescriptor> usedVariables = Sets.newHashSet();
|
||||||
JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy analyzeStrategy = new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy() {
|
JetControlFlowGraphTraverser.traverseAndAnalyzeInstructionGraph(pseudocode, new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy() {
|
||||||
@Override
|
@Override
|
||||||
public void execute(Instruction instruction) {
|
public void execute(Instruction instruction) {
|
||||||
VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction);
|
VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction);
|
||||||
if (variableDescriptor != null) {
|
if (variableDescriptor != null) {
|
||||||
localVariables.add(variableDescriptor);
|
usedVariables.add(variableDescriptor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
JetControlFlowGraphTraverser.traverseAndAnalyzeInstructionGraph(pseudocode, analyzeStrategy);
|
return usedVariables;
|
||||||
return localVariables;
|
}
|
||||||
|
|
||||||
|
private Collection<VariableDescriptor> collectDeclaredVariables(JetElement element) {
|
||||||
|
final Set<VariableDescriptor> concernedVariables = Sets.newHashSet();
|
||||||
|
element.accept(new JetTreeVisitor<Void>() {
|
||||||
|
@Override
|
||||||
|
public Void visitProperty(JetProperty property, Void data) {
|
||||||
|
DeclarationDescriptor descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, property);
|
||||||
|
assert descriptor instanceof VariableDescriptor;
|
||||||
|
concernedVariables.add((VariableDescriptor) descriptor);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Void visitForExpression(JetForExpression expression, Void data) {
|
||||||
|
JetParameter loopParameter = expression.getLoopParameter();
|
||||||
|
if (loopParameter != null) {
|
||||||
|
DeclarationDescriptor descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, loopParameter);
|
||||||
|
assert descriptor instanceof VariableDescriptor;
|
||||||
|
concernedVariables.add((VariableDescriptor) descriptor);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}, null);
|
||||||
|
return concernedVariables;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class InitializationPoints {
|
private static class InitializationPoints {
|
||||||
@@ -433,8 +509,12 @@ public class JetFlowInformationProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasPossibleInitializers() {
|
public Set<JetElement> getPossiblePoints() {
|
||||||
return !possiblePoints.isEmpty();
|
return possiblePoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canBeUninitialized() {
|
||||||
|
return canBeUninitialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -144,8 +144,9 @@ public interface Errors {
|
|||||||
|
|
||||||
PsiElementOnlyDiagnosticFactory1<JetSimpleNameExpression, DeclarationDescriptor> UNINITIALIZED_VARIABLE = PsiElementOnlyDiagnosticFactory1.create(ERROR, "Variable ''{0}'' must be initialized", NAME);
|
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);
|
PsiElementOnlyDiagnosticFactory1<JetSimpleNameExpression, DeclarationDescriptor> VAL_REASSIGNMENT = PsiElementOnlyDiagnosticFactory1.create(ERROR, "Val can not be reassigned", NAME);
|
||||||
|
PsiElementOnlyDiagnosticFactory1<JetSimpleNameExpression, DeclarationDescriptor> INITIALIZATION_USING_BACKING_FIELD = PsiElementOnlyDiagnosticFactory1.create(ERROR, "Initialization using backing field required", NAME);
|
||||||
|
|
||||||
PsiElementOnlyDiagnosticFactory1<JetSimpleNameExpression, DeclarationDescriptor> FUNCTION_PARAMETERS_OF_INLINE_FUNCTION = PsiElementOnlyDiagnosticFactory1.create(ERROR, "Funciton parameters of inline funciton can only be invoked", NAME);
|
PsiElementOnlyDiagnosticFactory1<JetSimpleNameExpression, DeclarationDescriptor> FUNCTION_PARAMETERS_OF_INLINE_FUNCTION = PsiElementOnlyDiagnosticFactory1.create(ERROR, "Function parameters of inline function can only be invoked", NAME);
|
||||||
|
|
||||||
SimpleDiagnosticFactory UNREACHABLE_CODE = SimpleDiagnosticFactory.create(ERROR, "Unreachable code");
|
SimpleDiagnosticFactory UNREACHABLE_CODE = SimpleDiagnosticFactory.create(ERROR, "Unreachable code");
|
||||||
|
|
||||||
|
|||||||
@@ -296,7 +296,7 @@ public class BodyResolver {
|
|||||||
ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor();
|
ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor();
|
||||||
assert primaryConstructor != null;
|
assert primaryConstructor != null;
|
||||||
final JetScope scopeForConstructor = getInnerScopeForConstructor(primaryConstructor, classDescriptor.getScopeForMemberResolution(), true);
|
final JetScope scopeForConstructor = getInnerScopeForConstructor(primaryConstructor, classDescriptor.getScopeForMemberResolution(), true);
|
||||||
ExpressionTypingServices typeInferrer = context.getSemanticServices().getTypeInferrerServices(createFieldAssignTrackingTrace()); // TODO : flow
|
ExpressionTypingServices typeInferrer = context.getSemanticServices().getTypeInferrerServices(traceForConstructors);
|
||||||
for (JetClassInitializer anonymousInitializer : anonymousInitializers) {
|
for (JetClassInitializer anonymousInitializer : anonymousInitializers) {
|
||||||
typeInferrer.getType(scopeForConstructor, anonymousInitializer.getBody(), NO_EXPECTED_TYPE);
|
typeInferrer.getType(scopeForConstructor, anonymousInitializer.getBody(), NO_EXPECTED_TYPE);
|
||||||
}
|
}
|
||||||
@@ -506,22 +506,6 @@ public class BodyResolver {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private ObservableBindingTrace createFieldAssignTrackingTrace() {
|
|
||||||
return new ObservableBindingTrace(traceForConstructors).addHandler(BindingContext.VARIABLE_ASSIGNMENT, new ObservableBindingTrace.RecordHandler<JetExpression, DeclarationDescriptor>() {
|
|
||||||
@Override
|
|
||||||
public void handleRecord(WritableSlice<JetExpression, DeclarationDescriptor> jetExpressionBooleanWritableSlice, JetExpression expression, DeclarationDescriptor descriptor) {
|
|
||||||
if (expression instanceof JetSimpleNameExpression) {
|
|
||||||
JetSimpleNameExpression variable = (JetSimpleNameExpression) expression;
|
|
||||||
if (variable.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER) {
|
|
||||||
if (descriptor instanceof PropertyDescriptor) {
|
|
||||||
traceForMembers.record(BindingContext.IS_INITIALIZED, (PropertyDescriptor) descriptor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void resolvePropertyInitializer(JetProperty property, PropertyDescriptor propertyDescriptor, JetExpression initializer, JetScope scope) {
|
private void resolvePropertyInitializer(JetProperty property, PropertyDescriptor propertyDescriptor, JetExpression initializer, JetScope scope) {
|
||||||
//JetFlowInformationProvider flowInformationProvider = context.getClassDescriptorResolver().computeFlowData(property, initializer); // TODO : flow JET-15
|
//JetFlowInformationProvider flowInformationProvider = context.getClassDescriptorResolver().computeFlowData(property, initializer); // TODO : flow JET-15
|
||||||
ExpressionTypingServices typeInferrer = context.getSemanticServices().getTypeInferrerServices(traceForConstructors);
|
ExpressionTypingServices typeInferrer = context.getSemanticServices().getTypeInferrerServices(traceForConstructors);
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ public class TopDownAnalyzer {
|
|||||||
new DelegationResolver(context).process();
|
new DelegationResolver(context).process();
|
||||||
new OverrideResolver(context).process();
|
new OverrideResolver(context).process();
|
||||||
new BodyResolver(context).resolveBehaviorDeclarationBodies();
|
new BodyResolver(context).resolveBehaviorDeclarationBodies();
|
||||||
new DeclarationsChecker(context).process();
|
|
||||||
new ControlFlowAnalyzer(context, flowDataTraceFactory, declaredLocally).process();
|
new ControlFlowAnalyzer(context, flowDataTraceFactory, declaredLocally).process();
|
||||||
|
new DeclarationsChecker(context).process();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void processStandardLibraryNamespace(
|
public static void processStandardLibraryNamespace(
|
||||||
|
|||||||
@@ -1,106 +0,0 @@
|
|||||||
namespace uninitialized_vals {
|
|
||||||
|
|
||||||
fun t1(b : Boolean) {
|
|
||||||
val v : Int
|
|
||||||
if (<!UNINITIALIZED_VARIABLE!>v<!> == 0) {}
|
|
||||||
|
|
||||||
var u: String
|
|
||||||
if (b) {
|
|
||||||
u = "s"
|
|
||||||
}
|
|
||||||
doSmth(<!UNINITIALIZED_VARIABLE!>u<!>)
|
|
||||||
|
|
||||||
var r: String
|
|
||||||
if (b) {
|
|
||||||
r = "s"
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
r = "tg"
|
|
||||||
}
|
|
||||||
doSmth(r)
|
|
||||||
|
|
||||||
var t: String
|
|
||||||
if (b)
|
|
||||||
doSmth(<!UNINITIALIZED_VARIABLE!>t<!>)
|
|
||||||
else
|
|
||||||
t = "ss"
|
|
||||||
doSmth(<!UNINITIALIZED_VARIABLE!>t<!>)
|
|
||||||
|
|
||||||
val i = 3
|
|
||||||
doSmth(i)
|
|
||||||
if (b) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
doSmth(i)
|
|
||||||
if (i is Int) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun t2() {
|
|
||||||
val s = "ss"
|
|
||||||
|
|
||||||
for (i in 0..2) {
|
|
||||||
doSmth(s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun doSmth(s: String) {}
|
|
||||||
fun doSmth(i: Int) {}
|
|
||||||
|
|
||||||
class A() {}
|
|
||||||
|
|
||||||
fun t4(a: A, val b: A, var c: A) {
|
|
||||||
<!VAL_REASSIGNMENT!>a<!> = A()
|
|
||||||
<!VAL_REASSIGNMENT!>b<!> = A()
|
|
||||||
c = A()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace reassigned_vals {
|
|
||||||
|
|
||||||
fun t1() {
|
|
||||||
val a : Int = 1
|
|
||||||
<!VAL_REASSIGNMENT!>a<!> = 2
|
|
||||||
|
|
||||||
var b : Int = 1
|
|
||||||
b = 3
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract enum class ProtocolState {
|
|
||||||
WAITING {
|
|
||||||
override fun signal() = ProtocolState.TALKING
|
|
||||||
}
|
|
||||||
|
|
||||||
TALKING {
|
|
||||||
override fun signal() = ProtocolState.WAITING
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract fun signal() : ProtocolState
|
|
||||||
}
|
|
||||||
|
|
||||||
fun t2() {
|
|
||||||
val x: ProtocolState = ProtocolState.WAITING
|
|
||||||
<!VAL_REASSIGNMENT!>x<!> = x.signal()
|
|
||||||
<!VAL_REASSIGNMENT!>x<!> = x.signal()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun t3() {
|
|
||||||
val x = 1
|
|
||||||
<!VAL_REASSIGNMENT!>x<!> += 2
|
|
||||||
val y = 3
|
|
||||||
<!VAL_REASSIGNMENT!>y<!> *= 4
|
|
||||||
var z = 5
|
|
||||||
z -= y
|
|
||||||
}
|
|
||||||
|
|
||||||
fun t4() {
|
|
||||||
for (i in 0..2) {
|
|
||||||
<!VAL_REASSIGNMENT!>i<!> += 1
|
|
||||||
fun t5() {
|
|
||||||
<!VAL_REASSIGNMENT!>i<!> += 3
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,250 @@
|
|||||||
|
namespace uninitialized_reassigned_variables
|
||||||
|
|
||||||
|
fun doSmth(s: String) {}
|
||||||
|
fun doSmth(i: Int) {}
|
||||||
|
|
||||||
|
// ------------------------------------------------
|
||||||
|
// uninitialized variables
|
||||||
|
|
||||||
|
fun t1(b : Boolean) {
|
||||||
|
val v : Int
|
||||||
|
if (<!UNINITIALIZED_VARIABLE!>v<!> == 0) {}
|
||||||
|
|
||||||
|
var u: String
|
||||||
|
if (b) {
|
||||||
|
u = "s"
|
||||||
|
}
|
||||||
|
doSmth(<!UNINITIALIZED_VARIABLE!>u<!>)
|
||||||
|
|
||||||
|
var r: String
|
||||||
|
if (b) {
|
||||||
|
r = "s"
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
r = "tg"
|
||||||
|
}
|
||||||
|
doSmth(r)
|
||||||
|
|
||||||
|
var t: String
|
||||||
|
if (b)
|
||||||
|
doSmth(<!UNINITIALIZED_VARIABLE!>t<!>)
|
||||||
|
else
|
||||||
|
t = "ss"
|
||||||
|
doSmth(<!UNINITIALIZED_VARIABLE!>t<!>)
|
||||||
|
|
||||||
|
val i = 3
|
||||||
|
doSmth(i)
|
||||||
|
if (b) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
doSmth(i)
|
||||||
|
if (i is Int) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun t2() {
|
||||||
|
val s = "ss"
|
||||||
|
|
||||||
|
for (i in 0..2) {
|
||||||
|
doSmth(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class A() {}
|
||||||
|
|
||||||
|
fun t4(a: A, val b: A, var c: A) {
|
||||||
|
<!VAL_REASSIGNMENT!>a<!> = A()
|
||||||
|
<!VAL_REASSIGNMENT!>b<!> = A()
|
||||||
|
c = A()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------
|
||||||
|
// reassigned vals
|
||||||
|
|
||||||
|
fun t1() {
|
||||||
|
val a : Int = 1
|
||||||
|
<!VAL_REASSIGNMENT!>a<!> = 2
|
||||||
|
|
||||||
|
var b : Int = 1
|
||||||
|
b = 3
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract enum class ProtocolState {
|
||||||
|
WAITING {
|
||||||
|
override fun signal() = ProtocolState.TALKING
|
||||||
|
}
|
||||||
|
|
||||||
|
TALKING {
|
||||||
|
override fun signal() = ProtocolState.WAITING
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract fun signal() : ProtocolState
|
||||||
|
}
|
||||||
|
|
||||||
|
fun t2() {
|
||||||
|
val x: ProtocolState = ProtocolState.WAITING
|
||||||
|
<!VAL_REASSIGNMENT!>x<!> = x.signal()
|
||||||
|
<!VAL_REASSIGNMENT!>x<!> = x.signal()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun t3() {
|
||||||
|
val x = 1
|
||||||
|
<!VAL_REASSIGNMENT!>x<!> += 2
|
||||||
|
val y = 3
|
||||||
|
<!VAL_REASSIGNMENT!>y<!> *= 4
|
||||||
|
var z = 5
|
||||||
|
z -= y
|
||||||
|
}
|
||||||
|
|
||||||
|
fun t4() {
|
||||||
|
for (i in 0..2) {
|
||||||
|
<!VAL_REASSIGNMENT!>i<!> += 1
|
||||||
|
fun t5() {
|
||||||
|
<!VAL_REASSIGNMENT!>i<!> += 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------
|
||||||
|
// backing fields
|
||||||
|
|
||||||
|
var x = 10
|
||||||
|
val y = 10
|
||||||
|
val z = 10
|
||||||
|
|
||||||
|
class AnonymousInitializers(var a: String, val b: String) {
|
||||||
|
{
|
||||||
|
$a = "30"
|
||||||
|
a = "s"
|
||||||
|
|
||||||
|
<!VAL_REASSIGNMENT!>$b<!> = "3"
|
||||||
|
<!VAL_REASSIGNMENT!>b<!> = "tt"
|
||||||
|
}
|
||||||
|
|
||||||
|
val i: Int
|
||||||
|
{
|
||||||
|
$i = 121
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
x = 11
|
||||||
|
<!UNRESOLVED_REFERENCE!>$y<!> = 11
|
||||||
|
<!VAL_REASSIGNMENT!>z<!> = 10
|
||||||
|
}
|
||||||
|
|
||||||
|
val j: Int
|
||||||
|
get() = 20
|
||||||
|
|
||||||
|
{
|
||||||
|
<!VAL_REASSIGNMENT!>$i<!> = 13
|
||||||
|
<!NO_BACKING_FIELD!>$j<!> = 30
|
||||||
|
<!VAL_REASSIGNMENT!>j<!> = 34
|
||||||
|
}
|
||||||
|
|
||||||
|
val k: String
|
||||||
|
{
|
||||||
|
if (1 < 3) {
|
||||||
|
<!INITIALIZATION_USING_BACKING_FIELD!>k<!> = "a"
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$k = "b"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val l: String
|
||||||
|
{
|
||||||
|
if (1 < 3) {
|
||||||
|
$l = "a"
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$l = "b"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val <!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>o<!>: String
|
||||||
|
{
|
||||||
|
if (1 < 3) {
|
||||||
|
$o = "a"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var m: Int = 30
|
||||||
|
|
||||||
|
{
|
||||||
|
$m = 400
|
||||||
|
}
|
||||||
|
|
||||||
|
val n: Int
|
||||||
|
|
||||||
|
{
|
||||||
|
while (<!UNINITIALIZED_VARIABLE!>n<!> == 0) {
|
||||||
|
}
|
||||||
|
$n = 10
|
||||||
|
while (n == 0) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var p = 1
|
||||||
|
{
|
||||||
|
p++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun reassignFunParams(val a: Int) {
|
||||||
|
<!VAL_REASSIGNMENT!>a<!> = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
open class Open(a: Int, w: Int) {}
|
||||||
|
|
||||||
|
class LocalValsVsProperties(val a: Int, w: Int) : Open(a, w) {
|
||||||
|
val x : Int
|
||||||
|
val <!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>y<!> : Int
|
||||||
|
{
|
||||||
|
$x = 1
|
||||||
|
val b = x
|
||||||
|
}
|
||||||
|
val b = a
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
val r : Int
|
||||||
|
doSmth(x)
|
||||||
|
doSmth(y)
|
||||||
|
doSmth(<!UNINITIALIZED_VARIABLE!>r<!>)
|
||||||
|
doSmth(a)
|
||||||
|
}
|
||||||
|
var xx = w
|
||||||
|
var yy : Int
|
||||||
|
{
|
||||||
|
<!VAL_REASSIGNMENT!>w<!> += 1
|
||||||
|
$yy = w
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Outer() {
|
||||||
|
val a : Int
|
||||||
|
var b : Int
|
||||||
|
|
||||||
|
{
|
||||||
|
$a = 1
|
||||||
|
$b = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
class Inner() {
|
||||||
|
{
|
||||||
|
<!VAL_REASSIGNMENT!>a<!>++
|
||||||
|
b++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
<!VAL_REASSIGNMENT!>a<!>++
|
||||||
|
b++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ForwardAccessToBackingField() { //kt-147
|
||||||
|
val a = <!UNRESOLVED_REFERENCE, UNINITIALIZED_VARIABLE!>$a<!> // error
|
||||||
|
val b = <!UNINITIALIZED_VARIABLE!>$c<!> // error
|
||||||
|
val c = 1
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user