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:
@@ -188,7 +188,7 @@ public class JetFlowInformationProvider {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Uninitialized variables analysis
|
||||
|
||||
public void markUninitializedVariables(final boolean processLocalDeclaration) {
|
||||
public void markUninitializedVariables() {
|
||||
final Collection<VariableDescriptor> varWithUninitializedErrorGenerated = Sets.newHashSet();
|
||||
final Collection<VariableDescriptor> varWithValReassignErrorGenerated = Sets.newHashSet();
|
||||
final boolean processClassOrObject = subroutine instanceof JetClassOrObject;
|
||||
@@ -218,7 +218,7 @@ public class JetFlowInformationProvider {
|
||||
JetElement element = ((WriteValueInstruction) instruction).getlValue();
|
||||
boolean error = checkBackingField(ctxt, element);
|
||||
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);
|
||||
}
|
||||
if (!error && processClassOrObject) {
|
||||
@@ -229,8 +229,11 @@ public class JetFlowInformationProvider {
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void recordInitializedVariables() {
|
||||
Pseudocode pseudocode = pseudocodeVariablesData.getPseudocode();
|
||||
Map<Instruction, Edges<Map<VariableDescriptor,VariableInitState>>> initializers = pseudocodeVariablesData.getVariableInitializers();
|
||||
recordInitializedVariables(pseudocode, initializers);
|
||||
for (LocalDeclarationInstruction instruction : pseudocode.getLocalDeclarations()) {
|
||||
recordInitializedVariables(instruction.getBody(), initializers);
|
||||
|
||||
@@ -18,7 +18,6 @@ package org.jetbrains.jet.lang.resolve;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
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.PropertyDescriptor;
|
||||
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 javax.inject.Inject;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
|
||||
@@ -48,13 +48,16 @@ public class ControlFlowAnalyzer {
|
||||
}
|
||||
|
||||
public void process(@NotNull BodiesResolveContext bodiesResolveContext) {
|
||||
for (JetFile file : bodiesResolveContext.getFiles()) {
|
||||
checkDeclarationContainer(file);
|
||||
}
|
||||
for (JetClass aClass : bodiesResolveContext.getClasses().keySet()) {
|
||||
if (!bodiesResolveContext.completeAnalysisNeeded(aClass)) continue;
|
||||
checkClassOrObject(aClass);
|
||||
checkDeclarationContainer(aClass);
|
||||
}
|
||||
for (JetObjectDeclaration objectDeclaration : bodiesResolveContext.getObjects().keySet()) {
|
||||
if (!bodiesResolveContext.completeAnalysisNeeded(objectDeclaration)) continue;
|
||||
checkClassOrObject(objectDeclaration);
|
||||
checkDeclarationContainer(objectDeclaration);
|
||||
}
|
||||
for (Map.Entry<JetNamedFunction, SimpleFunctionDescriptor> entry : bodiesResolveContext.getFunctions().entrySet()) {
|
||||
JetNamedFunction function = entry.getKey();
|
||||
@@ -73,10 +76,15 @@ public class ControlFlowAnalyzer {
|
||||
}
|
||||
}
|
||||
|
||||
private void checkClassOrObject(JetClassOrObject klass) {
|
||||
// A pseudocode of class initialization corresponds to a class
|
||||
JetFlowInformationProvider flowInformationProvider = new JetFlowInformationProvider(klass, trace);
|
||||
flowInformationProvider.markUninitializedVariables(topDownAnalysisParameters.isDeclaredLocally());
|
||||
private void checkDeclarationContainer(JetDeclarationContainer declarationContainer) {
|
||||
// A pseudocode of class/object initialization corresponds to a class/object
|
||||
// or initialization of properties corresponds to a package declared in a file
|
||||
JetFlowInformationProvider flowInformationProvider = new JetFlowInformationProvider((JetElement) declarationContainer, trace);
|
||||
flowInformationProvider.recordInitializedVariables();
|
||||
|
||||
if (topDownAnalysisParameters.isDeclaredLocally()) return;
|
||||
|
||||
flowInformationProvider.markUninitializedVariables();
|
||||
}
|
||||
|
||||
private void checkProperty(JetProperty property, PropertyDescriptor propertyDescriptor) {
|
||||
@@ -87,13 +95,6 @@ public class ControlFlowAnalyzer {
|
||||
assert accessorDescriptor != null;
|
||||
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) {
|
||||
@@ -103,11 +104,19 @@ public class ControlFlowAnalyzer {
|
||||
if (bodyExpression == null) return;
|
||||
JetFlowInformationProvider flowInformationProvider = new JetFlowInformationProvider((JetDeclaration) function, trace);
|
||||
|
||||
boolean isPropertyAccessor = function instanceof JetPropertyAccessor;
|
||||
if (!isPropertyAccessor) {
|
||||
flowInformationProvider.recordInitializedVariables();
|
||||
}
|
||||
|
||||
if (topDownAnalysisParameters.isDeclaredLocally()) return;
|
||||
|
||||
flowInformationProvider.checkDefiniteReturn(expectedReturnType);
|
||||
|
||||
// Property accessor is checked through initialization of a class check (at 'checkClassOrObject')
|
||||
boolean isPropertyAccessor = function instanceof JetPropertyAccessor;
|
||||
flowInformationProvider.markUninitializedVariables(topDownAnalysisParameters.isDeclaredLocally() || isPropertyAccessor);
|
||||
if (!isPropertyAccessor) {
|
||||
// Property accessor is checked through initialization of a class/object or package properties (at 'checkDeclarationContainer')
|
||||
flowInformationProvider.markUninitializedVariables();
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
@TestMetadata("propertiesOrderInPackage.kt")
|
||||
public void testPropertiesOrderInPackage() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/propertiesOrderInPackage.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("uninitializedInLocalDeclarations.kt")
|
||||
public void testUninitializedInLocalDeclarations() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/uninitializedInLocalDeclarations.kt");
|
||||
|
||||
Reference in New Issue
Block a user