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 1488a847e6f..7b977826a5b 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java @@ -91,23 +91,29 @@ public class JetFlowInformationProvider { return pseudocodeVariablesData; } - public void checkFunction( - @NotNull JetDeclarationWithBody function, - @NotNull JetType expectedReturnType, - boolean isLocalObject - ) { + public void checkForLocalClassOrObjectMode() { + // Local classes and objects are analyzed twice: when TopDownAnalyzer processes it and as a part of its container. + // Almost all checks can be done when the container is analyzed + // except recording initialized variables (this information is needed for DeclarationChecker). + recordInitializedVariables(); + } + + public void checkDeclaration() { + recordInitializedVariables(); - checkDefiniteReturn(expectedReturnType); checkLocalFunctions(); - if (isLocalObject) return; - markUninitializedVariables(); markUnusedVariables(); markUnusedLiteralsInBlock(); + } + + public void checkFunction(@Nullable JetType expectedReturnType) { + + checkDefiniteReturn(expectedReturnType != null ? expectedReturnType : NO_EXPECTED_TYPE); markTailCalls(); } @@ -175,16 +181,17 @@ public class JetFlowInformationProvider { private void checkLocalFunctions() { for (LocalFunctionDeclarationInstruction localDeclarationInstruction : pseudocode.getLocalDeclarations()) { JetElement element = localDeclarationInstruction.getElement(); - if (element instanceof JetNamedFunction) { - JetNamedFunction localFunction = (JetNamedFunction) element; - SimpleFunctionDescriptor functionDescriptor = trace.getBindingContext().get(BindingContext.FUNCTION, localFunction); + if (element instanceof JetDeclarationWithBody) { + JetDeclarationWithBody localDeclaration = (JetDeclarationWithBody) element; + if (localDeclaration instanceof JetFunctionLiteral) continue; + CallableDescriptor functionDescriptor = + (CallableDescriptor) trace.getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, localDeclaration); JetType expectedType = functionDescriptor != null ? functionDescriptor.getReturnType() : null; JetFlowInformationProvider providerForLocalDeclaration = - new JetFlowInformationProvider(localFunction, trace, localDeclarationInstruction.getBody()); + new JetFlowInformationProvider(localDeclaration, trace, localDeclarationInstruction.getBody()); - providerForLocalDeclaration.checkDefiniteReturn(expectedType != null ? expectedType : NO_EXPECTED_TYPE); - providerForLocalDeclaration.markTailCalls(); + providerForLocalDeclaration.checkFunction(expectedType); } } } 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 22e8444bd27..a386a357d59 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ControlFlowAnalyzer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ControlFlowAnalyzer.java @@ -17,6 +17,7 @@ package org.jetbrains.jet.lang.resolve; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider; import org.jetbrains.jet.lang.descriptors.PropertyAccessorDescriptor; import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; @@ -59,8 +60,6 @@ public class ControlFlowAnalyzer { JetType expectedReturnType = !function.hasBlockBody() && !function.hasDeclaredReturnType() ? NO_EXPECTED_TYPE : functionDescriptor.getReturnType(); - assert expectedReturnType != null - : "functionDescriptor is not yet fully initialized or broken so return type is null " + functionDescriptor; checkFunction(function, expectedReturnType); } for (Map.Entry entry : bodiesResolveContext.getProperties().entrySet()) { @@ -75,11 +74,11 @@ public class ControlFlowAnalyzer { // 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(); + if (topDownAnalysisParameters.isDeclaredLocally()) { + flowInformationProvider.checkForLocalClassOrObjectMode(); + return; + } + flowInformationProvider.checkDeclaration(); } private void checkProperty(JetProperty property, PropertyDescriptor propertyDescriptor) { @@ -89,15 +88,19 @@ public class ControlFlowAnalyzer { : propertyDescriptor.getSetter(); assert accessorDescriptor != null : "no property accessor descriptor " + accessor.getText(); JetType returnType = accessorDescriptor.getReturnType(); - assert returnType != null : "property accessor has no return type " + accessorDescriptor; checkFunction(accessor, returnType); } } - private void checkFunction(@NotNull JetDeclarationWithBody function, @NotNull JetType expectedReturnType) { + private void checkFunction(@NotNull JetDeclarationWithBody function, @Nullable JetType expectedReturnType) { JetExpression bodyExpression = function.getBodyExpression(); if (bodyExpression == null) return; JetFlowInformationProvider flowInformationProvider = new JetFlowInformationProvider(function, trace); - flowInformationProvider.checkFunction(function, expectedReturnType, topDownAnalysisParameters.isDeclaredLocally()); + if (topDownAnalysisParameters.isDeclaredLocally()) { + flowInformationProvider.checkForLocalClassOrObjectMode(); + return; + } + flowInformationProvider.checkDeclaration(); + flowInformationProvider.checkFunction(expectedReturnType); } } diff --git a/compiler/testData/diagnostics/tests/AnonymousInitializers.kt b/compiler/testData/diagnostics/tests/AnonymousInitializers.kt index 32687cba94b..86c15a5c185 100644 --- a/compiler/testData/diagnostics/tests/AnonymousInitializers.kt +++ b/compiler/testData/diagnostics/tests/AnonymousInitializers.kt @@ -15,15 +15,15 @@ class WithC() { { $x = 1 $y = 2 - val b = x + val b = x } val a : Int get() = 1 { - val z = b - val zz = x - val zzz = $a + val z = b + val zz = x + val zzz = $a } } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/UninitializedOrReassignedVariables.kt b/compiler/testData/diagnostics/tests/UninitializedOrReassignedVariables.kt index 240395309b8..214831534d8 100644 --- a/compiler/testData/diagnostics/tests/UninitializedOrReassignedVariables.kt +++ b/compiler/testData/diagnostics/tests/UninitializedOrReassignedVariables.kt @@ -199,7 +199,7 @@ class LocalValsVsProperties(val a: Int, w: Int) : Open(a, w) { val y : Int { $x = 1 - val b = x + val b = x } val b = a diff --git a/compiler/testData/diagnostics/tests/backingField/ReadForwardInAnonymous.kt b/compiler/testData/diagnostics/tests/backingField/ReadForwardInAnonymous.kt index 00406dc599c..df569d9c53e 100644 --- a/compiler/testData/diagnostics/tests/backingField/ReadForwardInAnonymous.kt +++ b/compiler/testData/diagnostics/tests/backingField/ReadForwardInAnonymous.kt @@ -1,6 +1,6 @@ class ReadForward() { { - val x = $a + val x = $a } val a = 1 diff --git a/compiler/testData/diagnostics/tests/backingField/ReadInAnonymous.kt b/compiler/testData/diagnostics/tests/backingField/ReadInAnonymous.kt index 183ac58ec72..4f76161cb6e 100644 --- a/compiler/testData/diagnostics/tests/backingField/ReadInAnonymous.kt +++ b/compiler/testData/diagnostics/tests/backingField/ReadInAnonymous.kt @@ -1,6 +1,6 @@ class ReadByAnotherPropertyInitializer() { val a = 1 { - val x = $a + val x = $a } } diff --git a/compiler/testData/diagnostics/tests/backingField/ReadNonexistentAbstractPropertyInAnonymous.kt b/compiler/testData/diagnostics/tests/backingField/ReadNonexistentAbstractPropertyInAnonymous.kt index 76e97f0b23d..e9a554270b1 100644 --- a/compiler/testData/diagnostics/tests/backingField/ReadNonexistentAbstractPropertyInAnonymous.kt +++ b/compiler/testData/diagnostics/tests/backingField/ReadNonexistentAbstractPropertyInAnonymous.kt @@ -2,6 +2,6 @@ abstract class ReadNonexistent() { abstract val aa: Int { - val x = $aa + val x = $aa } } diff --git a/compiler/testData/diagnostics/tests/backingField/ReadNonexistentCustomGetInAnonymous.kt b/compiler/testData/diagnostics/tests/backingField/ReadNonexistentCustomGetInAnonymous.kt index 1ad622d501b..0e9aaa34d55 100644 --- a/compiler/testData/diagnostics/tests/backingField/ReadNonexistentCustomGetInAnonymous.kt +++ b/compiler/testData/diagnostics/tests/backingField/ReadNonexistentCustomGetInAnonymous.kt @@ -3,6 +3,6 @@ class ReadNonexistent() { get() = 1 { - val x = $a + val x = $a } } diff --git a/compiler/testData/diagnostics/tests/backingField/ReadNonexistentPropertyInAnonymous.kt b/compiler/testData/diagnostics/tests/backingField/ReadNonexistentPropertyInAnonymous.kt index a2d911c6dea..8ad001b5e8f 100644 --- a/compiler/testData/diagnostics/tests/backingField/ReadNonexistentPropertyInAnonymous.kt +++ b/compiler/testData/diagnostics/tests/backingField/ReadNonexistentPropertyInAnonymous.kt @@ -1,5 +1,5 @@ class Cl() { { - val x = $a + val x = $a } } diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt4405.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt4405.kt new file mode 100644 index 00000000000..bc62830cce4 --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt4405.kt @@ -0,0 +1,30 @@ +//KT-4405 Control-flow analysis is not performed for some local declarations + +package d + +val closure = { + val x4 = "" // error: should be UNUSED_VARIABLE + + fun g() { + val x6 = "" // error: should be UNUSED_VARIABLE + } + + fun h(): Int { // error: should be NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY + } +} + +class A { + { + fun foo(): Int { + } + + val closure = { + val x = "" + + fun local(): Int { + } + } + + val y = "" + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/localClasses.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/localClasses.kt index 6c3890bcd69..65e96304249 100644 --- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/localClasses.kt +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/localClasses.kt @@ -15,7 +15,7 @@ fun f() { fun loc2(): Int { val x2_ = "" // error: should be UNUSED_VARIABLE - } + } } val v: String diff --git a/compiler/testData/diagnostics/tests/inner/extensionLambdaInsideNestedClass.kt b/compiler/testData/diagnostics/tests/inner/extensionLambdaInsideNestedClass.kt index 5b0328ab9fe..935122113a9 100644 --- a/compiler/testData/diagnostics/tests/inner/extensionLambdaInsideNestedClass.kt +++ b/compiler/testData/diagnostics/tests/inner/extensionLambdaInsideNestedClass.kt @@ -2,20 +2,20 @@ package f object A { class LoginFormPage() : Request({ - val failed = session.get("LOGIN_FAILED") + val failed = session.get("LOGIN_FAILED") }) } class B { class object { class LoginFormPage() : Request({ - val failed = session.get("LOGIN_FAILED") + val failed = session.get("LOGIN_FAILED") }) } class C { class LoginFormPage() : Request({ - val failed = session.get("LOGIN_FAILED") + val failed = session.get("LOGIN_FAILED") }) } } diff --git a/compiler/testData/diagnostics/tests/inner/referenceToSelfInLocal.kt b/compiler/testData/diagnostics/tests/inner/referenceToSelfInLocal.kt index 1b8965f90a5..e7b46fbd9b0 100644 --- a/compiler/testData/diagnostics/tests/inner/referenceToSelfInLocal.kt +++ b/compiler/testData/diagnostics/tests/inner/referenceToSelfInLocal.kt @@ -23,7 +23,7 @@ fun f() { val closure = { class MyClass { { - val x: MyClass = MyClass() + val x: MyClass = MyClass() } } } diff --git a/compiler/testData/diagnostics/tests/nullabilityAndAutoCasts/kt244.kt b/compiler/testData/diagnostics/tests/nullabilityAndAutoCasts/kt244.kt index f6780761a46..4d6cb2e3c2f 100644 --- a/compiler/testData/diagnostics/tests/nullabilityAndAutoCasts/kt244.kt +++ b/compiler/testData/diagnostics/tests/nullabilityAndAutoCasts/kt244.kt @@ -16,7 +16,7 @@ class A(a: String?) { val b = if (a != null) a.length else 1 { if (a != null) { - val c = a.length + val c = a.length } } diff --git a/compiler/testData/diagnostics/tests/regressions/kt1639-JFrame.kt b/compiler/testData/diagnostics/tests/regressions/kt1639-JFrame.kt index c5db0772cbe..721fa3e741a 100644 --- a/compiler/testData/diagnostics/tests/regressions/kt1639-JFrame.kt +++ b/compiler/testData/diagnostics/tests/regressions/kt1639-JFrame.kt @@ -4,6 +4,6 @@ import javax.swing.JFrame class KFrame() : JFrame() { { - val x = this.rootPaneCheckingEnabled // make sure field is visible + val x = this.rootPaneCheckingEnabled // make sure field is visible } } diff --git a/compiler/testData/diagnostics/tests/varargs/kt1838-param.kt b/compiler/testData/diagnostics/tests/varargs/kt1838-param.kt index 607bbfd1ebb..8a577f499d5 100644 --- a/compiler/testData/diagnostics/tests/varargs/kt1838-param.kt +++ b/compiler/testData/diagnostics/tests/varargs/kt1838-param.kt @@ -1,5 +1,5 @@ class A(vararg t : Int) { { - val t1 : IntArray = t + val t1 : IntArray = t } } diff --git a/compiler/testData/diagnostics/tests/varargs/kt1838-val.kt b/compiler/testData/diagnostics/tests/varargs/kt1838-val.kt index ae719ee3d42..c45857f56d7 100644 --- a/compiler/testData/diagnostics/tests/varargs/kt1838-val.kt +++ b/compiler/testData/diagnostics/tests/varargs/kt1838-val.kt @@ -1,5 +1,5 @@ class A(vararg val t : Int) { { - val t1 : IntArray = t + val t1 : IntArray = t } } diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index 1fa4afdad55..0cf50df8e92 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -1618,6 +1618,11 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/kt3501.kt"); } + @TestMetadata("kt4405.kt") + public void testKt4405() throws Exception { + doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/kt4405.kt"); + } + @TestMetadata("kt510.kt") public void testKt510() throws Exception { doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/kt510.kt"); diff --git a/idea/testData/checker/AnonymousInitializers.kt b/idea/testData/checker/AnonymousInitializers.kt index 336ac97ce74..841add1fad9 100644 --- a/idea/testData/checker/AnonymousInitializers.kt +++ b/idea/testData/checker/AnonymousInitializers.kt @@ -15,16 +15,16 @@ class WithC() { { $x = 1 $y = 2 - val b = x + val b = x } val a : Int get() = 1 { - val z = b - val zz = x - val zzz = $a + val z = b + val zz = x + val zzz = $a } } \ No newline at end of file diff --git a/idea/testData/checker/regression/ScopeForSecondaryConstructors.kt b/idea/testData/checker/regression/ScopeForSecondaryConstructors.kt index 34c41a81e96..00c6fddb76e 100644 --- a/idea/testData/checker/regression/ScopeForSecondaryConstructors.kt +++ b/idea/testData/checker/regression/ScopeForSecondaryConstructors.kt @@ -11,7 +11,7 @@ bar = 1 this.bar 1 : Int - val a : Int =1 + val a : Int =1 this : Foo } }