[FIR] Fix modifying CheckerContext inside checkers

`InlineFunctionBodyContext` was not moved
outside the class to preserve as much
git blame info as possible.

^KT-56460 Fixed
This commit is contained in:
Nikolay Lunyak
2023-06-28 18:12:48 +03:00
committed by Space Team
parent ed2f0c295b
commit 8c5b2ae85b
16 changed files with 268 additions and 148 deletions
@@ -5,19 +5,15 @@
package org.jetbrains.kotlin.fir.analysis.jvm.checkers package org.jetbrains.kotlin.fir.analysis.jvm.checkers
import org.jetbrains.kotlin.descriptors.EffectiveVisibility
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.diagnostics.reportOn import org.jetbrains.kotlin.diagnostics.reportOn
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.analysis.checkers.FirInlineCheckerPlatformSpecificComponent import org.jetbrains.kotlin.fir.analysis.checkers.FirInlineCheckerPlatformSpecificComponent
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirInlineDeclarationChecker
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.isLocalMember import org.jetbrains.kotlin.fir.analysis.checkers.declaration.isLocalMember
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirValueParameterSymbol
class FirJvmInlineCheckerComponent : FirInlineCheckerPlatformSpecificComponent() { class FirJvmInlineCheckerComponent : FirInlineCheckerPlatformSpecificComponent() {
override fun isGenerallyOk(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter): Boolean { override fun isGenerallyOk(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter): Boolean {
@@ -30,8 +26,6 @@ class FirJvmInlineCheckerComponent : FirInlineCheckerPlatformSpecificComponent()
} }
} }
override val inlineVisitor get() = ::JvmInlineVisitor
override fun checkSuspendFunctionalParameterWithDefaultValue( override fun checkSuspendFunctionalParameterWithDefaultValue(
param: FirValueParameter, param: FirValueParameter,
context: CheckerContext, context: CheckerContext,
@@ -69,33 +63,3 @@ class FirJvmInlineCheckerComponent : FirInlineCheckerPlatformSpecificComponent()
} }
} }
} }
class JvmInlineVisitor(
inlineFunction: FirFunction,
inlineFunEffectiveVisibility: EffectiveVisibility,
inalienableParameters: List<FirValueParameterSymbol>,
session: FirSession,
reporter: DiagnosticReporter
) : FirInlineDeclarationChecker.BasicInlineVisitor(
inlineFunction,
inlineFunEffectiveVisibility,
inalienableParameters,
session,
reporter
) {
override fun visitRegularClass(regularClass: FirRegularClass, data: CheckerContext) {
if (!regularClass.classKind.isSingleton && data.containingDeclarations.lastOrNull() === inlineFunction) {
reporter.reportOn(regularClass.source, FirErrors.NOT_YET_SUPPORTED_IN_INLINE, "Local classes", data)
} else {
super.visitRegularClass(regularClass, data)
}
}
override fun visitSimpleFunction(simpleFunction: FirSimpleFunction, data: CheckerContext) {
if (data.containingDeclarations.lastOrNull() === inlineFunction) {
reporter.reportOn(simpleFunction.source, FirErrors.NOT_YET_SUPPORTED_IN_INLINE, "Local functions", data)
} else {
super.visitSimpleFunction(simpleFunction, data)
}
}
}
@@ -31,6 +31,7 @@ object JvmDeclarationCheckers : DeclarationCheckers() {
FirJvmRecordChecker, FirJvmRecordChecker,
FirJvmInlineApplicabilityChecker, FirJvmInlineApplicabilityChecker,
FirJvmConflictsChecker, FirJvmConflictsChecker,
FirInlineBodyRegularClassChecker,
) )
override val propertyCheckers: Set<FirPropertyChecker> override val propertyCheckers: Set<FirPropertyChecker>
@@ -49,4 +50,9 @@ object JvmDeclarationCheckers : DeclarationCheckers() {
get() = setOf( get() = setOf(
FirUpperBoundsChecker, FirUpperBoundsChecker,
) )
override val simpleFunctionCheckers: Set<FirSimpleFunctionChecker>
get() = setOf(
FirInlineBodySimpleFunctionChecker,
)
} }
@@ -0,0 +1,23 @@
/*
* 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.jvm.checkers.declaration
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.declaration.FirRegularClassChecker
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
object FirInlineBodyRegularClassChecker : FirRegularClassChecker() {
override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) {
val inlineFunctionBodyContext = context.inlineFunctionBodyContext ?: return
if (!declaration.classKind.isSingleton && context.containingDeclarations.lastOrNull() === inlineFunctionBodyContext.inlineFunction) {
reporter.reportOn(declaration.source, FirErrors.NOT_YET_SUPPORTED_IN_INLINE, "Local classes", context)
}
}
}
@@ -0,0 +1,23 @@
/*
* 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.jvm.checkers.declaration
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.declaration.FirSimpleFunctionChecker
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
object FirInlineBodySimpleFunctionChecker : FirSimpleFunctionChecker() {
override fun check(declaration: FirSimpleFunction, context: CheckerContext, reporter: DiagnosticReporter) {
val inlineFunctionBodyContext = context.inlineFunctionBodyContext ?: return
if (context.containingDeclarations.lastOrNull() === inlineFunctionBodyContext.inlineFunction) {
reporter.reportOn(declaration.source, FirErrors.NOT_YET_SUPPORTED_IN_INLINE, "Local functions", context)
}
}
}
@@ -5,6 +5,9 @@
package org.jetbrains.kotlin.fir.analysis.checkers package org.jetbrains.kotlin.fir.analysis.checkers
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirInlineBodyQualifiedAccessExpressionChecker
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirInlineBodyResolvedQualifierChecker
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirInlineBodyVariableAssignmentChecker
import org.jetbrains.kotlin.fir.analysis.checkers.expression.* import org.jetbrains.kotlin.fir.analysis.checkers.expression.*
import org.jetbrains.kotlin.fir.analysis.checkers.syntax.FirCommaInWhenConditionChecker import org.jetbrains.kotlin.fir.analysis.checkers.syntax.FirCommaInWhenConditionChecker
import org.jetbrains.kotlin.fir.analysis.checkers.syntax.FirConfusingWhenBranchSyntaxChecker import org.jetbrains.kotlin.fir.analysis.checkers.syntax.FirConfusingWhenBranchSyntaxChecker
@@ -49,6 +52,7 @@ object CommonExpressionCheckers : ExpressionCheckers() {
FirSuspendCallChecker, FirSuspendCallChecker,
FirLateinitIntrinsicApplicabilityChecker, FirLateinitIntrinsicApplicabilityChecker,
FirAbstractClassInstantiationChecker, FirAbstractClassInstantiationChecker,
FirInlineBodyQualifiedAccessExpressionChecker,
) )
override val callCheckers: Set<FirCallChecker> override val callCheckers: Set<FirCallChecker>
@@ -82,6 +86,7 @@ object CommonExpressionCheckers : ExpressionCheckers() {
get() = setOf( get() = setOf(
FirReassignmentAndInvisibleSetterChecker, FirReassignmentAndInvisibleSetterChecker,
FirAssignmentTypeMismatchChecker, FirAssignmentTypeMismatchChecker,
FirInlineBodyVariableAssignmentChecker,
) )
override val whenExpressionCheckers: Set<FirWhenExpressionChecker> override val whenExpressionCheckers: Set<FirWhenExpressionChecker>
@@ -152,6 +157,7 @@ object CommonExpressionCheckers : ExpressionCheckers() {
FirOptInUsageQualifierChecker, FirOptInUsageQualifierChecker,
FirDeprecatedQualifierChecker, FirDeprecatedQualifierChecker,
FirVisibilityQualifierChecker, FirVisibilityQualifierChecker,
FirInlineBodyResolvedQualifierChecker,
) )
override val equalityOperatorCallCheckers: Set<FirEqualityOperatorCallChecker> override val equalityOperatorCallCheckers: Set<FirEqualityOperatorCallChecker>
@@ -9,7 +9,6 @@ import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.FirSessionComponent import org.jetbrains.kotlin.fir.FirSessionComponent
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirInlineDeclarationChecker
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
@@ -19,8 +18,6 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
abstract class FirInlineCheckerPlatformSpecificComponent : FirSessionComponent { abstract class FirInlineCheckerPlatformSpecificComponent : FirSessionComponent {
open fun isGenerallyOk(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter): Boolean = true open fun isGenerallyOk(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter): Boolean = true
open val inlineVisitor get() = FirInlineDeclarationChecker::BasicInlineVisitor
open fun checkSuspendFunctionalParameterWithDefaultValue( open fun checkSuspendFunctionalParameterWithDefaultValue(
param: FirValueParameter, param: FirValueParameter,
context: CheckerContext, context: CheckerContext,
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.diagnostics.Severity
import org.jetbrains.kotlin.fir.FirAnnotationContainer import org.jetbrains.kotlin.fir.FirAnnotationContainer
import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirInlineDeclarationChecker
import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.expressions.FirGetClassCall import org.jetbrains.kotlin.fir.expressions.FirGetClassCall
@@ -40,6 +41,7 @@ abstract class CheckerContext : DiagnosticContext {
abstract val annotationContainers: List<FirAnnotationContainer> abstract val annotationContainers: List<FirAnnotationContainer>
abstract val containingElements: List<FirElement> abstract val containingElements: List<FirElement>
abstract val isContractBody: Boolean abstract val isContractBody: Boolean
abstract val inlineFunctionBodyContext: FirInlineDeclarationChecker.InlineFunctionBodyContext?
// Suppress // Suppress
abstract val suppressedDiagnostics: Set<String> abstract val suppressedDiagnostics: Set<String>
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.analysis.checkers.context
import org.jetbrains.kotlin.fir.FirAnnotationContainer import org.jetbrains.kotlin.fir.FirAnnotationContainer
import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirInlineDeclarationChecker
import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.expressions.FirGetClassCall import org.jetbrains.kotlin.fir.expressions.FirGetClassCall
@@ -66,6 +67,10 @@ abstract class CheckerContextForProvider(
abstract fun exitContractBody(): CheckerContextForProvider abstract fun exitContractBody(): CheckerContextForProvider
abstract fun setInlineFunctionBodyContext(context: FirInlineDeclarationChecker.InlineFunctionBodyContext): CheckerContextForProvider
abstract fun unsetInlineFunctionBodyContext(): CheckerContextForProvider
abstract fun enterFile(file: FirFile): CheckerContextForProvider abstract fun enterFile(file: FirFile): CheckerContextForProvider
abstract fun exitFile(file: FirFile): CheckerContextForProvider abstract fun exitFile(file: FirFile): CheckerContextForProvider
@@ -9,8 +9,11 @@ import kotlinx.collections.immutable.PersistentSet
import kotlinx.collections.immutable.persistentSetOf import kotlinx.collections.immutable.persistentSetOf
import org.jetbrains.kotlin.fir.FirAnnotationContainer import org.jetbrains.kotlin.fir.FirAnnotationContainer
import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirInlineDeclarationChecker
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.createInlineFunctionBodyContext
import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirFunction
import org.jetbrains.kotlin.fir.expressions.FirGetClassCall import org.jetbrains.kotlin.fir.expressions.FirGetClassCall
import org.jetbrains.kotlin.fir.expressions.FirStatement import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.resolve.PersistentImplicitReceiverStack import org.jetbrains.kotlin.fir.resolve.PersistentImplicitReceiverStack
@@ -27,6 +30,7 @@ class MutableCheckerContext private constructor(
override val annotationContainers: MutableList<FirAnnotationContainer>, override val annotationContainers: MutableList<FirAnnotationContainer>,
override val containingElements: MutableList<FirElement>, override val containingElements: MutableList<FirElement>,
override var isContractBody: Boolean, override var isContractBody: Boolean,
override var inlineFunctionBodyContext: FirInlineDeclarationChecker.InlineFunctionBodyContext?,
override var containingFile: FirFile?, override var containingFile: FirFile?,
sessionHolder: SessionHolder, sessionHolder: SessionHolder,
returnTypeCalculator: ReturnTypeCalculator, returnTypeCalculator: ReturnTypeCalculator,
@@ -43,6 +47,7 @@ class MutableCheckerContext private constructor(
mutableListOf(), mutableListOf(),
mutableListOf(), mutableListOf(),
isContractBody = false, isContractBody = false,
inlineFunctionBodyContext = null,
containingFile = null, containingFile = null,
sessionHolder, sessionHolder,
returnTypeCalculator, returnTypeCalculator,
@@ -61,6 +66,7 @@ class MutableCheckerContext private constructor(
annotationContainers, annotationContainers,
containingElements, containingElements,
isContractBody, isContractBody,
inlineFunctionBodyContext,
containingFile, containingFile,
sessionHolder, sessionHolder,
returnTypeCalculator, returnTypeCalculator,
@@ -132,6 +138,7 @@ class MutableCheckerContext private constructor(
annotationContainers, annotationContainers,
containingElements, containingElements,
isContractBody, isContractBody,
inlineFunctionBodyContext,
containingFile, containingFile,
sessionHolder, sessionHolder,
returnTypeCalculator, returnTypeCalculator,
@@ -154,6 +161,16 @@ class MutableCheckerContext private constructor(
return this return this
} }
override fun setInlineFunctionBodyContext(context: FirInlineDeclarationChecker.InlineFunctionBodyContext): CheckerContextForProvider {
inlineFunctionBodyContext = context
return this
}
override fun unsetInlineFunctionBodyContext(): CheckerContextForProvider {
inlineFunctionBodyContext = null
return this
}
override fun enterFile(file: FirFile): CheckerContextForProvider { override fun enterFile(file: FirFile): CheckerContextForProvider {
containingFile = file containingFile = file
return this return this
@@ -11,8 +11,11 @@ import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.persistentSetOf import kotlinx.collections.immutable.persistentSetOf
import org.jetbrains.kotlin.fir.FirAnnotationContainer import org.jetbrains.kotlin.fir.FirAnnotationContainer
import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirInlineDeclarationChecker
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.createInlineFunctionBodyContext
import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirFunction
import org.jetbrains.kotlin.fir.expressions.FirGetClassCall import org.jetbrains.kotlin.fir.expressions.FirGetClassCall
import org.jetbrains.kotlin.fir.expressions.FirStatement import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.resolve.PersistentImplicitReceiverStack import org.jetbrains.kotlin.fir.resolve.PersistentImplicitReceiverStack
@@ -29,6 +32,7 @@ class PersistentCheckerContext private constructor(
override val annotationContainers: PersistentList<FirAnnotationContainer>, override val annotationContainers: PersistentList<FirAnnotationContainer>,
override val containingElements: PersistentList<FirElement>, override val containingElements: PersistentList<FirElement>,
override val isContractBody: Boolean, override val isContractBody: Boolean,
override val inlineFunctionBodyContext: FirInlineDeclarationChecker.InlineFunctionBodyContext?,
sessionHolder: SessionHolder, sessionHolder: SessionHolder,
returnTypeCalculator: ReturnTypeCalculator, returnTypeCalculator: ReturnTypeCalculator,
override val suppressedDiagnostics: PersistentSet<String>, override val suppressedDiagnostics: PersistentSet<String>,
@@ -45,6 +49,7 @@ class PersistentCheckerContext private constructor(
persistentListOf(), persistentListOf(),
persistentListOf(), persistentListOf(),
isContractBody = false, isContractBody = false,
inlineFunctionBodyContext = null,
sessionHolder, sessionHolder,
returnTypeCalculator, returnTypeCalculator,
persistentSetOf(), persistentSetOf(),
@@ -108,6 +113,7 @@ class PersistentCheckerContext private constructor(
containingElements: PersistentList<FirElement> = this.containingElements, containingElements: PersistentList<FirElement> = this.containingElements,
containingDeclarations: PersistentList<FirDeclaration> = this.containingDeclarations, containingDeclarations: PersistentList<FirDeclaration> = this.containingDeclarations,
isContractBody: Boolean = this.isContractBody, isContractBody: Boolean = this.isContractBody,
inlineFunctionBodyContext: FirInlineDeclarationChecker.InlineFunctionBodyContext? = this.inlineFunctionBodyContext,
allInfosSuppressed: Boolean = this.allInfosSuppressed, allInfosSuppressed: Boolean = this.allInfosSuppressed,
allWarningsSuppressed: Boolean = this.allWarningsSuppressed, allWarningsSuppressed: Boolean = this.allWarningsSuppressed,
allErrorsSuppressed: Boolean = this.allErrorsSuppressed, allErrorsSuppressed: Boolean = this.allErrorsSuppressed,
@@ -122,6 +128,7 @@ class PersistentCheckerContext private constructor(
annotationContainers, annotationContainers,
containingElements, containingElements,
isContractBody, isContractBody,
inlineFunctionBodyContext,
sessionHolder, sessionHolder,
returnTypeCalculator, returnTypeCalculator,
suppressedDiagnostics, suppressedDiagnostics,
@@ -139,6 +146,11 @@ class PersistentCheckerContext private constructor(
override fun exitContractBody(): CheckerContextForProvider = toggleContractBody(newValue = false) override fun exitContractBody(): CheckerContextForProvider = toggleContractBody(newValue = false)
override fun setInlineFunctionBodyContext(context: FirInlineDeclarationChecker.InlineFunctionBodyContext) =
copy(inlineFunctionBodyContext = context)
override fun unsetInlineFunctionBodyContext(): CheckerContextForProvider = copy(inlineFunctionBodyContext = null)
override fun enterFile(file: FirFile): CheckerContextForProvider = copy(containingFile = file) override fun enterFile(file: FirFile): CheckerContextForProvider = copy(containingFile = file)
override fun exitFile(file: FirFile): CheckerContextForProvider = copy(containingFile = null) override fun exitFile(file: FirFile): CheckerContextForProvider = copy(containingFile = null)
@@ -0,0 +1,27 @@
/*
* 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.declaration
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirQualifiedAccessExpressionChecker
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.expressions.toResolvedCallableSymbol
object FirInlineBodyQualifiedAccessExpressionChecker : FirQualifiedAccessExpressionChecker() {
override fun check(expression: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) {
val inlineFunctionBodyContext = context.inlineFunctionBodyContext ?: return
val targetSymbol = expression.toResolvedCallableSymbol()
inlineFunctionBodyContext.checkQualifiedAccess(expression, targetSymbol, context, reporter)
inlineFunctionBodyContext.checkReceiversOfQualifiedAccessExpression(expression, targetSymbol, context, reporter)
if (expression is FirFunctionCall) {
inlineFunctionBodyContext.checkArgumentsOfCall(expression, targetSymbol, context, reporter)
}
}
}
@@ -0,0 +1,24 @@
/*
* 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.declaration
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirResolvedQualifierChecker
import org.jetbrains.kotlin.fir.declarations.utils.isCompanion
import org.jetbrains.kotlin.fir.declarations.utils.visibility
import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
object FirInlineBodyResolvedQualifierChecker : FirResolvedQualifierChecker() {
override fun check(expression: FirResolvedQualifier, context: CheckerContext, reporter: DiagnosticReporter) {
val inlineFunctionBodyContext = context.inlineFunctionBodyContext ?: return
val accessedClass = expression.symbol ?: return
val source = expression.source ?: return
if (accessedClass.isCompanion) {
inlineFunctionBodyContext.checkAccessedDeclaration(source, accessedClass, accessedClass.visibility, context, reporter)
}
}
}
@@ -0,0 +1,23 @@
/*
* 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.declaration
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirVariableAssignmentChecker
import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment
import org.jetbrains.kotlin.fir.expressions.calleeReference
import org.jetbrains.kotlin.fir.references.toResolvedCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
object FirInlineBodyVariableAssignmentChecker : FirVariableAssignmentChecker() {
override fun check(expression: FirVariableAssignment, context: CheckerContext, reporter: DiagnosticReporter) {
val inlineFunctionBodyContext = context.inlineFunctionBodyContext ?: return
val propertySymbol = expression.calleeReference?.toResolvedCallableSymbol() as? FirPropertySymbol ?: return
val setterSymbol = propertySymbol.setterSymbol ?: return
inlineFunctionBodyContext.checkQualifiedAccess(expression, setterSymbol, context, reporter)
}
}
@@ -16,17 +16,17 @@ import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.diagnostics.reportOn import org.jetbrains.kotlin.diagnostics.reportOn
import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContextForProvider
import org.jetbrains.kotlin.fir.analysis.checkers.inlineCheckerExtension import org.jetbrains.kotlin.fir.analysis.checkers.inlineCheckerExtension
import org.jetbrains.kotlin.fir.analysis.checkers.isInlineOnly import org.jetbrains.kotlin.fir.analysis.checkers.isInlineOnly
import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope
import org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFunction
import org.jetbrains.kotlin.fir.declarations.FirPropertyAccessor
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.declarations.utils.* import org.jetbrains.kotlin.fir.declarations.utils.*
import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.references.FirSuperReference import org.jetbrains.kotlin.fir.references.FirSuperReference
import org.jetbrains.kotlin.fir.references.toResolvedCallableSymbol
import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.resolve.transformers.publishedApiEffectiveVisibility import org.jetbrains.kotlin.fir.resolve.transformers.publishedApiEffectiveVisibility
import org.jetbrains.kotlin.fir.scopes.getDirectOverriddenMembers import org.jetbrains.kotlin.fir.scopes.getDirectOverriddenMembers
@@ -34,7 +34,6 @@ import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor
import org.jetbrains.kotlin.fir.visitors.FirVisitor
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.utils.addToStdlib.shouldNotBeCalled import org.jetbrains.kotlin.utils.addToStdlib.shouldNotBeCalled
@@ -47,41 +46,14 @@ object FirInlineDeclarationChecker : FirFunctionChecker() {
if (context.session.inlineCheckerExtension?.isGenerallyOk(declaration, context, reporter) == false) return if (context.session.inlineCheckerExtension?.isGenerallyOk(declaration, context, reporter) == false) return
if (declaration !is FirPropertyAccessor && declaration !is FirSimpleFunction) return if (declaration !is FirPropertyAccessor && declaration !is FirSimpleFunction) return
val effectiveVisibility = declaration.publishedApiEffectiveVisibility ?: declaration.effectiveVisibility
checkInlineFunctionBody(declaration, effectiveVisibility, context, reporter)
checkCallableDeclaration(declaration, context, reporter) checkCallableDeclaration(declaration, context, reporter)
} }
private fun checkInlineFunctionBody( class InlineFunctionBodyContext(
function: FirFunction,
effectiveVisibility: EffectiveVisibility,
context: CheckerContext,
reporter: DiagnosticReporter
) {
val body = function.body ?: return
val inalienableParameters = function.valueParameters.filter {
if (it.isNoinline) return@filter false
val type = it.returnTypeRef.coneType
!type.isMarkedNullable && type.isNonReflectFunctionType(context.session)
}.map { it.symbol }
val createVisitor = context.session.inlineCheckerExtension?.inlineVisitor ?: ::BasicInlineVisitor
val visitor = createVisitor(
function,
effectiveVisibility,
inalienableParameters,
context.session,
reporter
)
body.checkChildrenWithCustomVisitor(context, visitor, function)
}
open class BasicInlineVisitor(
val inlineFunction: FirFunction, val inlineFunction: FirFunction,
private val inlineFunEffectiveVisibility: EffectiveVisibility, private val inlineFunEffectiveVisibility: EffectiveVisibility,
private val inalienableParameters: List<FirValueParameterSymbol>, private val inalienableParameters: List<FirValueParameterSymbol>,
val session: FirSession, val session: FirSession,
val reporter: DiagnosticReporter
) : FirDefaultVisitor<Unit, CheckerContext>() { ) : FirDefaultVisitor<Unit, CheckerContext>() {
private val isEffectivelyPrivateApiFunction: Boolean = inlineFunEffectiveVisibility.privateApi private val isEffectivelyPrivateApiFunction: Boolean = inlineFunEffectiveVisibility.privateApi
@@ -90,43 +62,15 @@ object FirInlineDeclarationChecker : FirFunctionChecker() {
override fun visitElement(element: FirElement, data: CheckerContext) {} override fun visitElement(element: FirElement, data: CheckerContext) {}
override fun visitFunctionCall(functionCall: FirFunctionCall, data: CheckerContext) {
val targetSymbol = functionCall.toResolvedCallableSymbol()
if (targetSymbol != null) {
checkReceiversOfQualifiedAccessExpression(functionCall, targetSymbol, data)
checkArgumentsOfCall(functionCall, targetSymbol, data)
checkQualifiedAccess(functionCall, targetSymbol, data)
}
}
override fun visitQualifiedAccessExpression(qualifiedAccessExpression: FirQualifiedAccessExpression, data: CheckerContext) {
val targetSymbol = qualifiedAccessExpression.toResolvedCallableSymbol()
checkQualifiedAccess(qualifiedAccessExpression, targetSymbol, data)
checkReceiversOfQualifiedAccessExpression(qualifiedAccessExpression, targetSymbol, data)
}
// prevent delegation to visitQualifiedAccessExpression, which causes redundant diagnostics // prevent delegation to visitQualifiedAccessExpression, which causes redundant diagnostics
override fun visitSmartCastExpression(smartCastExpression: FirSmartCastExpression, data: CheckerContext) {} override fun visitSmartCastExpression(smartCastExpression: FirSmartCastExpression, data: CheckerContext) {}
override fun visitVariableAssignment(variableAssignment: FirVariableAssignment, data: CheckerContext) { internal fun checkAccessedDeclaration(
val propertySymbol = variableAssignment.calleeReference?.toResolvedCallableSymbol() as? FirPropertySymbol ?: return
val setterSymbol = propertySymbol.setterSymbol ?: return
checkQualifiedAccess(variableAssignment, setterSymbol, data)
}
override fun visitResolvedQualifier(resolvedQualifier: FirResolvedQualifier, data: CheckerContext) {
val accessedClass = resolvedQualifier.symbol ?: return
val source = resolvedQualifier.source ?: return
if (accessedClass.isCompanion) {
checkAccessedDeclaration(source, accessedClass, accessedClass.visibility, data)
}
}
private fun checkAccessedDeclaration(
source: KtSourceElement, source: KtSourceElement,
accessedSymbol: FirBasedSymbol<*>, accessedSymbol: FirBasedSymbol<*>,
declarationVisibility: Visibility, declarationVisibility: Visibility,
context: CheckerContext context: CheckerContext,
reporter: DiagnosticReporter,
): AccessedDeclarationVisibilityData { ): AccessedDeclarationVisibilityData {
val recordedEffectiveVisibility = when (accessedSymbol) { val recordedEffectiveVisibility = when (accessedSymbol) {
is FirCallableSymbol<*> -> accessedSymbol.publishedApiEffectiveVisibility ?: accessedSymbol.effectiveVisibility is FirCallableSymbol<*> -> accessedSymbol.publishedApiEffectiveVisibility ?: accessedSymbol.effectiveVisibility
@@ -155,7 +99,7 @@ object FirInlineDeclarationChecker : FirFunctionChecker() {
context context
) )
} else { } else {
checkPrivateClassMemberAccess(accessedSymbol, source, context) checkPrivateClassMemberAccess(accessedSymbol, source, context, reporter)
} }
return AccessedDeclarationVisibilityData( return AccessedDeclarationVisibilityData(
isInlineFunPublicOrPublishedApi, isInlineFunPublicOrPublishedApi,
@@ -164,25 +108,27 @@ object FirInlineDeclarationChecker : FirFunctionChecker() {
) )
} }
private data class AccessedDeclarationVisibilityData( internal data class AccessedDeclarationVisibilityData(
val isInlineFunPublicOrPublishedApi: Boolean, val isInlineFunPublicOrPublishedApi: Boolean,
val isCalledFunPublicOrPublishedApi: Boolean, val isCalledFunPublicOrPublishedApi: Boolean,
val calledFunEffectiveVisibility: EffectiveVisibility val calledFunEffectiveVisibility: EffectiveVisibility
) )
private fun checkReceiversOfQualifiedAccessExpression( internal fun checkReceiversOfQualifiedAccessExpression(
qualifiedAccessExpression: FirQualifiedAccessExpression, qualifiedAccessExpression: FirQualifiedAccessExpression,
targetSymbol: FirBasedSymbol<*>?, targetSymbol: FirBasedSymbol<*>?,
context: CheckerContext context: CheckerContext,
reporter: DiagnosticReporter,
) { ) {
checkReceiver(qualifiedAccessExpression, qualifiedAccessExpression.dispatchReceiver, targetSymbol, context) checkReceiver(qualifiedAccessExpression, qualifiedAccessExpression.dispatchReceiver, targetSymbol, context, reporter)
checkReceiver(qualifiedAccessExpression, qualifiedAccessExpression.extensionReceiver, targetSymbol, context) checkReceiver(qualifiedAccessExpression, qualifiedAccessExpression.extensionReceiver, targetSymbol, context, reporter)
} }
private fun checkArgumentsOfCall( internal fun checkArgumentsOfCall(
functionCall: FirFunctionCall, functionCall: FirFunctionCall,
targetSymbol: FirBasedSymbol<*>?, targetSymbol: FirBasedSymbol<*>?,
context: CheckerContext context: CheckerContext,
reporter: DiagnosticReporter,
) { ) {
if (context.isContractBody) return if (context.isContractBody) return
val calledFunctionSymbol = targetSymbol as? FirNamedFunctionSymbol ?: return val calledFunctionSymbol = targetSymbol as? FirNamedFunctionSymbol ?: return
@@ -195,7 +141,9 @@ object FirInlineDeclarationChecker : FirFunctionChecker() {
if (valueParameterOfOriginalInlineFunction != null) { if (valueParameterOfOriginalInlineFunction != null) {
val factory = when { val factory = when {
calledFunctionSymbol.isInline -> when { calledFunctionSymbol.isInline -> when {
valueParameter.isNoinline -> FirErrors.USAGE_IS_NOT_INLINABLE valueParameter.isNoinline -> {
FirErrors.USAGE_IS_NOT_INLINABLE
}
valueParameter.isCrossinline && !valueParameterOfOriginalInlineFunction.isCrossinline valueParameter.isCrossinline && !valueParameterOfOriginalInlineFunction.isCrossinline
-> FirErrors.NON_LOCAL_RETURN_NOT_ALLOWED -> FirErrors.NON_LOCAL_RETURN_NOT_ALLOWED
else -> continue else -> continue
@@ -211,7 +159,8 @@ object FirInlineDeclarationChecker : FirFunctionChecker() {
qualifiedAccessExpression: FirQualifiedAccessExpression, qualifiedAccessExpression: FirQualifiedAccessExpression,
receiverExpression: FirExpression, receiverExpression: FirExpression,
targetSymbol: FirBasedSymbol<*>?, targetSymbol: FirBasedSymbol<*>?,
context: CheckerContext context: CheckerContext,
reporter: DiagnosticReporter,
) { ) {
val receiverSymbol = receiverExpression.toResolvedCallableSymbol() ?: return val receiverSymbol = receiverExpression.toResolvedCallableSymbol() ?: return
if (receiverSymbol in inalienableParameters) { if (receiverSymbol in inalienableParameters) {
@@ -234,10 +183,11 @@ object FirInlineDeclarationChecker : FirFunctionChecker() {
targetSymbol.dispatchReceiverType?.isSomeFunctionType(session) == true targetSymbol.dispatchReceiverType?.isSomeFunctionType(session) == true
} }
private fun checkQualifiedAccess( internal fun checkQualifiedAccess(
qualifiedAccess: FirStatement, qualifiedAccess: FirStatement,
targetSymbol: FirBasedSymbol<*>?, targetSymbol: FirBasedSymbol<*>?,
context: CheckerContext context: CheckerContext,
reporter: DiagnosticReporter,
) { ) {
val source = qualifiedAccess.source ?: return val source = qualifiedAccess.source ?: return
if (targetSymbol !is FirCallableSymbol<*>) return if (targetSymbol !is FirCallableSymbol<*>) return
@@ -247,8 +197,8 @@ object FirInlineDeclarationChecker : FirFunctionChecker() {
reporter.reportOn(source, FirErrors.USAGE_IS_NOT_INLINABLE, targetSymbol, context) reporter.reportOn(source, FirErrors.USAGE_IS_NOT_INLINABLE, targetSymbol, context)
} }
} }
checkVisibilityAndAccess(qualifiedAccess, targetSymbol, source, context) checkVisibilityAndAccess(qualifiedAccess, targetSymbol, source, context, reporter)
checkRecursion(targetSymbol, source, context) checkRecursion(targetSymbol, source, context, reporter)
} }
private fun FirStatement.partOfCall(context: CheckerContext): Boolean { private fun FirStatement.partOfCall(context: CheckerContext): Boolean {
@@ -265,7 +215,8 @@ object FirInlineDeclarationChecker : FirFunctionChecker() {
accessExpression: FirStatement, accessExpression: FirStatement,
calledDeclaration: FirCallableSymbol<*>?, calledDeclaration: FirCallableSymbol<*>?,
source: KtSourceElement, source: KtSourceElement,
context: CheckerContext context: CheckerContext,
reporter: DiagnosticReporter,
) { ) {
if ( if (
calledDeclaration == null || calledDeclaration == null ||
@@ -277,11 +228,12 @@ object FirInlineDeclarationChecker : FirFunctionChecker() {
source, source,
calledDeclaration, calledDeclaration,
calledDeclaration.visibility, calledDeclaration.visibility,
context context,
reporter,
) )
if (isInlineFunPublicOrPublishedApi && isCalledFunPublicOrPublishedApi) { if (isInlineFunPublicOrPublishedApi && isCalledFunPublicOrPublishedApi) {
checkSuperCalls(calledDeclaration, accessExpression, context) checkSuperCalls(calledDeclaration, accessExpression, context, reporter)
} }
val isConstructorCall = calledDeclaration is FirConstructorSymbol val isConstructorCall = calledDeclaration is FirConstructorSymbol
@@ -302,7 +254,8 @@ object FirInlineDeclarationChecker : FirFunctionChecker() {
private fun checkPrivateClassMemberAccess( private fun checkPrivateClassMemberAccess(
calledDeclaration: FirBasedSymbol<*>, calledDeclaration: FirBasedSymbol<*>,
source: KtSourceElement, source: KtSourceElement,
context: CheckerContext context: CheckerContext,
reporter: DiagnosticReporter,
) { ) {
if (!isEffectivelyPrivateApiFunction) { if (!isEffectivelyPrivateApiFunction) {
if (calledDeclaration.isInsidePrivateClass()) { if (calledDeclaration.isInsidePrivateClass()) {
@@ -320,7 +273,8 @@ object FirInlineDeclarationChecker : FirFunctionChecker() {
private fun checkSuperCalls( private fun checkSuperCalls(
calledDeclaration: FirCallableSymbol<*>, calledDeclaration: FirCallableSymbol<*>,
callExpression: FirStatement, callExpression: FirStatement,
context: CheckerContext context: CheckerContext,
reporter: DiagnosticReporter,
) { ) {
val receiver = when (callExpression) { val receiver = when (callExpression) {
is FirQualifiedAccessExpression -> callExpression.dispatchReceiver is FirQualifiedAccessExpression -> callExpression.dispatchReceiver
@@ -353,7 +307,8 @@ object FirInlineDeclarationChecker : FirFunctionChecker() {
private fun checkRecursion( private fun checkRecursion(
targetSymbol: FirBasedSymbol<*>, targetSymbol: FirBasedSymbol<*>,
source: KtSourceElement, source: KtSourceElement,
context: CheckerContext context: CheckerContext,
reporter: DiagnosticReporter,
) { ) {
if (targetSymbol == inlineFunction.symbol) { if (targetSymbol == inlineFunction.symbol) {
reporter.reportOn(source, FirErrors.RECURSION_IN_INLINE, targetSymbol, context) reporter.reportOn(source, FirErrors.RECURSION_IN_INLINE, targetSymbol, context)
@@ -511,24 +466,19 @@ object FirInlineDeclarationChecker : FirFunctionChecker() {
reporter.reportOn(declaration.source, FirErrors.OVERRIDE_BY_INLINE, context) reporter.reportOn(declaration.source, FirErrors.OVERRIDE_BY_INLINE, context)
} }
} }
}
private fun FirElement.checkChildrenWithCustomVisitor(
parentContext: CheckerContext, fun createInlineFunctionBodyContext(function: FirFunction, session: FirSession): FirInlineDeclarationChecker.InlineFunctionBodyContext {
visitorVoid: FirVisitor<Unit, CheckerContext>, val inlineableParameters = function.valueParameters.filter {
rootFunction: FirFunction, if (it.isNoinline) return@filter false
) { val type = it.returnTypeRef.coneType
// TODO: Get rid of this cast and the following context modification as it looks like a leaking abstraction (see KT-56460) !type.isMarkedNullable && type.isNonReflectFunctionType(session)
require(parentContext is CheckerContextForProvider) { }.map { it.symbol }
"This checked violates the contract for read-only checkers"
} return FirInlineDeclarationChecker.InlineFunctionBodyContext(
function,
parentContext.withDeclaration(rootFunction) { function.publishedApiEffectiveVisibility ?: function.effectiveVisibility,
val collectingVisitor = object : AbstractDiagnosticCollectorVisitor(it) { inlineableParameters,
override fun checkElement(element: FirElement) { session,
element.accept(visitorVoid, context) )
}
}
this.accept(collectingVisitor, null)
}
}
} }
@@ -9,8 +9,11 @@ import org.jetbrains.kotlin.fir.FirAnnotationContainer
import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.PrivateForInline import org.jetbrains.kotlin.fir.PrivateForInline
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContextForProvider import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContextForProvider
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.createInlineFunctionBodyContext
import org.jetbrains.kotlin.fir.contracts.FirContractDescription
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.builder.buildReceiverParameter import org.jetbrains.kotlin.fir.declarations.builder.buildReceiverParameter
import org.jetbrains.kotlin.fir.declarations.utils.isInline
import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.impl.FirContractCallBlock import org.jetbrains.kotlin.fir.expressions.impl.FirContractCallBlock
import org.jetbrains.kotlin.fir.resolve.defaultType import org.jetbrains.kotlin.fir.resolve.defaultType
@@ -105,7 +108,9 @@ abstract class AbstractDiagnosticCollectorVisitor(
override fun visitSimpleFunction(simpleFunction: FirSimpleFunction, data: Nothing?) { override fun visitSimpleFunction(simpleFunction: FirSimpleFunction, data: Nothing?) {
withAnnotationContainer(simpleFunction) { withAnnotationContainer(simpleFunction) {
visitWithDeclarationAndReceiver(simpleFunction, simpleFunction.name, simpleFunction.receiverParameter) withInlineFunctionBodyIfApplicable(simpleFunction, simpleFunction.isInline) {
visitWithDeclarationAndReceiver(simpleFunction, simpleFunction.name, simpleFunction.receiverParameter)
}
} }
} }
@@ -145,7 +150,9 @@ abstract class AbstractDiagnosticCollectorVisitor(
override fun visitPropertyAccessor(propertyAccessor: FirPropertyAccessor, data: Nothing?) { override fun visitPropertyAccessor(propertyAccessor: FirPropertyAccessor, data: Nothing?) {
val property = context.containingDeclarations.last() as FirProperty val property = context.containingDeclarations.last() as FirProperty
withAnnotationContainer(propertyAccessor) { withAnnotationContainer(propertyAccessor) {
visitWithDeclarationAndReceiver(propertyAccessor, property.name, property.receiverParameter) withInlineFunctionBodyIfApplicable(propertyAccessor, propertyAccessor.isInline || property.isInline) {
visitWithDeclarationAndReceiver(propertyAccessor, property.name, property.receiverParameter)
}
} }
} }
@@ -189,6 +196,12 @@ abstract class AbstractDiagnosticCollectorVisitor(
} }
} }
override fun visitContractDescription(contractDescription: FirContractDescription, data: Nothing?) {
suppressInlineFunctionBodyContext {
visitElement(contractDescription, data)
}
}
override fun visitTypeRef(typeRef: FirTypeRef, data: Nothing?) { override fun visitTypeRef(typeRef: FirTypeRef, data: Nothing?) {
if (typeRef.source?.kind?.shouldSkipErrorTypeReporting == false) { if (typeRef.source?.kind?.shouldSkipErrorTypeReporting == false) {
withTypeRefAnnotationContainer(typeRef) { withTypeRefAnnotationContainer(typeRef) {
@@ -286,6 +299,20 @@ abstract class AbstractDiagnosticCollectorVisitor(
} }
} }
@OptIn(PrivateForInline::class)
private inline fun <T> withInlineFunctionBodyIfApplicable(function: FirFunction, isInline: Boolean, block: () -> T): T {
return try {
if (isInline) {
context = context.setInlineFunctionBodyContext(createInlineFunctionBodyContext(function, context.session))
}
block()
} finally {
if (isInline) {
context = context.unsetInlineFunctionBodyContext()
}
}
}
private fun visitWithCallOrAssignment(callOrAssignment: FirStatement) { private fun visitWithCallOrAssignment(callOrAssignment: FirStatement) {
return withCallOrAssignment(callOrAssignment) { return withCallOrAssignment(callOrAssignment) {
visitElement(callOrAssignment, null) visitElement(callOrAssignment, null)
@@ -410,6 +437,20 @@ abstract class AbstractDiagnosticCollectorVisitor(
} }
} }
@OptIn(PrivateForInline::class)
private inline fun <R> suppressInlineFunctionBodyContext(block: () -> R): R {
val oldInlineFunctionBodyContext = context.inlineFunctionBodyContext?.also {
context = context.unsetInlineFunctionBodyContext()
}
return try {
block()
} finally {
oldInlineFunctionBodyContext?.let {
context = context.setInlineFunctionBodyContext(it)
}
}
}
@OptIn(PrivateForInline::class) @OptIn(PrivateForInline::class)
private inline fun <R> insideContractBody(block: () -> R): R { private inline fun <R> insideContractBody(block: () -> R): R {
context = context.enterContractBody() context = context.enterContractBody()
@@ -6,17 +6,17 @@ inline fun inlineFun(lambda: () -> String) = lambda()
fun noInlineFun(lambda: () -> String) = lambda() fun noInlineFun(lambda: () -> String) = lambda()
inline fun default0_1(lambda: () -> String, dlambda: () -> String = { lambda; "OK" }) { inline fun default0_1(lambda: () -> String, dlambda: () -> String = { <!USAGE_IS_NOT_INLINABLE!>lambda<!>; "OK" }) {
lambda() + dlambda() lambda() + dlambda()
} }
inline fun default0_2(lambda: () -> String, dlambda: () -> String = { noInlineFun (lambda) }) { inline fun default0_2(lambda: () -> String, dlambda: () -> String = { noInlineFun (<!USAGE_IS_NOT_INLINABLE!>lambda<!>) }) {
lambda() + dlambda() lambda() + dlambda()
} }
inline fun default0(lambda: () -> String, dlambda: () -> String = { noInlineFun (lambda) }) { inline fun default0(lambda: () -> String, dlambda: () -> String = { noInlineFun (<!USAGE_IS_NOT_INLINABLE!>lambda<!>) }) {
lambda() + dlambda() lambda() + dlambda()
} }