[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:
committed by
Space Team
parent
ed2f0c295b
commit
8c5b2ae85b
-36
@@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
+6
@@ -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,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+23
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+23
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+6
@@ -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>
|
||||||
|
|||||||
-3
@@ -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,
|
||||||
|
|||||||
+2
@@ -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>
|
||||||
|
|||||||
+5
@@ -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
|
||||||
|
|||||||
+17
@@ -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
|
||||||
|
|||||||
+12
@@ -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)
|
||||||
|
|||||||
+27
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+24
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+23
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
+54
-104
@@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+43
-2
@@ -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()
|
||||||
|
|||||||
+3
-3
@@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user