K2: add inline JVM target version checker

#KT-60777 Fixed
This commit is contained in:
Alexander Udalov
2024-02-28 15:55:34 +01:00
committed by Space Team
parent d475371394
commit 3bb2ea10b6
19 changed files with 260 additions and 16 deletions
@@ -193,6 +193,13 @@ object JVM_DIAGNOSTICS_LIST : DiagnosticList("FirJvmErrors") {
}
}
val INLINE by object : DiagnosticGroup("Inline") {
val INLINE_FROM_HIGHER_PLATFORM by error<PsiElement> {
parameter<String>("inlinedBytecodeVersion")
parameter<String>("currentModuleBytecodeVersion")
}
}
val MISC by object : DiagnosticGroup("Misc") {
val INAPPLICABLE_JVM_FIELD by error<KtAnnotationEntry> {
parameter<String>("message")
@@ -127,6 +127,9 @@ object FirJvmErrors {
// Suspension Point
val SUSPENSION_POINT_INSIDE_CRITICAL_SECTION: KtDiagnosticFactory1<FirCallableSymbol<*>> by error1<PsiElement, FirCallableSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
// Inline
val INLINE_FROM_HIGHER_PLATFORM: KtDiagnosticFactory2<String, String> by error2<PsiElement, String, String>()
// Misc
val INAPPLICABLE_JVM_FIELD: KtDiagnosticFactory1<String> by error1<KtAnnotationEntry, String>()
val INAPPLICABLE_JVM_FIELD_WARNING: KtDiagnosticFactory1<String> by warning1<KtAnnotationEntry, String>()
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.ILLEGAL_JV
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.INAPPLICABLE_JVM_FIELD
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.INAPPLICABLE_JVM_FIELD_WARNING
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.INAPPLICABLE_JVM_NAME
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.INLINE_FROM_HIGHER_PLATFORM
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.INNER_JVM_RECORD
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.INTERFACE_CANT_CALL_DEFAULT_METHOD_VIA_SUPER
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.JAVA_MODULE_DOES_NOT_DEPEND_ON_MODULE
@@ -303,6 +304,12 @@ object FirJvmErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
"The ''{0}'' suspension point is inside a critical section.",
DECLARATION_NAME
)
map.put(
INLINE_FROM_HIGHER_PLATFORM,
"Cannot inline bytecode built with {0} into bytecode that is being built with {1}. Please specify proper ''-jvm-target'' option.",
STRING,
STRING
)
map.put(
CONCURRENT_HASH_MAP_CONTAINS_OPERATOR,
"Method 'contains' from ConcurrentHashMap might have unexpected semantics: it calls 'containsValue' instead of 'containsKey'. " +
@@ -21,6 +21,7 @@ object JvmExpressionCheckers : ExpressionCheckers() {
FirJavaSamInterfaceConstructorReferenceChecker,
FirQualifiedAccessJavaNullabilityWarningChecker,
FirJvmModuleAccessibilityQualifiedAccessChecker,
FirJvmInlineTargetQualifiedAccessChecker,
)
override val propertyAccessExpressionCheckers: Set<FirPropertyAccessExpressionChecker>
@@ -0,0 +1,85 @@
/*
* Copyright 2010-2024 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.jvm.checkers.expression
import org.jetbrains.kotlin.config.JvmTarget
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.diagnostics.reportOn
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.analysis.checkers.MppCheckerKind
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirQualifiedAccessExpressionChecker
import org.jetbrains.kotlin.fir.analysis.checkers.isLhsOfAssignment
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors
import org.jetbrains.kotlin.fir.containingClassLookupTag
import org.jetbrains.kotlin.fir.declarations.utils.isInline
import org.jetbrains.kotlin.fir.declarations.utils.sourceElement
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.expressions.toReference
import org.jetbrains.kotlin.fir.java.jvmTargetProvider
import org.jetbrains.kotlin.fir.references.toResolvedCallableSymbol
import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.load.kotlin.FileBasedKotlinClass
import org.jetbrains.kotlin.load.kotlin.JvmPackagePartSource
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement
object FirJvmInlineTargetQualifiedAccessChecker : FirQualifiedAccessExpressionChecker(MppCheckerKind.Common) {
override fun check(expression: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) {
val callableSymbol = expression.calleeReference.toResolvedCallableSymbol() ?: return
if (callableSymbol.origin.fromSource) return
val isInline = when (callableSymbol) {
is FirFunctionSymbol<*> -> callableSymbol.isInline
is FirPropertySymbol -> {
val accessor = if (expression.isLhsOfAssignment(context)) callableSymbol.setterSymbol else callableSymbol.getterSymbol
accessor != null && accessor.isInline
}
else -> false
}
if (isInline) {
checkInlineTargetVersion(callableSymbol, context, reporter, expression)
}
}
private fun checkInlineTargetVersion(
callableSymbol: FirCallableSymbol<*>,
context: CheckerContext,
reporter: DiagnosticReporter,
element: FirElement,
) {
val currentJvmTarget = context.session.jvmTargetProvider?.jvmTarget ?: return
val containingClass = callableSymbol.containingClassLookupTag()
val binaryClass = if (containingClass != null) {
val containingClassSymbol = containingClass.toFirRegularClassSymbol(context.session) ?: return
@OptIn(SymbolInternals::class)
val sourceElement = containingClassSymbol.fir.sourceElement as? KotlinJvmBinarySourceElement ?: return
sourceElement.binaryClass
} else {
val containerSource = callableSymbol.containerSource as? JvmPackagePartSource ?: return
containerSource.knownJvmBinaryClass
}
val inlinedVersion = (binaryClass as? FileBasedKotlinClass)?.classVersion ?: return
val currentVersion = currentJvmTarget.majorVersion
if (currentVersion < inlinedVersion) {
reporter.reportOn(
element.toReference(context.session)?.source ?: element.source,
FirJvmErrors.INLINE_FROM_HIGHER_PLATFORM,
JvmTarget.getDescription(inlinedVersion),
JvmTarget.getDescription(currentVersion),
context,
)
}
}
}
@@ -561,6 +561,7 @@ val FIR_NON_SUPPRESSIBLE_ERROR_NAMES: Set<String> = setOf(
"INLINE_PROPERTY_WITH_BACKING_FIELD",
"ILLEGAL_INLINE_PARAMETER_MODIFIER",
"INLINE_SUSPEND_FUNCTION_TYPE_UNSUPPORTED",
"INLINE_FROM_HIGHER_PLATFORM",
"CANNOT_ALL_UNDER_IMPORT_FROM_SINGLETON",
"PACKAGE_CANNOT_BE_IMPORTED",
"CANNOT_BE_IMPORTED",