K1: introduce smartcast deprecation for a public API property in invisible class
#KT-56511 Fixed Related to KT-57290
This commit is contained in:
committed by
Space Team
parent
0b31e5ad63
commit
41c868445c
+9
-1
@@ -57,6 +57,13 @@ class DataFlowValue(
|
|||||||
// Should be unstable, but can be used as stable with deprecation warning
|
// Should be unstable, but can be used as stable with deprecation warning
|
||||||
LEGACY_ALIEN_BASE_PROPERTY("alien derived", "property declared in base class from different module"),
|
LEGACY_ALIEN_BASE_PROPERTY("alien derived", "property declared in base class from different module"),
|
||||||
|
|
||||||
|
// Protected / public member value from derived class from another module, in case the derived class is non-public API
|
||||||
|
// Should be unstable, but can be used as stable with deprecation warning
|
||||||
|
LEGACY_ALIEN_BASE_PROPERTY_INHERITED_IN_INVISIBLE_CLASS(
|
||||||
|
"alien inherited in invisible",
|
||||||
|
"property declared in base class from different module inherited in non-public API class"
|
||||||
|
),
|
||||||
|
|
||||||
// Protected / public member value from another module
|
// Protected / public member value from another module
|
||||||
// Smart casts are not safe
|
// Smart casts are not safe
|
||||||
ALIEN_PUBLIC_PROPERTY("alien public", "public API property declared in different module"),
|
ALIEN_PUBLIC_PROPERTY("alien public", "public API property declared in different module"),
|
||||||
@@ -88,7 +95,8 @@ class DataFlowValue(
|
|||||||
kind == Kind.STABLE_VARIABLE ||
|
kind == Kind.STABLE_VARIABLE ||
|
||||||
kind == Kind.STABLE_COMPLEX_EXPRESSION ||
|
kind == Kind.STABLE_COMPLEX_EXPRESSION ||
|
||||||
kind == Kind.LEGACY_STABLE_LOCAL_DELEGATED_PROPERTY ||
|
kind == Kind.LEGACY_STABLE_LOCAL_DELEGATED_PROPERTY ||
|
||||||
kind == Kind.LEGACY_ALIEN_BASE_PROPERTY
|
kind == Kind.LEGACY_ALIEN_BASE_PROPERTY ||
|
||||||
|
kind == Kind.LEGACY_ALIEN_BASE_PROPERTY_INHERITED_IN_INVISIBLE_CLASS
|
||||||
|
|
||||||
val canBeBound get() = identifierInfo.canBeBound
|
val canBeBound get() = identifierInfo.canBeBound
|
||||||
|
|
||||||
|
|||||||
+21
-14
@@ -7,7 +7,7 @@ package org.jetbrains.kotlin.resolve.calls.smartcasts
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.cfg.getDeclarationDescriptorIncludingConstructors
|
import org.jetbrains.kotlin.cfg.getDeclarationDescriptorIncludingConstructors
|
||||||
import org.jetbrains.kotlin.cfg.getElementParentDeclaration
|
import org.jetbrains.kotlin.cfg.getElementParentDeclaration
|
||||||
import org.jetbrains.kotlin.config.LanguageFeature
|
import org.jetbrains.kotlin.config.LanguageFeature.*
|
||||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
||||||
@@ -26,21 +26,29 @@ internal fun PropertyDescriptor.propertyKind(
|
|||||||
if (isVar) return DataFlowValue.Kind.MUTABLE_PROPERTY
|
if (isVar) return DataFlowValue.Kind.MUTABLE_PROPERTY
|
||||||
if (isOverridable) return DataFlowValue.Kind.PROPERTY_WITH_GETTER
|
if (isOverridable) return DataFlowValue.Kind.PROPERTY_WITH_GETTER
|
||||||
if (!hasDefaultGetter()) return DataFlowValue.Kind.PROPERTY_WITH_GETTER
|
if (!hasDefaultGetter()) return DataFlowValue.Kind.PROPERTY_WITH_GETTER
|
||||||
if (!isInvisibleFromOtherModules()) {
|
val originalDescriptor = DescriptorUtils.unwrapFakeOverride(this)
|
||||||
val declarationModule = DescriptorUtils.getContainingModule(this)
|
val isInvisibleFromOtherModuleUnwrappedFakeOverride = originalDescriptor.isInvisibleFromOtherModules()
|
||||||
if (!areCompiledTogether(usageModule, declarationModule)) {
|
if (isInvisibleFromOtherModuleUnwrappedFakeOverride) return DataFlowValue.Kind.STABLE_VALUE
|
||||||
return DataFlowValue.Kind.ALIEN_PUBLIC_PROPERTY
|
|
||||||
}
|
if (kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
|
||||||
if (kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
|
if (overriddenDescriptors.any { isDeclaredInAnotherModule(usageModule) }) {
|
||||||
if (overriddenDescriptors.any { isDeclaredInAnotherModule(usageModule) }) {
|
val deprecationForInvisibleFakeOverride =
|
||||||
return if (!languageVersionSettings.supportsFeature(LanguageFeature.ProhibitSmartcastsOnPropertyFromAlienBaseClass)) {
|
isInvisibleFromOtherModules() != isInvisibleFromOtherModuleUnwrappedFakeOverride &&
|
||||||
|
!languageVersionSettings.supportsFeature(ProhibitSmartcastsOnPropertyFromAlienBaseClassInheritedInInvisibleClass)
|
||||||
|
return when {
|
||||||
|
deprecationForInvisibleFakeOverride ->
|
||||||
|
DataFlowValue.Kind.LEGACY_ALIEN_BASE_PROPERTY_INHERITED_IN_INVISIBLE_CLASS
|
||||||
|
!languageVersionSettings.supportsFeature(ProhibitSmartcastsOnPropertyFromAlienBaseClass) ->
|
||||||
DataFlowValue.Kind.LEGACY_ALIEN_BASE_PROPERTY
|
DataFlowValue.Kind.LEGACY_ALIEN_BASE_PROPERTY
|
||||||
} else {
|
else ->
|
||||||
DataFlowValue.Kind.ALIEN_PUBLIC_PROPERTY
|
DataFlowValue.Kind.ALIEN_PUBLIC_PROPERTY
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val declarationModule = DescriptorUtils.getContainingModule(originalDescriptor)
|
||||||
|
if (!areCompiledTogether(usageModule, declarationModule)) return DataFlowValue.Kind.ALIEN_PUBLIC_PROPERTY
|
||||||
|
|
||||||
return DataFlowValue.Kind.STABLE_VALUE
|
return DataFlowValue.Kind.STABLE_VALUE
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,7 +84,7 @@ internal fun VariableDescriptor.variableKind(
|
|||||||
|
|
||||||
if (this is LocalVariableDescriptor && this.isDelegated) {
|
if (this is LocalVariableDescriptor && this.isDelegated) {
|
||||||
// Local delegated property: normally unstable, but can be treated as stable in legacy mode
|
// Local delegated property: normally unstable, but can be treated as stable in legacy mode
|
||||||
return if (languageVersionSettings.supportsFeature(LanguageFeature.ProhibitSmartcastsOnLocalDelegatedProperty))
|
return if (languageVersionSettings.supportsFeature(ProhibitSmartcastsOnLocalDelegatedProperty))
|
||||||
DataFlowValue.Kind.PROPERTY_WITH_GETTER
|
DataFlowValue.Kind.PROPERTY_WITH_GETTER
|
||||||
else
|
else
|
||||||
DataFlowValue.Kind.LEGACY_STABLE_LOCAL_DELEGATED_PROPERTY
|
DataFlowValue.Kind.LEGACY_STABLE_LOCAL_DELEGATED_PROPERTY
|
||||||
@@ -101,7 +109,7 @@ internal fun VariableDescriptor.variableKind(
|
|||||||
val variableContainingDeclaration = this.containingDeclaration
|
val variableContainingDeclaration = this.containingDeclaration
|
||||||
if (isAccessedInsideClosure(variableContainingDeclaration, bindingContext, accessElement)) {
|
if (isAccessedInsideClosure(variableContainingDeclaration, bindingContext, accessElement)) {
|
||||||
// stable iff we have no writers in closures AND this closure is AFTER all writers
|
// stable iff we have no writers in closures AND this closure is AFTER all writers
|
||||||
return if (preliminaryVisitor.languageVersionSettings.supportsFeature(LanguageFeature.CapturedInClosureSmartCasts) &&
|
return if (preliminaryVisitor.languageVersionSettings.supportsFeature(CapturedInClosureSmartCasts) &&
|
||||||
hasNoWritersInClosures(variableContainingDeclaration, writers, bindingContext) &&
|
hasNoWritersInClosures(variableContainingDeclaration, writers, bindingContext) &&
|
||||||
isAccessedInsideClosureAfterAllWriters(writers, accessElement)
|
isAccessedInsideClosureAfterAllWriters(writers, accessElement)
|
||||||
) {
|
) {
|
||||||
@@ -157,7 +165,6 @@ private fun isAccessedBeforeAllClosureWriters(
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun DeclarationDescriptorWithVisibility.isInvisibleFromOtherModules(): Boolean {
|
private fun DeclarationDescriptorWithVisibility.isInvisibleFromOtherModules(): Boolean {
|
||||||
if (DescriptorVisibilities.INVISIBLE_FROM_OTHER_MODULES.contains(visibility)) return true
|
if (DescriptorVisibilities.INVISIBLE_FROM_OTHER_MODULES.contains(visibility)) return true
|
||||||
|
|
||||||
|
|||||||
+1
@@ -226,6 +226,7 @@ class SmartCastManager(private val argumentTypeResolver: ArgumentTypeResolver) {
|
|||||||
if (KotlinBuiltIns.isNullableNothing(type)) return
|
if (KotlinBuiltIns.isNullableNothing(type)) return
|
||||||
if (dataFlowValue.isStable) {
|
if (dataFlowValue.isStable) {
|
||||||
if (dataFlowValue.kind == DataFlowValue.Kind.LEGACY_ALIEN_BASE_PROPERTY ||
|
if (dataFlowValue.kind == DataFlowValue.Kind.LEGACY_ALIEN_BASE_PROPERTY ||
|
||||||
|
dataFlowValue.kind == DataFlowValue.Kind.LEGACY_ALIEN_BASE_PROPERTY_INHERITED_IN_INVISIBLE_CLASS ||
|
||||||
dataFlowValue.kind == DataFlowValue.Kind.LEGACY_STABLE_LOCAL_DELEGATED_PROPERTY
|
dataFlowValue.kind == DataFlowValue.Kind.LEGACY_STABLE_LOCAL_DELEGATED_PROPERTY
|
||||||
) {
|
) {
|
||||||
trace.report(Errors.DEPRECATED_SMARTCAST.on(expression, type, expression.text, dataFlowValue.kind.description))
|
trace.report(Errors.DEPRECATED_SMARTCAST.on(expression, type, expression.text, dataFlowValue.kind.description))
|
||||||
|
|||||||
Vendored
+10
@@ -0,0 +1,10 @@
|
|||||||
|
// -- Module: <m1> --
|
||||||
|
|
||||||
|
// -- Module: <m2> --
|
||||||
|
/B.kt:13:13: warning: smart cast to 'String' is deprecated, because 'x' is a property declared in base class from different module inherited in non-public API class
|
||||||
|
x.length
|
||||||
|
^
|
||||||
|
/B.kt:22:9: warning: smart cast to 'String' is deprecated, because 'i.x' is a property declared in base class from different module inherited in non-public API class
|
||||||
|
i.x.length
|
||||||
|
^
|
||||||
|
|
||||||
Vendored
+9
@@ -1,3 +1,4 @@
|
|||||||
|
// RENDER_DIAGNOSTICS_FULL_TEXT
|
||||||
// MODULE: m1
|
// MODULE: m1
|
||||||
// FILE: A.kt
|
// FILE: A.kt
|
||||||
|
|
||||||
@@ -13,3 +14,11 @@ private class Derived : Base("123") {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class Internal : Base("456")
|
||||||
|
|
||||||
|
internal fun bar(i: Internal) {
|
||||||
|
if (i.x is String) {
|
||||||
|
i.x.length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+10
-1
@@ -1,3 +1,4 @@
|
|||||||
|
// RENDER_DIAGNOSTICS_FULL_TEXT
|
||||||
// MODULE: m1
|
// MODULE: m1
|
||||||
// FILE: A.kt
|
// FILE: A.kt
|
||||||
|
|
||||||
@@ -9,7 +10,15 @@ open class Base(val x: Any)
|
|||||||
private class Derived : Base("123") {
|
private class Derived : Base("123") {
|
||||||
fun foo() {
|
fun foo() {
|
||||||
if (x is String) {
|
if (x is String) {
|
||||||
<!DEBUG_INFO_SMARTCAST!>x<!>.length
|
<!DEBUG_INFO_SMARTCAST, DEPRECATED_SMARTCAST!>x<!>.length
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class Internal : Base("456")
|
||||||
|
|
||||||
|
internal fun bar(i: Internal) {
|
||||||
|
if (i.x is String) {
|
||||||
|
<!DEBUG_INFO_SMARTCAST, DEPRECATED_SMARTCAST!>i.x<!>.length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -285,6 +285,7 @@ enum class LanguageFeature(
|
|||||||
|
|
||||||
EnhanceNullabilityOfPrimitiveArrays(KOTLIN_2_0, kind = BUG_FIX), // KT-54521
|
EnhanceNullabilityOfPrimitiveArrays(KOTLIN_2_0, kind = BUG_FIX), // KT-54521
|
||||||
AllowEmptyIntersectionsInResultTypeResolver(KOTLIN_2_0, kind = OTHER), // KT-51221
|
AllowEmptyIntersectionsInResultTypeResolver(KOTLIN_2_0, kind = OTHER), // KT-51221
|
||||||
|
ProhibitSmartcastsOnPropertyFromAlienBaseClassInheritedInInvisibleClass(KOTLIN_2_0, kind = BUG_FIX), // KT-57290
|
||||||
|
|
||||||
// End of 2.* language features --------------------------------------------------
|
// End of 2.* language features --------------------------------------------------
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user