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
|
||||
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
|
||||
// Smart casts are not safe
|
||||
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_COMPLEX_EXPRESSION ||
|
||||
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
|
||||
|
||||
|
||||
+21
-14
@@ -7,7 +7,7 @@ package org.jetbrains.kotlin.resolve.calls.smartcasts
|
||||
|
||||
import org.jetbrains.kotlin.cfg.getDeclarationDescriptorIncludingConstructors
|
||||
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.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
||||
@@ -26,21 +26,29 @@ internal fun PropertyDescriptor.propertyKind(
|
||||
if (isVar) return DataFlowValue.Kind.MUTABLE_PROPERTY
|
||||
if (isOverridable) return DataFlowValue.Kind.PROPERTY_WITH_GETTER
|
||||
if (!hasDefaultGetter()) return DataFlowValue.Kind.PROPERTY_WITH_GETTER
|
||||
if (!isInvisibleFromOtherModules()) {
|
||||
val declarationModule = DescriptorUtils.getContainingModule(this)
|
||||
if (!areCompiledTogether(usageModule, declarationModule)) {
|
||||
return DataFlowValue.Kind.ALIEN_PUBLIC_PROPERTY
|
||||
}
|
||||
if (kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
|
||||
if (overriddenDescriptors.any { isDeclaredInAnotherModule(usageModule) }) {
|
||||
return if (!languageVersionSettings.supportsFeature(LanguageFeature.ProhibitSmartcastsOnPropertyFromAlienBaseClass)) {
|
||||
val originalDescriptor = DescriptorUtils.unwrapFakeOverride(this)
|
||||
val isInvisibleFromOtherModuleUnwrappedFakeOverride = originalDescriptor.isInvisibleFromOtherModules()
|
||||
if (isInvisibleFromOtherModuleUnwrappedFakeOverride) return DataFlowValue.Kind.STABLE_VALUE
|
||||
|
||||
if (kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
|
||||
if (overriddenDescriptors.any { isDeclaredInAnotherModule(usageModule) }) {
|
||||
val deprecationForInvisibleFakeOverride =
|
||||
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
|
||||
} else {
|
||||
else ->
|
||||
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
|
||||
}
|
||||
|
||||
@@ -76,7 +84,7 @@ internal fun VariableDescriptor.variableKind(
|
||||
|
||||
if (this is LocalVariableDescriptor && this.isDelegated) {
|
||||
// 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
|
||||
else
|
||||
DataFlowValue.Kind.LEGACY_STABLE_LOCAL_DELEGATED_PROPERTY
|
||||
@@ -101,7 +109,7 @@ internal fun VariableDescriptor.variableKind(
|
||||
val variableContainingDeclaration = this.containingDeclaration
|
||||
if (isAccessedInsideClosure(variableContainingDeclaration, bindingContext, accessElement)) {
|
||||
// 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) &&
|
||||
isAccessedInsideClosureAfterAllWriters(writers, accessElement)
|
||||
) {
|
||||
@@ -157,7 +165,6 @@ private fun isAccessedBeforeAllClosureWriters(
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
private fun DeclarationDescriptorWithVisibility.isInvisibleFromOtherModules(): Boolean {
|
||||
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 (dataFlowValue.isStable) {
|
||||
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
|
||||
) {
|
||||
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
|
||||
// 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
|
||||
// FILE: A.kt
|
||||
|
||||
@@ -9,7 +10,15 @@ open class Base(val x: Any)
|
||||
private class Derived : Base("123") {
|
||||
fun foo() {
|
||||
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
|
||||
AllowEmptyIntersectionsInResultTypeResolver(KOTLIN_2_0, kind = OTHER), // KT-51221
|
||||
ProhibitSmartcastsOnPropertyFromAlienBaseClassInheritedInInvisibleClass(KOTLIN_2_0, kind = BUG_FIX), // KT-57290
|
||||
|
||||
// End of 2.* language features --------------------------------------------------
|
||||
|
||||
|
||||
Reference in New Issue
Block a user