diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/context/CheckerContext.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/context/CheckerContext.kt index 50f8ae30f35..02bdebb26c5 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/context/CheckerContext.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/context/CheckerContext.kt @@ -11,17 +11,18 @@ import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentSetOf import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.FirDeclaration +import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess import org.jetbrains.kotlin.fir.resolve.ImplicitReceiverStack import org.jetbrains.kotlin.fir.resolve.PersistentImplicitReceiverStack import org.jetbrains.kotlin.fir.resolve.SessionHolder import org.jetbrains.kotlin.fir.resolve.calls.ImplicitReceiverValue -import org.jetbrains.kotlin.fir.resolve.calls.InapplicableArgumentDiagnostic import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculator import org.jetbrains.kotlin.name.Name abstract class CheckerContext { abstract val implicitReceiverStack: ImplicitReceiverStack abstract val containingDeclarations: List + abstract val qualifiedAccesses: List abstract val sessionHolder: SessionHolder abstract val returnTypeCalculator: ReturnTypeCalculator abstract val suppressedDiagnostics: Set @@ -48,6 +49,7 @@ abstract class CheckerContext { class PersistentCheckerContext private constructor( override val implicitReceiverStack: PersistentImplicitReceiverStack, override val containingDeclarations: PersistentList, + override val qualifiedAccesses: PersistentList, override val sessionHolder: SessionHolder, override val returnTypeCalculator: ReturnTypeCalculator, override val suppressedDiagnostics: PersistentSet, @@ -58,6 +60,7 @@ class PersistentCheckerContext private constructor( constructor(sessionHolder: SessionHolder, returnTypeCalculator: ReturnTypeCalculator) : this( PersistentImplicitReceiverStack(), persistentListOf(), + persistentListOf(), sessionHolder, returnTypeCalculator, persistentSetOf(), @@ -70,6 +73,7 @@ class PersistentCheckerContext private constructor( return PersistentCheckerContext( implicitReceiverStack.add(name, value), containingDeclarations, + qualifiedAccesses, sessionHolder, returnTypeCalculator, suppressedDiagnostics, @@ -83,6 +87,21 @@ class PersistentCheckerContext private constructor( return PersistentCheckerContext( implicitReceiverStack, containingDeclarations.add(declaration), + qualifiedAccesses, + sessionHolder, + returnTypeCalculator, + suppressedDiagnostics, + allInfosSuppressed, + allWarningsSuppressed, + allErrorsSuppressed + ) + } + + fun addQualifiedAccess(qualifiedAccess: FirQualifiedAccess): PersistentCheckerContext { + return PersistentCheckerContext( + implicitReceiverStack, + containingDeclarations, + qualifiedAccesses.add(qualifiedAccess), sessionHolder, returnTypeCalculator, suppressedDiagnostics, @@ -102,6 +121,7 @@ class PersistentCheckerContext private constructor( return PersistentCheckerContext( implicitReceiverStack, containingDeclarations, + qualifiedAccesses, sessionHolder, returnTypeCalculator, suppressedDiagnostics.addAll(diagnosticNames), diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/AbstractDiagnosticCollector.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/AbstractDiagnosticCollector.kt index 8591c9865dd..679b77a82cc 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/AbstractDiagnosticCollector.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/AbstractDiagnosticCollector.kt @@ -208,6 +208,14 @@ abstract class AbstractDiagnosticCollector( resolvedTypeRef.delegatedTypeRef?.accept(this, data) } + override fun visitFunctionCall(functionCall: FirFunctionCall, data: Nothing?) { + visitWithQualifiedAccess(functionCall) + } + + override fun visitQualifiedAccessExpression(qualifiedAccessExpression: FirQualifiedAccessExpression, data: Nothing?) { + visitWithQualifiedAccess(qualifiedAccessExpression) + } + private inline fun visitWithDeclaration( declaration: FirDeclaration, block: () -> Unit = { declaration.acceptChildren(this, null) } @@ -237,6 +245,17 @@ abstract class AbstractDiagnosticCollector( } } } + + private fun visitWithQualifiedAccess(qualifiedAccess: FirQualifiedAccess) { + val existingContext = context + context = context.addQualifiedAccess(qualifiedAccess) + try { + qualifiedAccess.runComponents() + qualifiedAccess.acceptChildren(this, null) + } finally { + context = existingContext + } + } } protected open fun onDeclarationEnter(declaration: FirDeclaration): DiagnosticCollectorDeclarationAction = diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/ErrorNodeDiagnosticCollectorComponent.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/ErrorNodeDiagnosticCollectorComponent.kt index 97fe8d669e2..87a7ba8203f 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/ErrorNodeDiagnosticCollectorComponent.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/ErrorNodeDiagnosticCollectorComponent.kt @@ -34,7 +34,8 @@ class ErrorNodeDiagnosticCollectorComponent(collector: AbstractDiagnosticCollect } override fun visitErrorNamedReference(errorNamedReference: FirErrorNamedReference, data: CheckerContext) { - val source = errorNamedReference.source ?: return + val source = data.qualifiedAccesses.lastOrNull()?.source?.takeIf { it.elementType == KtNodeTypes.DOT_QUALIFIED_EXPRESSION } + ?: errorNamedReference.source ?: return // Don't report duplicated unresolved reference on annotation entry (already reported on its type) if (source.elementType == KtNodeTypes.ANNOTATION_ENTRY && errorNamedReference.diagnostic is ConeUnresolvedNameError) return reportFirDiagnostic(errorNamedReference.diagnostic, source, reporter, data)