FIR: report resolve-time errors on qualified access instead of reference

This commit is contained in:
Mikhail Glukhikh
2021-02-19 15:19:22 +03:00
parent 5ffa72f1fa
commit 0accaf0f30
3 changed files with 42 additions and 2 deletions
@@ -11,17 +11,18 @@ import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.persistentSetOf import kotlinx.collections.immutable.persistentSetOf
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirDeclaration 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.ImplicitReceiverStack
import org.jetbrains.kotlin.fir.resolve.PersistentImplicitReceiverStack import org.jetbrains.kotlin.fir.resolve.PersistentImplicitReceiverStack
import org.jetbrains.kotlin.fir.resolve.SessionHolder import org.jetbrains.kotlin.fir.resolve.SessionHolder
import org.jetbrains.kotlin.fir.resolve.calls.ImplicitReceiverValue 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.fir.resolve.transformers.ReturnTypeCalculator
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
abstract class CheckerContext { abstract class CheckerContext {
abstract val implicitReceiverStack: ImplicitReceiverStack abstract val implicitReceiverStack: ImplicitReceiverStack
abstract val containingDeclarations: List<FirDeclaration> abstract val containingDeclarations: List<FirDeclaration>
abstract val qualifiedAccesses: List<FirQualifiedAccess>
abstract val sessionHolder: SessionHolder abstract val sessionHolder: SessionHolder
abstract val returnTypeCalculator: ReturnTypeCalculator abstract val returnTypeCalculator: ReturnTypeCalculator
abstract val suppressedDiagnostics: Set<String> abstract val suppressedDiagnostics: Set<String>
@@ -48,6 +49,7 @@ abstract class CheckerContext {
class PersistentCheckerContext private constructor( class PersistentCheckerContext private constructor(
override val implicitReceiverStack: PersistentImplicitReceiverStack, override val implicitReceiverStack: PersistentImplicitReceiverStack,
override val containingDeclarations: PersistentList<FirDeclaration>, override val containingDeclarations: PersistentList<FirDeclaration>,
override val qualifiedAccesses: PersistentList<FirQualifiedAccess>,
override val sessionHolder: SessionHolder, override val sessionHolder: SessionHolder,
override val returnTypeCalculator: ReturnTypeCalculator, override val returnTypeCalculator: ReturnTypeCalculator,
override val suppressedDiagnostics: PersistentSet<String>, override val suppressedDiagnostics: PersistentSet<String>,
@@ -58,6 +60,7 @@ class PersistentCheckerContext private constructor(
constructor(sessionHolder: SessionHolder, returnTypeCalculator: ReturnTypeCalculator) : this( constructor(sessionHolder: SessionHolder, returnTypeCalculator: ReturnTypeCalculator) : this(
PersistentImplicitReceiverStack(), PersistentImplicitReceiverStack(),
persistentListOf(), persistentListOf(),
persistentListOf(),
sessionHolder, sessionHolder,
returnTypeCalculator, returnTypeCalculator,
persistentSetOf(), persistentSetOf(),
@@ -70,6 +73,7 @@ class PersistentCheckerContext private constructor(
return PersistentCheckerContext( return PersistentCheckerContext(
implicitReceiverStack.add(name, value), implicitReceiverStack.add(name, value),
containingDeclarations, containingDeclarations,
qualifiedAccesses,
sessionHolder, sessionHolder,
returnTypeCalculator, returnTypeCalculator,
suppressedDiagnostics, suppressedDiagnostics,
@@ -83,6 +87,21 @@ class PersistentCheckerContext private constructor(
return PersistentCheckerContext( return PersistentCheckerContext(
implicitReceiverStack, implicitReceiverStack,
containingDeclarations.add(declaration), containingDeclarations.add(declaration),
qualifiedAccesses,
sessionHolder,
returnTypeCalculator,
suppressedDiagnostics,
allInfosSuppressed,
allWarningsSuppressed,
allErrorsSuppressed
)
}
fun addQualifiedAccess(qualifiedAccess: FirQualifiedAccess): PersistentCheckerContext {
return PersistentCheckerContext(
implicitReceiverStack,
containingDeclarations,
qualifiedAccesses.add(qualifiedAccess),
sessionHolder, sessionHolder,
returnTypeCalculator, returnTypeCalculator,
suppressedDiagnostics, suppressedDiagnostics,
@@ -102,6 +121,7 @@ class PersistentCheckerContext private constructor(
return PersistentCheckerContext( return PersistentCheckerContext(
implicitReceiverStack, implicitReceiverStack,
containingDeclarations, containingDeclarations,
qualifiedAccesses,
sessionHolder, sessionHolder,
returnTypeCalculator, returnTypeCalculator,
suppressedDiagnostics.addAll(diagnosticNames), suppressedDiagnostics.addAll(diagnosticNames),
@@ -208,6 +208,14 @@ abstract class AbstractDiagnosticCollector(
resolvedTypeRef.delegatedTypeRef?.accept(this, data) 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( private inline fun visitWithDeclaration(
declaration: FirDeclaration, declaration: FirDeclaration,
block: () -> Unit = { declaration.acceptChildren(this, null) } 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 = protected open fun onDeclarationEnter(declaration: FirDeclaration): DiagnosticCollectorDeclarationAction =
@@ -34,7 +34,8 @@ class ErrorNodeDiagnosticCollectorComponent(collector: AbstractDiagnosticCollect
} }
override fun visitErrorNamedReference(errorNamedReference: FirErrorNamedReference, data: CheckerContext) { 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) // 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 if (source.elementType == KtNodeTypes.ANNOTATION_ENTRY && errorNamedReference.diagnostic is ConeUnresolvedNameError) return
reportFirDiagnostic(errorNamedReference.diagnostic, source, reporter, data) reportFirDiagnostic(errorNamedReference.diagnostic, source, reporter, data)