[FIR] Rename qualifiedAccessOrAssignmentsOrAnnotationCalls to callsOrAssignments and add delegated constructor calls

This commit is contained in:
Kirill Rakhman
2023-06-23 11:37:19 +02:00
committed by Space Team
parent 6281faa063
commit 6d1d6e48c1
21 changed files with 69 additions and 64 deletions
@@ -50,9 +50,9 @@ internal interface KtFirAnalysisSessionComponent {
fun ConeDiagnostic.asKtDiagnostic( fun ConeDiagnostic.asKtDiagnostic(
source: KtSourceElement, source: KtSourceElement,
qualifiedAccessSource: KtSourceElement?, callOrAssignmentSource: KtSourceElement?,
): KtDiagnosticWithPsi<*>? { ): KtDiagnosticWithPsi<*>? {
val firDiagnostic = toFirDiagnostics(analysisSession.useSiteSession, source, qualifiedAccessSource).firstOrNull() ?: return null val firDiagnostic = toFirDiagnostics(analysisSession.useSiteSession, source, callOrAssignmentSource).firstOrNull() ?: return null
check(firDiagnostic is KtPsiDiagnostic) check(firDiagnostic is KtPsiDiagnostic)
return firDiagnostic.asKtDiagnostic() return firDiagnostic.asKtDiagnostic()
} }
@@ -28,7 +28,7 @@ object FirJvmSuspensionPointInsideMutexLockChecker : FirFunctionCallChecker() {
if (!symbol.isSuspend) return if (!symbol.isSuspend) return
val closestAnonymousFunction = context.findClosest<FirAnonymousFunction>() ?: return val closestAnonymousFunction = context.findClosest<FirAnonymousFunction>() ?: return
for (call in context.qualifiedAccessOrAssignmentsOrAnnotationCalls.asReversed()) { for (call in context.callsOrAssignments.asReversed()) {
if (call is FirFunctionCall) { if (call is FirFunctionCall) {
val callableSymbol = call.calleeReference.toResolvedCallableSymbol() ?: continue val callableSymbol = call.calleeReference.toResolvedCallableSymbol() ?: continue
if (callableSymbol.callableId == synchronizedCallableId) { if (callableSymbol.callableId == synchronizedCallableId) {
@@ -764,7 +764,7 @@ fun FirBasedSymbol<*>.getAnnotationStringParameter(classId: ClassId, session: Fi
fun FirElement.isLhsOfAssignment(context: CheckerContext): Boolean { fun FirElement.isLhsOfAssignment(context: CheckerContext): Boolean {
if (this !is FirQualifiedAccessExpression) return false if (this !is FirQualifiedAccessExpression) return false
val lastQualified = context.qualifiedAccessOrAssignmentsOrAnnotationCalls.lastOrNull { it != this } ?: return false val lastQualified = context.callsOrAssignments.lastOrNull { it != this } ?: return false
return lastQualified is FirVariableAssignment && lastQualified.lValue == this return lastQualified is FirVariableAssignment && lastQualified.lValue == this
} }
@@ -33,7 +33,9 @@ abstract class CheckerContext : DiagnosticContext {
// Context // Context
abstract val implicitReceiverStack: ImplicitReceiverStack abstract val implicitReceiverStack: ImplicitReceiverStack
abstract val containingDeclarations: List<FirDeclaration> abstract val containingDeclarations: List<FirDeclaration>
abstract val qualifiedAccessOrAssignmentsOrAnnotationCalls: List<FirStatement>
/** Contains qualified access, annotation call, delegated constructor call, and variable assignment. */
abstract val callsOrAssignments: List<FirStatement>
abstract val getClassCalls: List<FirGetClassCall> abstract val getClassCalls: List<FirGetClassCall>
abstract val annotationContainers: List<FirAnnotationContainer> abstract val annotationContainers: List<FirAnnotationContainer>
abstract val containingElements: List<FirElement> abstract val containingElements: List<FirElement>
@@ -50,9 +50,9 @@ abstract class CheckerContextForProvider(
} }
} }
abstract fun addQualifiedAccessOrAnnotationCall(qualifiedAccessOrAnnotationCall: FirStatement): CheckerContextForProvider abstract fun addCallOrAssignment(qualifiedAccessOrAnnotationCall: FirStatement): CheckerContextForProvider
abstract fun dropQualifiedAccessOrAnnotationCall() abstract fun dropCallOrAssignment()
abstract fun addGetClassCall(getClassCall: FirGetClassCall): CheckerContextForProvider abstract fun addGetClassCall(getClassCall: FirGetClassCall): CheckerContextForProvider
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.name.Name
class MutableCheckerContext private constructor( class MutableCheckerContext private constructor(
override val implicitReceiverStack: PersistentImplicitReceiverStack, override val implicitReceiverStack: PersistentImplicitReceiverStack,
override val containingDeclarations: MutableList<FirDeclaration>, override val containingDeclarations: MutableList<FirDeclaration>,
override val qualifiedAccessOrAssignmentsOrAnnotationCalls: MutableList<FirStatement>, override val callsOrAssignments: MutableList<FirStatement>,
override val getClassCalls: MutableList<FirGetClassCall>, override val getClassCalls: MutableList<FirGetClassCall>,
override val annotationContainers: MutableList<FirAnnotationContainer>, override val annotationContainers: MutableList<FirAnnotationContainer>,
override val containingElements: MutableList<FirElement>, override val containingElements: MutableList<FirElement>,
@@ -56,7 +56,7 @@ class MutableCheckerContext private constructor(
return MutableCheckerContext( return MutableCheckerContext(
implicitReceiverStack.add(name, value), implicitReceiverStack.add(name, value),
containingDeclarations, containingDeclarations,
qualifiedAccessOrAssignmentsOrAnnotationCalls, callsOrAssignments,
getClassCalls, getClassCalls,
annotationContainers, annotationContainers,
containingElements, containingElements,
@@ -80,13 +80,13 @@ class MutableCheckerContext private constructor(
containingDeclarations.removeLast() containingDeclarations.removeLast()
} }
override fun addQualifiedAccessOrAnnotationCall(qualifiedAccessOrAnnotationCall: FirStatement): MutableCheckerContext { override fun addCallOrAssignment(qualifiedAccessOrAnnotationCall: FirStatement): MutableCheckerContext {
qualifiedAccessOrAssignmentsOrAnnotationCalls.add(qualifiedAccessOrAnnotationCall) callsOrAssignments.add(qualifiedAccessOrAnnotationCall)
return this return this
} }
override fun dropQualifiedAccessOrAnnotationCall() { override fun dropCallOrAssignment() {
qualifiedAccessOrAssignmentsOrAnnotationCalls.removeLast() callsOrAssignments.removeLast()
} }
override fun addGetClassCall(getClassCall: FirGetClassCall): MutableCheckerContext { override fun addGetClassCall(getClassCall: FirGetClassCall): MutableCheckerContext {
@@ -127,7 +127,7 @@ class MutableCheckerContext private constructor(
return MutableCheckerContext( return MutableCheckerContext(
implicitReceiverStack, implicitReceiverStack,
containingDeclarations, containingDeclarations,
qualifiedAccessOrAssignmentsOrAnnotationCalls, callsOrAssignments,
getClassCalls, getClassCalls,
annotationContainers, annotationContainers,
containingElements, containingElements,
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.name.Name
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 qualifiedAccessOrAssignmentsOrAnnotationCalls: PersistentList<FirStatement>, override val callsOrAssignments: PersistentList<FirStatement>,
override val getClassCalls: PersistentList<FirGetClassCall>, override val getClassCalls: PersistentList<FirGetClassCall>,
override val annotationContainers: PersistentList<FirAnnotationContainer>, override val annotationContainers: PersistentList<FirAnnotationContainer>,
override val containingElements: PersistentList<FirElement>, override val containingElements: PersistentList<FirElement>,
@@ -62,13 +62,13 @@ class PersistentCheckerContext private constructor(
override fun dropDeclaration() {} override fun dropDeclaration() {}
override fun addQualifiedAccessOrAnnotationCall(qualifiedAccessOrAnnotationCall: FirStatement): PersistentCheckerContext = override fun addCallOrAssignment(qualifiedAccessOrAnnotationCall: FirStatement): PersistentCheckerContext =
copy( copy(
qualifiedAccessOrAssignmentsOrAnnotationCalls = qualifiedAccessOrAssignmentsOrAnnotationCalls =
qualifiedAccessOrAssignmentsOrAnnotationCalls.add(qualifiedAccessOrAnnotationCall) callsOrAssignments.add(qualifiedAccessOrAnnotationCall)
) )
override fun dropQualifiedAccessOrAnnotationCall() {} override fun dropCallOrAssignment() {}
override fun addGetClassCall(getClassCall: FirGetClassCall): PersistentCheckerContext = override fun addGetClassCall(getClassCall: FirGetClassCall): PersistentCheckerContext =
copy(getClassCalls = getClassCalls.add(getClassCall)) copy(getClassCalls = getClassCalls.add(getClassCall))
@@ -102,7 +102,7 @@ class PersistentCheckerContext private constructor(
private fun copy( private fun copy(
implicitReceiverStack: PersistentImplicitReceiverStack = this.implicitReceiverStack, implicitReceiverStack: PersistentImplicitReceiverStack = this.implicitReceiverStack,
qualifiedAccessOrAssignmentsOrAnnotationCalls: PersistentList<FirStatement> = this.qualifiedAccessOrAssignmentsOrAnnotationCalls, qualifiedAccessOrAssignmentsOrAnnotationCalls: PersistentList<FirStatement> = this.callsOrAssignments,
getClassCalls: PersistentList<FirGetClassCall> = this.getClassCalls, getClassCalls: PersistentList<FirGetClassCall> = this.getClassCalls,
annotationContainers: PersistentList<FirAnnotationContainer> = this.annotationContainers, annotationContainers: PersistentList<FirAnnotationContainer> = this.annotationContainers,
containingElements: PersistentList<FirElement> = this.containingElements, containingElements: PersistentList<FirElement> = this.containingElements,
@@ -253,8 +253,8 @@ object FirInlineDeclarationChecker : FirFunctionChecker() {
private fun FirStatement.partOfCall(context: CheckerContext): Boolean { private fun FirStatement.partOfCall(context: CheckerContext): Boolean {
if (this !is FirExpression) return false if (this !is FirExpression) return false
val containingQualifiedAccess = context.qualifiedAccessOrAssignmentsOrAnnotationCalls.getOrNull( val containingQualifiedAccess = context.callsOrAssignments.getOrNull(
context.qualifiedAccessOrAssignmentsOrAnnotationCalls.size - 2 context.callsOrAssignments.size - 2
) ?: return false ) ?: return false
if (this == (containingQualifiedAccess as? FirQualifiedAccessExpression)?.explicitReceiver) return true if (this == (containingQualifiedAccess as? FirQualifiedAccessExpression)?.explicitReceiver) return true
val call = containingQualifiedAccess as? FirCall ?: return false val call = containingQualifiedAccess as? FirCall ?: return false
@@ -12,7 +12,6 @@ import org.jetbrains.kotlin.diagnostics.reportOn
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.utils.isAbstract
import org.jetbrains.kotlin.fir.expressions.FirAnnotation import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.references.toResolvedConstructorSymbol import org.jetbrains.kotlin.fir.references.toResolvedConstructorSymbol
@@ -26,7 +25,7 @@ object FirConstructorCallChecker : FirFunctionCallChecker() {
if (declarationClass != null) { if (declarationClass != null) {
if (declarationClass.classKind == ClassKind.ANNOTATION_CLASS && if (declarationClass.classKind == ClassKind.ANNOTATION_CLASS &&
context.qualifiedAccessOrAssignmentsOrAnnotationCalls.all { call -> context.callsOrAssignments.all { call ->
call !is FirAnnotation call !is FirAnnotation
} && } &&
context.containingDeclarations.all { klass -> context.containingDeclarations.all { klass ->
@@ -14,7 +14,7 @@ import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
object FirReceiverAccessBeforeSuperCallChecker : FirInaccessibleReceiverChecker() { object FirReceiverAccessBeforeSuperCallChecker : FirInaccessibleReceiverChecker() {
override fun check(expression: FirInaccessibleReceiverExpression, context: CheckerContext, reporter: DiagnosticReporter) { override fun check(expression: FirInaccessibleReceiverExpression, context: CheckerContext, reporter: DiagnosticReporter) {
val containingCall = context.qualifiedAccessOrAssignmentsOrAnnotationCalls.last() as FirQualifiedAccessExpression val containingCall = context.callsOrAssignments.last() as FirQualifiedAccessExpression
containingCall.run { containingCall.run {
require(expression == dispatchReceiver || expression == extensionReceiver || expression in contextReceiverArguments) require(expression == dispatchReceiver || expression == extensionReceiver || expression in contextReceiverArguments)
} }
@@ -36,7 +36,7 @@ object FirReturnSyntaxAndLabelChecker : FirReturnExpressionChecker() {
if (targetSymbol is FirAnonymousFunctionSymbol) { if (targetSymbol is FirAnonymousFunctionSymbol) {
val label = targetSymbol.label val label = targetSymbol.label
if (label?.source?.kind !is KtRealSourceElementKind) { if (label?.source?.kind !is KtRealSourceElementKind) {
val functionCall = context.qualifiedAccessOrAssignmentsOrAnnotationCalls.asReversed().find { val functionCall = context.callsOrAssignments.asReversed().find {
it is FirFunctionCall && it is FirFunctionCall &&
(it.calleeReference.toResolvedFunctionSymbol())?.callableId == (it.calleeReference.toResolvedFunctionSymbol())?.callableId ==
FirSuspendCallChecker.KOTLIN_SUSPEND_BUILT_IN_FUNCTION_CALLABLE_ID FirSuspendCallChecker.KOTLIN_SUSPEND_BUILT_IN_FUNCTION_CALLABLE_ID
@@ -21,7 +21,7 @@ import org.jetbrains.kotlin.fir.types.isUnit
object FirStandaloneQualifierChecker : FirResolvedQualifierChecker() { object FirStandaloneQualifierChecker : FirResolvedQualifierChecker() {
override fun check(expression: FirResolvedQualifier, context: CheckerContext, reporter: DiagnosticReporter) { override fun check(expression: FirResolvedQualifier, context: CheckerContext, reporter: DiagnosticReporter) {
val lastQualifiedAccess = context.qualifiedAccessOrAssignmentsOrAnnotationCalls.lastOrNull() as? FirQualifiedAccessExpression val lastQualifiedAccess = context.callsOrAssignments.lastOrNull() as? FirQualifiedAccessExpression
// Note: qualifier isn't standalone when it's in receiver (SomeClass.foo) or getClass (SomeClass::class) position // Note: qualifier isn't standalone when it's in receiver (SomeClass.foo) or getClass (SomeClass::class) position
if (lastQualifiedAccess?.explicitReceiver === expression || lastQualifiedAccess?.dispatchReceiver === expression) return if (lastQualifiedAccess?.explicitReceiver === expression || lastQualifiedAccess?.dispatchReceiver === expression) return
val lastGetClass = context.getClassCalls.lastOrNull() val lastGetClass = context.getClassCalls.lastOrNull()
@@ -33,7 +33,7 @@ object FirTypeParameterInQualifiedAccessChecker : FirQualifiedAccessExpressionCh
// Make sure the current expression is not the receiver of a qualified access expression. // Make sure the current expression is not the receiver of a qualified access expression.
// E.g., for `T::toString`, which is a callable reference (a subtype of qualified access), type parameter T is checked once as an // E.g., for `T::toString`, which is a callable reference (a subtype of qualified access), type parameter T is checked once as an
// explicit receiver. When we visit `T` (as a qualified access expression), we should not regard it as an expression here. // explicit receiver. When we visit `T` (as a qualified access expression), we should not regard it as an expression here.
val secondLast = context.qualifiedAccessOrAssignmentsOrAnnotationCalls.elementAtOrNull(context.qualifiedAccessOrAssignmentsOrAnnotationCalls.size - 2) val secondLast = context.callsOrAssignments.elementAtOrNull(context.callsOrAssignments.size - 2)
if (secondLast is FirQualifiedAccessExpression && secondLast.explicitReceiver == expression) return if (secondLast is FirQualifiedAccessExpression && secondLast.explicitReceiver == expression) return
val diagnostic = expression.typeRef.coneTypeParameterInQualifiedAccess ?: return val diagnostic = expression.typeRef.coneTypeParameterInQualifiedAccess ?: return
@@ -20,7 +20,7 @@ import org.jetbrains.kotlin.fir.expressions.*
object FirUnsupportedArrayLiteralChecker : FirArrayOfCallChecker() { object FirUnsupportedArrayLiteralChecker : FirArrayOfCallChecker() {
override fun check(expression: FirArrayOfCall, context: CheckerContext, reporter: DiagnosticReporter) { override fun check(expression: FirArrayOfCall, context: CheckerContext, reporter: DiagnosticReporter) {
if (!isInsideAnnotationCall(expression, context) && if (!isInsideAnnotationCall(expression, context) &&
(context.qualifiedAccessOrAssignmentsOrAnnotationCalls.isNotEmpty() || !isInsideAnnotationClass(context)) (context.callsOrAssignments.isNotEmpty() || !isInsideAnnotationClass(context))
) { ) {
reporter.reportOn( reporter.reportOn(
expression.source, expression.source,
@@ -32,7 +32,7 @@ object FirUnsupportedArrayLiteralChecker : FirArrayOfCallChecker() {
} }
private fun isInsideAnnotationCall(expression: FirArrayOfCall, context: CheckerContext): Boolean { private fun isInsideAnnotationCall(expression: FirArrayOfCall, context: CheckerContext): Boolean {
context.qualifiedAccessOrAssignmentsOrAnnotationCalls.lastOrNull()?.let { context.callsOrAssignments.lastOrNull()?.let {
val arguments = when (it) { val arguments = when (it) {
is FirFunctionCall -> is FirFunctionCall ->
if (it.typeRef.toRegularClassSymbol(context.session)?.classKind == ClassKind.ANNOTATION_CLASS) { if (it.typeRef.toRegularClassSymbol(context.session)?.classKind == ClassKind.ANNOTATION_CLASS) {
@@ -36,7 +36,7 @@ object FirOptInUsageTypeRefChecker : FirTypeRefChecker() {
val symbol = coneType.lookupTag.toSymbol(context.session) ?: return val symbol = coneType.lookupTag.toSymbol(context.session) ?: return
symbol.lazyResolveToPhase(FirResolvePhase.STATUS) symbol.lazyResolveToPhase(FirResolvePhase.STATUS)
val classId = symbol.classId val classId = symbol.classId
val lastAnnotationCall = context.qualifiedAccessOrAssignmentsOrAnnotationCalls.lastOrNull() as? FirAnnotation val lastAnnotationCall = context.callsOrAssignments.lastOrNull() as? FirAnnotation
if (lastAnnotationCall == null || lastAnnotationCall.annotationTypeRef !== typeRef) { if (lastAnnotationCall == null || lastAnnotationCall.annotationTypeRef !== typeRef) {
if (classId == OptInNames.REQUIRES_OPT_IN_CLASS_ID || classId == OptInNames.OPT_IN_CLASS_ID) { if (classId == OptInNames.REQUIRES_OPT_IN_CLASS_ID || classId == OptInNames.OPT_IN_CLASS_ID) {
reporter.reportOn(source, OPT_IN_CAN_ONLY_BE_USED_AS_ANNOTATION, context) reporter.reportOn(source, OPT_IN_CAN_ONLY_BE_USED_AS_ANNOTATION, context)
@@ -216,23 +216,27 @@ abstract class AbstractDiagnosticCollectorVisitor(
} }
override fun visitFunctionCall(functionCall: FirFunctionCall, data: Nothing?) { override fun visitFunctionCall(functionCall: FirFunctionCall, data: Nothing?) {
visitWithQualifiedAccessOrAnnotationCall(functionCall) visitWithCallOrAssignment(functionCall)
} }
override fun visitQualifiedAccessExpression(qualifiedAccessExpression: FirQualifiedAccessExpression, data: Nothing?) { override fun visitQualifiedAccessExpression(qualifiedAccessExpression: FirQualifiedAccessExpression, data: Nothing?) {
visitWithQualifiedAccessOrAnnotationCall(qualifiedAccessExpression) visitWithCallOrAssignment(qualifiedAccessExpression)
} }
override fun visitPropertyAccessExpression(propertyAccessExpression: FirPropertyAccessExpression, data: Nothing?) { override fun visitPropertyAccessExpression(propertyAccessExpression: FirPropertyAccessExpression, data: Nothing?) {
visitWithQualifiedAccessOrAnnotationCall(propertyAccessExpression) visitWithCallOrAssignment(propertyAccessExpression)
} }
override fun visitAnnotationCall(annotationCall: FirAnnotationCall, data: Nothing?) { override fun visitAnnotationCall(annotationCall: FirAnnotationCall, data: Nothing?) {
visitWithQualifiedAccessOrAnnotationCall(annotationCall) visitWithCallOrAssignment(annotationCall)
} }
override fun visitVariableAssignment(variableAssignment: FirVariableAssignment, data: Nothing?) { override fun visitVariableAssignment(variableAssignment: FirVariableAssignment, data: Nothing?) {
visitWithQualifiedAccessOrAnnotationCall(variableAssignment) visitWithCallOrAssignment(variableAssignment)
}
override fun visitDelegatedConstructorCall(delegatedConstructorCall: FirDelegatedConstructorCall, data: Nothing?) {
visitWithCallOrAssignment(delegatedConstructorCall)
} }
override fun visitGetClassCall(getClassCall: FirGetClassCall, data: Nothing?) { override fun visitGetClassCall(getClassCall: FirGetClassCall, data: Nothing?) {
@@ -273,9 +277,9 @@ abstract class AbstractDiagnosticCollectorVisitor(
} }
} }
private fun visitWithQualifiedAccessOrAnnotationCall(qualifiedAccessOrAnnotationCall: FirStatement) { private fun visitWithCallOrAssignment(callOrAssignment: FirStatement) {
return withQualifiedAccessOrAnnotationCall(qualifiedAccessOrAnnotationCall) { return withCallOrAssignment(callOrAssignment) {
visitElement(qualifiedAccessOrAnnotationCall, null) visitElement(callOrAssignment, null)
} }
} }
@@ -286,15 +290,15 @@ abstract class AbstractDiagnosticCollectorVisitor(
} }
@OptIn(PrivateForInline::class) @OptIn(PrivateForInline::class)
inline fun <R> withQualifiedAccessOrAnnotationCall(qualifiedAccessOrAnnotationCall: FirStatement, block: () -> R): R { inline fun <R> withCallOrAssignment(callOrAssignment: FirStatement, block: () -> R): R {
val existingContext = context val existingContext = context
context = context.addQualifiedAccessOrAnnotationCall(qualifiedAccessOrAnnotationCall) context = context.addCallOrAssignment(callOrAssignment)
try { try {
return whileAnalysing(context.session, qualifiedAccessOrAnnotationCall) { return whileAnalysing(context.session, callOrAssignment) {
block() block()
} }
} finally { } finally {
existingContext.dropQualifiedAccessOrAnnotationCall() existingContext.dropCallOrAssignment()
context = existingContext context = existingContext
} }
} }
@@ -63,7 +63,7 @@ class ErrorNodeDiagnosticCollectorComponent(
private fun processErrorReference(reference: FirNamedReference, diagnostic: ConeDiagnostic, context: CheckerContext) { private fun processErrorReference(reference: FirNamedReference, diagnostic: ConeDiagnostic, context: CheckerContext) {
var source = reference.source ?: return var source = reference.source ?: return
val qualifiedAccessOrAnnotationCall = context.qualifiedAccessOrAssignmentsOrAnnotationCalls.lastOrNull()?.takeIf { val callOrAssignment = context.callsOrAssignments.lastOrNull()?.takeIf {
// Use the source of the enclosing FirQualifiedAccess if it is exactly the call to the erroneous callee. // Use the source of the enclosing FirQualifiedAccess if it is exactly the call to the erroneous callee.
it.calleeReference == reference it.calleeReference == reference
} }
@@ -75,10 +75,10 @@ class ErrorNodeDiagnosticCollectorComponent(
) return ) return
// If the receiver cannot be resolved, we skip reporting any further problems for this call. // If the receiver cannot be resolved, we skip reporting any further problems for this call.
if (qualifiedAccessOrAnnotationCall is FirQualifiedAccessExpression) { if (callOrAssignment is FirQualifiedAccessExpression) {
if (qualifiedAccessOrAnnotationCall.dispatchReceiver.cannotBeResolved() || if (callOrAssignment.dispatchReceiver.cannotBeResolved() ||
qualifiedAccessOrAnnotationCall.extensionReceiver.cannotBeResolved() || callOrAssignment.extensionReceiver.cannotBeResolved() ||
qualifiedAccessOrAnnotationCall.explicitReceiver.cannotBeResolved() callOrAssignment.explicitReceiver.cannotBeResolved()
) return ) return
} }
@@ -87,7 +87,7 @@ class ErrorNodeDiagnosticCollectorComponent(
source = property.delegate?.source?.fakeElement(KtFakeSourceElementKind.DelegatedPropertyAccessor) ?: return source = property.delegate?.source?.fakeElement(KtFakeSourceElementKind.DelegatedPropertyAccessor) ?: return
} }
reportFirDiagnostic(diagnostic, source, context, qualifiedAccessOrAnnotationCall?.source) reportFirDiagnostic(diagnostic, source, context, callOrAssignment?.source)
} }
private fun FirExpression?.cannotBeResolved(): Boolean { private fun FirExpression?.cannotBeResolved(): Boolean {
@@ -129,7 +129,7 @@ class ErrorNodeDiagnosticCollectorComponent(
diagnostic: ConeDiagnostic, diagnostic: ConeDiagnostic,
source: KtSourceElement, source: KtSourceElement,
context: CheckerContext, context: CheckerContext,
qualifiedAccessSource: KtSourceElement? = null callOrAssignmentSource: KtSourceElement? = null
) { ) {
// Will be handled by [FirDestructuringDeclarationChecker] // Will be handled by [FirDestructuringDeclarationChecker]
if (source.elementType == KtNodeTypes.DESTRUCTURING_DECLARATION_ENTRY) { if (source.elementType == KtNodeTypes.DESTRUCTURING_DECLARATION_ENTRY) {
@@ -153,7 +153,7 @@ class ErrorNodeDiagnosticCollectorComponent(
return return
} }
for (coneDiagnostic in diagnostic.toFirDiagnostics(session, source, qualifiedAccessSource)) { for (coneDiagnostic in diagnostic.toFirDiagnostics(session, source, callOrAssignmentSource)) {
reporter.report(coneDiagnostic, context) reporter.report(coneDiagnostic, context)
} }
} }
@@ -46,7 +46,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.shouldNotBeCalled
private fun ConeDiagnostic.toKtDiagnostic( private fun ConeDiagnostic.toKtDiagnostic(
source: KtSourceElement, source: KtSourceElement,
qualifiedAccessSource: KtSourceElement? callOrAssignmentSource: KtSourceElement?
): KtDiagnostic? = when (this) { ): KtDiagnostic? = when (this) {
is ConeUnresolvedReferenceError -> FirErrors.UNRESOLVED_REFERENCE.createOn( is ConeUnresolvedReferenceError -> FirErrors.UNRESOLVED_REFERENCE.createOn(
source, source,
@@ -83,7 +83,7 @@ private fun ConeDiagnostic.toKtDiagnostic(
applicability.isSuccess -> FirErrors.OVERLOAD_RESOLUTION_AMBIGUITY.createOn(source, this.candidates.map { it.symbol }) applicability.isSuccess -> FirErrors.OVERLOAD_RESOLUTION_AMBIGUITY.createOn(source, this.candidates.map { it.symbol })
applicability == CandidateApplicability.UNSAFE_CALL -> { applicability == CandidateApplicability.UNSAFE_CALL -> {
val (unsafeCall, candidate) = candidates.firstNotNullOf { it.diagnostics.firstIsInstanceOrNull<UnsafeCall>()?.to(it) } val (unsafeCall, candidate) = candidates.firstNotNullOf { it.diagnostics.firstIsInstanceOrNull<UnsafeCall>()?.to(it) }
mapUnsafeCallError(candidate, unsafeCall, source, qualifiedAccessSource) mapUnsafeCallError(candidate, unsafeCall, source, callOrAssignmentSource)
} }
applicability == CandidateApplicability.UNSTABLE_SMARTCAST -> { applicability == CandidateApplicability.UNSTABLE_SMARTCAST -> {
@@ -109,22 +109,22 @@ private fun ConeDiagnostic.toKtDiagnostic(
FirErrors.WRONG_NUMBER_OF_TYPE_ARGUMENTS.createOn(this.source, this.desiredCount, this.symbol) FirErrors.WRONG_NUMBER_OF_TYPE_ARGUMENTS.createOn(this.source, this.desiredCount, this.symbol)
is ConeOuterClassArgumentsRequired -> is ConeOuterClassArgumentsRequired ->
FirErrors.OUTER_CLASS_ARGUMENTS_REQUIRED.createOn(qualifiedAccessSource ?: source, this.symbol) FirErrors.OUTER_CLASS_ARGUMENTS_REQUIRED.createOn(callOrAssignmentSource ?: source, this.symbol)
is ConeNoTypeArgumentsOnRhsError -> is ConeNoTypeArgumentsOnRhsError ->
FirErrors.NO_TYPE_ARGUMENTS_ON_RHS.createOn(qualifiedAccessSource ?: source, this.desiredCount, this.symbol) FirErrors.NO_TYPE_ARGUMENTS_ON_RHS.createOn(callOrAssignmentSource ?: source, this.desiredCount, this.symbol)
is ConeSyntaxDiagnostic -> FirSyntaxErrors.SYNTAX.createOn(qualifiedAccessSource ?: source, reason) is ConeSyntaxDiagnostic -> FirSyntaxErrors.SYNTAX.createOn(callOrAssignmentSource ?: source, reason)
is ConeSimpleDiagnostic -> when { is ConeSimpleDiagnostic -> when {
source.kind is KtFakeSourceElementKind && source.kind != KtFakeSourceElementKind.ReferenceInAtomicQualifiedAccess -> null source.kind is KtFakeSourceElementKind && source.kind != KtFakeSourceElementKind.ReferenceInAtomicQualifiedAccess -> null
else -> this.getFactory(source).createOn(qualifiedAccessSource ?: source) else -> this.getFactory(source).createOn(callOrAssignmentSource ?: source)
} }
is ConeDestructuringDeclarationsOnTopLevel -> null // TODO Currently a parsing error. Would be better to report here instead KT-58563 is ConeDestructuringDeclarationsOnTopLevel -> null // TODO Currently a parsing error. Would be better to report here instead KT-58563
is ConeCannotInferTypeParameterType -> FirErrors.CANNOT_INFER_PARAMETER_TYPE.createOn(source) is ConeCannotInferTypeParameterType -> FirErrors.CANNOT_INFER_PARAMETER_TYPE.createOn(source)
is ConeCannotInferValueParameterType -> FirErrors.CANNOT_INFER_PARAMETER_TYPE.createOn(source) is ConeCannotInferValueParameterType -> FirErrors.CANNOT_INFER_PARAMETER_TYPE.createOn(source)
is ConeTypeVariableTypeIsNotInferred -> FirErrors.INFERENCE_ERROR.createOn(qualifiedAccessSource ?: source) is ConeTypeVariableTypeIsNotInferred -> FirErrors.INFERENCE_ERROR.createOn(callOrAssignmentSource ?: source)
is ConeInstanceAccessBeforeSuperCall -> FirErrors.INSTANCE_ACCESS_BEFORE_SUPER_CALL.createOn(source, this.target) is ConeInstanceAccessBeforeSuperCall -> FirErrors.INSTANCE_ACCESS_BEFORE_SUPER_CALL.createOn(source, this.target)
is ConeStubDiagnostic -> null is ConeStubDiagnostic -> null
is ConeIntermediateDiagnostic -> null is ConeIntermediateDiagnostic -> null
@@ -162,12 +162,12 @@ fun FirBasedSymbol<*>.toInvisibleReferenceDiagnostic(source: KtSourceElement?):
fun ConeDiagnostic.toFirDiagnostics( fun ConeDiagnostic.toFirDiagnostics(
session: FirSession, session: FirSession,
source: KtSourceElement, source: KtSourceElement,
qualifiedAccessSource: KtSourceElement? callOrAssignmentSource: KtSourceElement?
): List<KtDiagnostic> { ): List<KtDiagnostic> {
return when (this) { return when (this) {
is ConeInapplicableCandidateError -> mapInapplicableCandidateError(session, this, source, qualifiedAccessSource) is ConeInapplicableCandidateError -> mapInapplicableCandidateError(session, this, source, callOrAssignmentSource)
is ConeConstraintSystemHasContradiction -> mapSystemHasContradictionError(session, this, source, qualifiedAccessSource) is ConeConstraintSystemHasContradiction -> mapSystemHasContradictionError(session, this, source, callOrAssignmentSource)
else -> listOfNotNull(toKtDiagnostic(source, qualifiedAccessSource)) else -> listOfNotNull(toKtDiagnostic(source, callOrAssignmentSource))
} }
} }
@@ -6,7 +6,7 @@ enum class TestOk(val x: String = "OK") {
enum class TestErrors(val x: String) { enum class TestErrors(val x: String) {
<!NO_VALUE_FOR_PARAMETER!>TEST1,<!> <!NO_VALUE_FOR_PARAMETER!>TEST1,<!>
TEST2<!NO_VALUE_FOR_PARAMETER!><!>(), TEST2<!NO_VALUE_FOR_PARAMETER!>()<!>,
TEST3("Hello") TEST3("Hello")
} }
@@ -3,7 +3,7 @@ open class B0(x: Int)
class A0 : B0 { class A0 : B0 {
<!EXPLICIT_DELEGATION_CALL_REQUIRED!>constructor()<!> <!EXPLICIT_DELEGATION_CALL_REQUIRED!>constructor()<!>
constructor(x: Int) : <!NO_VALUE_FOR_PARAMETER!>super<!>() constructor(x: Int) : <!NO_VALUE_FOR_PARAMETER!>super()<!>
} }
// -------------------------- // --------------------------
@@ -17,4 +17,4 @@ val test2 = <!NO_VALUE_FOR_PARAMETER!>C2_Alias()<!>
class Test3 : <!API_NOT_AVAILABLE!>C1_Alias<!>() class Test3 : <!API_NOT_AVAILABLE!>C1_Alias<!>()
class Test4 : <!NO_VALUE_FOR_PARAMETER!>C2_Alias<!>() class Test4 : <!NO_VALUE_FOR_PARAMETER!>C2_Alias()<!>