FIR: report resolve-time errors on qualified access instead of reference
This commit is contained in:
+21
-1
@@ -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),
|
||||||
|
|||||||
+19
@@ -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 =
|
||||||
|
|||||||
+2
-1
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user