diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowGraphTraverser.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowGraphTraverser.java index d9b090ff885..9eda16b291a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowGraphTraverser.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowGraphTraverser.java @@ -31,7 +31,7 @@ public class JetControlFlowGraphTraverser { } public void collectInformationFromInstructionGraph( - InstructionsMergeStrategy instructionsMergeStrategy, + InstructionDataMergeStrategy instructionDataMergeStrategy, D initialDataValue, D initialDataValueForEnterInstruction, boolean straightDirection) { @@ -43,7 +43,7 @@ public class JetControlFlowGraphTraverser { changed[0] = true; while (changed[0]) { changed[0] = false; - traverseSubGraph(pseudocode, instructionsMergeStrategy, Collections.emptyList(), straightDirection, changed, false); + traverseSubGraph(pseudocode, instructionDataMergeStrategy, Collections.emptyList(), straightDirection, changed, false); } } @@ -62,7 +62,7 @@ public class JetControlFlowGraphTraverser { private void traverseSubGraph( Pseudocode pseudocode, - InstructionsMergeStrategy instructionsMergeStrategy, + InstructionDataMergeStrategy instructionDataMergeStrategy, Collection previousSubGraphInstructions, boolean straightDirection, boolean[] changed, @@ -87,7 +87,7 @@ public class JetControlFlowGraphTraverser { if (lookInside && instruction instanceof LocalDeclarationInstruction) { Pseudocode subroutinePseudocode = ((LocalDeclarationInstruction) instruction).getBody(); - traverseSubGraph(subroutinePseudocode, instructionsMergeStrategy, previousInstructions, straightDirection, changed, true); + traverseSubGraph(subroutinePseudocode, instructionDataMergeStrategy, previousInstructions, straightDirection, changed, true); } Pair previousDataValue = dataMap.get(instruction); @@ -99,7 +99,7 @@ public class JetControlFlowGraphTraverser { incomingEdgesData.add(previousData.getSecond()); } } - Pair mergedData = instructionsMergeStrategy.execute(instruction, incomingEdgesData); + Pair mergedData = instructionDataMergeStrategy.execute(instruction, incomingEdgesData); if (!mergedData.equals(previousDataValue)) { changed[0] = true; dataMap.put(instruction, mergedData); @@ -132,7 +132,7 @@ public class JetControlFlowGraphTraverser { return dataMap.get(pseudocode.getSinkInstruction()).getFirst(); } - interface InstructionsMergeStrategy { + interface InstructionDataMergeStrategy { Pair execute(Instruction instruction, @NotNull Collection incomingEdgesData); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java index 426048e91fb..c88b2264c5d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java @@ -187,176 +187,204 @@ public class JetFlowInformationProvider { return JetPsiUtil.findRootExpressions(unreachableElements); } - public void markUninitializedVariables(@NotNull JetElement subroutine, final boolean inAnonymousInitializers, final boolean inLocalDeclaration) { +//////////////////////////////////////////////////////////////////////////////// +// Uninitialized variables analysis + + public void markUninitializedVariables(@NotNull JetElement subroutine, final boolean processLocalDeclaration) { final Pseudocode pseudocode = pseudocodeMap.get(subroutine); assert pseudocode != null; - JetControlFlowGraphTraverser> traverser = JetControlFlowGraphTraverser.create(pseudocode, false); - - JetControlFlowGraphTraverser.InstructionsMergeStrategy> instructionsMergeStrategy = - new JetControlFlowGraphTraverser.InstructionsMergeStrategy>() { - @Override - public Pair, Map> execute( - Instruction instruction, - @NotNull Collection> incomingEdgesData) { - - Set variablesInScope = Sets.newHashSet(); - for (Map edgePointsMap : incomingEdgesData) { - variablesInScope.addAll(edgePointsMap.keySet()); - } - - Map enterInstructionPointsMap = Maps.newHashMap(); - for (VariableDescriptor variable : variablesInScope) { - Set edgesDataForVariable = Sets.newHashSet(); - for (Map edgePointsMap : incomingEdgesData) { - InitializationPoints points = edgePointsMap.get(variable); - if (points != null) { - edgesDataForVariable.add(points); - } - } - enterInstructionPointsMap.put(variable, new InitializationPoints(edgesDataForVariable)); - } - - Map exitInstructionPointsMap = Maps.newHashMap(enterInstructionPointsMap); - if (instruction instanceof WriteValueInstruction) { - VariableDescriptor variable = extractVariableDescriptorIfAny(instruction, false); - InitializationPoints initializationAtThisPoint = new InitializationPoints(((WriteValueInstruction) instruction).getElement()); - exitInstructionPointsMap.put(variable, initializationAtThisPoint); - } - - return Pair.create(enterInstructionPointsMap, exitInstructionPointsMap); - } - }; + JetControlFlowGraphTraverser> traverser = JetControlFlowGraphTraverser.create(pseudocode, false); Collection usedVariables = collectUsedVariables(pseudocode); final Collection declaredVariables = collectDeclaredVariables(subroutine); - Map initialMapForStartInstruction = prepareInitialMapForStartInstruction(usedVariables, declaredVariables); - - traverser.collectInformationFromInstructionGraph(instructionsMergeStrategy, - Collections.emptyMap(), - initialMapForStartInstruction, - true); + Map initialMapForStartInstruction = prepareInitialMapForStartInstruction(usedVariables, declaredVariables); + + JetControlFlowGraphTraverser.InstructionDataMergeStrategy> variableInitializersMergeStrategy = + new JetControlFlowGraphTraverser.InstructionDataMergeStrategy>() { + @Override + public Pair, Map> execute( + Instruction instruction, + @NotNull Collection> incomingEdgesData) { + + Map enterInstructionData = mergeIncomingEdgesData(incomingEdgesData); + Map exitInstructionData = addVariableInitializerFromCurrentInstructionIfAny(instruction, enterInstructionData); + return Pair.create(enterInstructionData, exitInstructionData); + } + }; + + traverser.collectInformationFromInstructionGraph(variableInitializersMergeStrategy, Collections.emptyMap(), initialMapForStartInstruction, true); final Collection varWithUninitializedErrorGenerated = Sets.newHashSet(); final Collection varWithValReassignErrorGenerated = Sets.newHashSet(); - traverser.traverseAndAnalyzeInstructionGraph(new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy>() { + final boolean processClassOrObject = subroutine instanceof JetClassOrObject; + traverser.traverseAndAnalyzeInstructionGraph(new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy>() { @Override - public void execute(Instruction instruction, @Nullable Map enterData, @Nullable Map exitData) { + public void execute(Instruction instruction, @Nullable Map enterData, @Nullable Map exitData) { assert enterData != null && exitData != null; if (instruction instanceof ReadValueInstruction) { VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction, false); - JetElement element = ((ReadValueInstruction) instruction).getElement(); - if (element instanceof JetSimpleNameExpression && variableDescriptor != null && declaredVariables.contains(variableDescriptor)) { - - InitializationPoints exitInitializationPoints = exitData.get(variableDescriptor); - assert exitInitializationPoints != null; - - boolean isInitialized = exitInitializationPoints.isInitialized(); - if (variableDescriptor instanceof PropertyDescriptor) { - if (!trace.get(BindingContext.BACKING_FIELD_REQUIRED, (PropertyDescriptor) variableDescriptor)) { - isInitialized = true; - } - } - if (!inLocalDeclaration && !isInitialized && !varWithUninitializedErrorGenerated.contains(variableDescriptor)) { - varWithUninitializedErrorGenerated.add(variableDescriptor); - trace.report(Errors.UNINITIALIZED_VARIABLE.on((JetSimpleNameExpression) element, variableDescriptor)); - } + if (variableDescriptor != null && declaredVariables.contains(variableDescriptor)) { + checkIsInitialized(variableDescriptor, ((ReadValueInstruction) instruction).getElement(), exitData.get(variableDescriptor), varWithUninitializedErrorGenerated); } } else if (instruction instanceof WriteValueInstruction) { - JetElement element = ((WriteValueInstruction) instruction).getlValue(); VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction, true); - if (element instanceof JetExpression && variableDescriptor != null) { - InitializationPoints enterInitializationPoints = enterData.get(variableDescriptor); - assert enterInitializationPoints != null; - InitializationPoints exitInitializationPoints = exitData.get(variableDescriptor); - assert exitInitializationPoints != null; - Set possiblePoints = enterInitializationPoints.getPossiblePoints(); - boolean hasInitializer = !possiblePoints.isEmpty() || enterInitializationPoints.isInitialized(); - if (possiblePoints.size() == 1) { - JetElement initializer = possiblePoints.iterator().next(); - if (initializer instanceof JetProperty && initializer == element.getParent()) { - hasInitializer = false; - } + JetElement element = ((WriteValueInstruction) instruction).getlValue(); + if (variableDescriptor != null && element instanceof JetExpression) { + if (!processLocalDeclaration) { // error has been generated before while processing outer function of this local declaration + checkValReassignment(variableDescriptor, (JetExpression) element, enterData.get(variableDescriptor), varWithValReassignErrorGenerated); } - JetExpression expression = (JetExpression) element; - if (!inLocalDeclaration && hasInitializer && !variableDescriptor.isVar() && !varWithValReassignErrorGenerated.contains(variableDescriptor)) { - PsiElement psiElement = trace.get(BindingContext.DESCRIPTOR_TO_DECLARATION, variableDescriptor); - JetProperty property = psiElement instanceof JetProperty ? (JetProperty) psiElement : null; - varWithValReassignErrorGenerated.add(variableDescriptor); - boolean hasReassignMethodReturningUnit = false; - JetSimpleNameExpression operationReference = null; - PsiElement parent = expression.getParent(); - if (parent instanceof JetBinaryExpression) { - operationReference = ((JetBinaryExpression) parent).getOperationReference(); - } - else if (parent instanceof JetUnaryExpression) { - operationReference = ((JetUnaryExpression) parent).getOperationSign(); - } - if (operationReference != null) { - DeclarationDescriptor descriptor = trace.get(BindingContext.REFERENCE_TARGET, operationReference); - if (descriptor instanceof FunctionDescriptor) { - if (JetStandardClasses.isUnit(((FunctionDescriptor) descriptor).getReturnType())) { - hasReassignMethodReturningUnit = true; - } - } - } - if (!hasReassignMethodReturningUnit) { - trace.report(Errors.VAL_REASSIGNMENT.on(expression, variableDescriptor, property == null ? new JetProperty[0] : new JetProperty[]{property})); - } - } - if (inAnonymousInitializers && variableDescriptor instanceof PropertyDescriptor && !enterInitializationPoints.isInitialized() && - exitInitializationPoints.isInitialized()) { - JetExpression variable = expression; - if (expression instanceof JetDotQualifiedExpression) { - if (((JetDotQualifiedExpression) expression).getReceiverExpression() instanceof JetThisExpression) { - variable = ((JetDotQualifiedExpression) expression).getSelectorExpression(); - } - } - if (variable instanceof JetSimpleNameExpression) { - JetSimpleNameExpression simpleNameExpression = (JetSimpleNameExpression) variable; - if (simpleNameExpression.getReferencedNameElementType() != JetTokens.FIELD_IDENTIFIER) { - trace.report(Errors.INITIALIZATION_USING_BACKING_FIELD.on(simpleNameExpression, expression, variableDescriptor)); - } - } + if (processClassOrObject) { + checkInitializationUsingBackingField(variableDescriptor, (JetExpression) element, enterData.get(variableDescriptor), exitData.get(variableDescriptor)); } } } } }); - Map lastInfo = traverser.getResultInfo(); - for (Map.Entry entry : lastInfo.entrySet()) { - VariableDescriptor variable = entry.getKey(); - if (variable instanceof PropertyDescriptor && declaredVariables.contains(variable)) { - InitializationPoints initializationPoints = entry.getValue(); - trace.record(BindingContext.IS_INITIALIZED, (PropertyDescriptor) variable, initializationPoints.isInitialized()); + recordInitializedVariables(declaredVariables, traverser.getResultInfo()); + analyzeLocalDeclarations(processLocalDeclaration, pseudocode); + } + + private void checkIsInitialized(@NotNull VariableDescriptor variableDescriptor, @NotNull JetElement element, @NotNull VariableInitializers variableInitializers, @NotNull Collection varWithUninitializedErrorGenerated) { + if (!(element instanceof JetSimpleNameExpression)) return; + + boolean isInitialized = variableInitializers.isInitialized(); + if (variableDescriptor instanceof PropertyDescriptor) { + if (!trace.get(BindingContext.BACKING_FIELD_REQUIRED, (PropertyDescriptor) variableDescriptor)) { + isInitialized = true; } } - for (Instruction instruction : pseudocode.getInstructions()) { - if (instruction instanceof LocalDeclarationInstruction) { - JetElement element = ((LocalDeclarationInstruction) instruction).getElement(); - markUninitializedVariables(element, false, inLocalDeclaration); + if (!isInitialized && !varWithUninitializedErrorGenerated.contains(variableDescriptor)) { + varWithUninitializedErrorGenerated.add(variableDescriptor); + trace.report(Errors.UNINITIALIZED_VARIABLE.on((JetSimpleNameExpression) element, variableDescriptor)); + } + } + + private void checkValReassignment(@NotNull VariableDescriptor variableDescriptor, @NotNull JetExpression expression, @NotNull VariableInitializers enterInitializers, @NotNull Collection varWithValReassignErrorGenerated) { + boolean isInitializedNotHere = enterInitializers.isInitialized(); + Set possibleLocalInitializers = enterInitializers.getPossibleLocalInitializers(); + if (possibleLocalInitializers.size() == 1) { + JetElement initializer = possibleLocalInitializers.iterator().next(); + if (initializer instanceof JetProperty && initializer == expression.getParent()) { + isInitializedNotHere = false; + } + } + boolean hasBackingField = true; + if (variableDescriptor instanceof PropertyDescriptor) { + hasBackingField = trace.get(BindingContext.BACKING_FIELD_REQUIRED, (PropertyDescriptor) variableDescriptor); + } + if ((isInitializedNotHere || !hasBackingField) && !variableDescriptor.isVar() && !varWithValReassignErrorGenerated.contains(variableDescriptor)) { + varWithValReassignErrorGenerated.add(variableDescriptor); + + boolean hasReassignMethodReturningUnit = false; + JetSimpleNameExpression operationReference = null; + PsiElement parent = expression.getParent(); + if (parent instanceof JetBinaryExpression) { + operationReference = ((JetBinaryExpression) parent).getOperationReference(); + } + else if (parent instanceof JetUnaryExpression) { + operationReference = ((JetUnaryExpression) parent).getOperationSign(); + } + if (operationReference != null) { + DeclarationDescriptor descriptor = trace.get(BindingContext.REFERENCE_TARGET, operationReference); + if (descriptor instanceof FunctionDescriptor) { + if (JetStandardClasses.isUnit(((FunctionDescriptor) descriptor).getReturnType())) { + hasReassignMethodReturningUnit = true; + } + } + } + if (!hasReassignMethodReturningUnit) { + trace.report(Errors.VAL_REASSIGNMENT.on(expression, variableDescriptor)); + } + } + } + + private void checkInitializationUsingBackingField(@NotNull VariableDescriptor variableDescriptor, @NotNull JetExpression expression, @NotNull VariableInitializers enterInitializers, @NotNull VariableInitializers exitInitializers) { + if (variableDescriptor instanceof PropertyDescriptor && !enterInitializers.isInitialized() && exitInitializers.isInitialized()) { + JetExpression variable = expression; + if (expression instanceof JetDotQualifiedExpression) { + if (((JetDotQualifiedExpression) expression).getReceiverExpression() instanceof JetThisExpression) { + variable = ((JetDotQualifiedExpression) expression).getSelectorExpression(); + } + } + if (variable instanceof JetSimpleNameExpression) { + JetSimpleNameExpression simpleNameExpression = (JetSimpleNameExpression) variable; + if (simpleNameExpression.getReferencedNameElementType() != JetTokens.FIELD_IDENTIFIER) { + trace.report(Errors.INITIALIZATION_USING_BACKING_FIELD.on(simpleNameExpression, expression, variableDescriptor)); + } } } } - private Map prepareInitialMapForStartInstruction(Collection usedVariables, Collection declaredVariables) { - Map initialMapForStartInstruction = Maps.newHashMap(); - InitializationPoints initialPointsForDeclaredVariable = new InitializationPoints(false); - InitializationPoints initialPointsForExternalVariable = new InitializationPoints(true); + private void recordInitializedVariables(Collection declaredVariables, Map resultInfo) { + for (Map.Entry entry : resultInfo.entrySet()) { + VariableDescriptor variable = entry.getKey(); + if (variable instanceof PropertyDescriptor && declaredVariables.contains(variable)) { + VariableInitializers initializers = entry.getValue(); + trace.record(BindingContext.IS_INITIALIZED, (PropertyDescriptor) variable, initializers.isInitialized()); + } + } + } + + private void analyzeLocalDeclarations(boolean processLocalDeclaration, Pseudocode pseudocode) { + for (Instruction instruction : pseudocode.getInstructions()) { + if (instruction instanceof LocalDeclarationInstruction) { + JetElement element = ((LocalDeclarationInstruction) instruction).getElement(); + markUninitializedVariables(element, processLocalDeclaration); + } + } + } + + private Map addVariableInitializerFromCurrentInstructionIfAny(Instruction instruction, Map enterInstructionData) { + Map exitInstructionData = Maps.newHashMap(enterInstructionData); + if (instruction instanceof WriteValueInstruction) { + VariableDescriptor variable = extractVariableDescriptorIfAny(instruction, false); + VariableInitializers initializationAtThisElement = new VariableInitializers(((WriteValueInstruction) instruction).getElement()); + exitInstructionData.put(variable, initializationAtThisElement); + } + return exitInstructionData; + } + + private Map mergeIncomingEdgesData(Collection> incomingEdgesData) { + Set variablesInScope = Sets.newHashSet(); + for (Map edgeData : incomingEdgesData) { + variablesInScope.addAll(edgeData.keySet()); + } + + Map enterInstructionData = Maps.newHashMap(); + for (VariableDescriptor variable : variablesInScope) { + Set edgesDataForVariable = Sets.newHashSet(); + for (Map edgeData : incomingEdgesData) { + VariableInitializers initializers = edgeData.get(variable); + if (initializers != null) { + edgesDataForVariable.add(initializers); + } + } + enterInstructionData.put(variable, new VariableInitializers(edgesDataForVariable)); + } + return enterInstructionData; + } + + private Map prepareInitialMapForStartInstruction(Collection usedVariables, Collection declaredVariables) { + Map initialMapForStartInstruction = Maps.newHashMap(); + VariableInitializers isInitializedForExternalVariable = new VariableInitializers(true); + VariableInitializers isNotInitializedForDeclaredVariable = new VariableInitializers(false); for (VariableDescriptor variable : usedVariables) { if (declaredVariables.contains(variable)) { - initialMapForStartInstruction.put(variable, initialPointsForDeclaredVariable); + initialMapForStartInstruction.put(variable, isNotInitializedForDeclaredVariable); } else { - initialMapForStartInstruction.put(variable, initialPointsForExternalVariable); + initialMapForStartInstruction.put(variable, isInitializedForExternalVariable); } } return initialMapForStartInstruction; } +//////////////////////////////////////////////////////////////////////////////// + public void markNotOnlyInvokedFunctionVariables(@NotNull JetElement subroutine, List variables) { final List functionVariables = Lists.newArrayList(); for (VariableDescriptor variable : variables) { @@ -384,7 +412,10 @@ public class JetFlowInformationProvider { } }); } - + +//////////////////////////////////////////////////////////////////////////////// +// "Unused variable" & "unused value" analyses + public void markUnusedVariables(@NotNull JetElement subroutine) { Pseudocode pseudocode = pseudocodeMap.get(subroutine); assert pseudocode != null; @@ -403,10 +434,11 @@ public class JetFlowInformationProvider { for (VariableDescriptor declaredVariable : declaredVariables) { if (!usedVariables.contains(declaredVariable)) { PsiElement element = trace.get(BindingContext.DESCRIPTOR_TO_DECLARATION, declaredVariable); - if (element instanceof JetProperty && JetPsiUtil.isLocal((JetProperty) element)) { - PsiElement nameIdentifier = ((JetProperty) element).getNameIdentifier(); + //todo + if (element instanceof JetProperty && JetPsiUtil.isLocal((JetNamedDeclaration) element)) { + PsiElement nameIdentifier = ((JetNamedDeclaration) element).getNameIdentifier(); PsiElement elementToMark = nameIdentifier != null ? nameIdentifier : element; - trace.report(Errors.UNUSED_VARIABLE.on((JetProperty)element, elementToMark, declaredVariable)); + trace.report(Errors.UNUSED_VARIABLE.on((JetNamedDeclaration)element, elementToMark, declaredVariable)); } } } @@ -416,7 +448,7 @@ public class JetFlowInformationProvider { private void markUnusedValues(@NotNull JetElement subroutine, Pseudocode pseudocode, final Collection declaredVariables) { JetControlFlowGraphTraverser> traverser = JetControlFlowGraphTraverser.create(pseudocode, true); - traverser.collectInformationFromInstructionGraph(new JetControlFlowGraphTraverser.InstructionsMergeStrategy>() { + traverser.collectInformationFromInstructionGraph(new JetControlFlowGraphTraverser.InstructionDataMergeStrategy>() { @Override public Pair, Set> execute(Instruction instruction, @NotNull Collection> incomingEdgesData) { Set enterResult = Sets.newHashSet(); @@ -448,8 +480,10 @@ public class JetFlowInformationProvider { if (variableDescriptor != null && declaredVariables.contains(variableDescriptor)) { if (!enterData.contains(variableDescriptor)) { PsiElement variableDeclarationElement = trace.get(BindingContext.DESCRIPTOR_TO_DECLARATION, variableDescriptor); - assert variableDeclarationElement instanceof JetProperty || variableDeclarationElement instanceof JetParameter; - boolean isLocal = !(variableDeclarationElement instanceof JetProperty) || JetPsiUtil.isLocal((JetProperty) variableDeclarationElement); +// assert variableDeclarationElement instanceof JetProperty || variableDeclarationElement instanceof JetParameter; +// boolean isLocal = !(variableDeclarationElement instanceof JetProperty) || JetPsiUtil.isLocal((JetProperty) variableDeclarationElement); + assert variableDeclarationElement instanceof JetDeclaration; + boolean isLocal = JetPsiUtil.isLocal((JetDeclaration) variableDeclarationElement); if (isLocal) { JetElement element = ((WriteValueInstruction) instruction).getElement(); if (element instanceof JetBinaryExpression && ((JetBinaryExpression) element).getOperationToken() == JetTokens.EQ) { @@ -472,6 +506,9 @@ public class JetFlowInformationProvider { }); } +//////////////////////////////////////////////////////////////////////////////// +// Util methods + @Nullable private VariableDescriptor extractVariableDescriptorIfAny(Instruction instruction, boolean onlyReference) { VariableDescriptor variableDescriptor = null; @@ -521,31 +558,34 @@ public class JetFlowInformationProvider { return declaredVariables; } - private static class InitializationPoints { - private Set possiblePoints = Sets.newHashSet(); +//////////////////////////////////////////////////////////////////////////////// +// Local class for uninitialized variables analysis + + private static class VariableInitializers { + private Set possibleLocalInitializers = Sets.newHashSet(); private boolean isInitialized; - public InitializationPoints(boolean isInitialized) { + public VariableInitializers(boolean isInitialized) { this.isInitialized = isInitialized; } - public InitializationPoints(JetElement element) { + public VariableInitializers(JetElement element) { isInitialized = true; - possiblePoints.add(element); + possibleLocalInitializers.add(element); } - public InitializationPoints(Set edgesData) { + public VariableInitializers(Set edgesData) { isInitialized = true; - for (InitializationPoints edgeData : edgesData) { + for (VariableInitializers edgeData : edgesData) { if (!edgeData.isInitialized) { isInitialized = false; } - possiblePoints.addAll(edgeData.possiblePoints); + possibleLocalInitializers.addAll(edgeData.possibleLocalInitializers); } } - public Set getPossiblePoints() { - return possiblePoints; + public Set getPossibleLocalInitializers() { + return possibleLocalInitializers; } public boolean isInitialized() { @@ -555,12 +595,12 @@ public class JetFlowInformationProvider { @Override public boolean equals(Object o) { if (this == o) return true; - if (!(o instanceof InitializationPoints)) return false; + if (!(o instanceof VariableInitializers)) return false; - InitializationPoints that = (InitializationPoints) o; + VariableInitializers that = (VariableInitializers) o; if (isInitialized != that.isInitialized) return false; - if (possiblePoints != null ? !possiblePoints.equals(that.possiblePoints) : that.possiblePoints != null) { + if (possibleLocalInitializers != null ? !possibleLocalInitializers.equals(that.possibleLocalInitializers) : that.possibleLocalInitializers != null) { return false; } @@ -569,7 +609,7 @@ public class JetFlowInformationProvider { @Override public int hashCode() { - int result = possiblePoints != null ? possiblePoints.hashCode() : 0; + int result = possibleLocalInitializers != null ? possibleLocalInitializers.hashCode() : 0; result = 31 * result + (isInitialized ? 1 : 0); return result; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java index 0fb77fc8703..bdd55b0b25e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java @@ -104,9 +104,9 @@ public class JetPsiUtil { } } - public static boolean isLocal(@NotNull JetProperty property) { - JetClassOrObject classOrObject = PsiTreeUtil.getParentOfType(property, JetClassOrObject.class); - JetDeclarationWithBody function = PsiTreeUtil.getParentOfType(property, JetDeclarationWithBody.class); + public static boolean isLocal(@NotNull JetDeclaration declaration) { + JetClassOrObject classOrObject = PsiTreeUtil.getParentOfType(declaration, JetClassOrObject.class); + JetDeclarationWithBody function = PsiTreeUtil.getParentOfType(declaration, JetDeclarationWithBody.class); if (function != null && PsiTreeUtil.isAncestor(classOrObject, function, false)) { return true; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContextUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContextUtils.java index 1fdff1d39fb..4b24227c3cd 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContextUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContextUtils.java @@ -13,6 +13,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.DECLARATION_TO_DESCR /** * @author abreslav + * @author svtk */ public class BindingContextUtils { private BindingContextUtils() { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ControlFlowAnalyzer.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ControlFlowAnalyzer.java index 96d09dce0bc..82e31375232 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ControlFlowAnalyzer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ControlFlowAnalyzer.java @@ -19,12 +19,12 @@ import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE; public class ControlFlowAnalyzer { private TopDownAnalysisContext context; private final JetControlFlowDataTraceFactory flowDataTraceFactory; - private final boolean inLocalDeclaration; + private final boolean processLocalDeclaration; - public ControlFlowAnalyzer(TopDownAnalysisContext context, JetControlFlowDataTraceFactory flowDataTraceFactory, boolean inLocalDeclaration) { + public ControlFlowAnalyzer(TopDownAnalysisContext context, JetControlFlowDataTraceFactory flowDataTraceFactory, boolean processLocalDeclaration) { this.context = context; this.flowDataTraceFactory = flowDataTraceFactory; - this.inLocalDeclaration = inLocalDeclaration; + this.processLocalDeclaration = processLocalDeclaration; } public void process() { @@ -53,7 +53,7 @@ public class ControlFlowAnalyzer { private void checkClassOrObject(JetClassOrObject klass) { JetFlowInformationProvider flowInformationProvider = new JetFlowInformationProvider((JetDeclaration) klass, (JetExpression) klass, flowDataTraceFactory, context.getTrace()); - flowInformationProvider.markUninitializedVariables((JetElement) klass, true, inLocalDeclaration); + flowInformationProvider.markUninitializedVariables((JetElement) klass, processLocalDeclaration); List declarations = klass.getDeclarations(); for (JetDeclaration declaration : declarations) { @@ -82,7 +82,7 @@ public class ControlFlowAnalyzer { flowInformationProvider.checkDefiniteReturn(function, expectedReturnType); - flowInformationProvider.markUninitializedVariables(function.asElement(), false, inLocalDeclaration); + flowInformationProvider.markUninitializedVariables(function.asElement(), processLocalDeclaration); flowInformationProvider.markUnusedVariables(function.asElement()); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java index fc27060c882..e6a9f31e64d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java @@ -53,7 +53,7 @@ public class TopDownAnalyzer { NamespaceLike owner, Collection declarations, JetControlFlowDataTraceFactory flowDataTraceFactory, - boolean declaredLocally) { + boolean processLocalDeclaration) { // context.enableDebugOutput(); context.debug("Enter"); @@ -64,7 +64,7 @@ public class TopDownAnalyzer { new OverloadResolver(context).process(); if (!context.analyzingBootstrapLibrary()) { new BodyResolver(context).resolveBehaviorDeclarationBodies(); - new ControlFlowAnalyzer(context, flowDataTraceFactory, declaredLocally).process(); + new ControlFlowAnalyzer(context, flowDataTraceFactory, processLocalDeclaration).process(); new DeclarationsChecker(context).process(); } diff --git a/compiler/testData/checkerWithErrorTypes/quick/UninitializedOrReassignedVariables.jet b/compiler/testData/checkerWithErrorTypes/quick/UninitializedOrReassignedVariables.jet index 63739b20d4b..eb7807c0797 100644 --- a/compiler/testData/checkerWithErrorTypes/quick/UninitializedOrReassignedVariables.jet +++ b/compiler/testData/checkerWithErrorTypes/quick/UninitializedOrReassignedVariables.jet @@ -137,8 +137,8 @@ class AnonymousInitializers(var a: String, val b: String) { { $i = 13 - $j = 30 - j = 34 + $j = 30 + j = 34 } val k: String diff --git a/compiler/testData/checkerWithErrorTypes/quick/regressions/kt607.jet b/compiler/testData/checkerWithErrorTypes/quick/regressions/kt607.jet new file mode 100644 index 00000000000..238661318d1 --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/quick/regressions/kt607.jet @@ -0,0 +1,18 @@ +//KT-607 Val reassignment is not marked as an error + +namespace kt607 + +fun foo(a: A) { + val o = object { + val y : Int + get() = 42 + } + + a.z = 23 + o.y = 11 //Should be an error here +} + +class A() { + val z : Int + get() = 3 +} \ No newline at end of file