K2: implement FirLateinitIntrinsicApplicabilityChecker ^KT-55495 Fixed

This commit is contained in:
Kirill Rakhman
2023-01-03 16:52:18 +01:00
committed by Space Team
parent cfe8bc682c
commit 721a37f7e7
19 changed files with 199 additions and 208 deletions
@@ -1018,6 +1018,13 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
val LOCAL_VARIABLE_WITH_TYPE_PARAMETERS_WARNING by warning<KtProperty>(PositioningStrategy.TYPE_PARAMETERS_LIST)
val LOCAL_VARIABLE_WITH_TYPE_PARAMETERS by error<KtProperty>(PositioningStrategy.TYPE_PARAMETERS_LIST)
val EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS by error<KtExpression>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED)
val LATEINIT_INTRINSIC_CALL_ON_NON_LITERAL by error<PsiElement>()
val LATEINIT_INTRINSIC_CALL_ON_NON_LATEINIT by error<PsiElement>()
val LATEINIT_INTRINSIC_CALL_IN_INLINE_FUNCTION by error<PsiElement>()
val LATEINIT_INTRINSIC_CALL_ON_NON_ACCESSIBLE_PROPERTY by error<PsiElement>() {
parameter<Symbol>("declaration")
}
}
val MPP_PROJECTS by object : DiagnosticGroup("Multi-platform projects") {
@@ -557,6 +557,10 @@ object FirErrors {
val LOCAL_VARIABLE_WITH_TYPE_PARAMETERS_WARNING by warning0<KtProperty>(SourceElementPositioningStrategies.TYPE_PARAMETERS_LIST)
val LOCAL_VARIABLE_WITH_TYPE_PARAMETERS by error0<KtProperty>(SourceElementPositioningStrategies.TYPE_PARAMETERS_LIST)
val EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS by error0<KtExpression>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
val LATEINIT_INTRINSIC_CALL_ON_NON_LITERAL by error0<PsiElement>()
val LATEINIT_INTRINSIC_CALL_ON_NON_LATEINIT by error0<PsiElement>()
val LATEINIT_INTRINSIC_CALL_IN_INLINE_FUNCTION by error0<PsiElement>()
val LATEINIT_INTRINSIC_CALL_ON_NON_ACCESSIBLE_PROPERTY by error1<PsiElement, FirBasedSymbol<*>>()
// Multi-platform projects
val EXPECTED_DECLARATION_WITH_BODY by error0<KtDeclaration>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
@@ -46,6 +46,7 @@ object CommonExpressionCheckers : ExpressionCheckers() {
FirFunInterfaceConstructorReferenceChecker,
FirReifiedChecker,
FirSuspendCallChecker,
FirLateinitIntrinsicApplicabilityChecker,
)
override val callCheckers: Set<FirCallChecker>
@@ -0,0 +1,80 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.analysis.checkers.expression
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.getContainingClassSymbol
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFunction
import org.jetbrains.kotlin.fir.declarations.hasAnnotation
import org.jetbrains.kotlin.fir.declarations.utils.isInline
import org.jetbrains.kotlin.fir.declarations.utils.isLateInit
import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.references.toResolvedPropertySymbol
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.name.StandardClassIds.Annotations
object FirLateinitIntrinsicApplicabilityChecker : FirQualifiedAccessExpressionChecker() {
override fun check(expression: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) {
val resolvedSymbol = expression.calleeReference.toResolvedPropertySymbol() ?: return
// An optimization
if (resolvedSymbol.name.identifierOrNullIfSpecial != "isInitialized") return
val receiverParameter = resolvedSymbol.receiverParameter ?: return
if (!receiverParameter.hasAnnotation(Annotations.AccessibleLateinitPropertyLiteral, context.session)) return
val source = expression.calleeReference.source
val extensionReceiver = expression.extensionReceiver
if (extensionReceiver !is FirCallableReferenceAccess) {
reporter.reportOn(source, FirErrors.LATEINIT_INTRINSIC_CALL_ON_NON_LITERAL, context)
return
}
val calleePropertySymbol = extensionReceiver.calleeReference.toResolvedPropertySymbol() ?: return
if (!calleePropertySymbol.isLateInit) {
reporter.reportOn(source, FirErrors.LATEINIT_INTRINSIC_CALL_ON_NON_LATEINIT, context)
return
}
// property must be declared in one of the outer lexical scopes
if (calleePropertySymbol.containingClassOrFile(context) !in context.containingDeclarations) {
reporter.reportOn(
source,
FirErrors.LATEINIT_INTRINSIC_CALL_ON_NON_ACCESSIBLE_PROPERTY,
calleePropertySymbol,
context
)
return
}
val closestOwnFunction = context.containingDeclarations.lastOrNull()
if (closestOwnFunction is FirFunction && closestOwnFunction.isInline) {
reporter.reportOn(source, FirErrors.LATEINIT_INTRINSIC_CALL_IN_INLINE_FUNCTION, context)
}
}
/**
* Returns the containing class or file if the property is top-level.
*/
@OptIn(SymbolInternals::class)
private fun FirPropertySymbol.containingClassOrFile(
context: CheckerContext
): FirDeclaration? {
return getContainingClassSymbol(context.session)?.fir
?: context.session.firProvider.getFirCallableContainerFile(this)
}
}
@@ -289,6 +289,10 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ITERATOR_MISSING
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ITERATOR_ON_NULLABLE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.KCLASS_WITH_NULLABLE_TYPE_PARAMETER_IN_SIGNATURE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.LATEINIT_FIELD_IN_VAL_PROPERTY
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.LATEINIT_INTRINSIC_CALL_ON_NON_LITERAL
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.LATEINIT_INTRINSIC_CALL_ON_NON_LATEINIT
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.LATEINIT_INTRINSIC_CALL_ON_NON_ACCESSIBLE_PROPERTY
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.LATEINIT_INTRINSIC_CALL_IN_INLINE_FUNCTION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.LATEINIT_NULLABLE_BACKING_FIELD
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.LATEINIT_PROPERTY_FIELD_DECLARATION_WITH_INITIALIZER
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.LEAKED_IN_PLACE_LAMBDA
@@ -1646,6 +1650,11 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
map.put(LOCAL_VARIABLE_WITH_TYPE_PARAMETERS, "Local variables are not allowed to have type parameters")
map.put(EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS, "A property access cannot have explicit type arguments")
map.put(LATEINIT_INTRINSIC_CALL_ON_NON_LITERAL, "This declaration can only be called on a property literal (e.g. 'Foo::bar')")
map.put(LATEINIT_INTRINSIC_CALL_ON_NON_LATEINIT, "This declaration can only be called on a reference to a lateinit property")
map.put(LATEINIT_INTRINSIC_CALL_IN_INLINE_FUNCTION, "This declaration can not be used inside an inline function")
map.put(LATEINIT_INTRINSIC_CALL_ON_NON_ACCESSIBLE_PROPERTY, "Backing field of ''{0}'' is not accessible at this point", SYMBOL)
map.put(CONST_VAL_NOT_TOP_LEVEL_OR_OBJECT, "Const 'val' are only allowed on top level, in named objects, or in companion objects")
map.put(CONST_VAL_WITH_GETTER, "Const 'val' should not have a getter")
map.put(CONST_VAL_WITH_DELEGATE, "Const 'val' should not have a delegate")
@@ -113,6 +113,10 @@ fun FirBasedSymbol<*>.hasAnnotation(classId: ClassId, session: FirSession): Bool
return resolvedAnnotationsWithClassIds.hasAnnotation(classId, session)
}
fun FirAnnotationContainer.hasAnnotation(classId: ClassId, session: FirSession): Boolean {
return annotations.hasAnnotation(classId, session)
}
fun List<FirAnnotation>.hasAnnotation(classId: ClassId, session: FirSession): Boolean {
return this.any { it.toAnnotationClassId(session) == classId }
}