From 7cc3f7de629e737c53bad7ef1596f700daf0777f Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Wed, 25 Jan 2023 14:17:09 +0100 Subject: [PATCH] K1: introduce assignment checkers and convert JvmSyntheticAssignmentChecker Related to KT-56061 --- .../checkers/JvmSyntheticAssignmentChecker.kt | 19 +++++++------------ .../jvm/platform/JvmPlatformConfigurator.kt | 5 ++++- .../resolve/PlatformConfiguratorBase.kt | 2 ++ .../calls/checkers/AssignmentChecker.kt | 13 +++++++++++++ .../ExpressionTypingComponents.java | 7 +++++++ .../ExpressionTypingVisitorForStatements.java | 15 +++++++++++++++ 6 files changed, 48 insertions(+), 13 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/AssignmentChecker.kt diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JvmSyntheticAssignmentChecker.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JvmSyntheticAssignmentChecker.kt index 3db3d68b218..977326df6c9 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JvmSyntheticAssignmentChecker.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JvmSyntheticAssignmentChecker.kt @@ -5,32 +5,27 @@ package org.jetbrains.kotlin.resolve.jvm.checkers -import com.intellij.psi.PsiElement import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.psi.KtBinaryExpression -import org.jetbrains.kotlin.psi.KtNameReferenceExpression -import org.jetbrains.kotlin.psi.psiUtil.getParentOfType -import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker +import org.jetbrains.kotlin.resolve.calls.checkers.AssignmentChecker import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext -import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.tower.isSynthesized +import org.jetbrains.kotlin.resolve.calls.util.getResolvedCall import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor import org.jetbrains.kotlin.types.IndexedParametersSubstitution import org.jetbrains.kotlin.types.TypeProjection import org.jetbrains.kotlin.types.TypeSubstitutor import org.jetbrains.kotlin.types.Variance -import org.jetbrains.kotlin.types.expressions.BasicExpressionTypingVisitor import org.jetbrains.kotlin.types.typeUtil.isNothing -object JvmSyntheticAssignmentChecker : CallChecker { - override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) { +object JvmSyntheticAssignmentChecker : AssignmentChecker { + override fun check(assignmentExpression: KtBinaryExpression, context: CallCheckerContext) { + val left = assignmentExpression.left ?: return + val resolvedCall = left.getResolvedCall(context.trace.bindingContext) ?: return val resultingDescriptor = resolvedCall.resultingDescriptor if (!resultingDescriptor.isSynthesized) return if (resultingDescriptor !is SyntheticJavaPropertyDescriptor) return - if (reportOn !is KtNameReferenceExpression) return - val binaryExpression = reportOn.getParentOfType(strict = true) ?: return - if (!BasicExpressionTypingVisitor.isLValue(reportOn, binaryExpression)) return val receiverType = resolvedCall.extensionReceiver?.type ?: return val unsubstitutedReceiverType = resolvedCall.candidateDescriptor.extensionReceiverParameter?.type ?: return if (receiverType.constructor !== unsubstitutedReceiverType.constructor) return @@ -50,6 +45,6 @@ object JvmSyntheticAssignmentChecker : CallChecker { ) val substitutedPropertyType = substitutor.substitute(propertyType.unwrap(), Variance.IN_VARIANCE) if (substitutedPropertyType == null || !substitutedPropertyType.isNothing()) return - context.trace.report(ErrorsJvm.SYNTHETIC_SETTER_PROJECTED_OUT.on(binaryExpression.left ?: reportOn, resultingDescriptor)) + context.trace.report(ErrorsJvm.SYNTHETIC_SETTER_PROJECTED_OUT.on(left, resultingDescriptor)) } } \ No newline at end of file diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatformConfigurator.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatformConfigurator.kt index 5f476bd28ac..39b5418ddab 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatformConfigurator.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatformConfigurator.kt @@ -63,11 +63,14 @@ object JvmPlatformConfigurator : PlatformConfiguratorBase( SamInterfaceConstructorReferenceCallChecker, EnumDeclaringClassDeprecationChecker, UpperBoundViolatedInTypealiasConstructorChecker, - JvmSyntheticAssignmentChecker, LateinitIntrinsicApplicabilityChecker(isWarningInPre19 = false), JvmPropertyVsFieldAmbiguityCallChecker, ), + additionalAssignmentCheckers = listOf( + JvmSyntheticAssignmentChecker, + ), + additionalTypeCheckers = listOf( RuntimeAssertionsTypeChecker, JavaGenericVarianceViolationTypeChecker, diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/PlatformConfiguratorBase.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/PlatformConfiguratorBase.kt index dc8207b54f3..8cba3c38c88 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/PlatformConfiguratorBase.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/PlatformConfiguratorBase.kt @@ -110,6 +110,7 @@ abstract class PlatformConfiguratorBase( private val dynamicTypesSettings: DynamicTypesSettings? = null, private val additionalDeclarationCheckers: List = emptyList(), private val additionalCallCheckers: List = emptyList(), + private val additionalAssignmentCheckers: List = emptyList(), private val additionalTypeCheckers: List = emptyList(), private val additionalClassifierUsageCheckers: List = emptyList(), private val additionalAnnotationCheckers: List = emptyList(), @@ -135,6 +136,7 @@ abstract class PlatformConfiguratorBase( useInstanceIfNotNull(dynamicTypesSettings) additionalDeclarationCheckers.forEach { useInstance(it) } additionalCallCheckers.forEach { useInstance(it) } + additionalAssignmentCheckers.forEach { useInstance(it) } additionalTypeCheckers.forEach { useInstance(it) } additionalClassifierUsageCheckers.forEach { useInstance(it) } additionalAnnotationCheckers.forEach { useInstance(it) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/AssignmentChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/AssignmentChecker.kt new file mode 100644 index 00000000000..73077850006 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/AssignmentChecker.kt @@ -0,0 +1,13 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.resolve.calls.checkers + +import org.jetbrains.kotlin.psi.KtBinaryExpression + +interface AssignmentChecker { + + fun check(assignmentExpression: KtBinaryExpression, context: CallCheckerContext) +} \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingComponents.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingComponents.java index cb72788da86..0f642b0fdcd 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingComponents.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingComponents.java @@ -17,6 +17,7 @@ import org.jetbrains.kotlin.incremental.components.LookupTracker; import org.jetbrains.kotlin.resolve.*; import org.jetbrains.kotlin.resolve.calls.CallExpressionResolver; import org.jetbrains.kotlin.resolve.calls.CallResolver; +import org.jetbrains.kotlin.resolve.calls.checkers.AssignmentChecker; import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker; import org.jetbrains.kotlin.resolve.calls.checkers.RttiExpressionChecker; import org.jetbrains.kotlin.resolve.calls.model.KotlinCallComponents; @@ -52,6 +53,7 @@ public class ExpressionTypingComponents { public ModifiersChecker modifiersChecker; public DataFlowAnalyzer dataFlowAnalyzer; public Iterable callCheckers; + public Iterable assignmentCheckers; public IdentifierChecker identifierChecker; public DeclarationsCheckerBuilder declarationsCheckerBuilder; public LocalVariableResolver localVariableResolver; @@ -188,6 +190,11 @@ public class ExpressionTypingComponents { this.callCheckers = callCheckers; } + @Inject + public void setAssignmentCheckers(@NotNull Iterable assignmentCheckers) { + this.assignmentCheckers = assignmentCheckers; + } + @Inject public void setDeclarationsCheckerBuilder(@NotNull DeclarationsCheckerBuilder declarationsCheckerBuilder) { this.declarationsCheckerBuilder = declarationsCheckerBuilder; diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingVisitorForStatements.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingVisitorForStatements.java index 1231802c9dd..441477dee8c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingVisitorForStatements.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingVisitorForStatements.java @@ -32,6 +32,8 @@ import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.BindingContextUtils; import org.jetbrains.kotlin.resolve.TemporaryBindingTrace; import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver; +import org.jetbrains.kotlin.resolve.calls.checkers.AssignmentChecker; +import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext; import org.jetbrains.kotlin.resolve.calls.checkers.NewSchemeOfIntegerOperatorResolutionChecker; import org.jetbrains.kotlin.resolve.calls.context.CallPosition; import org.jetbrains.kotlin.resolve.calls.context.ContextDependency; @@ -482,6 +484,19 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito } if (expectedType != null && leftOperand != null) { //if expectedType == null, some other error has been generated basic.checkLValue(context.trace, context, leftOperand, right, expression, false); + + CallCheckerContext callCheckerContext = + new CallCheckerContext( + context, + components.deprecationResolver, + components.moduleDescriptor, + components.missingSupertypesResolver, + components.callComponents, + context.trace + ); + for (AssignmentChecker checker : components.assignmentCheckers) { + checker.check(expression, callCheckerContext); + } } if (!refineJavaFieldInTypeProperly) {