From d8b7b7b2dcf50674376f459f736c3815af7d54f4 Mon Sep 17 00:00:00 2001 From: Andrey Zinovyev Date: Tue, 20 Jul 2021 18:53:54 +0300 Subject: [PATCH] [FIR] Add DECLARATION_CANT_BE_INLINED diagnostic --- .../diagnostics/FirDiagnosticsList.kt | 2 + .../fir/analysis/diagnostics/FirErrors.kt | 1 + .../checkers/CommonDeclarationCheckers.kt | 1 + .../FirInlineDeclarationChecker.kt | 22 ++++++++- .../declaration/FirInlinePropertyChecker.kt | 30 ++++++++++++ .../diagnostics/FirDefaultErrorMessages.kt | 2 + .../inline/nonVirtualMembersWithInline.fir.kt | 47 ------------------- .../inline/nonVirtualMembersWithInline.kt | 1 + .../tests/inline/overrideWithInline.fir.kt | 6 +-- .../inline/property/virtualProperty.fir.kt | 38 --------------- .../tests/inline/property/virtualProperty.kt | 1 + .../diagnostics/KtFirDataClassConverters.kt | 6 +++ .../api/fir/diagnostics/KtFirDiagnostics.kt | 4 ++ .../fir/diagnostics/KtFirDiagnosticsImpl.kt | 7 +++ 14 files changed, 79 insertions(+), 89 deletions(-) create mode 100644 compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirInlinePropertyChecker.kt delete mode 100644 compiler/testData/diagnostics/tests/inline/nonVirtualMembersWithInline.fir.kt delete mode 100644 compiler/testData/diagnostics/tests/inline/property/virtualProperty.fir.kt diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt index 3dc588b8bd7..bf049c4310b 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt @@ -1173,6 +1173,8 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { val SUPER_CALL_FROM_PUBLIC_INLINE by warning(PositioningStrategy.REFERENCE_BY_QUALIFIED) { parameter("symbol") } + + val DECLARATION_CANT_BE_INLINED by error(PositioningStrategy.DECLARATION_SIGNATURE) } val IMPORTS by object : DiagnosticGroup("Imports") { diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index 1f6bfc1f17c..bebc71dc01b 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -608,6 +608,7 @@ object FirErrors { val PROTECTED_CALL_FROM_PUBLIC_INLINE by warning2, FirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED) val PRIVATE_CLASS_MEMBER_FROM_INLINE by error2, FirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED) val SUPER_CALL_FROM_PUBLIC_INLINE by warning1>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED) + val DECLARATION_CANT_BE_INLINED by error0(SourceElementPositioningStrategies.DECLARATION_SIGNATURE) // Imports val CANNOT_ALL_UNDER_IMPORT_FROM_SINGLETON by error1(SourceElementPositioningStrategies.IMPORT_LAST_NAME) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt index 74690ebe134..d22a36625ac 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt @@ -56,6 +56,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() { FirPropertyTypeParametersChecker, FirInitializerTypeMismatchChecker, FirDelegatedPropertyChecker, + FirInlinePropertyChecker, ) override val classCheckers: Set diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirInlineDeclarationChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirInlineDeclarationChecker.kt index 91900b1b200..0bdd26ebfb8 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirInlineDeclarationChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirInlineDeclarationChecker.kt @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.PersistentCheckerContext +import org.jetbrains.kotlin.fir.analysis.checkers.context.findClosest import org.jetbrains.kotlin.fir.analysis.checkers.isInlineOnly import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope import org.jetbrains.kotlin.fir.analysis.checkers.util.checkChildrenWithCustomVisitor @@ -50,6 +51,7 @@ object FirInlineDeclarationChecker : FirFunctionChecker() { checkInlineFunctionBody(declaration, effectiveVisibility, context, reporter) checkParameters(declaration, context, reporter) checkNothingToInline(declaration, context, reporter) + checkCanBeInlined(declaration, effectiveVisibility, context, reporter) } private fun checkInlineFunctionBody( @@ -402,7 +404,25 @@ object FirInlineDeclarationChecker : FirFunctionChecker() { } if (hasInlinableParameters) return if (function.isInlineOnly()) return - + reporter.reportOn(function.source, FirErrors.NOTHING_TO_INLINE, context) } + + private fun checkCanBeInlined( + declaration: FirFunction, + effectiveVisibility: EffectiveVisibility, + context: CheckerContext, + reporter: DiagnosticReporter + ) { + if (declaration !is FirSimpleFunction) return + if (declaration.containingClass() == null) return + if (effectiveVisibility == EffectiveVisibility.PrivateInClass) return + val isFinal = when (declaration) { + is FirPropertyAccessor -> context.findClosest()?.isFinal ?: declaration.isFinal + else -> declaration.isFinal + } + if (!isFinal) { + reporter.reportOn(declaration.source, FirErrors.DECLARATION_CANT_BE_INLINED, context) + } + } } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirInlinePropertyChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirInlinePropertyChecker.kt new file mode 100644 index 00000000000..1d96f66a2eb --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirInlinePropertyChecker.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2010-2021 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.declaration + +import org.jetbrains.kotlin.descriptors.EffectiveVisibility +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors +import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn +import org.jetbrains.kotlin.fir.containingClass +import org.jetbrains.kotlin.fir.declarations.FirProperty +import org.jetbrains.kotlin.fir.declarations.utils.effectiveVisibility +import org.jetbrains.kotlin.fir.declarations.utils.isFinal +import org.jetbrains.kotlin.fir.declarations.utils.isInline + +object FirInlinePropertyChecker : FirPropertyChecker() { + + override fun check(declaration: FirProperty, context: CheckerContext, reporter: DiagnosticReporter) { + if (declaration.containingClass() == null) return + if (declaration.effectiveVisibility == EffectiveVisibility.PrivateInClass) return + + if (!declaration.isFinal && (declaration.getter?.isInline == true || declaration.setter?.isInline == true)) { + reporter.reportOn(declaration.source, FirErrors.DECLARATION_CANT_BE_INLINED, context) + } + + } +} \ No newline at end of file diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt index cd9a84125b3..b53ce5b50bd 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt @@ -112,6 +112,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DATA_CLASS_NOT_PR import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DATA_CLASS_OVERRIDE_CONFLICT import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DATA_CLASS_VARARG_PARAMETER import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DATA_CLASS_WITHOUT_PARAMETERS +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DECLARATION_CANT_BE_INLINED import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DELEGATED_PROPERTY_INSIDE_INLINE_CLASS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DELEGATED_PROPERTY_IN_INTERFACE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DELEGATE_SPECIAL_FUNCTION_AMBIGUITY @@ -928,6 +929,7 @@ class FirDefaultErrorMessages { map.put(INLINE_CLASS_CANNOT_IMPLEMENT_INTERFACE_BY_DELEGATION, "Inline class cannot implement an interface by delegation") map.put(INLINE_CLASS_CANNOT_EXTEND_CLASSES, "Inline class cannot extend classes") map.put(INLINE_CLASS_CANNOT_BE_RECURSIVE, "Inline class cannot be recursive") + map.put(DECLARATION_CANT_BE_INLINED, "'inline' modifier is not allowed on virtual members. Only private or final members can be inlined") map.put(RESERVED_MEMBER_INSIDE_INLINE_CLASS, "Member with the name ''{0}'' is reserved for future releases", TO_STRING) map.put( SECONDARY_CONSTRUCTOR_WITH_BODY_INSIDE_INLINE_CLASS, diff --git a/compiler/testData/diagnostics/tests/inline/nonVirtualMembersWithInline.fir.kt b/compiler/testData/diagnostics/tests/inline/nonVirtualMembersWithInline.fir.kt deleted file mode 100644 index fb437750c26..00000000000 --- a/compiler/testData/diagnostics/tests/inline/nonVirtualMembersWithInline.fir.kt +++ /dev/null @@ -1,47 +0,0 @@ -// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE -NOTHING_TO_INLINE - -inline private fun a() {} - -inline fun b() {} - -inline public fun c() {} - -abstract class A { - inline private fun good1() {} - inline public final fun good2() {} - inline protected final fun good3() {} - inline final fun good4() {} - - - inline open protected fun wrong1() {} - - inline open public fun wrong2() {} - - inline open fun wrong3() {} - - inline abstract protected fun wrong4() - - inline abstract public fun wrong5() - - inline abstract fun wrong6() -} - - -interface B { - - inline private fun good1() {} - - inline fun wrong1() {} - - inline open fun wrong2() {} - - inline open public fun wrong3() {} - - inline open fun wrong4() {} - - inline fun wrong5() - - inline public fun wrong6() - - inline fun wrong7() -} diff --git a/compiler/testData/diagnostics/tests/inline/nonVirtualMembersWithInline.kt b/compiler/testData/diagnostics/tests/inline/nonVirtualMembersWithInline.kt index bcc84bf8ac2..7f469a01d7f 100644 --- a/compiler/testData/diagnostics/tests/inline/nonVirtualMembersWithInline.kt +++ b/compiler/testData/diagnostics/tests/inline/nonVirtualMembersWithInline.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE -NOTHING_TO_INLINE inline private fun a() {} diff --git a/compiler/testData/diagnostics/tests/inline/overrideWithInline.fir.kt b/compiler/testData/diagnostics/tests/inline/overrideWithInline.fir.kt index ee3753a83a2..3f1bcf0aabf 100644 --- a/compiler/testData/diagnostics/tests/inline/overrideWithInline.fir.kt +++ b/compiler/testData/diagnostics/tests/inline/overrideWithInline.fir.kt @@ -34,12 +34,12 @@ class CDerived : IBase { open class COpen : IBase { override inline final fun foo() {} - override inline fun bar() {} + override inline fun bar() {} override inline final fun qux(x: T) {} open class COpenNested : IBase { override inline final fun foo() {} - override inline fun bar() {} + override inline fun bar() {} override inline final fun qux(x: T) {} } @@ -52,7 +52,7 @@ open class COpen : IBase { fun aMethod() { open class COpenLocal : IBase { override inline final fun foo() {} - override inline fun bar() {} + override inline fun bar() {} override inline final fun qux(x: T) {} } } diff --git a/compiler/testData/diagnostics/tests/inline/property/virtualProperty.fir.kt b/compiler/testData/diagnostics/tests/inline/property/virtualProperty.fir.kt deleted file mode 100644 index e95efd83238..00000000000 --- a/compiler/testData/diagnostics/tests/inline/property/virtualProperty.fir.kt +++ /dev/null @@ -1,38 +0,0 @@ -final class FinalProperty { - inline val valProp: Int - get() = 1 - - val valProp_1: Int - inline get() = 1 - - inline var varProp: Int - get() = 1 - set(p: Int) {} - - var varProp_2: Int - get() = 1 - inline set(p: Int) {} -} - - -open class OpenProperty { - inline open val valProp: Int - get() = 1 - - open val valProp_1: Int - inline get() = 1 - - inline open var varProp: Int - get() = 1 - set(p: Int) {} - - open var varProp_2: Int - get() = 1 - inline set(p: Int) {} -} - - -interface AbstractProperty { - inline abstract val valProp: Int - inline abstract var varProp: Int -} diff --git a/compiler/testData/diagnostics/tests/inline/property/virtualProperty.kt b/compiler/testData/diagnostics/tests/inline/property/virtualProperty.kt index 4789da733c2..761e8bbbbe6 100644 --- a/compiler/testData/diagnostics/tests/inline/property/virtualProperty.kt +++ b/compiler/testData/diagnostics/tests/inline/property/virtualProperty.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL final class FinalProperty { inline val valProp: Int get() = 1 diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt index 8f42514086d..3ae75df17c1 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -3167,6 +3167,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.DECLARATION_CANT_BE_INLINED) { firDiagnostic -> + DeclarationCantBeInlinedImpl( + firDiagnostic as FirPsiDiagnostic, + token, + ) + } add(FirErrors.CANNOT_ALL_UNDER_IMPORT_FROM_SINGLETON) { firDiagnostic -> CannotAllUnderImportFromSingletonImpl( firDiagnostic.a, diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt index c4b25e93d88..53f0ae6f22c 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt @@ -2210,6 +2210,10 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { abstract val symbol: KtSymbol } + abstract class DeclarationCantBeInlined : KtFirDiagnostic() { + override val diagnosticClass get() = DeclarationCantBeInlined::class + } + abstract class CannotAllUnderImportFromSingleton : KtFirDiagnostic() { override val diagnosticClass get() = CannotAllUnderImportFromSingleton::class abstract val objectName: Name diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index c6388277e7b..190d8335c23 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -3567,6 +3567,13 @@ internal class SuperCallFromPublicInlineImpl( override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) } +internal class DeclarationCantBeInlinedImpl( + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.DeclarationCantBeInlined(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + internal class CannotAllUnderImportFromSingletonImpl( override val objectName: Name, firDiagnostic: FirPsiDiagnostic,