K2: implement FirLateinitIntrinsicApplicabilityChecker ^KT-55495 Fixed
This commit is contained in:
committed by
Space Team
parent
cfe8bc682c
commit
721a37f7e7
+7
@@ -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)
|
||||
|
||||
+1
@@ -46,6 +46,7 @@ object CommonExpressionCheckers : ExpressionCheckers() {
|
||||
FirFunInterfaceConstructorReferenceChecker,
|
||||
FirReifiedChecker,
|
||||
FirSuspendCallChecker,
|
||||
FirLateinitIntrinsicApplicabilityChecker,
|
||||
)
|
||||
|
||||
override val callCheckers: Set<FirCallChecker>
|
||||
|
||||
+80
@@ -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)
|
||||
}
|
||||
}
|
||||
+9
@@ -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 }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user