FIR IDE: separate diagnostics collection and checker context collection

This commit is contained in:
Ilya Kirillov
2021-03-24 17:58:05 +01:00
parent 29a0c448a6
commit e79c133331
12 changed files with 405 additions and 349 deletions
@@ -20,12 +20,12 @@ abstract class AbstractDiagnosticCollector(
override val session: FirSession, override val session: FirSession,
override val scopeSession: ScopeSession = ScopeSession(), override val scopeSession: ScopeSession = ScopeSession(),
) : SessionHolder { ) : SessionHolder {
fun collectDiagnostics(firFile: FirFile): List<FirDiagnostic<*>> { fun collectDiagnostics(firDeclaration: FirDeclaration): List<FirDiagnostic<*>> {
if (!componentsInitialized) { if (!componentsInitialized) {
throw IllegalStateException("Components are not initialized") throw IllegalStateException("Components are not initialized")
} }
initializeCollector() initializeCollector()
firFile.accept(visitor, null) firDeclaration.accept(visitor, null)
return getCollectedDiagnostics() return getCollectedDiagnostics()
} }
@@ -7,24 +7,236 @@ package org.jetbrains.kotlin.fir.analysis.collectors
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.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.PrivateForInline import org.jetbrains.kotlin.fir.PrivateForInline
import org.jetbrains.kotlin.fir.analysis.checkers.context.PersistentCheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.PersistentCheckerContext
import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.analysis.collectors.components.AbstractDiagnosticCollectorComponent
import org.jetbrains.kotlin.fir.expressions.FirGetClassCall import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.resolve.collectImplicitReceivers import org.jetbrains.kotlin.fir.resolve.collectImplicitReceivers
import org.jetbrains.kotlin.fir.resolve.defaultType
import org.jetbrains.kotlin.fir.types.ConeKotlinType import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.fir.types.FirTypeRef import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.fir.types.coneTypeSafe import org.jetbrains.kotlin.fir.types.coneTypeSafe
import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
abstract class AbstractDiagnosticCollectorVisitor( abstract class AbstractDiagnosticCollectorVisitor(
@set:PrivateForInline var context: PersistentCheckerContext @set:PrivateForInline var context: PersistentCheckerContext,
protected val components: List<AbstractDiagnosticCollectorComponent>,
) : FirDefaultVisitor<Unit, Nothing?>() { ) : FirDefaultVisitor<Unit, Nothing?>() {
protected var currentAction = DiagnosticCollectorDeclarationAction.CHECK_IN_CURRENT_DECLARATION_AND_LOOKUP_FOR_NESTED
protected open fun beforeRunningAllComponentsOnElement(element: FirElement) {}
protected open fun beforeRunningSingleComponentOnElement(element: FirElement) {}
protected abstract fun goToNestedDeclarations(element: FirElement)
protected abstract fun runComponents(element: FirElement)
override fun visitElement(element: FirElement, data: Nothing?) {
if (element is FirAnnotationContainer) {
visitAnnotationContainer(element, data)
return
}
runComponents(element)
goToNestedDeclarations(element)
}
override fun visitAnnotationContainer(annotationContainer: FirAnnotationContainer, data: Nothing?) {
withSuppressedDiagnostics(annotationContainer) {
runComponents(annotationContainer)
goToNestedDeclarations(annotationContainer)
}
}
private fun visitJump(loopJump: FirLoopJump) {
withSuppressedDiagnostics(loopJump) {
runComponents(loopJump)
loopJump.target.labeledElement.takeIf { it is FirErrorLoop }?.accept(this, null)
}
}
override fun visitBreakExpression(breakExpression: FirBreakExpression, data: Nothing?) {
visitJump(breakExpression)
}
override fun visitContinueExpression(continueExpression: FirContinueExpression, data: Nothing?) {
visitJump(continueExpression)
}
private fun visitClassAndChildren(klass: FirClass<*>, type: ConeKotlinType) {
val typeRef = buildResolvedTypeRef {
this.type = type
}
visitWithDeclarationAndReceiver(klass, (klass as? FirRegularClass)?.name, typeRef)
}
override fun visitRegularClass(regularClass: FirRegularClass, data: Nothing?) {
withSuppressedDiagnostics(regularClass) {
visitClassAndChildren(regularClass, regularClass.defaultType())
}
}
override fun visitAnonymousObject(anonymousObject: FirAnonymousObject, data: Nothing?) {
withSuppressedDiagnostics(anonymousObject) {
visitClassAndChildren(anonymousObject, anonymousObject.defaultType())
}
}
override fun visitSimpleFunction(simpleFunction: FirSimpleFunction, data: Nothing?) {
withSuppressedDiagnostics(simpleFunction) {
visitWithDeclarationAndReceiver(simpleFunction, simpleFunction.name, simpleFunction.receiverTypeRef)
}
}
override fun visitConstructor(constructor: FirConstructor, data: Nothing?) {
withSuppressedDiagnostics(constructor) {
visitWithDeclaration(constructor)
}
}
override fun visitAnonymousFunction(anonymousFunction: FirAnonymousFunction, data: Nothing?) {
withSuppressedDiagnostics(anonymousFunction) {
val labelName = anonymousFunction.label?.name?.let { Name.identifier(it) }
visitWithDeclarationAndReceiver(
anonymousFunction,
labelName,
anonymousFunction.receiverTypeRef
)
}
}
override fun visitProperty(property: FirProperty, data: Nothing?) {
withSuppressedDiagnostics(property) {
visitWithDeclaration(property)
}
}
override fun visitPropertyAccessor(propertyAccessor: FirPropertyAccessor, data: Nothing?) {
if (propertyAccessor !is FirDefaultPropertyAccessor) {
val property = context.containingDeclarations.last() as FirProperty
withSuppressedDiagnostics(propertyAccessor) {
visitWithDeclarationAndReceiver(propertyAccessor, property.name, property.receiverTypeRef)
}
}
}
override fun visitValueParameter(valueParameter: FirValueParameter, data: Nothing?) {
withSuppressedDiagnostics(valueParameter) {
visitWithDeclaration(valueParameter)
}
}
override fun visitEnumEntry(enumEntry: FirEnumEntry, data: Nothing?) {
withSuppressedDiagnostics(enumEntry) {
visitWithDeclaration(enumEntry)
}
}
override fun visitFile(file: FirFile, data: Nothing?) {
withSuppressedDiagnostics(file) {
visitWithDeclaration(file)
}
}
override fun visitAnonymousInitializer(anonymousInitializer: FirAnonymousInitializer, data: Nothing?) {
visitWithDeclaration(anonymousInitializer)
}
override fun visitBlock(block: FirBlock, data: Nothing?) {
withSuppressedDiagnostics(block) {
visitExpression(block, data)
}
}
override fun visitTypeRef(typeRef: FirTypeRef, data: Nothing?) {
if (typeRef.source != null && typeRef.source?.kind !is FirFakeSourceElementKind) {
withSuppressedDiagnostics(typeRef) {
runComponents(typeRef)
goToNestedDeclarations(typeRef)
}
}
}
override fun visitResolvedTypeRef(resolvedTypeRef: FirResolvedTypeRef, data: Nothing?) {
super.visitResolvedTypeRef(resolvedTypeRef, data)
resolvedTypeRef.delegatedTypeRef?.accept(this, data)
}
override fun visitFunctionCall(functionCall: FirFunctionCall, data: Nothing?) {
visitWithQualifiedAccess(functionCall)
}
override fun visitQualifiedAccessExpression(qualifiedAccessExpression: FirQualifiedAccessExpression, data: Nothing?) {
visitWithQualifiedAccess(qualifiedAccessExpression)
}
override fun visitGetClassCall(getClassCall: FirGetClassCall, data: Nothing?) {
visitWithGetClassCall(getClassCall)
}
private inline fun visitWithDeclaration(
declaration: FirDeclaration,
block: () -> Unit = { declaration.acceptChildren(this, null) }
) {
if (!currentAction.lookupForNestedDeclaration) return
val action = getDeclarationActionOnDeclarationEnter(declaration)
withDiagnosticsAction(action) {
runComponents(declaration)
withDeclaration(declaration) {
block()
}
}
onDeclarationExit(declaration)
}
private fun visitWithDeclarationAndReceiver(declaration: FirDeclaration, labelName: Name?, receiverTypeRef: FirTypeRef?) {
visitWithDeclaration(declaration) {
withLabelAndReceiverType(
labelName,
declaration,
receiverTypeRef?.coneTypeSafe()
) {
goToNestedDeclarations(declaration)
}
}
}
private fun visitWithQualifiedAccess(qualifiedAccess: FirQualifiedAccess) {
return withQualifiedAccess(qualifiedAccess) {
runComponents(qualifiedAccess)
goToNestedDeclarations(qualifiedAccess)
}
}
private fun visitWithGetClassCall(getClassCall: FirGetClassCall) {
return withGetClassCall(getClassCall) {
runComponents(getClassCall)
goToNestedDeclarations(getClassCall)
}
}
protected open fun getDeclarationActionOnDeclarationEnter(declaration: FirDeclaration): DiagnosticCollectorDeclarationAction =
DiagnosticCollectorDeclarationAction.CHECK_IN_CURRENT_DECLARATION_AND_LOOKUP_FOR_NESTED
protected open fun onDeclarationExit(declaration: FirDeclaration) {}
private inline fun <R> withDiagnosticsAction(action: DiagnosticCollectorDeclarationAction, block: () -> R): R {
val oldAction = currentAction
currentAction = action
return try {
block()
} finally {
currentAction = oldAction
}
}
@OptIn(PrivateForInline::class) @OptIn(PrivateForInline::class)
protected inline fun <R> withQualifiedAccess(qualifiedAccess: FirQualifiedAccess, block: () -> R): R { inline fun <R> withQualifiedAccess(qualifiedAccess: FirQualifiedAccess, block: () -> R): R {
val existingContext = context val existingContext = context
context = context.addQualifiedAccess(qualifiedAccess) context = context.addQualifiedAccess(qualifiedAccess)
try { try {
@@ -36,7 +248,7 @@ abstract class AbstractDiagnosticCollectorVisitor(
@OptIn(PrivateForInline::class) @OptIn(PrivateForInline::class)
protected inline fun <R> withGetClassCall(getClassCall: FirGetClassCall, block: () -> R): R { inline fun <R> withGetClassCall(getClassCall: FirGetClassCall, block: () -> R): R {
val existingContext = context val existingContext = context
context = context.addGetClassCall(getClassCall) context = context.addGetClassCall(getClassCall)
try { try {
@@ -48,7 +260,7 @@ abstract class AbstractDiagnosticCollectorVisitor(
@OptIn(PrivateForInline::class) @OptIn(PrivateForInline::class)
protected inline fun <R> withDeclaration(declaration: FirDeclaration, block: () -> R): R { inline fun <R> withDeclaration(declaration: FirDeclaration, block: () -> R): R {
val existingContext = context val existingContext = context
context = context.addDeclaration(declaration) context = context.addDeclaration(declaration)
try { try {
@@ -60,7 +272,7 @@ abstract class AbstractDiagnosticCollectorVisitor(
@OptIn(PrivateForInline::class) @OptIn(PrivateForInline::class)
protected inline fun <R> withLabelAndReceiverType( inline fun <R> withLabelAndReceiverType(
labelName: Name?, labelName: Name?,
owner: FirDeclaration, owner: FirDeclaration,
type: ConeKotlinType?, type: ConeKotlinType?,
@@ -83,7 +295,7 @@ abstract class AbstractDiagnosticCollectorVisitor(
@OptIn(PrivateForInline::class) @OptIn(PrivateForInline::class)
protected inline fun <R> withSuppressedDiagnostics(annotationContainer: FirAnnotationContainer, block: () -> R): R { inline fun <R> withSuppressedDiagnostics(annotationContainer: FirAnnotationContainer, block: () -> R): R {
val existingContext = context val existingContext = context
addSuppressedDiagnosticsToContext(annotationContainer) addSuppressedDiagnosticsToContext(annotationContainer)
return try { return try {
@@ -95,7 +307,7 @@ abstract class AbstractDiagnosticCollectorVisitor(
@OptIn(PrivateForInline::class) @OptIn(PrivateForInline::class)
protected fun addSuppressedDiagnosticsToContext(annotationContainer: FirAnnotationContainer) { fun addSuppressedDiagnosticsToContext(annotationContainer: FirAnnotationContainer) {
val arguments = AbstractDiagnosticCollector.getDiagnosticsSuppressedForContainer(annotationContainer) ?: return val arguments = AbstractDiagnosticCollector.getDiagnosticsSuppressedForContainer(annotationContainer) ?: return
context = context.addSuppressedDiagnostics( context = context.addSuppressedDiagnostics(
arguments, arguments,
@@ -5,237 +5,27 @@
package org.jetbrains.kotlin.fir.analysis.collectors package org.jetbrains.kotlin.fir.analysis.collectors
import org.jetbrains.kotlin.fir.FirAnnotationContainer
import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.analysis.checkers.context.PersistentCheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.PersistentCheckerContext
import org.jetbrains.kotlin.fir.analysis.collectors.components.AbstractDiagnosticCollectorComponent import org.jetbrains.kotlin.fir.analysis.collectors.components.AbstractDiagnosticCollectorComponent
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.resolve.defaultType
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.fir.types.coneTypeSafe
import org.jetbrains.kotlin.name.Name
open class CheckerRunningDiagnosticCollectorVisitor( open class CheckerRunningDiagnosticCollectorVisitor(
context: PersistentCheckerContext, context: PersistentCheckerContext,
private val components: List<AbstractDiagnosticCollectorComponent> components: List<AbstractDiagnosticCollectorComponent>
) : AbstractDiagnosticCollectorVisitor(context) { ) : AbstractDiagnosticCollectorVisitor(context, components) {
private var currentAction = DiagnosticCollectorDeclarationAction.CHECK_IN_CURRENT_DECLARATION_AND_LOOKUP_FOR_NESTED protected val session get() = context.session
protected open fun beforeRunningAllComponentsOnElement(element: FirElement) {} override fun goToNestedDeclarations(element: FirElement) {
protected open fun beforeRunningSingleComponentOnElement(element: FirElement) {}
private fun <T : FirElement> T.runComponents() {
if (currentAction.checkInCurrentDeclaration) {
beforeRunningAllComponentsOnElement(this)
components.forEach {
beforeRunningSingleComponentOnElement(this)
this.accept(it, context)
}
}
}
override fun visitElement(element: FirElement, data: Nothing?) {
if (element is FirAnnotationContainer) {
visitAnnotationContainer(element, data)
return
}
element.runComponents()
element.acceptChildren(this, null) element.acceptChildren(this, null)
} }
override fun visitAnnotationContainer(annotationContainer: FirAnnotationContainer, data: Nothing?) { override fun runComponents(element: FirElement) {
withSuppressedDiagnostics(annotationContainer) { if (currentAction.checkInCurrentDeclaration) {
annotationContainer.runComponents() beforeRunningAllComponentsOnElement(element)
annotationContainer.acceptChildren(this, null) components.forEach {
} beforeRunningSingleComponentOnElement(element)
} element.accept(it, context)
private fun visitJump(loopJump: FirLoopJump) {
withSuppressedDiagnostics(loopJump) {
loopJump.runComponents()
loopJump.target.labeledElement.takeIf { it is FirErrorLoop }?.accept(this, null)
}
}
override fun visitBreakExpression(breakExpression: FirBreakExpression, data: Nothing?) {
visitJump(breakExpression)
}
override fun visitContinueExpression(continueExpression: FirContinueExpression, data: Nothing?) {
visitJump(continueExpression)
}
private fun visitClassAndChildren(klass: FirClass<*>, type: ConeKotlinType) {
val typeRef = buildResolvedTypeRef {
this.type = type
}
visitWithDeclarationAndReceiver(klass, (klass as? FirRegularClass)?.name, typeRef)
}
override fun visitRegularClass(regularClass: FirRegularClass, data: Nothing?) {
withSuppressedDiagnostics(regularClass) {
visitClassAndChildren(regularClass, regularClass.defaultType())
}
}
override fun visitAnonymousObject(anonymousObject: FirAnonymousObject, data: Nothing?) {
withSuppressedDiagnostics(anonymousObject) {
visitClassAndChildren(anonymousObject, anonymousObject.defaultType())
}
}
override fun visitSimpleFunction(simpleFunction: FirSimpleFunction, data: Nothing?) {
withSuppressedDiagnostics(simpleFunction) {
visitWithDeclarationAndReceiver(simpleFunction, simpleFunction.name, simpleFunction.receiverTypeRef)
}
}
override fun visitConstructor(constructor: FirConstructor, data: Nothing?) {
withSuppressedDiagnostics(constructor) {
visitWithDeclaration(constructor)
}
}
override fun visitAnonymousFunction(anonymousFunction: FirAnonymousFunction, data: Nothing?) {
withSuppressedDiagnostics(anonymousFunction) {
val labelName = anonymousFunction.label?.name?.let { Name.identifier(it) }
visitWithDeclarationAndReceiver(
anonymousFunction,
labelName,
anonymousFunction.receiverTypeRef
)
}
}
override fun visitProperty(property: FirProperty, data: Nothing?) {
withSuppressedDiagnostics(property) {
visitWithDeclaration(property)
}
}
override fun visitPropertyAccessor(propertyAccessor: FirPropertyAccessor, data: Nothing?) {
if (propertyAccessor !is FirDefaultPropertyAccessor) {
val property = context.containingDeclarations.last() as FirProperty
withSuppressedDiagnostics(propertyAccessor) {
visitWithDeclarationAndReceiver(propertyAccessor, property.name, property.receiverTypeRef)
} }
} }
} }
override fun visitValueParameter(valueParameter: FirValueParameter, data: Nothing?) {
withSuppressedDiagnostics(valueParameter) {
visitWithDeclaration(valueParameter)
}
}
override fun visitEnumEntry(enumEntry: FirEnumEntry, data: Nothing?) {
withSuppressedDiagnostics(enumEntry) {
visitWithDeclaration(enumEntry)
}
}
override fun visitFile(file: FirFile, data: Nothing?) {
withSuppressedDiagnostics(file) {
visitWithDeclaration(file)
}
}
override fun visitAnonymousInitializer(anonymousInitializer: FirAnonymousInitializer, data: Nothing?) {
visitWithDeclaration(anonymousInitializer)
}
override fun visitBlock(block: FirBlock, data: Nothing?) {
withSuppressedDiagnostics(block) {
visitExpression(block, data)
}
}
override fun visitTypeRef(typeRef: FirTypeRef, data: Nothing?) {
if (typeRef.source != null && typeRef.source?.kind !is FirFakeSourceElementKind) {
withSuppressedDiagnostics(typeRef) {
typeRef.runComponents()
typeRef.acceptChildren(this, data)
}
}
}
override fun visitResolvedTypeRef(resolvedTypeRef: FirResolvedTypeRef, data: Nothing?) {
super.visitResolvedTypeRef(resolvedTypeRef, data)
resolvedTypeRef.delegatedTypeRef?.accept(this, data)
}
override fun visitFunctionCall(functionCall: FirFunctionCall, data: Nothing?) {
visitWithQualifiedAccess(functionCall)
}
override fun visitQualifiedAccessExpression(qualifiedAccessExpression: FirQualifiedAccessExpression, data: Nothing?) {
visitWithQualifiedAccess(qualifiedAccessExpression)
}
override fun visitGetClassCall(getClassCall: FirGetClassCall, data: Nothing?) {
visitWithGetClassCall(getClassCall)
}
private inline fun visitWithDeclaration(
declaration: FirDeclaration,
block: () -> Unit = { declaration.acceptChildren(this, null) }
) {
if (!currentAction.lookupForNestedDeclaration) return
val action = getDeclarationActionOnDeclarationEnter(declaration)
withDiagnosticsAction(action) {
declaration.runComponents()
withDeclaration(declaration) {
block()
}
}
onDeclarationExit(declaration)
}
private fun visitWithDeclarationAndReceiver(declaration: FirDeclaration, labelName: Name?, receiverTypeRef: FirTypeRef?) {
visitWithDeclaration(declaration) {
withLabelAndReceiverType(
labelName,
declaration,
receiverTypeRef?.coneTypeSafe()
) {
declaration.acceptChildren(this, null)
}
}
}
private fun visitWithQualifiedAccess(qualifiedAccess: FirQualifiedAccess) {
return withQualifiedAccess(qualifiedAccess) {
qualifiedAccess.runComponents()
qualifiedAccess.acceptChildren(this, null)
}
}
private fun visitWithGetClassCall(getClassCall: FirGetClassCall) {
return withGetClassCall(getClassCall) {
getClassCall.runComponents()
getClassCall.acceptChildren(this, null)
}
}
protected open fun getDeclarationActionOnDeclarationEnter(declaration: FirDeclaration): DiagnosticCollectorDeclarationAction =
DiagnosticCollectorDeclarationAction.CHECK_IN_CURRENT_DECLARATION_AND_LOOKUP_FOR_NESTED
protected open fun onDeclarationExit(declaration: FirDeclaration) {}
private inline fun <R> withDiagnosticsAction(action: DiagnosticCollectorDeclarationAction, block: () -> R): R {
val oldAction = currentAction
currentAction = action
return try {
block()
} finally {
currentAction = oldAction
}
}
} }
@@ -36,6 +36,8 @@ interface SessionHolder {
val scopeSession: ScopeSession val scopeSession: ScopeSession
} }
data class SessionHolderImpl(override val session: FirSession, override val scopeSession: ScopeSession): SessionHolder
abstract class BodyResolveComponents : SessionHolder { abstract class BodyResolveComponents : SessionHolder {
abstract val returnTypeCalculator: ReturnTypeCalculator abstract val returnTypeCalculator: ReturnTypeCalculator
abstract val implicitReceiverStack: ImplicitReceiverStack abstract val implicitReceiverStack: ImplicitReceiverStack
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.fir.analysis.checkers.context.PersistentCheckerConte
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.DeclarationCheckers import org.jetbrains.kotlin.fir.analysis.checkers.declaration.DeclarationCheckers
import org.jetbrains.kotlin.fir.analysis.checkers.expression.ExpressionCheckers import org.jetbrains.kotlin.fir.analysis.checkers.expression.ExpressionCheckers
import org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector import org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector
import org.jetbrains.kotlin.fir.analysis.collectors.CheckerRunningDiagnosticCollectorVisitor
import org.jetbrains.kotlin.fir.analysis.collectors.components.* import org.jetbrains.kotlin.fir.analysis.collectors.components.*
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnostic import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnostic
@@ -34,23 +35,6 @@ internal abstract class AbstractFirIdeDiagnosticsCollector(
) : AbstractDiagnosticCollector( ) : AbstractDiagnosticCollector(
session session
) { ) {
private val beforeElementDiagnosticCollectionHandler: BeforeElementDiagnosticCollectionHandler? =
session.beforeElementDiagnosticCollectionHandler
@Suppress("LeakingThis")
override val visitor = run {
val returnTypeCalculator = createReturnTypeCalculatorForIDE(
session,
ScopeSession(),
ImplicitBodyResolveComputationSession(),
::FirIdeDesignatedBodyResolveTransformerForReturnTypeCalculator
)
CollectingVisitor(
PersistentCheckerContext(this, returnTypeCalculator),
components
)
}
init { init {
val declarationCheckers = CheckersFactory.createDeclarationCheckers(useExtendedCheckers) val declarationCheckers = CheckersFactory.createDeclarationCheckers(useExtendedCheckers)
val expressionCheckers = CheckersFactory.createExpressionCheckers(useExtendedCheckers) val expressionCheckers = CheckersFactory.createExpressionCheckers(useExtendedCheckers)
@@ -80,19 +64,6 @@ internal abstract class AbstractFirIdeDiagnosticsCollector(
reporter = Reporter() reporter = Reporter()
} }
inner class CollectingVisitor(
context: PersistentCheckerContext,
components: List<AbstractDiagnosticCollectorComponent>
) : DiagnosticCollectingVisitor(context, components) {
override fun beforeRunningSingleComponentOnElement(element: FirElement) {
checkCanceled()
}
override fun beforeRunningAllComponentsOnElement(element: FirElement) {
beforeElementDiagnosticCollectionHandler?.beforeCollectingForElement(element)
}
}
override fun getCollectedDiagnostics(): List<FirDiagnostic<*>> { override fun getCollectedDiagnostics(): List<FirDiagnostic<*>> {
// Not necessary in IDE // Not necessary in IDE
@@ -5,8 +5,22 @@
package org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics package org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics
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.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.SessionHolderImpl
import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.fir.PersistenceContextCollector
internal abstract class FileStructureElementDiagnosticRetriever { internal abstract class FileStructureElementDiagnosticRetriever {
abstract fun retrieve(firFile: FirFile, collector: FileStructureElementDiagnosticsCollector): FileStructureElementDiagnosticList abstract fun retrieve(firFile: FirFile, collector: FileStructureElementDiagnosticsCollector): FileStructureElementDiagnosticList
}
internal class SingleNonLocalDeclarationDiagnosticRetriever(
private val declaration: FirDeclaration
) : FileStructureElementDiagnosticRetriever() {
override fun retrieve(firFile: FirFile, collector: FileStructureElementDiagnosticsCollector): FileStructureElementDiagnosticList {
val sessionHolder = SessionHolderImpl(firFile.session, ScopeSession())
val context = PersistenceContextCollector.collectContext(sessionHolder, firFile, declaration)
return collector.collectForStructureElement(declaration, context)
}
} }
@@ -7,10 +7,12 @@ package org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.analysis.checkers.context.PersistentCheckerContext
import org.jetbrains.kotlin.fir.analysis.collectors.DiagnosticCollectorDeclarationAction import org.jetbrains.kotlin.fir.analysis.collectors.DiagnosticCollectorDeclarationAction
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic import org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic
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.idea.fir.low.level.api.diagnostics.fir.PersistentCheckerContextFactory
import org.jetbrains.kotlin.idea.fir.low.level.api.util.addValueFor import org.jetbrains.kotlin.idea.fir.low.level.api.util.addValueFor
internal class FileStructureElementDiagnosticsCollector private constructor(private val useExtendedCheckers: Boolean) { internal class FileStructureElementDiagnosticsCollector private constructor(private val useExtendedCheckers: Boolean) {
@@ -20,22 +22,27 @@ internal class FileStructureElementDiagnosticsCollector private constructor(priv
} }
fun collectForStructureElement( fun collectForStructureElement(
firFile: FirFile, firDeclaration: FirDeclaration,
initialContext: PersistentCheckerContext?,
onDeclarationExit: (FirDeclaration) -> Unit = {}, onDeclarationExit: (FirDeclaration) -> Unit = {},
onDeclarationEnter: (FirDeclaration) -> DiagnosticCollectorDeclarationAction, onDeclarationEnter: (FirDeclaration) -> DiagnosticCollectorDeclarationAction = {
DiagnosticCollectorDeclarationAction.CHECK_IN_CURRENT_DECLARATION_AND_LOOKUP_FOR_NESTED
},
): FileStructureElementDiagnosticList = ): FileStructureElementDiagnosticList =
FirIdeStructureElementDiagnosticsCollector( FirIdeStructureElementDiagnosticsCollector(
firFile.session, firDeclaration.session,
initialContext,
useExtendedCheckers, useExtendedCheckers,
onDeclarationEnter, onDeclarationEnter,
onDeclarationExit onDeclarationExit
).let { collector -> ).let { collector ->
collector.collectDiagnostics(firFile) collector.collectDiagnostics(firDeclaration)
FileStructureElementDiagnosticList(collector.result) FileStructureElementDiagnosticList(collector.result)
} }
private class FirIdeStructureElementDiagnosticsCollector( private class FirIdeStructureElementDiagnosticsCollector(
session: FirSession, session: FirSession,
initialContext: PersistentCheckerContext?,
useExtendedCheckers: Boolean, useExtendedCheckers: Boolean,
private val onDeclarationEnter: (FirDeclaration) -> DiagnosticCollectorDeclarationAction, private val onDeclarationEnter: (FirDeclaration) -> DiagnosticCollectorDeclarationAction,
private val onDeclarationExit: (FirDeclaration) -> Unit private val onDeclarationExit: (FirDeclaration) -> Unit
@@ -49,13 +56,18 @@ internal class FileStructureElementDiagnosticsCollector private constructor(priv
result.addValueFor(diagnostic.psiElement, diagnostic) result.addValueFor(diagnostic.psiElement, diagnostic)
} }
override fun getDeclarationActionOnDeclarationEnter( override val visitor = object : FirIdeDiagnosticVisitor(
declaration: FirDeclaration, initialContext ?: PersistentCheckerContextFactory.createEmptyPersistenceCheckerContext(this),
): DiagnosticCollectorDeclarationAction = components
onDeclarationEnter.invoke(declaration) ) {
override fun getDeclarationActionOnDeclarationEnter(
declaration: FirDeclaration,
): DiagnosticCollectorDeclarationAction =
onDeclarationEnter.invoke(declaration)
override fun onDeclarationExit(declaration: FirDeclaration) { override fun onDeclarationExit(declaration: FirDeclaration) {
onDeclarationExit.invoke(declaration) onDeclarationExit.invoke(declaration)
}
} }
} }
} }
@@ -0,0 +1,27 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.PersistentCheckerContext
import org.jetbrains.kotlin.fir.analysis.collectors.CheckerRunningDiagnosticCollectorVisitor
import org.jetbrains.kotlin.fir.analysis.collectors.components.AbstractDiagnosticCollectorComponent
import org.jetbrains.kotlin.fir.resolve.SessionHolder
import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.fir.PersistentCheckerContextFactory
import org.jetbrains.kotlin.idea.fir.low.level.api.util.checkCanceled
open class FirIdeDiagnosticVisitor(
context: PersistentCheckerContext,
components: List<AbstractDiagnosticCollectorComponent>
) : CheckerRunningDiagnosticCollectorVisitor(context, components) {
override fun beforeRunningSingleComponentOnElement(element: FirElement) {
checkCanceled()
}
override fun beforeRunningAllComponentsOnElement(element: FirElement) {
session.beforeElementDiagnosticCollectionHandler?.beforeCollectingForElement(element)
}
}
@@ -0,0 +1,63 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.fir
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.PersistentCheckerContext
import org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.renderWithType
import org.jetbrains.kotlin.fir.resolve.SessionHolder
import org.jetbrains.kotlin.idea.fir.low.level.api.util.collectDesignation
private class ContextCollectingDiagnosticCollectorVisitor private constructor(
sessionHolder: SessionHolder,
private val designation: Iterator<FirDeclaration>,
) : AbstractDiagnosticCollectorVisitor(
PersistentCheckerContextFactory.createEmptyPersistenceCheckerContext(sessionHolder),
components = emptyList()
) {
private var savedContext: PersistentCheckerContext? = null
override fun goToNestedDeclarations(element: FirElement) {
if (designation.hasNext()) {
designation.next().accept(this, null)
} else {
savedContext = context
}
}
override fun runComponents(element: FirElement) {}
companion object {
fun collect(sessionHolder: SessionHolder, firFile: FirFile, designation: List<FirDeclaration>): PersistentCheckerContext {
val visitor = ContextCollectingDiagnosticCollectorVisitor(sessionHolder, designation.iterator())
firFile.accept(visitor, null)
return visitor.savedContext
?: error("Context was not saved")
}
}
}
internal object PersistenceContextCollector {
fun collectContext(
sessionHolder: SessionHolder,
firFile: FirFile,
declaration: FirDeclaration,
): PersistentCheckerContext {
val isLocal = when (declaration) {
is FirClassLikeDeclaration<*> -> declaration.symbol.classId.isLocal
is FirCallableDeclaration<*> -> declaration.symbol.callableId.isLocal
else -> error("Unsupported declaration ${declaration.renderWithType()}")
}
require(!isLocal) {
"Cannot collect context for local declaration ${declaration.renderWithType()}"
}
val designation = declaration.collectDesignation()
return ContextCollectingDiagnosticCollectorVisitor.collect(sessionHolder, firFile, designation)
}
}
@@ -0,0 +1,25 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.fir
import org.jetbrains.kotlin.fir.analysis.checkers.context.PersistentCheckerContext
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.SessionHolder
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.ImplicitBodyResolveComputationSession
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.createReturnTypeCalculatorForIDE
import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FirIdeDesignatedBodyResolveTransformerForReturnTypeCalculator
internal object PersistentCheckerContextFactory {
fun createEmptyPersistenceCheckerContext(sessionHolder: SessionHolder): PersistentCheckerContext {
val returnTypeCalculator = createReturnTypeCalculatorForIDE(
sessionHolder.session,
ScopeSession(),
ImplicitBodyResolveComputationSession(),
::FirIdeDesignatedBodyResolveTransformerForReturnTypeCalculator
)
return PersistentCheckerContext(sessionHolder, returnTypeCalculator)
}
}
@@ -44,7 +44,7 @@ internal class FileStructure(
val structureElement = structureElements.compute(declaration) { _, structureElement -> val structureElement = structureElements.compute(declaration) { _, structureElement ->
when { when {
structureElement == null -> createStructureElement(declaration) structureElement == null -> createStructureElement(declaration)
structureElement is ReanalyzableStructureElement<KtDeclaration> && !structureElement.isUpToDate() -> { structureElement is ReanalyzableStructureElement<KtDeclaration, *> && !structureElement.isUpToDate() -> {
structureElement.reanalyze( structureElement.reanalyze(
newKtDeclaration = declaration as KtDeclaration, newKtDeclaration = declaration as KtDeclaration,
cache = moduleFileCache, cache = moduleFileCache,
@@ -90,7 +90,7 @@ internal class FileStructure(
override fun visitDeclaration(dcl: KtDeclaration) { override fun visitDeclaration(dcl: KtDeclaration) {
val structureElement = getStructureElementFor(dcl) val structureElement = getStructureElementFor(dcl)
structureElements += structureElement structureElements += structureElement
if (structureElement !is ReanalyzableStructureElement<*>) { if (structureElement !is ReanalyzableStructureElement<*, *>) {
dcl.acceptChildren(this) dcl.acceptChildren(this)
} }
} }
@@ -12,10 +12,12 @@ import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.*
import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.FileStructureElementDiagnosticList import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.FileStructureElementDiagnosticList
import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.FileStructureElementDiagnosticRetriever import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.FileStructureElementDiagnosticRetriever
import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.FileStructureElementDiagnostics import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.FileStructureElementDiagnostics
import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.FileStructureElementDiagnosticsCollector import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.FileStructureElementDiagnosticsCollector
import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.SingleNonLocalDeclarationDiagnosticRetriever
import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FirTowerDataContextCollector import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FirTowerDataContextCollector
import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.ModuleFileCache import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.ModuleFileCache
import org.jetbrains.kotlin.idea.fir.low.level.api.lazy.resolve.FirLazyDeclarationResolver import org.jetbrains.kotlin.idea.fir.low.level.api.lazy.resolve.FirLazyDeclarationResolver
@@ -31,9 +33,11 @@ internal sealed class FileStructureElement(val firFile: FirFile) {
abstract val diagnostics: FileStructureElementDiagnostics abstract val diagnostics: FileStructureElementDiagnostics
} }
internal sealed class ReanalyzableStructureElement<KT : KtDeclaration>(firFile: FirFile) : FileStructureElement(firFile) { internal sealed class ReanalyzableStructureElement<KT : KtDeclaration, S: AbstractFirBasedSymbol<*>>(
firFile: FirFile,
protected val firSymbol: S,
) : FileStructureElement(firFile) {
abstract override val psi: KtDeclaration abstract override val psi: KtDeclaration
abstract val firSymbol: AbstractFirBasedSymbol<*>
abstract val timestamp: Long abstract val timestamp: Long
/** /**
@@ -46,36 +50,11 @@ internal sealed class ReanalyzableStructureElement<KT : KtDeclaration>(firFile:
firLazyDeclarationResolver: FirLazyDeclarationResolver, firLazyDeclarationResolver: FirLazyDeclarationResolver,
firIdeProvider: FirIdeProvider, firIdeProvider: FirIdeProvider,
towerDataContextCollector: FirTowerDataContextCollector, towerDataContextCollector: FirTowerDataContextCollector,
): ReanalyzableStructureElement<KT> ): ReanalyzableStructureElement<KT, S>
fun isUpToDate(): Boolean = psi.getModificationStamp() == timestamp fun isUpToDate(): Boolean = psi.getModificationStamp() == timestamp
override val diagnostics = FileStructureElementDiagnostics(firFile, FileStructureElementSingleDeclarationDiagnosticRetriever()) override val diagnostics = FileStructureElementDiagnostics(firFile, SingleNonLocalDeclarationDiagnosticRetriever(firSymbol.fir as FirDeclaration))
inner class FileStructureElementSingleDeclarationDiagnosticRetriever : FileStructureElementDiagnosticRetriever() {
override fun retrieve(firFile: FirFile, collector: FileStructureElementDiagnosticsCollector): FileStructureElementDiagnosticList {
var inCurrentDeclaration = false
val declaration = firSymbol.fir as FirDeclaration
return collector.collectForStructureElement(
firFile,
onDeclarationEnter = { firDeclaration ->
when {
firDeclaration == declaration -> {
inCurrentDeclaration = true
DiagnosticCollectorDeclarationAction.CHECK_IN_CURRENT_DECLARATION_AND_LOOKUP_FOR_NESTED
}
inCurrentDeclaration -> DiagnosticCollectorDeclarationAction.CHECK_IN_CURRENT_DECLARATION_AND_LOOKUP_FOR_NESTED
else -> DiagnosticCollectorDeclarationAction.DO_NOT_CHECK_IN_CURRENT_DECLARATION_AND_LOOKUP_FOR_NESTED
}
},
onDeclarationExit = { firDeclaration ->
if (declaration == firDeclaration) {
inCurrentDeclaration = false
}
}
)
}
}
companion object { companion object {
val recorder = FirElementsRecorder() val recorder = FirElementsRecorder()
@@ -85,9 +64,9 @@ internal sealed class ReanalyzableStructureElement<KT : KtDeclaration>(firFile:
internal class ReanalyzableFunctionStructureElement( internal class ReanalyzableFunctionStructureElement(
firFile: FirFile, firFile: FirFile,
override val psi: KtNamedFunction, override val psi: KtNamedFunction,
override val firSymbol: FirFunctionSymbol<*>, firSymbol: FirFunctionSymbol<*>,
override val timestamp: Long override val timestamp: Long
) : ReanalyzableStructureElement<KtNamedFunction>(firFile) { ) : ReanalyzableStructureElement<KtNamedFunction, FirFunctionSymbol<*>>(firFile, firSymbol) {
override val mappings: Map<KtElement, FirElement> = override val mappings: Map<KtElement, FirElement> =
FirElementsRecorder.recordElementsFrom(firSymbol.fir, recorder) FirElementsRecorder.recordElementsFrom(firSymbol.fir, recorder)
@@ -125,9 +104,9 @@ internal class ReanalyzableFunctionStructureElement(
internal class ReanalyzablePropertyStructureElement( internal class ReanalyzablePropertyStructureElement(
firFile: FirFile, firFile: FirFile,
override val psi: KtProperty, override val psi: KtProperty,
override val firSymbol: FirPropertySymbol, firSymbol: FirPropertySymbol,
override val timestamp: Long override val timestamp: Long
) : ReanalyzableStructureElement<KtProperty>(firFile) { ) : ReanalyzableStructureElement<KtProperty, FirPropertySymbol>(firFile, firSymbol) {
override val mappings: Map<KtElement, FirElement> = override val mappings: Map<KtElement, FirElement> =
FirElementsRecorder.recordElementsFrom(firSymbol.fir, recorder) FirElementsRecorder.recordElementsFrom(firSymbol.fir, recorder)
@@ -164,52 +143,13 @@ internal class ReanalyzablePropertyStructureElement(
internal class NonReanalyzableDeclarationStructureElement( internal class NonReanalyzableDeclarationStructureElement(
firFile: FirFile, firFile: FirFile,
private val fir: FirDeclaration, fir: FirDeclaration,
override val psi: KtDeclaration, override val psi: KtDeclaration,
) : FileStructureElement(firFile) { ) : FileStructureElement(firFile) {
override val mappings: Map<KtElement, FirElement> = override val mappings: Map<KtElement, FirElement> =
FirElementsRecorder.recordElementsFrom(fir, recorder) FirElementsRecorder.recordElementsFrom(fir, recorder)
override val diagnostics = FileStructureElementDiagnostics(firFile, DiagnosticRetriever()) override val diagnostics = FileStructureElementDiagnostics(firFile, SingleNonLocalDeclarationDiagnosticRetriever(fir))
private inner class DiagnosticRetriever : FileStructureElementDiagnosticRetriever() {
override fun retrieve(firFile: FirFile, collector: FileStructureElementDiagnosticsCollector): FileStructureElementDiagnosticList {
var inCurrentDeclaration = false
return collector.collectForStructureElement(
firFile,
onDeclarationEnter = { firDeclaration ->
when {
firDeclaration.isGeneratedDeclaration -> when {
// a generated primary constructor need to be checked. For example it may have a delegated super constructor
// call or some annotations
firDeclaration is FirConstructor && firDeclaration.isPrimary ->
DiagnosticCollectorDeclarationAction.CHECK_IN_CURRENT_DECLARATION_AND_LOOKUP_FOR_NESTED
// Some generated declaration contains structures that we need to check. For example the FIR representation of an
// enum entry initializer, when present, is a generated anonymous object of kind `ENUM_ENTRY`.
else -> DiagnosticCollectorDeclarationAction.DO_NOT_CHECK_IN_CURRENT_DECLARATION_AND_LOOKUP_FOR_NESTED
}
firDeclaration is FirFile -> DiagnosticCollectorDeclarationAction.DO_NOT_CHECK_IN_CURRENT_DECLARATION_AND_LOOKUP_FOR_NESTED
firDeclaration == fir -> {
inCurrentDeclaration = true
DiagnosticCollectorDeclarationAction.CHECK_IN_CURRENT_DECLARATION_AND_LOOKUP_FOR_NESTED
}
FileElementFactory.isReanalyzableContainer(firDeclaration.ktDeclaration) -> {
DiagnosticCollectorDeclarationAction.SKIP
}
inCurrentDeclaration -> {
DiagnosticCollectorDeclarationAction.CHECK_IN_CURRENT_DECLARATION_AND_LOOKUP_FOR_NESTED
}
else -> DiagnosticCollectorDeclarationAction.DO_NOT_CHECK_IN_CURRENT_DECLARATION_AND_LOOKUP_FOR_NESTED
}
},
onDeclarationExit = { firDeclaration ->
if (firDeclaration == fir) {
inCurrentDeclaration = false
}
},
)
}
}
companion object { companion object {
@@ -243,7 +183,7 @@ internal class RootStructureElement(
private object DiagnosticRetriever : FileStructureElementDiagnosticRetriever() { private object DiagnosticRetriever : FileStructureElementDiagnosticRetriever() {
override fun retrieve(firFile: FirFile, collector: FileStructureElementDiagnosticsCollector): FileStructureElementDiagnosticList { override fun retrieve(firFile: FirFile, collector: FileStructureElementDiagnosticsCollector): FileStructureElementDiagnosticList {
return collector.collectForStructureElement(firFile) { firDeclaration -> return collector.collectForStructureElement(firFile, initialContext = null) { firDeclaration ->
if (firDeclaration is FirFile) DiagnosticCollectorDeclarationAction.CHECK_IN_CURRENT_DECLARATION_AND_DO_NOT_LOOKUP_FOR_NESTED if (firDeclaration is FirFile) DiagnosticCollectorDeclarationAction.CHECK_IN_CURRENT_DECLARATION_AND_DO_NOT_LOOKUP_FOR_NESTED
else DiagnosticCollectorDeclarationAction.SKIP else DiagnosticCollectorDeclarationAction.SKIP
} }