[FIR] Add stack of all FIR elements to CheckerContext

^KT-56472 Fixed
This commit is contained in:
Dmitriy Novozhilov
2023-02-07 18:10:04 +02:00
committed by Space Team
parent 41192b022d
commit f3fd4b3e01
5 changed files with 87 additions and 42 deletions
@@ -35,6 +35,7 @@ abstract class CheckerContext : DiagnosticContext {
abstract val qualifiedAccessOrAssignmentsOrAnnotationCalls: List<FirStatement> abstract val qualifiedAccessOrAssignmentsOrAnnotationCalls: List<FirStatement>
abstract val getClassCalls: List<FirGetClassCall> abstract val getClassCalls: List<FirGetClassCall>
abstract val annotationContainers: List<FirAnnotationContainer> abstract val annotationContainers: List<FirAnnotationContainer>
abstract val containingElements: List<FirElement>
abstract val isContractBody: Boolean abstract val isContractBody: Boolean
// Suppress // Suppress
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.fir.analysis.checkers.context 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.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
@@ -69,4 +70,7 @@ abstract class CheckerContextForProvider(
abstract fun exitFile(file: FirFile): CheckerContextForProvider abstract fun exitFile(file: FirFile): CheckerContextForProvider
abstract fun addElement(element: FirElement): CheckerContextForProvider
abstract fun dropElement()
} }
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.analysis.checkers.context
import kotlinx.collections.immutable.PersistentSet 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.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
@@ -24,6 +25,7 @@ class MutableCheckerContext private constructor(
override val qualifiedAccessOrAssignmentsOrAnnotationCalls: MutableList<FirStatement>, override val qualifiedAccessOrAssignmentsOrAnnotationCalls: MutableList<FirStatement>,
override val getClassCalls: MutableList<FirGetClassCall>, override val getClassCalls: MutableList<FirGetClassCall>,
override val annotationContainers: MutableList<FirAnnotationContainer>, override val annotationContainers: MutableList<FirAnnotationContainer>,
override val containingElements: MutableList<FirElement>,
override var isContractBody: Boolean, override var isContractBody: Boolean,
override var containingFile: FirFile?, override var containingFile: FirFile?,
sessionHolder: SessionHolder, sessionHolder: SessionHolder,
@@ -39,6 +41,7 @@ class MutableCheckerContext private constructor(
mutableListOf(), mutableListOf(),
mutableListOf(), mutableListOf(),
mutableListOf(), mutableListOf(),
mutableListOf(),
isContractBody = false, isContractBody = false,
containingFile = null, containingFile = null,
sessionHolder, sessionHolder,
@@ -56,6 +59,7 @@ class MutableCheckerContext private constructor(
qualifiedAccessOrAssignmentsOrAnnotationCalls, qualifiedAccessOrAssignmentsOrAnnotationCalls,
getClassCalls, getClassCalls,
annotationContainers, annotationContainers,
containingElements,
isContractBody, isContractBody,
containingFile, containingFile,
sessionHolder, sessionHolder,
@@ -73,7 +77,7 @@ class MutableCheckerContext private constructor(
} }
override fun dropDeclaration() { override fun dropDeclaration() {
containingDeclarations.removeAt(containingDeclarations.size - 1) containingDeclarations.removeLast()
} }
override fun addQualifiedAccessOrAnnotationCall(qualifiedAccessOrAnnotationCall: FirStatement): MutableCheckerContext { override fun addQualifiedAccessOrAnnotationCall(qualifiedAccessOrAnnotationCall: FirStatement): MutableCheckerContext {
@@ -82,7 +86,7 @@ class MutableCheckerContext private constructor(
} }
override fun dropQualifiedAccessOrAnnotationCall() { override fun dropQualifiedAccessOrAnnotationCall() {
qualifiedAccessOrAssignmentsOrAnnotationCalls.removeAt(qualifiedAccessOrAssignmentsOrAnnotationCalls.size - 1) qualifiedAccessOrAssignmentsOrAnnotationCalls.removeLast()
} }
override fun addGetClassCall(getClassCall: FirGetClassCall): MutableCheckerContext { override fun addGetClassCall(getClassCall: FirGetClassCall): MutableCheckerContext {
@@ -91,7 +95,7 @@ class MutableCheckerContext private constructor(
} }
override fun dropGetClassCall() { override fun dropGetClassCall() {
getClassCalls.removeAt(getClassCalls.size - 1) getClassCalls.removeLast()
} }
override fun addAnnotationContainer(annotationContainer: FirAnnotationContainer): CheckerContextForProvider { override fun addAnnotationContainer(annotationContainer: FirAnnotationContainer): CheckerContextForProvider {
@@ -100,7 +104,17 @@ class MutableCheckerContext private constructor(
} }
override fun dropAnnotationContainer() { override fun dropAnnotationContainer() {
annotationContainers.removeAt(annotationContainers.size - 1) annotationContainers.removeLast()
}
override fun addElement(element: FirElement): CheckerContextForProvider {
assert(containingElements.lastOrNull() !== element)
containingElements.add(element)
return this
}
override fun dropElement() {
containingElements.removeLast()
} }
override fun addSuppressedDiagnostics( override fun addSuppressedDiagnostics(
@@ -116,6 +130,7 @@ class MutableCheckerContext private constructor(
qualifiedAccessOrAssignmentsOrAnnotationCalls, qualifiedAccessOrAssignmentsOrAnnotationCalls,
getClassCalls, getClassCalls,
annotationContainers, annotationContainers,
containingElements,
isContractBody, isContractBody,
containingFile, containingFile,
sessionHolder, sessionHolder,
@@ -10,6 +10,7 @@ import kotlinx.collections.immutable.PersistentSet
import kotlinx.collections.immutable.persistentListOf 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.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
@@ -26,6 +27,7 @@ class PersistentCheckerContext private constructor(
override val qualifiedAccessOrAssignmentsOrAnnotationCalls: PersistentList<FirStatement>, override val qualifiedAccessOrAssignmentsOrAnnotationCalls: PersistentList<FirStatement>,
override val getClassCalls: PersistentList<FirGetClassCall>, override val getClassCalls: PersistentList<FirGetClassCall>,
override val annotationContainers: PersistentList<FirAnnotationContainer>, override val annotationContainers: PersistentList<FirAnnotationContainer>,
override val containingElements: PersistentList<FirElement>,
override val isContractBody: Boolean, override val isContractBody: Boolean,
sessionHolder: SessionHolder, sessionHolder: SessionHolder,
returnTypeCalculator: ReturnTypeCalculator, returnTypeCalculator: ReturnTypeCalculator,
@@ -41,6 +43,7 @@ class PersistentCheckerContext private constructor(
persistentListOf(), persistentListOf(),
persistentListOf(), persistentListOf(),
persistentListOf(), persistentListOf(),
persistentListOf(),
isContractBody = false, isContractBody = false,
sessionHolder, sessionHolder,
returnTypeCalculator, returnTypeCalculator,
@@ -57,8 +60,7 @@ class PersistentCheckerContext private constructor(
override fun addDeclaration(declaration: FirDeclaration): PersistentCheckerContext = override fun addDeclaration(declaration: FirDeclaration): PersistentCheckerContext =
copy(containingDeclarations = containingDeclarations.add(declaration)) copy(containingDeclarations = containingDeclarations.add(declaration))
override fun dropDeclaration() { override fun dropDeclaration() {}
}
override fun addQualifiedAccessOrAnnotationCall(qualifiedAccessOrAnnotationCall: FirStatement): PersistentCheckerContext = override fun addQualifiedAccessOrAnnotationCall(qualifiedAccessOrAnnotationCall: FirStatement): PersistentCheckerContext =
copy( copy(
@@ -66,22 +68,22 @@ class PersistentCheckerContext private constructor(
qualifiedAccessOrAssignmentsOrAnnotationCalls.add(qualifiedAccessOrAnnotationCall) qualifiedAccessOrAssignmentsOrAnnotationCalls.add(qualifiedAccessOrAnnotationCall)
) )
override fun dropQualifiedAccessOrAnnotationCall() { override fun dropQualifiedAccessOrAnnotationCall() {}
}
override fun addGetClassCall(getClassCall: FirGetClassCall): PersistentCheckerContext = override fun addGetClassCall(getClassCall: FirGetClassCall): PersistentCheckerContext =
copy( copy(getClassCalls = getClassCalls.add(getClassCall))
getClassCalls = getClassCalls.add(getClassCall),
)
override fun dropGetClassCall() { override fun dropGetClassCall() {}
}
override fun addAnnotationContainer(annotationContainer: FirAnnotationContainer): PersistentCheckerContext = override fun addAnnotationContainer(annotationContainer: FirAnnotationContainer): PersistentCheckerContext =
copy(annotationContainers = annotationContainers.add(annotationContainer)) copy(annotationContainers = annotationContainers.add(annotationContainer))
override fun dropAnnotationContainer() { override fun dropAnnotationContainer() {}
}
override fun addElement(element: FirElement): PersistentCheckerContext =
copy(containingElements = containingElements.add(element))
override fun dropElement() {}
override fun addSuppressedDiagnostics( override fun addSuppressedDiagnostics(
diagnosticNames: Collection<String>, diagnosticNames: Collection<String>,
@@ -103,6 +105,7 @@ class PersistentCheckerContext private constructor(
qualifiedAccessOrAssignmentsOrAnnotationCalls: PersistentList<FirStatement> = this.qualifiedAccessOrAssignmentsOrAnnotationCalls, qualifiedAccessOrAssignmentsOrAnnotationCalls: PersistentList<FirStatement> = this.qualifiedAccessOrAssignmentsOrAnnotationCalls,
getClassCalls: PersistentList<FirGetClassCall> = this.getClassCalls, getClassCalls: PersistentList<FirGetClassCall> = this.getClassCalls,
annotationContainers: PersistentList<FirAnnotationContainer> = this.annotationContainers, annotationContainers: PersistentList<FirAnnotationContainer> = this.annotationContainers,
containingElements: PersistentList<FirElement> = this.containingElements,
containingDeclarations: PersistentList<FirDeclaration> = this.containingDeclarations, containingDeclarations: PersistentList<FirDeclaration> = this.containingDeclarations,
isContractBody: Boolean = this.isContractBody, isContractBody: Boolean = this.isContractBody,
allInfosSuppressed: Boolean = this.allInfosSuppressed, allInfosSuppressed: Boolean = this.allInfosSuppressed,
@@ -112,8 +115,16 @@ class PersistentCheckerContext private constructor(
containingFile: FirFile? = this.containingFile, containingFile: FirFile? = this.containingFile,
): PersistentCheckerContext { ): PersistentCheckerContext {
return PersistentCheckerContext( return PersistentCheckerContext(
implicitReceiverStack, containingDeclarations, qualifiedAccessOrAssignmentsOrAnnotationCalls, implicitReceiverStack,
getClassCalls, annotationContainers, isContractBody, sessionHolder, returnTypeCalculator, suppressedDiagnostics, containingDeclarations,
qualifiedAccessOrAssignmentsOrAnnotationCalls,
getClassCalls,
annotationContainers,
containingElements,
isContractBody,
sessionHolder,
returnTypeCalculator,
suppressedDiagnostics,
allInfosSuppressed, allWarningsSuppressed, allErrorsSuppressed, containingFile, allInfosSuppressed, allWarningsSuppressed, allErrorsSuppressed, containingFile,
) )
} }
@@ -5,7 +5,6 @@
package org.jetbrains.kotlin.fir.analysis.collectors package org.jetbrains.kotlin.fir.analysis.collectors
import org.jetbrains.kotlin.KtFakeSourceElementKind
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.PrivateForInline import org.jetbrains.kotlin.fir.PrivateForInline
@@ -35,16 +34,16 @@ abstract class AbstractDiagnosticCollectorVisitor(
protected abstract fun checkElement(element: FirElement) protected abstract fun checkElement(element: FirElement)
override fun visitElement(element: FirElement, data: Nothing?) { override fun visitElement(element: FirElement, data: Nothing?) {
if (element is FirAnnotationContainer) { when (element) {
withAnnotationContainer(element) { is FirAnnotationContainer -> withAnnotationContainer(element) {
checkElement(element)
visitNestedElements(element)
}
else -> withElement(element) {
checkElement(element) checkElement(element)
visitNestedElements(element) visitNestedElements(element)
} }
return
} }
checkElement(element)
visitNestedElements(element)
} }
override fun visitAnnotationContainer(annotationContainer: FirAnnotationContainer, data: Nothing?) { override fun visitAnnotationContainer(annotationContainer: FirAnnotationContainer, data: Nothing?) {
@@ -166,18 +165,18 @@ abstract class AbstractDiagnosticCollectorVisitor(
} }
override fun visitAnonymousInitializer(anonymousInitializer: FirAnonymousInitializer, data: Nothing?) { override fun visitAnonymousInitializer(anonymousInitializer: FirAnonymousInitializer, data: Nothing?) {
visitWithDeclaration(anonymousInitializer) withElement(anonymousInitializer) {
visitWithDeclaration(anonymousInitializer)
}
} }
override fun visitBlock(block: FirBlock, data: Nothing?) { override fun visitBlock(block: FirBlock, data: Nothing?) {
withAnnotationContainer(block) { if (block is FirContractCallBlock) {
if (block is FirContractCallBlock) { insideContractBody {
insideContractBody {
visitExpression(block, data)
}
} else {
visitExpression(block, data) visitExpression(block, data)
} }
} else {
visitExpression(block, data)
} }
} }
@@ -341,6 +340,19 @@ abstract class AbstractDiagnosticCollectorVisitor(
context = existingContext context = existingContext
} }
} }
@OptIn(PrivateForInline::class)
inline fun <T> withElement(element: FirElement, block: () -> T): T {
val existingContext = context
context = context.addElement(element)
return try {
whileAnalysing(context.session, element) {
block()
}
} finally {
existingContext.dropElement()
context = existingContext
}
}
@OptIn(PrivateForInline::class) @OptIn(PrivateForInline::class)
inline fun <R> withLabelAndReceiverType( inline fun <R> withLabelAndReceiverType(
@@ -367,19 +379,21 @@ abstract class AbstractDiagnosticCollectorVisitor(
@OptIn(PrivateForInline::class) @OptIn(PrivateForInline::class)
inline fun <R> withAnnotationContainer(annotationContainer: FirAnnotationContainer, block: () -> R): R { inline fun <R> withAnnotationContainer(annotationContainer: FirAnnotationContainer, block: () -> R): R {
val existingContext = context return withElement(annotationContainer) {
addSuppressedDiagnosticsToContext(annotationContainer) val existingContext = context
val notEmptyAnnotations = annotationContainer.annotations.isNotEmpty() addSuppressedDiagnosticsToContext(annotationContainer)
if (notEmptyAnnotations) { val notEmptyAnnotations = annotationContainer.annotations.isNotEmpty()
context = context.addAnnotationContainer(annotationContainer)
}
return try {
block()
} finally {
if (notEmptyAnnotations) { if (notEmptyAnnotations) {
existingContext.dropAnnotationContainer() context = context.addAnnotationContainer(annotationContainer)
}
try {
block()
} finally {
if (notEmptyAnnotations) {
existingContext.dropAnnotationContainer()
}
context = existingContext
} }
context = existingContext
} }
} }