K2: Extract CheckerContextForProvider from CheckerContext
So, the idea is that CheckerContext should remain just read-only while the one who runs the checkers might build/modify the context. ^KT-56460 Related
This commit is contained in:
committed by
Space Team
parent
d24092e467
commit
a311d6eea0
+2
-2
@@ -10,7 +10,7 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirModuleResolveCompone
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.diagnostics.fir.PersistenceContextCollector
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.diagnostics.fir.PersistentCheckerContextFactory
|
||||
import org.jetbrains.kotlin.fir.FirElement
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContextForProvider
|
||||
import org.jetbrains.kotlin.fir.analysis.collectors.DiagnosticCollectorComponents
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.resolve.SessionHolderImpl
|
||||
@@ -46,7 +46,7 @@ internal class SingleNonLocalDeclarationDiagnosticRetriever(
|
||||
|
||||
private class Visitor(
|
||||
private val structureElementDeclaration: FirDeclaration,
|
||||
context: CheckerContext,
|
||||
context: CheckerContextForProvider,
|
||||
components: DiagnosticCollectorComponents
|
||||
) : LLFirDiagnosticVisitor(context, components) {
|
||||
private var insideAlwaysVisitableDeclarations = 0
|
||||
|
||||
+5
-5
@@ -5,15 +5,15 @@
|
||||
|
||||
package org.jetbrains.kotlin.analysis.low.level.api.fir.diagnostics
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirElement
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.collectors.CheckerRunningDiagnosticCollectorVisitor
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkCanceled
|
||||
import org.jetbrains.kotlin.fir.FirElement
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContextForProvider
|
||||
import org.jetbrains.kotlin.fir.analysis.collectors.CheckerRunningDiagnosticCollectorVisitor
|
||||
import org.jetbrains.kotlin.fir.analysis.collectors.DiagnosticCollectorComponents
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
||||
|
||||
internal open class LLFirDiagnosticVisitor(
|
||||
context: CheckerContext,
|
||||
context: CheckerContextForProvider,
|
||||
components: DiagnosticCollectorComponents,
|
||||
) : CheckerRunningDiagnosticCollectorVisitor(context, components) {
|
||||
private val beforeElementDiagnosticCollectionHandler = context.session.beforeElementDiagnosticCollectionHandler
|
||||
|
||||
+5
-5
@@ -10,7 +10,7 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDesignationWithFil
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.collectDesignation
|
||||
import org.jetbrains.kotlin.fir.FirElement
|
||||
import org.jetbrains.kotlin.fir.FirElementWithResolvePhase
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContextForProvider
|
||||
import org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor
|
||||
import org.jetbrains.kotlin.fir.containingClass
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
@@ -23,8 +23,8 @@ private class ContextCollectingDiagnosticCollectorVisitor private constructor(
|
||||
) : AbstractDiagnosticCollectorVisitor(
|
||||
PersistentCheckerContextFactory.createEmptyPersistenceCheckerContext(sessionHolder)
|
||||
) {
|
||||
private val contextCollector = object : ContextByDesignationCollector<CheckerContext>(designation) {
|
||||
override fun getCurrentContext(): CheckerContext = context
|
||||
private val contextCollector = object : ContextByDesignationCollector<CheckerContextForProvider>(designation) {
|
||||
override fun getCurrentContext(): CheckerContextForProvider = context
|
||||
|
||||
override fun goToNestedDeclaration(target: FirElementWithResolvePhase) {
|
||||
target.accept(this@ContextCollectingDiagnosticCollectorVisitor, null)
|
||||
@@ -42,7 +42,7 @@ private class ContextCollectingDiagnosticCollectorVisitor private constructor(
|
||||
override fun checkElement(element: FirElement) {}
|
||||
|
||||
companion object {
|
||||
fun collect(sessionHolder: SessionHolder, designation: FirDesignationWithFile): CheckerContext {
|
||||
fun collect(sessionHolder: SessionHolder, designation: FirDesignationWithFile): CheckerContextForProvider {
|
||||
val visitor = ContextCollectingDiagnosticCollectorVisitor(sessionHolder, designation)
|
||||
designation.firFile.accept(visitor, null)
|
||||
return visitor.contextCollector.getCollectedContext()
|
||||
@@ -55,7 +55,7 @@ internal object PersistenceContextCollector {
|
||||
sessionHolder: SessionHolder,
|
||||
firFile: FirFile,
|
||||
declaration: FirDeclaration,
|
||||
): CheckerContext {
|
||||
): CheckerContextForProvider {
|
||||
val isLocal = when (declaration) {
|
||||
is FirClassLikeDeclaration -> declaration.symbol.classId.isLocal
|
||||
is FirCallableDeclaration -> declaration.symbol.callableId.isLocal
|
||||
|
||||
+5
-35
@@ -6,8 +6,8 @@
|
||||
package org.jetbrains.kotlin.fir.analysis.checkers.context
|
||||
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticContext
|
||||
import org.jetbrains.kotlin.diagnostics.KtDiagnostic
|
||||
import org.jetbrains.kotlin.diagnostics.MutableDiagnosticContext
|
||||
import org.jetbrains.kotlin.diagnostics.Severity
|
||||
import org.jetbrains.kotlin.fir.FirAnnotationContainer
|
||||
import org.jetbrains.kotlin.fir.FirElement
|
||||
@@ -19,11 +19,12 @@ import org.jetbrains.kotlin.fir.expressions.FirStatement
|
||||
import org.jetbrains.kotlin.fir.languageVersionSettings
|
||||
import org.jetbrains.kotlin.fir.resolve.ImplicitReceiverStack
|
||||
import org.jetbrains.kotlin.fir.resolve.SessionHolder
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.ImplicitReceiverValue
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculator
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
abstract class CheckerContext : MutableDiagnosticContext() {
|
||||
/**
|
||||
* This class is assumed to be read-only (all the modifications are assumed to happen on CheckerContextForProvider side)
|
||||
*/
|
||||
abstract class CheckerContext : DiagnosticContext {
|
||||
// Services
|
||||
abstract val sessionHolder: SessionHolder
|
||||
abstract val returnTypeCalculator: ReturnTypeCalculator
|
||||
@@ -45,37 +46,6 @@ abstract class CheckerContext : MutableDiagnosticContext() {
|
||||
val session: FirSession
|
||||
get() = sessionHolder.session
|
||||
|
||||
abstract fun addImplicitReceiver(name: Name?, value: ImplicitReceiverValue<*>): CheckerContext
|
||||
|
||||
abstract fun addDeclaration(declaration: FirDeclaration): CheckerContext
|
||||
|
||||
abstract fun dropDeclaration()
|
||||
|
||||
fun <T> withDeclaration(declaration: FirDeclaration, f: (CheckerContext) -> T): T {
|
||||
val newContext = addDeclaration(declaration)
|
||||
try {
|
||||
return f(newContext)
|
||||
} finally {
|
||||
newContext.dropDeclaration()
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun addQualifiedAccessOrAnnotationCall(qualifiedAccessOrAnnotationCall: FirStatement): CheckerContext
|
||||
|
||||
abstract fun dropQualifiedAccessOrAnnotationCall()
|
||||
|
||||
abstract fun addGetClassCall(getClassCall: FirGetClassCall): CheckerContext
|
||||
|
||||
abstract fun dropGetClassCall()
|
||||
|
||||
abstract fun addAnnotationContainer(annotationContainer: FirAnnotationContainer): CheckerContext
|
||||
|
||||
abstract fun dropAnnotationContainer()
|
||||
|
||||
abstract fun enterContractBody(): CheckerContext
|
||||
|
||||
abstract fun exitContractBody(): CheckerContext
|
||||
|
||||
override fun isDiagnosticSuppressed(diagnostic: KtDiagnostic): Boolean {
|
||||
val factory = diagnostic.factory
|
||||
val name = factory.name
|
||||
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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.context
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirAnnotationContainer
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
||||
import org.jetbrains.kotlin.fir.expressions.FirGetClassCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirStatement
|
||||
import org.jetbrains.kotlin.fir.resolve.SessionHolder
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.ImplicitReceiverValue
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculator
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
/**
|
||||
* This class should be invisible for checkers, but should be only used by DiagnosticCollectorVisitor who runs those checkers
|
||||
* It contains all context-modification-related methods unlike CheckerContext that is assumed to be read-only
|
||||
*/
|
||||
abstract class CheckerContextForProvider(
|
||||
sessionHolder: SessionHolder,
|
||||
returnTypeCalculator: ReturnTypeCalculator,
|
||||
allInfosSuppressed: Boolean,
|
||||
allWarningsSuppressed: Boolean,
|
||||
allErrorsSuppressed: Boolean
|
||||
) : AbstractCheckerContext(sessionHolder, returnTypeCalculator, allInfosSuppressed, allWarningsSuppressed, allErrorsSuppressed) {
|
||||
|
||||
abstract fun addSuppressedDiagnostics(
|
||||
diagnosticNames: Collection<String>,
|
||||
allInfosSuppressed: Boolean,
|
||||
allWarningsSuppressed: Boolean,
|
||||
allErrorsSuppressed: Boolean
|
||||
): CheckerContextForProvider
|
||||
|
||||
abstract fun addImplicitReceiver(name: Name?, value: ImplicitReceiverValue<*>): CheckerContextForProvider
|
||||
|
||||
abstract fun addDeclaration(declaration: FirDeclaration): CheckerContextForProvider
|
||||
|
||||
abstract fun dropDeclaration()
|
||||
|
||||
fun <T> withDeclaration(declaration: FirDeclaration, f: (CheckerContextForProvider) -> T): T {
|
||||
val newContext = addDeclaration(declaration)
|
||||
try {
|
||||
return f(newContext)
|
||||
} finally {
|
||||
newContext.dropDeclaration()
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun addQualifiedAccessOrAnnotationCall(qualifiedAccessOrAnnotationCall: FirStatement): CheckerContextForProvider
|
||||
|
||||
abstract fun dropQualifiedAccessOrAnnotationCall()
|
||||
|
||||
abstract fun addGetClassCall(getClassCall: FirGetClassCall): CheckerContextForProvider
|
||||
|
||||
abstract fun dropGetClassCall()
|
||||
|
||||
abstract fun addAnnotationContainer(annotationContainer: FirAnnotationContainer): CheckerContextForProvider
|
||||
|
||||
abstract fun dropAnnotationContainer()
|
||||
|
||||
abstract fun enterContractBody(): CheckerContextForProvider
|
||||
|
||||
abstract fun exitContractBody(): CheckerContextForProvider
|
||||
|
||||
}
|
||||
+5
-5
@@ -30,7 +30,7 @@ class MutableCheckerContext private constructor(
|
||||
allInfosSuppressed: Boolean,
|
||||
allWarningsSuppressed: Boolean,
|
||||
allErrorsSuppressed: Boolean
|
||||
) : AbstractCheckerContext(sessionHolder, returnTypeCalculator, allInfosSuppressed, allWarningsSuppressed, allErrorsSuppressed) {
|
||||
) : CheckerContextForProvider(sessionHolder, returnTypeCalculator, allInfosSuppressed, allWarningsSuppressed, allErrorsSuppressed) {
|
||||
constructor(sessionHolder: SessionHolder, returnTypeCalculator: ReturnTypeCalculator) : this(
|
||||
PersistentImplicitReceiverStack(),
|
||||
mutableListOf(),
|
||||
@@ -90,7 +90,7 @@ class MutableCheckerContext private constructor(
|
||||
getClassCalls.removeAt(getClassCalls.size - 1)
|
||||
}
|
||||
|
||||
override fun addAnnotationContainer(annotationContainer: FirAnnotationContainer): CheckerContext {
|
||||
override fun addAnnotationContainer(annotationContainer: FirAnnotationContainer): CheckerContextForProvider {
|
||||
annotationContainers.add(annotationContainer)
|
||||
return this
|
||||
}
|
||||
@@ -104,7 +104,7 @@ class MutableCheckerContext private constructor(
|
||||
allInfosSuppressed: Boolean,
|
||||
allWarningsSuppressed: Boolean,
|
||||
allErrorsSuppressed: Boolean
|
||||
): MutableCheckerContext {
|
||||
): CheckerContextForProvider {
|
||||
if (diagnosticNames.isEmpty()) return this
|
||||
return MutableCheckerContext(
|
||||
implicitReceiverStack,
|
||||
@@ -122,13 +122,13 @@ class MutableCheckerContext private constructor(
|
||||
)
|
||||
}
|
||||
|
||||
override fun enterContractBody(): CheckerContext {
|
||||
override fun enterContractBody(): CheckerContextForProvider {
|
||||
check(!isContractBody)
|
||||
isContractBody = true
|
||||
return this
|
||||
}
|
||||
|
||||
override fun exitContractBody(): CheckerContext {
|
||||
override fun exitContractBody(): CheckerContextForProvider {
|
||||
check(isContractBody)
|
||||
isContractBody = false
|
||||
return this
|
||||
|
||||
+5
-5
@@ -32,7 +32,7 @@ class PersistentCheckerContext private constructor(
|
||||
allInfosSuppressed: Boolean,
|
||||
allWarningsSuppressed: Boolean,
|
||||
allErrorsSuppressed: Boolean
|
||||
) : AbstractCheckerContext(sessionHolder, returnTypeCalculator, allInfosSuppressed, allWarningsSuppressed, allErrorsSuppressed) {
|
||||
) : CheckerContextForProvider(sessionHolder, returnTypeCalculator, allInfosSuppressed, allWarningsSuppressed, allErrorsSuppressed) {
|
||||
constructor(sessionHolder: SessionHolder, returnTypeCalculator: ReturnTypeCalculator) : this(
|
||||
PersistentImplicitReceiverStack(),
|
||||
persistentListOf(),
|
||||
@@ -150,7 +150,7 @@ class PersistentCheckerContext private constructor(
|
||||
allInfosSuppressed: Boolean,
|
||||
allWarningsSuppressed: Boolean,
|
||||
allErrorsSuppressed: Boolean
|
||||
): PersistentCheckerContext {
|
||||
): CheckerContextForProvider {
|
||||
if (diagnosticNames.isEmpty()) return this
|
||||
return PersistentCheckerContext(
|
||||
implicitReceiverStack,
|
||||
@@ -168,7 +168,7 @@ class PersistentCheckerContext private constructor(
|
||||
)
|
||||
}
|
||||
|
||||
private fun toggleContractBody(newValue: Boolean): CheckerContext {
|
||||
private fun toggleContractBody(newValue: Boolean): CheckerContextForProvider {
|
||||
check(isContractBody != newValue)
|
||||
|
||||
return PersistentCheckerContext(
|
||||
@@ -187,11 +187,11 @@ class PersistentCheckerContext private constructor(
|
||||
)
|
||||
}
|
||||
|
||||
override fun enterContractBody(): CheckerContext {
|
||||
override fun enterContractBody(): CheckerContextForProvider {
|
||||
return toggleContractBody(newValue = true)
|
||||
}
|
||||
|
||||
override fun exitContractBody(): CheckerContext {
|
||||
override fun exitContractBody(): CheckerContextForProvider {
|
||||
return toggleContractBody(newValue = false)
|
||||
}
|
||||
}
|
||||
|
||||
+16
-9
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.*
|
||||
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.getModifier
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.isInlineOnly
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope
|
||||
@@ -72,9 +73,7 @@ abstract class FirInlineDeclarationChecker : FirFunctionChecker() {
|
||||
context.session,
|
||||
reporter
|
||||
)
|
||||
context.withDeclaration(function) {
|
||||
body.checkChildrenWithCustomVisitor(it, visitor)
|
||||
}
|
||||
body.checkChildrenWithCustomVisitor(context, visitor, function)
|
||||
}
|
||||
|
||||
open val inlineVisitor get() = ::BasicInlineVisitor
|
||||
@@ -538,13 +537,21 @@ abstract class FirInlineDeclarationChecker : FirFunctionChecker() {
|
||||
|
||||
private fun FirElement.checkChildrenWithCustomVisitor(
|
||||
parentContext: CheckerContext,
|
||||
visitorVoid: FirVisitor<Unit, CheckerContext>
|
||||
visitorVoid: FirVisitor<Unit, CheckerContext>,
|
||||
rootFunction: FirFunction,
|
||||
) {
|
||||
val collectingVisitor = object : AbstractDiagnosticCollectorVisitor(parentContext) {
|
||||
override fun checkElement(element: FirElement) {
|
||||
element.accept(visitorVoid, context)
|
||||
}
|
||||
// TODO: Get rid of this cast and the following context modification as it looks like a leaking abstraction (see KT-56460)
|
||||
require(parentContext is CheckerContextForProvider) {
|
||||
"This checked violates the contract for read-only checkers"
|
||||
}
|
||||
|
||||
parentContext.withDeclaration(rootFunction) {
|
||||
val collectingVisitor = object : AbstractDiagnosticCollectorVisitor(it) {
|
||||
override fun checkElement(element: FirElement) {
|
||||
element.accept(visitorVoid, context)
|
||||
}
|
||||
}
|
||||
this.accept(collectingVisitor, null)
|
||||
}
|
||||
this.accept(collectingVisitor, null)
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -9,7 +9,7 @@ import org.jetbrains.kotlin.KtFakeSourceElementKind
|
||||
import org.jetbrains.kotlin.fir.FirAnnotationContainer
|
||||
import org.jetbrains.kotlin.fir.FirElement
|
||||
import org.jetbrains.kotlin.fir.PrivateForInline
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContextForProvider
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.builder.buildReceiverParameter
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.fir.whileAnalysing
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
abstract class AbstractDiagnosticCollectorVisitor(
|
||||
@set:PrivateForInline var context: CheckerContext,
|
||||
@set:PrivateForInline var context: CheckerContextForProvider,
|
||||
) : FirDefaultVisitor<Unit, Nothing?>() {
|
||||
|
||||
protected open fun shouldVisitDeclaration(declaration: FirDeclaration) = true
|
||||
@@ -393,6 +393,6 @@ abstract class AbstractDiagnosticCollectorVisitor(
|
||||
allInfosSuppressed = AbstractDiagnosticCollector.SUPPRESS_ALL_INFOS in arguments,
|
||||
allWarningsSuppressed = AbstractDiagnosticCollector.SUPPRESS_ALL_WARNINGS in arguments,
|
||||
allErrorsSuppressed = AbstractDiagnosticCollector.SUPPRESS_ALL_ERRORS in arguments
|
||||
) as CheckerContext
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+2
-3
@@ -6,13 +6,12 @@
|
||||
package org.jetbrains.kotlin.fir.analysis.collectors
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirElement
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.collectors.components.AbstractDiagnosticCollectorComponent
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContextForProvider
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||
|
||||
open class CheckerRunningDiagnosticCollectorVisitor(
|
||||
context: CheckerContext,
|
||||
context: CheckerContextForProvider,
|
||||
protected val components: DiagnosticCollectorComponents
|
||||
) : AbstractDiagnosticCollectorVisitor(context) {
|
||||
|
||||
|
||||
+1
-10
@@ -16,15 +16,6 @@ interface DiagnosticContext {
|
||||
val languageVersionSettings: LanguageVersionSettings
|
||||
}
|
||||
|
||||
abstract class MutableDiagnosticContext : DiagnosticContext {
|
||||
abstract fun addSuppressedDiagnostics(
|
||||
diagnosticNames: Collection<String>,
|
||||
allInfosSuppressed: Boolean,
|
||||
allWarningsSuppressed: Boolean,
|
||||
allErrorsSuppressed: Boolean
|
||||
): DiagnosticContext
|
||||
}
|
||||
|
||||
abstract class DiagnosticReporter {
|
||||
abstract fun report(diagnostic: KtDiagnostic?, context: DiagnosticContext)
|
||||
|
||||
@@ -97,4 +88,4 @@ open class KtDiagnosticReporterWithContext(
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user