Deprecate smart cast on alien derived property #KT-48101 Fixed
This commit is contained in:
+14
-1
@@ -41,25 +41,37 @@ class DataFlowValue(
|
||||
// or protected / public member value from the same module without open / custom getter
|
||||
// Smart casts are completely safe
|
||||
STABLE_VALUE("stable val"),
|
||||
|
||||
// Block, or if / else, or when
|
||||
STABLE_COMPLEX_EXPRESSION("complex expression", ""),
|
||||
|
||||
// Should be unstable, but can be used as stable with deprecation warning
|
||||
LEGACY_STABLE_LOCAL_DELEGATED_PROPERTY("local delegated property"),
|
||||
|
||||
// Member value with open / custom getter
|
||||
// Smart casts are not safe
|
||||
PROPERTY_WITH_GETTER("custom getter", "property that has open or custom getter"),
|
||||
|
||||
// Protected / public member value from derived class from another module
|
||||
// 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 another module
|
||||
// Smart casts are not safe
|
||||
ALIEN_PUBLIC_PROPERTY("alien public", "public API property declared in different module"),
|
||||
|
||||
// Local variable not yet captured by a changing closure
|
||||
// Smart casts are safe but possible changes in loops / closures ahead must be taken into account
|
||||
STABLE_VARIABLE("stable var", "local variable that can be changed since the check in a loop"),
|
||||
|
||||
// Local variable already captured by a changing closure
|
||||
// Smart casts are not safe
|
||||
CAPTURED_VARIABLE("captured var", "local variable that is captured by a changing closure"),
|
||||
|
||||
// Member variable regardless of its visibility
|
||||
// Smart casts are not safe
|
||||
MUTABLE_PROPERTY("member", "mutable property that could have been changed by this time"),
|
||||
|
||||
// Some complex expression
|
||||
// Smart casts are not safe
|
||||
OTHER("other", "complex expression");
|
||||
@@ -74,7 +86,8 @@ class DataFlowValue(
|
||||
val isStable = kind == Kind.STABLE_VALUE ||
|
||||
kind == Kind.STABLE_VARIABLE ||
|
||||
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
|
||||
|
||||
val canBeBound get() = identifierInfo.canBeBound
|
||||
|
||||
|
||||
+25
-3
@@ -19,7 +19,10 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.types.expressions.AssignedVariablesSearcher
|
||||
import org.jetbrains.kotlin.types.expressions.PreliminaryDeclarationVisitor
|
||||
|
||||
internal fun PropertyDescriptor.propertyKind(usageModule: ModuleDescriptor?): DataFlowValue.Kind {
|
||||
internal fun PropertyDescriptor.propertyKind(
|
||||
usageModule: ModuleDescriptor?,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
): DataFlowValue.Kind {
|
||||
if (isVar) return DataFlowValue.Kind.MUTABLE_PROPERTY
|
||||
if (isOverridable) return DataFlowValue.Kind.PROPERTY_WITH_GETTER
|
||||
if (!hasDefaultGetter()) return DataFlowValue.Kind.PROPERTY_WITH_GETTER
|
||||
@@ -28,11 +31,30 @@ internal fun PropertyDescriptor.propertyKind(usageModule: ModuleDescriptor?): Da
|
||||
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)) {
|
||||
DataFlowValue.Kind.LEGACY_ALIEN_BASE_PROPERTY
|
||||
} else {
|
||||
DataFlowValue.Kind.ALIEN_PUBLIC_PROPERTY
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return DataFlowValue.Kind.STABLE_VALUE
|
||||
}
|
||||
|
||||
internal fun areCompiledTogether(
|
||||
private fun PropertyDescriptor.isDeclaredInAnotherModule(usageModule: ModuleDescriptor?): Boolean {
|
||||
if (!areCompiledTogether(usageModule, DescriptorUtils.getContainingModule(this))) {
|
||||
return true
|
||||
}
|
||||
if (kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
|
||||
return overriddenDescriptors.any { it.isDeclaredInAnotherModule(usageModule) }
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun areCompiledTogether(
|
||||
usageModule: ModuleDescriptor?,
|
||||
declarationModule: ModuleDescriptor,
|
||||
): Boolean {
|
||||
@@ -49,7 +71,7 @@ internal fun VariableDescriptor.variableKind(
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
): DataFlowValue.Kind {
|
||||
if (this is PropertyDescriptor) {
|
||||
return propertyKind(usageModule)
|
||||
return propertyKind(usageModule, languageVersionSettings)
|
||||
}
|
||||
|
||||
if (this is LocalVariableDescriptor && this.isDelegated) {
|
||||
|
||||
+3
-1
@@ -226,7 +226,9 @@ class SmartCastManager(private val argumentTypeResolver: ArgumentTypeResolver) {
|
||||
) {
|
||||
if (KotlinBuiltIns.isNullableNothing(type)) return
|
||||
if (dataFlowValue.isStable) {
|
||||
if (dataFlowValue.kind == DataFlowValue.Kind.LEGACY_STABLE_LOCAL_DELEGATED_PROPERTY) {
|
||||
if (dataFlowValue.kind == DataFlowValue.Kind.LEGACY_ALIEN_BASE_PROPERTY ||
|
||||
dataFlowValue.kind == DataFlowValue.Kind.LEGACY_STABLE_LOCAL_DELEGATED_PROPERTY
|
||||
) {
|
||||
trace.report(Errors.DEPRECATED_SMARTCAST.on(expression, type, expression.text, dataFlowValue.kind.description))
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user