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
|
// 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");
|
||||||
|
|||||||
Reference in New Issue
Block a user