Skip to content

Commit

Permalink
Introduce SuspiciousValueClassCheck to avoid isInline/isValue separat…
Browse files Browse the repository at this point in the history
…e calls

Related to KT-73785
  • Loading branch information
mglukhikh authored and qodana-bot committed Dec 12, 2024
1 parent faaae3e commit d26ccb8
Show file tree
Hide file tree
Showing 15 changed files with 34 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ internal class KaFirNamedClassSymbol private constructor(
if (backingPsi != null) {
backingPsi.hasModifier(KtTokens.VALUE_KEYWORD) || backingPsi.hasModifier(KtTokens.INLINE_KEYWORD)
} else {
firSymbol.isInline || firSymbol.isValue
firSymbol.isInlineOrValue
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors
import org.jetbrains.kotlin.fir.containingClassLookupTag
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.getAnnotationByClassId
import org.jetbrains.kotlin.fir.declarations.isInlineOrValueClass
import org.jetbrains.kotlin.fir.declarations.utils.*
import org.jetbrains.kotlin.fir.languageVersionSettings
import org.jetbrains.kotlin.fir.resolve.getContainingDeclaration
Expand Down Expand Up @@ -102,7 +101,7 @@ object FirJvmFieldApplicabilityChecker : FirPropertyChecker(MppCheckerKind.Commo

private fun FirTypeRef.isInlineClassThatRequiresMangling(session: FirSession): Boolean {
val symbol = this.coneType.toRegularClassSymbol(session) ?: return false
return symbol.isInlineOrValueClass() && !symbol.isDontMangleClass()
return symbol.isInlineOrValue && !symbol.isDontMangleClass()
}

private fun FirRegularClassSymbol.isDontMangleClass(): Boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@ import org.jetbrains.kotlin.fir.analysis.checkers.getModifier
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.getAnnotationByClassId
import org.jetbrains.kotlin.fir.declarations.utils.SuspiciousValueClassCheck
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
import org.jetbrains.kotlin.fir.declarations.utils.isValue
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.resolve.JVM_INLINE_ANNOTATION_CLASS_ID

object FirJvmInlineApplicabilityChecker : FirRegularClassChecker(MppCheckerKind.Common) {
@OptIn(SuspiciousValueClassCheck::class)
override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) {
val annotation = declaration.getAnnotationByClassId(JVM_INLINE_ANNOTATION_CLASS_ID, context.session)
if (annotation != null && !declaration.isValue) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ import org.jetbrains.kotlin.fir.declarations.FirFunction
import org.jetbrains.kotlin.fir.declarations.getAnnotationByClassId
import org.jetbrains.kotlin.fir.declarations.utils.isAbstract
import org.jetbrains.kotlin.fir.declarations.utils.isInline
import org.jetbrains.kotlin.fir.declarations.utils.isInlineOrValue
import org.jetbrains.kotlin.fir.declarations.utils.isSuspend
import org.jetbrains.kotlin.fir.declarations.utils.isValue
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.isSuspendOrKSuspendFunctionType
import org.jetbrains.kotlin.name.JvmStandardClassIds.SYNCHRONIZED_ANNOTATION_CLASS_ID
Expand All @@ -47,7 +47,7 @@ object FirSynchronizedAnnotationChecker : FirFunctionChecker(MppCheckerKind.Comm
reporter.reportOn(annotation.source, FirJvmErrors.SYNCHRONIZED_IN_INTERFACE, context)
containingClass.classKind == ClassKind.ANNOTATION_CLASS ->
reporter.reportOn(annotation.source, FirJvmErrors.SYNCHRONIZED_IN_ANNOTATION, context)
containingClass.isInline || containingClass.isValue ->
containingClass.isInlineOrValue ->
reporter.reportOn(annotation.source, FirJvmErrors.SYNCHRONIZED_ON_VALUE_CLASS, context)
declaration.isAbstract ->
reporter.reportOn(annotation.source, FirJvmErrors.SYNCHRONIZED_ON_ABSTRACT, context)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.fir.collectUpperBounds
import org.jetbrains.kotlin.fir.declarations.fullyExpandedClass
import org.jetbrains.kotlin.fir.declarations.isInlineOrValueClass
import org.jetbrains.kotlin.fir.declarations.utils.*
import org.jetbrains.kotlin.fir.isPrimitiveType
import org.jetbrains.kotlin.fir.languageVersionSettings
Expand Down Expand Up @@ -441,7 +440,7 @@ object ConeTypeCompatibilityChecker {
firClass.isPrimitiveType() ||
(ctx.prohibitComparisonOfIncompatibleClasses && firClass.classId == StandardClassIds.KClass) ||
firClass.classId == StandardClassIds.String || firClass.classId == StandardClassIds.Unit ||
(firClass is FirRegularClassSymbol && (firClass.isData || firClass.isInlineOrValueClass()))
(firClass is FirRegularClassSymbol && (firClass.isData || firClass.isInlineOrValue))
}

private val FirClassSymbol<*>.isFinal: Boolean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,8 @@ fun FirClassSymbol<*>.isSupertypeOf(other: FirClassSymbol<*>, session: FirSessio
}

fun ConeKotlinType.isValueClass(session: FirSession): Boolean {
// Value classes have inline modifier in FIR
return toRegularClassSymbol(session)?.isInlineOrValueClass() == true
// Value classes have `inline` or `value` modifier in FIR
return toRegularClassSymbol(session)?.isInlineOrValue == true
}

fun ConeKotlinType.isSingleFieldValueClass(session: FirSession): Boolean = with(session.typeContext) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ internal fun ConeKotlinType.toTypeInfo(session: FirSession): TypeInfo {
isEnumClass = boundsSymbols.any { it.isEnumClass },
isPrimitive = bounds.any { it.isPrimitiveOrNullablePrimitive },
isBuiltin = boundsSymbols.any { it.isBuiltin },
isValueClass = boundsSymbols.any { it.isInline || it.isValue },
isValueClass = boundsSymbols.any { it.isInlineOrValue },
isFinal = boundsSymbols.any { it.isFinalClass },
isClass = boundsSymbols.any { it.isClass },
// In K1's intersector, `canHaveSubtypes()` is called for `nullabilityStripped`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ object FirExpectActualDeclarationChecker : FirBasicDeclarationChecker(MppChecker
symbol: FirBasedSymbol<*>,
actualContainingClass: FirRegularClassSymbol,
platformSession: FirSession
): Boolean = (actualContainingClass.isInlineOrValueClass()) &&
): Boolean = (actualContainingClass.isInlineOrValue) &&
symbol is FirPropertySymbol &&
symbol.receiverParameter == null &&
actualContainingClass.primaryConstructorSymbol(platformSession)?.valueParameterSymbols?.singleOrNull()?.name == symbol.name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ package org.jetbrains.kotlin.fir.declarations
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.containingClassLookupTag
import org.jetbrains.kotlin.fir.declarations.utils.isInline
import org.jetbrains.kotlin.fir.declarations.utils.isInlineOrValue
import org.jetbrains.kotlin.fir.declarations.utils.isSuspend
import org.jetbrains.kotlin.fir.declarations.utils.isValue
import org.jetbrains.kotlin.fir.languageVersionSettings
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.defaultType
Expand Down Expand Up @@ -108,7 +107,7 @@ object OperatorFunctionChecks {
}
return buildString {
append("must override 'equals()' in Any")
if (customEqualsSupported && containingClassSymbol.isInlineOrValueClass()) {
if (customEqualsSupported && containingClassSymbol.isInlineOrValue) {
val expectedParameterTypeRendered =
containingClassSymbol.defaultType().replaceArgumentsWithStarProjections().renderReadable()
append(" or define 'equals(other: ${expectedParameterTypeRendered}): Boolean'")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ fun FirSimpleFunction.isTypedEqualsInValueClass(session: FirSession): Boolean =
with(this@isTypedEqualsInValueClass) {
contextParameters.isEmpty() && receiverParameter == null
&& name == OperatorNameConventions.EQUALS
&& this@run.isInlineOrValueClass() && valueParameters.size == 1
&& this@run.isInlineOrValue && valueParameters.size == 1
&& returnTypeRef.coneType.fullyExpandedType(session).let {
it.isBoolean || it.isNothing
} && valueParameters[0].returnTypeRef.coneType.let {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ package org.jetbrains.kotlin.fir.declarations

import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.utils.isInline
import org.jetbrains.kotlin.fir.declarations.utils.isValue
import org.jetbrains.kotlin.fir.declarations.utils.isInlineOrValue
import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.scopes.*
import org.jetbrains.kotlin.fir.scopes.impl.declaredMemberScope
Expand Down Expand Up @@ -76,7 +75,7 @@ fun FirConstructorSymbol.getConstructedClass(session: FirSession): FirRegularCla
fun FirRegularClassSymbol.isInlineOrValueClass(): Boolean {
if (this.classKind != ClassKind.CLASS) return false

return isInline || isValue
return isInlineOrValue
}

@PrivateForInline
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,16 @@ inline val FirMemberDeclaration.isOverride: Boolean get() = status.isOverride
inline val FirMemberDeclaration.isOperator: Boolean get() = status.isOperator
inline val FirMemberDeclaration.isInfix: Boolean get() = status.isInfix
inline val FirMemberDeclaration.isInline: Boolean get() = status.isInline

@RequiresOptIn(message = "Please consider using isInlineOrValue, as separate isInline or isValue calls don't cover other case")
annotation class SuspiciousValueClassCheck

@SuspiciousValueClassCheck
inline val FirClass.isValue: Boolean get() = status.isValue

@OptIn(SuspiciousValueClassCheck::class)
inline val FirClass.isInlineOrValue: Boolean get() = status.isInline || status.isValue

inline val FirMemberDeclaration.isTailRec: Boolean get() = status.isTailRec
inline val FirMemberDeclaration.isExternal: Boolean get() = status.isExternal
inline val FirMemberDeclaration.isSuspend: Boolean get() = status.isSuspend
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,16 @@ inline val FirClassLikeSymbol<*>.isActual: Boolean get() = rawStatus.isActual
inline val FirClassLikeSymbol<*>.isExpect: Boolean get() = rawStatus.isExpect
inline val FirClassLikeSymbol<*>.isInner: Boolean get() = rawStatus.isInner
inline val FirClassLikeSymbol<*>.isStatic: Boolean get() = rawStatus.isStatic

@SuspiciousValueClassCheck
inline val FirClassLikeSymbol<*>.isInline: Boolean get() = rawStatus.isInline

@SuspiciousValueClassCheck
inline val FirClassLikeSymbol<*>.isValue: Boolean get() = rawStatus.isValue

@OptIn(SuspiciousValueClassCheck::class)
inline val FirClassLikeSymbol<*>.isInlineOrValue: Boolean get() = isInline || isValue

inline val FirClassLikeSymbol<*>.isExternal: Boolean get() = rawStatus.isExternal
inline val FirClassLikeSymbol<*>.isFromSealedClass: Boolean get() = rawStatus.isFromSealedClass
inline val FirClassLikeSymbol<*>.isFromEnumClass: Boolean get() = rawStatus.isFromEnumClass
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class FirAllModifierRenderer : FirModifierRenderer() {
if (memberDeclaration.isInline) {
renderModifier("inline")
}
@OptIn(SuspiciousValueClassCheck::class)
if (memberDeclaration is FirClass && memberDeclaration.isValue) {
renderModifier("value")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ object FirSerializationPluginClassChecker : FirClassChecker(MppCheckerKind.Commo
return false
}

if ((classSymbol.isInline || classSymbol.isValue) && !session.versionReader.canSupportInlineClasses) {
if (classSymbol.isInlineOrValue && !session.versionReader.canSupportInlineClasses) {
reporter.reportOn(
classSymbol.serializableOrMetaAnnotationSource(session),
FirSerializationErrors.INLINE_CLASSES_NOT_SUPPORTED,
Expand Down

0 comments on commit d26ccb8

Please sign in to comment.