FIR IDE: separate diagnostics collection and checker context collection
This commit is contained in:
+2
-2
@@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+222
-10
@@ -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,
|
||||||
|
|||||||
+10
-220
@@ -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
|
||||||
|
|||||||
+1
-30
@@ -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
|
||||||
|
|||||||
+14
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
+22
-10
@@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+27
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
+63
@@ -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)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+25
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-2
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-75
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user