FIR/FE10: fix false positives described in KT-24643

This commit is contained in:
Mikhail Glukhikh
2022-06-24 12:02:10 +02:00
committed by Space
parent 3223d3c3e9
commit 4aed9511f6
3 changed files with 57 additions and 19 deletions
@@ -8,14 +8,16 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.diagnostics.reportOn
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.scopes.processAllProperties
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.toSymbol
import org.jetbrains.kotlin.fir.types.type
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
object FirDelegateUsesExtensionPropertyTypeParameterChecker : FirPropertyChecker() {
@@ -30,17 +32,32 @@ object FirDelegateUsesExtensionPropertyTypeParameterChecker : FirPropertyChecker
}
private fun ConeKotlinType.findUsedTypeParameterSymbol(
parameters: HashSet<FirTypeParameterSymbol>,
typeParameterSymbols: HashSet<FirTypeParameterSymbol>,
delegate: FirFunctionCall,
context: CheckerContext,
reporter: DiagnosticReporter,
): FirTypeParameterSymbol? {
val expandedDelegateClassLikeType =
delegate.typeRef.coneType.lowerBoundIfFlexible().fullyExpandedType(context.session)
.unwrapDefinitelyNotNull() as? ConeClassLikeType ?: return null
val delegateClassSymbol = expandedDelegateClassLikeType.lookupTag.toSymbol(context.session) as? FirRegularClassSymbol ?: return null
val delegateClassScope by lazy { delegateClassSymbol.unsubstitutedScope(context) }
for (it in typeArguments) {
val theType = it.type ?: continue
val symbol = theType.toSymbol(context.session) as? FirTypeParameterSymbol
val argumentAsTypeParameterSymbol = theType.toSymbol(context.session) as? FirTypeParameterSymbol
if (symbol in parameters) return symbol
val usedTypeParameterSymbol = theType.findUsedTypeParameterSymbol(parameters, delegate, context, reporter)
if (argumentAsTypeParameterSymbol in typeParameterSymbols) {
var propertyWithTypeParameterTypeFound = false
delegateClassScope.processAllProperties { symbol ->
if (symbol.resolvedReturnType.contains { it is ConeTypeParameterType }) {
propertyWithTypeParameterTypeFound = true
}
}
if (propertyWithTypeParameterTypeFound) {
return argumentAsTypeParameterSymbol
}
}
val usedTypeParameterSymbol = theType.findUsedTypeParameterSymbol(typeParameterSymbols, delegate, context, reporter)
if (usedTypeParameterSymbol != null) {
return usedTypeParameterSymbol
}
@@ -26,8 +26,8 @@ import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory0
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.diagnostics.Errors.*
import org.jetbrains.kotlin.incremental.KotlinLookupLocation
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.hasActualModifier
@@ -494,7 +494,7 @@ class DeclarationsChecker(
val declaration = classOrObject.primaryConstructor ?: return
for (parameter in declaration.valueParameters) {
trace.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, parameter)?.let {
trace.get(PRIMARY_CONSTRUCTOR_PARAMETER, parameter)?.let {
modifiersChecker.checkModifiersForDeclaration(parameter, it)
LateinitModifierApplicabilityChecker.checkLateinitModifierApplicability(trace, parameter, it)
}
@@ -703,7 +703,7 @@ class DeclarationsChecker(
return
}
val backingFieldRequired = trace.bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor) ?: false
val backingFieldRequired = trace.bindingContext.get(BACKING_FIELD_REQUIRED, propertyDescriptor) ?: false
if (inInterface && backingFieldRequired && hasAccessorImplementation) {
trace.report(BACKING_FIELD_IN_INTERFACE.on(property))
}
@@ -726,6 +726,15 @@ class DeclarationsChecker(
trace.report(EXPECTED_DELEGATED_PROPERTY.on(delegate))
} else if (property.receiverTypeReference != null) {
val delegatedPropertyResolvedCall = trace.get(DELEGATED_PROPERTY_RESOLVED_CALL, propertyDescriptor.getter)
val provideDelegateResolvedCall = trace.get(PROVIDE_DELEGATE_RESOLVED_CALL, propertyDescriptor)
val delegateType = provideDelegateResolvedCall?.resultingDescriptor?.returnType
?: delegate.expression?.let { trace.getType(it) } ?: return
val delegateClassDescriptor =
delegateType.lowerIfFlexible().unwrap().constructor.declarationDescriptor.let {
it as? ClassDescriptor ?: (it as? TypeAliasDescriptor)?.expandedType?.constructor?.declarationDescriptor
} as? ClassDescriptor ?: return
val delegateClassScope by lazy { delegateClassDescriptor.unsubstitutedMemberScope }
val dispatchReceiverType = delegatedPropertyResolvedCall?.dispatchReceiver?.type
val extensionReceiverType = delegatedPropertyResolvedCall?.extensionReceiver?.type
val usedParameter = propertyDescriptor.typeParameters.find { typeParameter ->
@@ -733,6 +742,18 @@ class DeclarationsChecker(
extensionReceiverType?.contains { it.constructor == typeParameter.typeConstructor } == true
}
if (usedParameter != null) {
var propertyWithTypeParameterTypeFound = false
val names = delegateClassScope.getVariableNames()
for (name in names) {
delegateClassScope.getContributedVariables(name, KotlinLookupLocation(delegate))
.forEach { propertyInDelegateClass ->
if (propertyInDelegateClass.type.contains { it.constructor.declarationDescriptor is TypeParameterDescriptor }) {
propertyWithTypeParameterTypeFound = true
return@forEach
}
}
}
if (!propertyWithTypeParameterTypeFound) return
trace.report(
DELEGATE_USES_EXTENSION_PROPERTY_TYPE_PARAMETER.on(
languageVersionSettings,
@@ -743,7 +764,7 @@ class DeclarationsChecker(
}
}
} else {
val isUninitialized = trace.bindingContext.get(BindingContext.IS_UNINITIALIZED, propertyDescriptor) ?: false
val isUninitialized = trace.bindingContext.get(IS_UNINITIALIZED, propertyDescriptor) ?: false
val isExternal = propertyDescriptor.isEffectivelyExternal()
if (backingFieldRequired && !inInterface && !propertyDescriptor.isLateInit && !isExpect && isUninitialized && !isExternal) {
if (propertyDescriptor.extensionReceiverParameter != null && !hasAccessorImplementation) {
@@ -757,7 +778,7 @@ class DeclarationsChecker(
}
} else if (property.typeReference == null && !languageVersionSettings.supportsFeature(LanguageFeature.ShortSyntaxForPropertyGetters)) {
trace.report(
Errors.UNSUPPORTED_FEATURE.on(
UNSUPPORTED_FEATURE.on(
property,
LanguageFeature.ShortSyntaxForPropertyGetters to languageVersionSettings
)
@@ -920,9 +941,9 @@ class DeclarationsChecker(
)
if (accessor.isGetter) {
if (accessorDescriptor.visibility != propertyDescriptor.visibility) {
reportVisibilityModifierDiagnostics(tokens.values, Errors.GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY)
reportVisibilityModifierDiagnostics(tokens.values, GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY)
} else {
reportVisibilityModifierDiagnostics(tokens.values, Errors.REDUNDANT_MODIFIER_IN_GETTER)
reportVisibilityModifierDiagnostics(tokens.values, REDUNDANT_MODIFIER_IN_GETTER)
}
} else {
if (propertyDescriptor.isOverridable
@@ -930,14 +951,14 @@ class DeclarationsChecker(
&& propertyDescriptor.visibility != DescriptorVisibilities.PRIVATE
) {
if (propertyDescriptor.modality == Modality.ABSTRACT) {
reportVisibilityModifierDiagnostics(tokens.values, Errors.PRIVATE_SETTER_FOR_ABSTRACT_PROPERTY)
reportVisibilityModifierDiagnostics(tokens.values, PRIVATE_SETTER_FOR_ABSTRACT_PROPERTY)
} else {
reportVisibilityModifierDiagnostics(tokens.values, Errors.PRIVATE_SETTER_FOR_OPEN_PROPERTY)
reportVisibilityModifierDiagnostics(tokens.values, PRIVATE_SETTER_FOR_OPEN_PROPERTY)
}
} else {
val compare = DescriptorVisibilities.compare(accessorDescriptor.visibility, propertyDescriptor.visibility)
if (compare == null || compare > 0) {
reportVisibilityModifierDiagnostics(tokens.values, Errors.SETTER_VISIBILITY_INCONSISTENT_WITH_PROPERTY_VISIBILITY)
reportVisibilityModifierDiagnostics(tokens.values, SETTER_VISIBILITY_INCONSISTENT_WITH_PROPERTY_VISIBILITY)
}
}
}
@@ -11,7 +11,7 @@ fun <T, V> logged(getter: (T) -> V) =
getter(thisRef)
}
val <T> List<T>.second: T <!DELEGATE_USES_EXTENSION_PROPERTY_TYPE_PARAMETER_ERROR!>by logged { it[1] }<!>
val <T> List<T>.second: T by logged { it[1] }
class Delegate<T>(private val fn: (List<T>) -> T) {
private var cache: T? = null