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 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<FirDeclaration>
abstract val qualifiedAccesses: List<FirQualifiedAccess>
abstract val sessionHolder: SessionHolder
abstract val returnTypeCalculator: ReturnTypeCalculator
abstract val suppressedDiagnostics: Set<String>
@@ -48,6 +49,7 @@ abstract class CheckerContext {
class PersistentCheckerContext private constructor(
override val implicitReceiverStack: PersistentImplicitReceiverStack,
override val containingDeclarations: PersistentList<FirDeclaration>,
override val qualifiedAccesses: PersistentList<FirQualifiedAccess>,
override val sessionHolder: SessionHolder,
override val returnTypeCalculator: ReturnTypeCalculator,
override val suppressedDiagnostics: PersistentSet<String>,
@@ -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),
@@ -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 =
@@ -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)