check package declaration in a file

to have the right properties initialization order
not to report errors if isDeclaredLocally (only recordInitializedVariables)
This commit is contained in:
Svetlana Isakova
2012-12-18 15:52:39 +04:00
parent 57518c1200
commit 11bc01795f
4 changed files with 40 additions and 19 deletions
@@ -188,7 +188,7 @@ public class JetFlowInformationProvider {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Uninitialized variables analysis // Uninitialized variables analysis
public void markUninitializedVariables(final boolean processLocalDeclaration) { public void markUninitializedVariables() {
final Collection<VariableDescriptor> varWithUninitializedErrorGenerated = Sets.newHashSet(); final Collection<VariableDescriptor> varWithUninitializedErrorGenerated = Sets.newHashSet();
final Collection<VariableDescriptor> varWithValReassignErrorGenerated = Sets.newHashSet(); final Collection<VariableDescriptor> varWithValReassignErrorGenerated = Sets.newHashSet();
final boolean processClassOrObject = subroutine instanceof JetClassOrObject; final boolean processClassOrObject = subroutine instanceof JetClassOrObject;
@@ -218,7 +218,7 @@ public class JetFlowInformationProvider {
JetElement element = ((WriteValueInstruction) instruction).getlValue(); JetElement element = ((WriteValueInstruction) instruction).getlValue();
boolean error = checkBackingField(ctxt, element); boolean error = checkBackingField(ctxt, element);
if (!(element instanceof JetExpression)) return; if (!(element instanceof JetExpression)) return;
if (!error && !processLocalDeclaration) { // error has been generated before, while processing outer function of this local declaration if (!error) {
error = checkValReassignment(ctxt, (JetExpression) element, varWithValReassignErrorGenerated); error = checkValReassignment(ctxt, (JetExpression) element, varWithValReassignErrorGenerated);
} }
if (!error && processClassOrObject) { if (!error && processClassOrObject) {
@@ -229,8 +229,11 @@ public class JetFlowInformationProvider {
} }
} }
}); });
}
public void recordInitializedVariables() {
Pseudocode pseudocode = pseudocodeVariablesData.getPseudocode(); Pseudocode pseudocode = pseudocodeVariablesData.getPseudocode();
Map<Instruction, Edges<Map<VariableDescriptor,VariableInitState>>> initializers = pseudocodeVariablesData.getVariableInitializers();
recordInitializedVariables(pseudocode, initializers); recordInitializedVariables(pseudocode, initializers);
for (LocalDeclarationInstruction instruction : pseudocode.getLocalDeclarations()) { for (LocalDeclarationInstruction instruction : pseudocode.getLocalDeclarations()) {
recordInitializedVariables(instruction.getBody(), initializers); recordInitializedVariables(instruction.getBody(), initializers);
@@ -18,7 +18,6 @@ package org.jetbrains.jet.lang.resolve;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider; import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider;
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
import org.jetbrains.jet.lang.descriptors.PropertyAccessorDescriptor; import org.jetbrains.jet.lang.descriptors.PropertyAccessorDescriptor;
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor; import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor;
@@ -26,6 +25,7 @@ import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetType;
import javax.inject.Inject; import javax.inject.Inject;
import java.util.List;
import java.util.Map; import java.util.Map;
import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE; import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
@@ -48,13 +48,16 @@ public class ControlFlowAnalyzer {
} }
public void process(@NotNull BodiesResolveContext bodiesResolveContext) { public void process(@NotNull BodiesResolveContext bodiesResolveContext) {
for (JetFile file : bodiesResolveContext.getFiles()) {
checkDeclarationContainer(file);
}
for (JetClass aClass : bodiesResolveContext.getClasses().keySet()) { for (JetClass aClass : bodiesResolveContext.getClasses().keySet()) {
if (!bodiesResolveContext.completeAnalysisNeeded(aClass)) continue; if (!bodiesResolveContext.completeAnalysisNeeded(aClass)) continue;
checkClassOrObject(aClass); checkDeclarationContainer(aClass);
} }
for (JetObjectDeclaration objectDeclaration : bodiesResolveContext.getObjects().keySet()) { for (JetObjectDeclaration objectDeclaration : bodiesResolveContext.getObjects().keySet()) {
if (!bodiesResolveContext.completeAnalysisNeeded(objectDeclaration)) continue; if (!bodiesResolveContext.completeAnalysisNeeded(objectDeclaration)) continue;
checkClassOrObject(objectDeclaration); checkDeclarationContainer(objectDeclaration);
} }
for (Map.Entry<JetNamedFunction, SimpleFunctionDescriptor> entry : bodiesResolveContext.getFunctions().entrySet()) { for (Map.Entry<JetNamedFunction, SimpleFunctionDescriptor> entry : bodiesResolveContext.getFunctions().entrySet()) {
JetNamedFunction function = entry.getKey(); JetNamedFunction function = entry.getKey();
@@ -73,10 +76,15 @@ public class ControlFlowAnalyzer {
} }
} }
private void checkClassOrObject(JetClassOrObject klass) { private void checkDeclarationContainer(JetDeclarationContainer declarationContainer) {
// A pseudocode of class initialization corresponds to a class // A pseudocode of class/object initialization corresponds to a class/object
JetFlowInformationProvider flowInformationProvider = new JetFlowInformationProvider(klass, trace); // or initialization of properties corresponds to a package declared in a file
flowInformationProvider.markUninitializedVariables(topDownAnalysisParameters.isDeclaredLocally()); JetFlowInformationProvider flowInformationProvider = new JetFlowInformationProvider((JetElement) declarationContainer, trace);
flowInformationProvider.recordInitializedVariables();
if (topDownAnalysisParameters.isDeclaredLocally()) return;
flowInformationProvider.markUninitializedVariables();
} }
private void checkProperty(JetProperty property, PropertyDescriptor propertyDescriptor) { private void checkProperty(JetProperty property, PropertyDescriptor propertyDescriptor) {
@@ -87,13 +95,6 @@ public class ControlFlowAnalyzer {
assert accessorDescriptor != null; assert accessorDescriptor != null;
checkFunction(accessor, accessorDescriptor.getReturnType()); checkFunction(accessor, accessorDescriptor.getReturnType());
} }
if (property.getInitializer() != null && propertyDescriptor.getContainingDeclaration() instanceof NamespaceDescriptor) {
// check initializer's pseudocode for uninitialized values
// initializers of properties inside classes/objects are checked in 'checkClassOrObject',
// because class/object may have anonymous initialization blocks that affect analysis
JetFlowInformationProvider flowInformationProvider = new JetFlowInformationProvider(property, trace);
flowInformationProvider.markUninitializedVariables(false);
}
} }
private void checkFunction(JetDeclarationWithBody function, final @NotNull JetType expectedReturnType) { private void checkFunction(JetDeclarationWithBody function, final @NotNull JetType expectedReturnType) {
@@ -103,11 +104,19 @@ public class ControlFlowAnalyzer {
if (bodyExpression == null) return; if (bodyExpression == null) return;
JetFlowInformationProvider flowInformationProvider = new JetFlowInformationProvider((JetDeclaration) function, trace); JetFlowInformationProvider flowInformationProvider = new JetFlowInformationProvider((JetDeclaration) function, trace);
boolean isPropertyAccessor = function instanceof JetPropertyAccessor;
if (!isPropertyAccessor) {
flowInformationProvider.recordInitializedVariables();
}
if (topDownAnalysisParameters.isDeclaredLocally()) return;
flowInformationProvider.checkDefiniteReturn(expectedReturnType); flowInformationProvider.checkDefiniteReturn(expectedReturnType);
// Property accessor is checked through initialization of a class check (at 'checkClassOrObject') if (!isPropertyAccessor) {
boolean isPropertyAccessor = function instanceof JetPropertyAccessor; // Property accessor is checked through initialization of a class/object or package properties (at 'checkDeclarationContainer')
flowInformationProvider.markUninitializedVariables(topDownAnalysisParameters.isDeclaredLocally() || isPropertyAccessor); flowInformationProvider.markUninitializedVariables();
}
flowInformationProvider.markUnusedVariables(); flowInformationProvider.markUnusedVariables();
@@ -0,0 +1,4 @@
package a
val a : Int = <!UNINITIALIZED_VARIABLE!>b<!>
val b : Int = a
@@ -964,6 +964,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/kt897.kt"); doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/kt897.kt");
} }
@TestMetadata("propertiesOrderInPackage.kt")
public void testPropertiesOrderInPackage() throws Exception {
doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/propertiesOrderInPackage.kt");
}
@TestMetadata("uninitializedInLocalDeclarations.kt") @TestMetadata("uninitializedInLocalDeclarations.kt")
public void testUninitializedInLocalDeclarations() throws Exception { public void testUninitializedInLocalDeclarations() throws Exception {
doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/uninitializedInLocalDeclarations.kt"); doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/uninitializedInLocalDeclarations.kt");