diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/LocalVariableResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/LocalVariableResolver.kt index a04a2bbf9ed..1d735fefe42 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/LocalVariableResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/LocalVariableResolver.kt @@ -30,6 +30,7 @@ import org.jetbrains.kotlin.psi.KtPsiUtil import org.jetbrains.kotlin.psi.KtVariableDeclaration import org.jetbrains.kotlin.resolve.calls.context.ContextDependency import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo +import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory import org.jetbrains.kotlin.resolve.calls.util.isSingleUnderscore import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil @@ -98,7 +99,7 @@ class LocalVariableResolver( val type = typeInfo.type if (type != null) { val initializerDataFlowValue = DataFlowValueFactory.createDataFlowValue(initializer, type, context) - if (!propertyDescriptor.isVar) { + if (!propertyDescriptor.isVar && initializerDataFlowValue.canBeBound) { context.trace.record(BindingContext.BOUND_INITIALIZER_VALUE, propertyDescriptor, initializerDataFlowValue) } // At this moment we do not take initializer value into account if type is given for a property diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowValue.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowValue.kt index 9c827882b7c..4f285bd55c7 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowValue.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowValue.kt @@ -69,6 +69,8 @@ class DataFlowValue(val identifierInfo: IdentifierInfo, */ val isStable = (kind == Kind.STABLE_VALUE || kind == Kind.STABLE_VARIABLE || kind == Kind.STABLE_COMPLEX_EXPRESSION) + val canBeBound get() = identifierInfo.canBeBound + override fun equals(other: Any?): Boolean { if (this === other) return true if (other !is DataFlowValue) return false diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/IdentifierInfo.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/IdentifierInfo.kt index 7a8adcaf8e6..142cac8a583 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/IdentifierInfo.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/IdentifierInfo.kt @@ -27,6 +27,8 @@ interface IdentifierInfo { val kind: DataFlowValue.Kind get() = OTHER + val canBeBound get() = false + object NO : IdentifierInfo { override fun toString() = "NO_IDENTIFIER_INFO" } @@ -45,6 +47,9 @@ interface IdentifierInfo { val bound: DataFlowValue? ) : IdentifierInfo { + override val canBeBound + get() = kind == STABLE_VALUE + override fun equals(other: Any?) = other is Variable && variable == other.variable override fun hashCode() = variable.hashCode() @@ -74,6 +79,9 @@ interface IdentifierInfo { ) : IdentifierInfo { override val kind: DataFlowValue.Kind get() = if (receiverInfo.kind == STABLE_VALUE) selectorInfo.kind else OTHER + override val canBeBound + get() = receiverInfo.canBeBound + override fun equals(other: Any?) = other is Qualified && receiverInfo == other.receiverInfo && selectorInfo == other.selectorInfo override fun hashCode() = 31 * receiverInfo.hashCode() + selectorInfo.hashCode() diff --git a/compiler/testData/diagnostics/tests/smartCasts/varnotnull/boundInitializerWrong.kt b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/boundInitializerWrong.kt new file mode 100644 index 00000000000..90324b99e7c --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/boundInitializerWrong.kt @@ -0,0 +1,45 @@ +// KT-15792 and related + +fun foo() { + var x: String? = "" + val y = x + x = null + if (y != null) { + x.hashCode() + } +} + +fun foo2() { + var x: String? = "" + val y = x + if (y != null) { + x.hashCode() + } +} + +fun bar(s: String?) { + var ss = s + val hashCode = ss?.hashCode() + ss = null + if (hashCode != null) { + ss.hashCode() + } +} + +fun bar2(s: String?) { + var ss = s + val hashCode = ss?.hashCode() + if (hashCode != null) { + ss.hashCode() + } +} + +class Some(var s: String?) + +fun baz(arg: Some?) { + val ss = arg?.s + if (ss != null) { + arg.hashCode() + arg.s.hashCode() + } +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/varnotnull/boundInitializerWrong.txt b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/boundInitializerWrong.txt new file mode 100644 index 00000000000..9e89414bdf3 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/boundInitializerWrong.txt @@ -0,0 +1,15 @@ +package + +public fun bar(/*0*/ s: kotlin.String?): kotlin.Unit +public fun bar2(/*0*/ s: kotlin.String?): kotlin.Unit +public fun baz(/*0*/ arg: Some?): kotlin.Unit +public fun foo(): kotlin.Unit +public fun foo2(): kotlin.Unit + +public final class Some { + public constructor Some(/*0*/ s: kotlin.String?) + public final var s: kotlin.String? + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 5b9e234341e..ab50fbb2236 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -20652,6 +20652,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("boundInitializerWrong.kt") + public void testBoundInitializerWrong() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/varnotnull/boundInitializerWrong.kt"); + doTest(fileName); + } + @TestMetadata("doWhileWithBreak.kt") public void testDoWhileWithBreak() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/varnotnull/doWhileWithBreak.kt");