Refactor CallChecker and subclasses

Encapsulate everything that is needed in checkers into CallCheckerContext. Pass
an instance of this context instead of BasicCallResolutionContext to checkers.

Also pass an instance of the element to report errors on: this is useful
because before this, every checker had its own way of determining where should
the error be reported on. Some of them, for example, were not doing anything if
Call#calleeExpression returned null, which is wrong, see operatorCall.kt

 #KT-12875 Open
This commit is contained in:
Alexander Udalov
2016-06-27 16:36:29 +03:00
parent f6f825e0dc
commit 6ba32ed624
38 changed files with 278 additions and 290 deletions
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.load.kotlin package org.jetbrains.kotlin.load.kotlin
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory0 import org.jetbrains.kotlin.diagnostics.DiagnosticFactory0
@@ -25,14 +26,14 @@ import org.jetbrains.kotlin.psi.KtAnnotationEntry
import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.calls.checkers.SimpleCallChecker import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
class JavaAnnotationCallChecker : SimpleCallChecker { class JavaAnnotationCallChecker : CallChecker {
override fun check(resolvedCall: ResolvedCall<*>, context: BasicCallResolutionContext) { override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
val resultingDescriptor = resolvedCall.resultingDescriptor.original val resultingDescriptor = resolvedCall.resultingDescriptor.original
if (resultingDescriptor !is JavaConstructorDescriptor || if (resultingDescriptor !is JavaConstructorDescriptor ||
resultingDescriptor.containingDeclaration.kind != ClassKind.ANNOTATION_CLASS) return resultingDescriptor.containingDeclaration.kind != ClassKind.ANNOTATION_CLASS) return
@@ -41,7 +42,7 @@ class JavaAnnotationCallChecker : SimpleCallChecker {
reportDeprecatedJavaAnnotation(resolvedCall, context) reportDeprecatedJavaAnnotation(resolvedCall, context)
} }
private fun reportDeprecatedJavaAnnotation(resolvedCall: ResolvedCall<*>, context: BasicCallResolutionContext) { private fun reportDeprecatedJavaAnnotation(resolvedCall: ResolvedCall<*>, context: CallCheckerContext) {
val annotationEntry = resolvedCall.call.callElement as? KtAnnotationEntry ?: return val annotationEntry = resolvedCall.call.callElement as? KtAnnotationEntry ?: return
val type = context.trace.get(BindingContext.TYPE, annotationEntry.typeReference) ?: return val type = context.trace.get(BindingContext.TYPE, annotationEntry.typeReference) ?: return
JavaAnnotationMapper.javaToKotlinNameMap[type.constructor.declarationDescriptor?.let { DescriptorUtils.getFqNameSafe(it) }]?.let { JavaAnnotationMapper.javaToKotlinNameMap[type.constructor.declarationDescriptor?.let { DescriptorUtils.getFqNameSafe(it) }]?.let {
@@ -49,25 +50,20 @@ class JavaAnnotationCallChecker : SimpleCallChecker {
} }
} }
private fun reportErrorsOnPositionedArguments(resolvedCall: ResolvedCall<*>, context: BasicCallResolutionContext) { private fun reportErrorsOnPositionedArguments(resolvedCall: ResolvedCall<*>, context: CallCheckerContext) {
getJavaAnnotationCallValueArgumentsThatShouldBeNamed(resolvedCall).forEach { getJavaAnnotationCallValueArgumentsThatShouldBeNamed(resolvedCall).forEach {
reportOnValueArgument(context, it, ErrorsJvm.POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION) reportOnValueArgument(context, it, ErrorsJvm.POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION)
} }
} }
private fun reportOnValueArgument( private fun reportOnValueArgument(
context: BasicCallResolutionContext, context: CallCheckerContext,
argument: Map.Entry<ValueParameterDescriptor, ResolvedValueArgument>, arguments: Map.Entry<ValueParameterDescriptor, ResolvedValueArgument>,
diagnostic: DiagnosticFactory0<KtExpression> diagnostic: DiagnosticFactory0<KtExpression>
) { ) {
argument.value.arguments.forEach { for (valueArgument in arguments.value.arguments) {
if (it.getArgumentExpression() != null) { val argumentExpression = valueArgument.getArgumentExpression() ?: continue
context.trace.report( context.trace.report(diagnostic.on(argumentExpression))
diagnostic.on(
it.getArgumentExpression()!!
)
)
}
} }
} }
} }
@@ -30,21 +30,16 @@ import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DeclarationChecker import org.jetbrains.kotlin.resolve.DeclarationChecker
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
import org.jetbrains.kotlin.resolve.calls.checkers.elementToReportOn import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.descriptorUtil.overriddenTreeUniqueAsSequence import org.jetbrains.kotlin.resolve.descriptorUtil.overriddenTreeUniqueAsSequence
object AdditionalBuiltInsMembersCallChecker : CallChecker { object AdditionalBuiltInsMembersCallChecker : CallChecker {
override fun check( override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
resolvedCall: ResolvedCall<*>, if (context.languageFeatureSettings.supportsFeature(LanguageFeature.AdditionalBuiltInsMembers)) return
context: BasicCallResolutionContext,
languageFeatureSettings: LanguageFeatureSettings
) {
if (languageFeatureSettings.supportsFeature(LanguageFeature.AdditionalBuiltInsMembers)) return
val resultingDescriptor = resolvedCall.resultingDescriptor as? CallableMemberDescriptor ?: return val resultingDescriptor = resolvedCall.resultingDescriptor as? CallableMemberDescriptor ?: return
reportErrorIfAdditionalBuiltinDescriptor(resultingDescriptor, context.trace, resolvedCall.elementToReportOn) reportErrorIfAdditionalBuiltinDescriptor(resultingDescriptor, context.trace, reportOn)
} }
} }
@@ -16,19 +16,20 @@
package org.jetbrains.kotlin.resolve.jvm.checkers package org.jetbrains.kotlin.resolve.jvm.checkers
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.resolve.calls.checkers.SimpleCallChecker import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
import org.jetbrains.kotlin.types.KotlinTypeFactory import org.jetbrains.kotlin.types.KotlinTypeFactory
import org.jetbrains.kotlin.types.TypeProjectionImpl import org.jetbrains.kotlin.types.TypeProjectionImpl
class JavaClassOnCompanionChecker : SimpleCallChecker { class JavaClassOnCompanionChecker : CallChecker {
override fun check(resolvedCall: ResolvedCall<*>, context: BasicCallResolutionContext) { override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
val descriptor = resolvedCall.resultingDescriptor val descriptor = resolvedCall.resultingDescriptor
if (descriptor !is PropertyDescriptor || descriptor.name.asString() != "javaClass") return if (descriptor !is PropertyDescriptor || descriptor.name.asString() != "javaClass") return
@@ -45,7 +46,7 @@ class JavaClassOnCompanionChecker : SimpleCallChecker {
val arguments = listOf(TypeProjectionImpl(containingClass.defaultType)) val arguments = listOf(TypeProjectionImpl(containingClass.defaultType))
val expectedType = KotlinTypeFactory.simpleType(Annotations.EMPTY, javaLangClass.typeConstructor, arguments, val expectedType = KotlinTypeFactory.simpleType(Annotations.EMPTY, javaLangClass.typeConstructor, arguments,
actualType.isMarkedNullable) actualType.isMarkedNullable)
context.trace.report(ErrorsJvm.JAVA_CLASS_ON_COMPANION.on(resolvedCall.call.callElement, actualType, expectedType)) context.trace.report(ErrorsJvm.JAVA_CLASS_ON_COMPANION.on(reportOn, actualType, expectedType))
} }
} }
} }
@@ -16,12 +16,13 @@
package org.jetbrains.kotlin.resolve.jvm.checkers package org.jetbrains.kotlin.resolve.jvm.checkers
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.resolve.calls.checkers.SimpleCallChecker import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
import org.jetbrains.kotlin.resolve.calls.checkers.isComputingDeferredType import org.jetbrains.kotlin.resolve.calls.checkers.isComputingDeferredType
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.descriptorUtil.classId import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
@@ -29,10 +30,10 @@ import org.jetbrains.kotlin.serialization.deserialization.NotFoundClasses
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.utils.newLinkedHashSetWithExpectedSize import org.jetbrains.kotlin.utils.newLinkedHashSetWithExpectedSize
class MissingDependencyClassChecker : SimpleCallChecker { class MissingDependencyClassChecker : CallChecker {
override fun check(resolvedCall: ResolvedCall<*>, context: BasicCallResolutionContext) { override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
for (classId in collectNotFoundClasses(resolvedCall.resultingDescriptor)) { for (classId in collectNotFoundClasses(resolvedCall.resultingDescriptor)) {
context.trace.report(ErrorsJvm.MISSING_DEPENDENCY_CLASS.on(resolvedCall.call.callElement, classId.asSingleFqName())) context.trace.report(ErrorsJvm.MISSING_DEPENDENCY_CLASS.on(reportOn, classId.asSingleFqName()))
} }
} }
@@ -16,18 +16,19 @@
package org.jetbrains.kotlin.resolve.jvm.checkers package org.jetbrains.kotlin.resolve.jvm.checkers
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.annotations.hasJvmStaticAnnotation import org.jetbrains.kotlin.resolve.annotations.hasJvmStaticAnnotation
import org.jetbrains.kotlin.resolve.calls.checkers.SimpleCallChecker import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
class ProtectedInSuperClassCompanionCallChecker : SimpleCallChecker { class ProtectedInSuperClassCompanionCallChecker : CallChecker {
override fun check(resolvedCall: ResolvedCall<*>, context: BasicCallResolutionContext) { override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
val targetDescriptor = resolvedCall.resultingDescriptor.original val targetDescriptor = resolvedCall.resultingDescriptor.original
// Protected non-JVM static // Protected non-JVM static
if (targetDescriptor.visibility != Visibilities.PROTECTED) return if (targetDescriptor.visibility != Visibilities.PROTECTED) return
@@ -42,7 +43,7 @@ class ProtectedInSuperClassCompanionCallChecker : SimpleCallChecker {
if (!parentClassDescriptors.any { DescriptorUtils.isSubclass(it, companionOwnerDescriptor) }) return if (!parentClassDescriptors.any { DescriptorUtils.isSubclass(it, companionOwnerDescriptor) }) return
// Called not within the same companion object or its owner class // Called not within the same companion object or its owner class
if (companionDescriptor !in parentClassDescriptors && companionOwnerDescriptor !in parentClassDescriptors) { if (companionDescriptor !in parentClassDescriptors && companionOwnerDescriptor !in parentClassDescriptors) {
context.trace.report(ErrorsJvm.SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC.on(resolvedCall.call.callElement)) context.trace.report(ErrorsJvm.SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC.on(reportOn))
} }
} }
} }
@@ -16,10 +16,11 @@
package org.jetbrains.kotlin.resolve.jvm.checkers package org.jetbrains.kotlin.resolve.jvm.checkers
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.resolve.calls.checkers.SimpleCallChecker import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.calls.smartcasts.getReceiverValueWithSmartCast import org.jetbrains.kotlin.resolve.calls.smartcasts.getReceiverValueWithSmartCast
@@ -27,8 +28,8 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.synthetic.SamAdapterExtensionFunctionDescriptor import org.jetbrains.kotlin.synthetic.SamAdapterExtensionFunctionDescriptor
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
object ProtectedSyntheticExtensionCallChecker : SimpleCallChecker { object ProtectedSyntheticExtensionCallChecker : CallChecker {
override fun check(resolvedCall: ResolvedCall<*>, context: BasicCallResolutionContext) { override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
val descriptor = resolvedCall.resultingDescriptor val descriptor = resolvedCall.resultingDescriptor
val sourceFunction = when (descriptor) { val sourceFunction = when (descriptor) {
@@ -46,10 +47,11 @@ object ProtectedSyntheticExtensionCallChecker : SimpleCallChecker {
val receiverValue = resolvedCall.extensionReceiver as ReceiverValue val receiverValue = resolvedCall.extensionReceiver as ReceiverValue
val receiverTypes = listOf(receiverValue.type) + context.dataFlowInfo.getPredictableTypes( val receiverTypes = listOf(receiverValue.type) + context.dataFlowInfo.getPredictableTypes(
DataFlowValueFactory.createDataFlowValue(receiverValue, context)) DataFlowValueFactory.createDataFlowValue(receiverValue, context.trace.bindingContext, context.scope.ownerDescriptor)
)
if (receiverTypes.none { Visibilities.isVisible(getReceiverValueWithSmartCast(null, it), sourceFunction, from) }) { if (receiverTypes.none { Visibilities.isVisible(getReceiverValueWithSmartCast(null, it), sourceFunction, from) }) {
context.trace.report(Errors.INVISIBLE_MEMBER.on(resolvedCall.call.callElement, descriptor, descriptor.visibility, from)) context.trace.report(Errors.INVISIBLE_MEMBER.on(reportOn, descriptor, descriptor.visibility, from))
} }
} }
} }
@@ -16,13 +16,14 @@
package org.jetbrains.kotlin.resolve.jvm.checkers package org.jetbrains.kotlin.resolve.jvm.checkers
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.builtins.ReflectionTypes import org.jetbrains.kotlin.builtins.ReflectionTypes
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.calls.checkers.SimpleCallChecker import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm.NO_REFLECTION_IN_CLASS_PATH import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm.NO_REFLECTION_IN_CLASS_PATH
import org.jetbrains.kotlin.serialization.deserialization.findClassAcrossModuleDependencies import org.jetbrains.kotlin.serialization.deserialization.findClassAcrossModuleDependencies
@@ -34,7 +35,7 @@ import org.jetbrains.kotlin.util.OperatorNameConventions
* If there's no Kotlin reflection implementation found in the classpath, checks that there are no usages * If there's no Kotlin reflection implementation found in the classpath, checks that there are no usages
* of reflection API which will fail at runtime. * of reflection API which will fail at runtime.
*/ */
class ReflectionAPICallChecker(private val module: ModuleDescriptor, storageManager: StorageManager) : SimpleCallChecker { class ReflectionAPICallChecker(private val module: ModuleDescriptor, storageManager: StorageManager) : CallChecker {
private val isReflectionAvailable by storageManager.createLazyValue { private val isReflectionAvailable by storageManager.createLazyValue {
module.findClassAcrossModuleDependencies(JvmAbi.REFLECTION_FACTORY_IMPL) != null module.findClassAcrossModuleDependencies(JvmAbi.REFLECTION_FACTORY_IMPL) != null
} }
@@ -44,7 +45,7 @@ class ReflectionAPICallChecker(private val module: ModuleDescriptor, storageMana
setOf(reflectionTypes.kProperty0, reflectionTypes.kProperty1, reflectionTypes.kProperty2) setOf(reflectionTypes.kProperty0, reflectionTypes.kProperty1, reflectionTypes.kProperty2)
} }
override fun check(resolvedCall: ResolvedCall<*>, context: BasicCallResolutionContext) { override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
if (isReflectionAvailable) return if (isReflectionAvailable) return
val descriptor = resolvedCall.resultingDescriptor val descriptor = resolvedCall.resultingDescriptor
@@ -63,6 +64,6 @@ class ReflectionAPICallChecker(private val module: ModuleDescriptor, storageMana
kPropertyClasses.any { kProperty -> DescriptorUtils.isSubclass(containingClass, kProperty) } -> return kPropertyClasses.any { kProperty -> DescriptorUtils.isSubclass(containingClass, kProperty) } -> return
} }
context.trace.report(NO_REFLECTION_IN_CLASS_PATH.on(resolvedCall.getCall().getCallElement())) context.trace.report(NO_REFLECTION_IN_CLASS_PATH.on(reportOn))
} }
} }
@@ -16,17 +16,18 @@
package org.jetbrains.kotlin.resolve.jvm.checkers package org.jetbrains.kotlin.resolve.jvm.checkers
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.getSuperCallExpression import org.jetbrains.kotlin.resolve.calls.callResolverUtil.getSuperCallExpression
import org.jetbrains.kotlin.resolve.calls.callUtil.usesDefaultArguments import org.jetbrains.kotlin.resolve.calls.callUtil.usesDefaultArguments
import org.jetbrains.kotlin.resolve.calls.checkers.SimpleCallChecker import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
class SuperCallWithDefaultArgumentsChecker : SimpleCallChecker { class SuperCallWithDefaultArgumentsChecker : CallChecker {
override fun check(resolvedCall: ResolvedCall<*>, context: BasicCallResolutionContext) { override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
val superCallExpression = getSuperCallExpression(resolvedCall.call) val superCallExpression = getSuperCallExpression(resolvedCall.call)
if (superCallExpression == null || !resolvedCall.usesDefaultArguments()) return if (superCallExpression == null || !resolvedCall.usesDefaultArguments()) return
context.trace.report(ErrorsJvm.SUPER_CALL_WITH_DEFAULT_PARAMETERS.on(superCallExpression.parent, resolvedCall.resultingDescriptor.name.asString())) context.trace.report(ErrorsJvm.SUPER_CALL_WITH_DEFAULT_PARAMETERS.on(reportOn, resolvedCall.resultingDescriptor.name.asString()))
} }
} }
@@ -16,20 +16,18 @@
package org.jetbrains.kotlin.resolve.jvm.checkers package org.jetbrains.kotlin.resolve.jvm.checkers
import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.getSuperCallExpression import org.jetbrains.kotlin.resolve.calls.callResolverUtil.getSuperCallExpression
import org.jetbrains.kotlin.resolve.calls.checkers.SimpleCallChecker import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
class TraitDefaultMethodCallChecker : SimpleCallChecker { class TraitDefaultMethodCallChecker : CallChecker {
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
override fun check(resolvedCall: ResolvedCall<*>, context: BasicCallResolutionContext) {
if (getSuperCallExpression(resolvedCall.call) == null) return if (getSuperCallExpression(resolvedCall.call) == null) return
val targetDescriptor = resolvedCall.resultingDescriptor.original val targetDescriptor = resolvedCall.resultingDescriptor.original
@@ -40,13 +38,8 @@ class TraitDefaultMethodCallChecker : SimpleCallChecker {
val classifier = DescriptorUtils.getParentOfType(context.scope.ownerDescriptor, ClassifierDescriptor::class.java) val classifier = DescriptorUtils.getParentOfType(context.scope.ownerDescriptor, ClassifierDescriptor::class.java)
if (classifier != null && DescriptorUtils.isInterface(classifier)) { if (classifier != null && DescriptorUtils.isInterface(classifier)) {
context.trace.report( context.trace.report(ErrorsJvm.INTERFACE_CANT_CALL_DEFAULT_METHOD_VIA_SUPER.on(reportOn))
ErrorsJvm.INTERFACE_CANT_CALL_DEFAULT_METHOD_VIA_SUPER.on(
PsiTreeUtil.getParentOfType(resolvedCall.call.callElement, KtExpression::class.java)!!
)
)
} }
} }
} }
} }
@@ -16,22 +16,23 @@
package org.jetbrains.kotlin.resolve.jvm.checkers package org.jetbrains.kotlin.resolve.jvm.checkers
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.diagnostics.Errors.UNSUPPORTED import org.jetbrains.kotlin.diagnostics.Errors.UNSUPPORTED
import org.jetbrains.kotlin.psi.KtCallableReferenceExpression import org.jetbrains.kotlin.psi.KtCallableReferenceExpression
import org.jetbrains.kotlin.psi.KtNameReferenceExpression import org.jetbrains.kotlin.psi.KtNameReferenceExpression
import org.jetbrains.kotlin.resolve.calls.checkers.SimpleCallChecker import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
class UnsupportedSyntheticCallableReferenceChecker : SimpleCallChecker { class UnsupportedSyntheticCallableReferenceChecker : CallChecker {
override fun check(resolvedCall: ResolvedCall<*>, context: BasicCallResolutionContext) { override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
val expression = context.call.callElement val expression = resolvedCall.call.callElement
if (expression !is KtNameReferenceExpression || expression.parent !is KtCallableReferenceExpression) return if (expression !is KtNameReferenceExpression || expression.parent !is KtCallableReferenceExpression) return
// TODO: support references to synthetic Java extension properties (KT-8575) // TODO: support references to synthetic Java extension properties (KT-8575)
if (resolvedCall.resultingDescriptor is SyntheticJavaPropertyDescriptor) { if (resolvedCall.resultingDescriptor is SyntheticJavaPropertyDescriptor) {
context.trace.report(UNSUPPORTED.on(expression, "reference to the synthetic extension property for a Java get/set method")) context.trace.report(UNSUPPORTED.on(reportOn, "reference to the synthetic extension property for a Java get/set method"))
} }
} }
} }
@@ -24,7 +24,6 @@ import org.jetbrains.kotlin.diagnostics.Errors;
import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.psi.KtAnnotationEntry; import org.jetbrains.kotlin.psi.KtAnnotationEntry;
import org.jetbrains.kotlin.psi.KtDeclaration; import org.jetbrains.kotlin.psi.KtDeclaration;
import org.jetbrains.kotlin.psi.KtElement;
import org.jetbrains.kotlin.psi.KtExpression; import org.jetbrains.kotlin.psi.KtExpression;
import org.jetbrains.kotlin.types.KotlinType; import org.jetbrains.kotlin.types.KotlinType;
@@ -74,12 +73,12 @@ public interface ErrorsJvm {
DiagnosticFactory0<KtAnnotationEntry> NON_SOURCE_REPEATED_ANNOTATION = DiagnosticFactory0.create(ERROR); DiagnosticFactory0<KtAnnotationEntry> NON_SOURCE_REPEATED_ANNOTATION = DiagnosticFactory0.create(ERROR);
DiagnosticFactory1<KtAnnotationEntry, FqName> ANNOTATION_IS_NOT_APPLICABLE_TO_MULTIFILE_CLASSES = DiagnosticFactory1.create(ERROR); DiagnosticFactory1<KtAnnotationEntry, FqName> ANNOTATION_IS_NOT_APPLICABLE_TO_MULTIFILE_CLASSES = DiagnosticFactory1.create(ERROR);
DiagnosticFactory0<KtElement> INTERFACE_CANT_CALL_DEFAULT_METHOD_VIA_SUPER = DiagnosticFactory0.create(ERROR); DiagnosticFactory0<PsiElement> INTERFACE_CANT_CALL_DEFAULT_METHOD_VIA_SUPER = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtElement> SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC = DiagnosticFactory0.create(ERROR); DiagnosticFactory0<PsiElement> SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtElement> NO_REFLECTION_IN_CLASS_PATH = DiagnosticFactory0.create(WARNING); DiagnosticFactory0<PsiElement> NO_REFLECTION_IN_CLASS_PATH = DiagnosticFactory0.create(WARNING);
DiagnosticFactory2<KtElement, KotlinType, KotlinType> JAVA_CLASS_ON_COMPANION = DiagnosticFactory2.create(WARNING); DiagnosticFactory2<PsiElement, KotlinType, KotlinType> JAVA_CLASS_ON_COMPANION = DiagnosticFactory2.create(WARNING);
DiagnosticFactory2<KtExpression, KotlinType, KotlinType> JAVA_TYPE_MISMATCH = DiagnosticFactory2.create(ERROR); DiagnosticFactory2<KtExpression, KotlinType, KotlinType> JAVA_TYPE_MISMATCH = DiagnosticFactory2.create(ERROR);
DiagnosticFactory2<PsiElement, String, String> DUPLICATE_CLASS_NAMES = DiagnosticFactory2.create(ERROR); DiagnosticFactory2<PsiElement, String, String> DUPLICATE_CLASS_NAMES = DiagnosticFactory2.create(ERROR);
@@ -75,7 +75,7 @@ public interface Errors {
DiagnosticFactory3.create(ERROR); DiagnosticFactory3.create(ERROR);
DiagnosticFactory3<PsiElement, DeclarationDescriptor, Visibility, DeclarationDescriptor> INVISIBLE_MEMBER = DiagnosticFactory3.create(ERROR, CALL_ELEMENT); DiagnosticFactory3<PsiElement, DeclarationDescriptor, Visibility, DeclarationDescriptor> INVISIBLE_MEMBER = DiagnosticFactory3.create(ERROR, CALL_ELEMENT);
DiagnosticFactory1<KtExpression, ConstructorDescriptor> PROTECTED_CONSTRUCTOR_NOT_IN_SUPER_CALL = DiagnosticFactory1.create(ERROR); DiagnosticFactory1<PsiElement, ConstructorDescriptor> PROTECTED_CONSTRUCTOR_NOT_IN_SUPER_CALL = DiagnosticFactory1.create(ERROR);
// Exposed visibility group // Exposed visibility group
DiagnosticFactory3<PsiElement, EffectiveVisibility, DescriptorWithRelation, EffectiveVisibility> EXPOSED_PROPERTY_TYPE = DiagnosticFactory3.create(ERROR); DiagnosticFactory3<PsiElement, EffectiveVisibility, DescriptorWithRelation, EffectiveVisibility> EXPOSED_PROPERTY_TYPE = DiagnosticFactory3.create(ERROR);
@@ -812,7 +812,7 @@ public interface Errors {
DiagnosticFactory0<KtDeclaration> INLINE_PROPERTY_WITH_BACKING_FIELD = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE); DiagnosticFactory0<KtDeclaration> INLINE_PROPERTY_WITH_BACKING_FIELD = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
DiagnosticFactory0<KtElement> NON_LOCAL_SUSPENSION_POINT = DiagnosticFactory0.create(ERROR); DiagnosticFactory0<PsiElement> NON_LOCAL_SUSPENSION_POINT = DiagnosticFactory0.create(ERROR);
// Error sets // Error sets
@@ -16,12 +16,13 @@
package org.jetbrains.kotlin.resolve package org.jetbrains.kotlin.resolve
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.psi.KtInstanceExpressionWithLabel import org.jetbrains.kotlin.psi.KtInstanceExpressionWithLabel
import org.jetbrains.kotlin.resolve.calls.checkers.SimpleCallChecker import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.scopes.LexicalScope import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.resolve.scopes.LexicalScopeKind import org.jetbrains.kotlin.resolve.scopes.LexicalScopeKind
@@ -29,26 +30,27 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.Receiver import org.jetbrains.kotlin.resolve.scopes.receivers.Receiver
import org.jetbrains.kotlin.resolve.scopes.utils.parentsWithSelf import org.jetbrains.kotlin.resolve.scopes.utils.parentsWithSelf
object ConstructorHeaderCallChecker : SimpleCallChecker { object ConstructorHeaderCallChecker : CallChecker {
override fun check(resolvedCall: ResolvedCall<*>, context: BasicCallResolutionContext) { override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
val dispatchReceiverClass = resolvedCall.dispatchReceiver.classDescriptorForImplicitReceiver val dispatchReceiverClass = resolvedCall.dispatchReceiver.classDescriptorForImplicitReceiver
val extensionReceiverClass = resolvedCall.extensionReceiver.classDescriptorForImplicitReceiver val extensionReceiverClass = resolvedCall.extensionReceiver.classDescriptorForImplicitReceiver
val callElement = resolvedCall.call.callElement
val labelReferenceClass = val labelReferenceClass =
(resolvedCall.call.callElement as? KtInstanceExpressionWithLabel)?.let { if (callElement is KtInstanceExpressionWithLabel) {
instanceExpressionWithLabel -> context.trace.get(BindingContext.REFERENCE_TARGET, callElement.instanceReference) as? ClassDescriptor
context.trace.get(BindingContext.REFERENCE_TARGET, instanceExpressionWithLabel.instanceReference) as? ClassDescriptor
} }
else null
if (dispatchReceiverClass == null && extensionReceiverClass == null && labelReferenceClass == null) return if (dispatchReceiverClass == null && extensionReceiverClass == null && labelReferenceClass == null) return
if (context.scope.parentsWithSelf.any() { val classes = setOf(dispatchReceiverClass, extensionReceiverClass, labelReferenceClass)
it is LexicalScope && it.kind == LexicalScopeKind.CONSTRUCTOR_HEADER
&& (it.ownerDescriptor as ConstructorDescriptor).containingDeclaration in if (context.scope.parentsWithSelf.any { scope ->
setOf(dispatchReceiverClass, extensionReceiverClass, labelReferenceClass) scope is LexicalScope && scope.kind == LexicalScopeKind.CONSTRUCTOR_HEADER &&
(scope.ownerDescriptor as ConstructorDescriptor).containingDeclaration in classes
}) { }) {
context.trace.report( context.trace.report(Errors.INSTANCE_ACCESS_BEFORE_SUPER_CALL.on(reportOn, resolvedCall.resultingDescriptor))
Errors.INSTANCE_ACCESS_BEFORE_SUPER_CALL.on(context.call.calleeExpression ?: return, resolvedCall.resultingDescriptor))
} }
} }
} }
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.resolve.calls.callResolverUtil.ResolveArgumentsMode.
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.getEffectiveExpectedType import org.jetbrains.kotlin.resolve.calls.callResolverUtil.getEffectiveExpectedType
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isInvokeCallOnVariable import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isInvokeCallOnVariable
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
import org.jetbrains.kotlin.resolve.calls.context.CallCandidateResolutionContext import org.jetbrains.kotlin.resolve.calls.context.CallCandidateResolutionContext
import org.jetbrains.kotlin.resolve.calls.context.CallPosition import org.jetbrains.kotlin.resolve.calls.context.CallPosition
@@ -83,14 +84,16 @@ class CallCompleter(
} }
if (resolvedCall != null) { if (resolvedCall != null) {
for (callChecker in callCheckers) {
callChecker.check(resolvedCall, context, languageFeatureSettings)
}
val element = if (resolvedCall is VariableAsFunctionResolvedCall) val element = if (resolvedCall is VariableAsFunctionResolvedCall)
resolvedCall.variableCall.call.calleeExpression resolvedCall.variableCall.call.calleeExpression
else else
resolvedCall.call.calleeExpression resolvedCall.call.calleeExpression
val reportOn = element ?: resolvedCall.call.callElement
val callCheckerContext = CallCheckerContext(context, languageFeatureSettings)
for (callChecker in callCheckers) {
callChecker.check(resolvedCall, reportOn, callCheckerContext)
}
for (validator in symbolUsageValidators) { for (validator in symbolUsageValidators) {
validator.validateCall(resolvedCall, context.trace, element!!) validator.validateCall(resolvedCall, context.trace, element!!)
@@ -16,30 +16,30 @@
package org.jetbrains.kotlin.resolve.calls.checkers package org.jetbrains.kotlin.resolve.calls.checkers
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.config.LanguageFeatureSettings import org.jetbrains.kotlin.config.LanguageFeatureSettings
import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.types.DeferredType import org.jetbrains.kotlin.types.DeferredType
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
interface CallChecker { interface CallChecker {
// TODO: Think about encapsulating these parameters into specific class like CheckerParameters when you're about to add another one fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext)
fun check(
resolvedCall: ResolvedCall<*>,
context: BasicCallResolutionContext,
languageFeatureSettings: LanguageFeatureSettings
)
} }
interface SimpleCallChecker : CallChecker { class CallCheckerContext(
override fun check( val trace: BindingTrace,
resolvedCall: ResolvedCall<*>, val scope: LexicalScope,
context: BasicCallResolutionContext, val languageFeatureSettings: LanguageFeatureSettings,
languageFeatureSettings: LanguageFeatureSettings val dataFlowInfo: DataFlowInfo,
) = check(resolvedCall, context) val isAnnotationContext: Boolean
) {
fun check(resolvedCall: ResolvedCall<*>, context: BasicCallResolutionContext) constructor(c: ResolutionContext<*>, languageFeatureSettings: LanguageFeatureSettings) : this(
c.trace, c.scope, languageFeatureSettings, c.dataFlowInfo, c.isAnnotationContext
)
} }
// Use this utility to avoid premature computation of deferred return type of a resolved callable descriptor. // Use this utility to avoid premature computation of deferred return type of a resolved callable descriptor.
@@ -48,6 +48,3 @@ interface SimpleCallChecker : CallChecker {
@Suppress("unused") @Suppress("unused")
fun CallChecker.isComputingDeferredType(type: KotlinType) = fun CallChecker.isComputingDeferredType(type: KotlinType) =
type is DeferredType && type.isComputing type is DeferredType && type.isComputing
val ResolvedCall<*>.elementToReportOn: KtElement
get() = call.calleeExpression ?: call.callElement
@@ -16,20 +16,16 @@
package org.jetbrains.kotlin.resolve.calls.checkers package org.jetbrains.kotlin.resolve.calls.checkers
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.isArrayOfNothing import org.jetbrains.kotlin.types.typeUtil.isArrayOfNothing
class CallReturnsArrayOfNothingChecker : SimpleCallChecker { class CallReturnsArrayOfNothingChecker : CallChecker {
override fun check(resolvedCall: ResolvedCall<*>, context: BasicCallResolutionContext) { override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
val returnType = resolvedCall.resultingDescriptor.returnType if (resolvedCall.resultingDescriptor.returnType.containsArrayOfNothing()) {
context.trace.report(Errors.UNSUPPORTED.on(reportOn, "Array<Nothing> in return type is illegal"))
if (returnType.containsArrayOfNothing()) {
val callElement = resolvedCall.call.callElement
val diagnostic = Errors.UNSUPPORTED.on(callElement, "Array<Nothing> in return type is illegal")
context.trace.report(diagnostic)
} }
} }
@@ -16,21 +16,21 @@
package org.jetbrains.kotlin.resolve.calls.checkers package org.jetbrains.kotlin.resolve.calls.checkers
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.psi.KtFunction import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingContext.CAPTURED_IN_CLOSURE import org.jetbrains.kotlin.resolve.BindingContext.CAPTURED_IN_CLOSURE
import org.jetbrains.kotlin.resolve.BindingTrace import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
import org.jetbrains.kotlin.resolve.inline.InlineUtil import org.jetbrains.kotlin.resolve.inline.InlineUtil
import org.jetbrains.kotlin.resolve.scopes.LexicalScope import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.types.expressions.CaptureKind import org.jetbrains.kotlin.types.expressions.CaptureKind
class CapturingInClosureChecker : SimpleCallChecker { class CapturingInClosureChecker : CallChecker {
override fun check(resolvedCall: ResolvedCall<*>, context: BasicCallResolutionContext) { override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
val variableResolvedCall = if (resolvedCall is VariableAsFunctionResolvedCall) resolvedCall.variableCall else resolvedCall val variableResolvedCall = if (resolvedCall is VariableAsFunctionResolvedCall) resolvedCall.variableCall else resolvedCall
val variableDescriptor = variableResolvedCall.resultingDescriptor as? VariableDescriptor val variableDescriptor = variableResolvedCall.resultingDescriptor as? VariableDescriptor
if (variableDescriptor != null) { if (variableDescriptor != null) {
@@ -68,9 +68,9 @@ class CapturingInClosureChecker : SimpleCallChecker {
if (!InlineUtil.canBeInlineArgument(scopeDeclaration)) return false if (!InlineUtil.canBeInlineArgument(scopeDeclaration)) return false
if (InlineUtil.isInlinedArgument(scopeDeclaration as KtFunction, context, false)) { if (InlineUtil.isInlinedArgument(scopeDeclaration as KtFunction, context, false)) {
val scopeContainerParent = scopeContainer.containingDeclaration val scopeContainerParent = scopeContainer.containingDeclaration ?: error("parent is null for $scopeContainer")
assert(scopeContainerParent != null) { "parent is null for " + scopeContainer } return !isCapturedVariable(variableParent, scopeContainerParent) ||
return !isCapturedVariable(variableParent, scopeContainerParent!!) || isCapturedInInline(context, scopeContainerParent, variableParent) isCapturedInInline(context, scopeContainerParent, variableParent)
} }
return false return false
} }
@@ -17,12 +17,10 @@
package org.jetbrains.kotlin.resolve.calls.checkers package org.jetbrains.kotlin.resolve.calls.checkers
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.config.LanguageFeatureSettings
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.psi.KtBinaryExpression import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.psi.KtOperationReferenceExpression import org.jetbrains.kotlin.psi.KtOperationReferenceExpression
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic
@@ -30,14 +28,15 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.ErrorUtils
class InfixCallChecker : CallChecker { class InfixCallChecker : CallChecker {
override fun check(resolvedCall: ResolvedCall<*>, context: BasicCallResolutionContext, languageFeatureSettings: LanguageFeatureSettings) { override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
val functionDescriptor = resolvedCall.resultingDescriptor as? FunctionDescriptor ?: return val functionDescriptor = resolvedCall.resultingDescriptor as? FunctionDescriptor ?: return
if (functionDescriptor.isDynamic() || ErrorUtils.isError(functionDescriptor)) return if (functionDescriptor.isInfix || functionDescriptor.isDynamic() || ErrorUtils.isError(functionDescriptor)) return
val element = ((resolvedCall as? VariableAsFunctionResolvedCall)?.variableCall ?: resolvedCall).call.calleeExpression val element = ((resolvedCall as? VariableAsFunctionResolvedCall)?.variableCall ?: resolvedCall).call.calleeExpression
if (isInfixCall(element) && !functionDescriptor.isInfix) { if (isInfixCall(element)) {
val operationRefExpression = element as? KtOperationReferenceExpression ?: return
val containingDeclarationName = functionDescriptor.containingDeclaration.fqNameUnsafe.asString() val containingDeclarationName = functionDescriptor.containingDeclaration.fqNameUnsafe.asString()
context.trace.report(Errors.INFIX_MODIFIER_REQUIRED.on(operationRefExpression, functionDescriptor, containingDeclarationName)) context.trace.report(Errors.INFIX_MODIFIER_REQUIRED.on(
reportOn as? KtOperationReferenceExpression ?: return, functionDescriptor, containingDeclarationName
))
} }
} }
@@ -20,7 +20,6 @@ import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.FunctionTypesKt; import org.jetbrains.kotlin.builtins.FunctionTypesKt;
import org.jetbrains.kotlin.config.LanguageFeatureSettings;
import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.diagnostics.Errors; import org.jetbrains.kotlin.diagnostics.Errors;
import org.jetbrains.kotlin.lexer.KtToken; import org.jetbrains.kotlin.lexer.KtToken;
@@ -28,7 +27,6 @@ import org.jetbrains.kotlin.lexer.KtTokens;
import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.DescriptorUtils; import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt; import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext;
import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument; import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument; import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument;
@@ -49,7 +47,7 @@ import static org.jetbrains.kotlin.diagnostics.Errors.USAGE_IS_NOT_INLINABLE;
import static org.jetbrains.kotlin.resolve.inline.InlineUtil.allowsNonLocalReturns; import static org.jetbrains.kotlin.resolve.inline.InlineUtil.allowsNonLocalReturns;
import static org.jetbrains.kotlin.resolve.inline.InlineUtil.checkNonLocalReturnUsage; import static org.jetbrains.kotlin.resolve.inline.InlineUtil.checkNonLocalReturnUsage;
class InlineChecker implements SimpleCallChecker { class InlineChecker implements CallChecker {
private final FunctionDescriptor descriptor; private final FunctionDescriptor descriptor;
private final Set<CallableDescriptor> inlinableParameters = new LinkedHashSet<CallableDescriptor>(); private final Set<CallableDescriptor> inlinableParameters = new LinkedHashSet<CallableDescriptor>();
private final boolean isEffectivelyPublicApiFunction; private final boolean isEffectivelyPublicApiFunction;
@@ -68,17 +66,8 @@ class InlineChecker implements SimpleCallChecker {
} }
@Override @Override
public void check( public void check(@NotNull ResolvedCall<?> resolvedCall, @NotNull PsiElement reportOn, @NotNull CallCheckerContext context) {
@NotNull ResolvedCall<?> resolvedCall, KtExpression expression = resolvedCall.getCall().getCalleeExpression();
@NotNull BasicCallResolutionContext context,
@NotNull LanguageFeatureSettings languageFeatureSettings
) {
SimpleCallChecker.DefaultImpls.check(this, resolvedCall, context, languageFeatureSettings);
}
@Override
public void check(@NotNull ResolvedCall<?> resolvedCall, @NotNull BasicCallResolutionContext context) {
KtExpression expression = context.call.getCalleeExpression();
if (expression == null) { if (expression == null) {
return; return;
} }
@@ -90,7 +79,7 @@ class InlineChecker implements SimpleCallChecker {
if (inlinableParameters.contains(targetDescriptor)) { if (inlinableParameters.contains(targetDescriptor)) {
if (!isInsideCall(expression)) { if (!isInsideCall(expression)) {
context.trace.report(USAGE_IS_NOT_INLINABLE.on(expression, expression, descriptor)); context.getTrace().report(USAGE_IS_NOT_INLINABLE.on(expression, expression, descriptor));
} }
} }
@@ -133,10 +122,8 @@ class InlineChecker implements SimpleCallChecker {
return parent != null; return parent != null;
} }
private void checkValueParameter( private void checkValueParameter(
@NotNull BasicCallResolutionContext context, @NotNull CallCheckerContext context,
@NotNull CallableDescriptor targetDescriptor, @NotNull CallableDescriptor targetDescriptor,
@NotNull ValueArgument targetArgument, @NotNull ValueArgument targetArgument,
@NotNull ValueParameterDescriptor targetParameterDescriptor @NotNull ValueParameterDescriptor targetParameterDescriptor
@@ -150,20 +137,20 @@ class InlineChecker implements SimpleCallChecker {
if (argumentCallee != null && inlinableParameters.contains(argumentCallee)) { if (argumentCallee != null && inlinableParameters.contains(argumentCallee)) {
if (InlineUtil.isInline(targetDescriptor) && isInlinableParameter(targetParameterDescriptor)) { if (InlineUtil.isInline(targetDescriptor) && isInlinableParameter(targetParameterDescriptor)) {
if (allowsNonLocalReturns(argumentCallee) && !allowsNonLocalReturns(targetParameterDescriptor)) { if (allowsNonLocalReturns(argumentCallee) && !allowsNonLocalReturns(targetParameterDescriptor)) {
context.trace.report(NON_LOCAL_RETURN_NOT_ALLOWED.on(argumentExpression, argumentExpression)); context.getTrace().report(NON_LOCAL_RETURN_NOT_ALLOWED.on(argumentExpression, argumentExpression));
} }
else { else {
checkNonLocalReturn(context, argumentCallee, argumentExpression); checkNonLocalReturn(context, argumentCallee, argumentExpression);
} }
} }
else { else {
context.trace.report(USAGE_IS_NOT_INLINABLE.on(argumentExpression, argumentExpression, descriptor)); context.getTrace().report(USAGE_IS_NOT_INLINABLE.on(argumentExpression, argumentExpression, descriptor));
} }
} }
} }
private void checkCallWithReceiver( private void checkCallWithReceiver(
@NotNull BasicCallResolutionContext context, @NotNull CallCheckerContext context,
@NotNull CallableDescriptor targetDescriptor, @NotNull CallableDescriptor targetDescriptor,
@Nullable ReceiverValue receiver, @Nullable ReceiverValue receiver,
@Nullable KtExpression expression @Nullable KtExpression expression
@@ -194,13 +181,13 @@ class InlineChecker implements SimpleCallChecker {
@Nullable @Nullable
private static CallableDescriptor getCalleeDescriptor( private static CallableDescriptor getCalleeDescriptor(
@NotNull BasicCallResolutionContext context, @NotNull CallCheckerContext context,
@NotNull KtExpression expression, @NotNull KtExpression expression,
boolean unwrapVariableAsFunction boolean unwrapVariableAsFunction
) { ) {
if (!(expression instanceof KtSimpleNameExpression || expression instanceof KtThisExpression)) return null; if (!(expression instanceof KtSimpleNameExpression || expression instanceof KtThisExpression)) return null;
ResolvedCall<?> thisCall = CallUtilKt.getResolvedCall(expression, context.trace.getBindingContext()); ResolvedCall<?> thisCall = CallUtilKt.getResolvedCall(expression, context.getTrace().getBindingContext());
if (unwrapVariableAsFunction && thisCall instanceof VariableAsFunctionResolvedCall) { if (unwrapVariableAsFunction && thisCall instanceof VariableAsFunctionResolvedCall) {
return ((VariableAsFunctionResolvedCall) thisCall).getVariableCall().getResultingDescriptor(); return ((VariableAsFunctionResolvedCall) thisCall).getVariableCall().getResultingDescriptor();
} }
@@ -208,27 +195,27 @@ class InlineChecker implements SimpleCallChecker {
} }
private void checkLambdaInvokeOrExtensionCall( private void checkLambdaInvokeOrExtensionCall(
@NotNull BasicCallResolutionContext context, @NotNull CallCheckerContext context,
@NotNull CallableDescriptor lambdaDescriptor, @NotNull CallableDescriptor lambdaDescriptor,
@NotNull CallableDescriptor callDescriptor, @NotNull CallableDescriptor callDescriptor,
@NotNull KtExpression receiverExpression @NotNull KtExpression receiverExpression
) { ) {
boolean inlinableCall = isInvokeOrInlineExtension(callDescriptor); boolean inlinableCall = isInvokeOrInlineExtension(callDescriptor);
if (!inlinableCall) { if (!inlinableCall) {
context.trace.report(USAGE_IS_NOT_INLINABLE.on(receiverExpression, receiverExpression, descriptor)); context.getTrace().report(USAGE_IS_NOT_INLINABLE.on(receiverExpression, receiverExpression, descriptor));
} }
else { else {
checkNonLocalReturn(context, lambdaDescriptor, receiverExpression); checkNonLocalReturn(context, lambdaDescriptor, receiverExpression);
} }
} }
public void checkRecursion( private void checkRecursion(
@NotNull BasicCallResolutionContext context, @NotNull CallCheckerContext context,
@NotNull CallableDescriptor targetDescriptor, @NotNull CallableDescriptor targetDescriptor,
@NotNull KtElement expression @NotNull KtElement expression
) { ) {
if (targetDescriptor.getOriginal() == descriptor) { if (targetDescriptor.getOriginal() == descriptor) {
context.trace.report(Errors.RECURSION_IN_INLINE.on(expression, expression, descriptor)); context.getTrace().report(Errors.RECURSION_IN_INLINE.on(expression, expression, descriptor));
} }
} }
@@ -250,10 +237,17 @@ class InlineChecker implements SimpleCallChecker {
return isInvoke || InlineUtil.isInline(descriptor); return isInvoke || InlineUtil.isInline(descriptor);
} }
private void checkVisibilityAndAccess(@NotNull CallableDescriptor declarationDescriptor, @NotNull KtElement expression, @NotNull BasicCallResolutionContext context){ private void checkVisibilityAndAccess(
boolean declarationDescriptorIsPublicApi = DescriptorUtilsKt.isEffectivelyPublicApi(declarationDescriptor) || isDefinedInInlineFunction(declarationDescriptor); @NotNull CallableDescriptor declarationDescriptor,
if (isEffectivelyPublicApiFunction && !declarationDescriptorIsPublicApi && declarationDescriptor.getVisibility() != Visibilities.LOCAL) { @NotNull KtElement expression,
context.trace.report(Errors.NON_PUBLIC_CALL_FROM_PUBLIC_INLINE.on(expression, declarationDescriptor, descriptor)); @NotNull CallCheckerContext context
) {
boolean declarationDescriptorIsPublicApi = DescriptorUtilsKt.isEffectivelyPublicApi(declarationDescriptor) ||
isDefinedInInlineFunction(declarationDescriptor);
if (isEffectivelyPublicApiFunction &&
!declarationDescriptorIsPublicApi &&
declarationDescriptor.getVisibility() != Visibilities.LOCAL) {
context.getTrace().report(Errors.NON_PUBLIC_CALL_FROM_PUBLIC_INLINE.on(expression, declarationDescriptor, descriptor));
} }
else { else {
checkPrivateClassMemberAccess(declarationDescriptor, expression, context); checkPrivateClassMemberAccess(declarationDescriptor, expression, context);
@@ -263,11 +257,11 @@ class InlineChecker implements SimpleCallChecker {
private void checkPrivateClassMemberAccess( private void checkPrivateClassMemberAccess(
@NotNull DeclarationDescriptor declarationDescriptor, @NotNull DeclarationDescriptor declarationDescriptor,
@NotNull KtElement expression, @NotNull KtElement expression,
@NotNull BasicCallResolutionContext context @NotNull CallCheckerContext context
) { ) {
if (!isEffectivelyPrivateApiFunction) { if (!isEffectivelyPrivateApiFunction) {
if (DescriptorUtilsKt.isInsidePrivateClass(declarationDescriptor)) { if (DescriptorUtilsKt.isInsidePrivateClass(declarationDescriptor)) {
context.trace.report(Errors.PRIVATE_CLASS_MEMBER_FROM_INLINE.on(expression, declarationDescriptor, descriptor)); context.getTrace().report(Errors.PRIVATE_CLASS_MEMBER_FROM_INLINE.on(expression, declarationDescriptor, descriptor));
} }
} }
} }
@@ -285,14 +279,14 @@ class InlineChecker implements SimpleCallChecker {
} }
private void checkNonLocalReturn( private void checkNonLocalReturn(
@NotNull BasicCallResolutionContext context, @NotNull CallCheckerContext context,
@NotNull CallableDescriptor inlinableParameterDescriptor, @NotNull CallableDescriptor inlinableParameterDescriptor,
@NotNull KtExpression parameterUsage @NotNull KtExpression parameterUsage
) { ) {
if (!allowsNonLocalReturns(inlinableParameterDescriptor)) return; if (!allowsNonLocalReturns(inlinableParameterDescriptor)) return;
if (!checkNonLocalReturnUsage(descriptor, parameterUsage, context.trace)) { if (!checkNonLocalReturnUsage(descriptor, parameterUsage, context.getTrace())) {
context.trace.report(NON_LOCAL_RETURN_NOT_ALLOWED.on(parameterUsage, parameterUsage)); context.getTrace().report(NON_LOCAL_RETURN_NOT_ALLOWED.on(parameterUsage, parameterUsage));
} }
} }
} }
@@ -16,17 +16,17 @@
package org.jetbrains.kotlin.resolve.calls.checkers package org.jetbrains.kotlin.resolve.calls.checkers
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.inline.InlineUtil import org.jetbrains.kotlin.resolve.inline.InlineUtil
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
class InlineCheckerWrapper : SimpleCallChecker { class InlineCheckerWrapper : CallChecker {
private var checkersCache: WeakReference<MutableMap<DeclarationDescriptor, SimpleCallChecker>>? = null private var checkersCache: WeakReference<MutableMap<DeclarationDescriptor, CallChecker>>? = null
override fun check(resolvedCall: ResolvedCall<*>, context: BasicCallResolutionContext) { override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
if (context.isAnnotationContext) return if (context.isAnnotationContext) return
var parentDescriptor: DeclarationDescriptor? = context.scope.ownerDescriptor var parentDescriptor: DeclarationDescriptor? = context.scope.ownerDescriptor
@@ -34,14 +34,14 @@ class InlineCheckerWrapper : SimpleCallChecker {
while (parentDescriptor != null) { while (parentDescriptor != null) {
if (InlineUtil.isInline(parentDescriptor)) { if (InlineUtil.isInline(parentDescriptor)) {
val checker = getChecker(parentDescriptor as FunctionDescriptor) val checker = getChecker(parentDescriptor as FunctionDescriptor)
checker.check(resolvedCall, context) checker.check(resolvedCall, reportOn, context)
} }
parentDescriptor = parentDescriptor.containingDeclaration parentDescriptor = parentDescriptor.containingDeclaration
} }
} }
private fun getChecker(descriptor: FunctionDescriptor): SimpleCallChecker { private fun getChecker(descriptor: FunctionDescriptor): CallChecker {
val map = checkersCache?.get() ?: hashMapOf() val map = checkersCache?.get() ?: hashMapOf()
checkersCache = checkersCache ?: WeakReference(map) checkersCache = checkersCache ?: WeakReference(map)
return map.getOrPut(descriptor) { InlineChecker(descriptor) } return map.getOrPut(descriptor) { InlineChecker(descriptor) }
@@ -16,15 +16,15 @@
package org.jetbrains.kotlin.resolve.calls.checkers package org.jetbrains.kotlin.resolve.calls.checkers
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.builtins.isExtensionFunctionType import org.jetbrains.kotlin.builtins.isExtensionFunctionType
import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCallImpl import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCallImpl
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
class InvokeConventionChecker : SimpleCallChecker { class InvokeConventionChecker : CallChecker {
override fun check(resolvedCall: ResolvedCall<*>, context: BasicCallResolutionContext) { override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
if (resolvedCall is VariableAsFunctionResolvedCallImpl) { if (resolvedCall is VariableAsFunctionResolvedCallImpl) {
val functionCall = resolvedCall.functionCall val functionCall = resolvedCall.functionCall
val variableCall = resolvedCall.variableCall val variableCall = resolvedCall.variableCall
@@ -17,14 +17,12 @@
package org.jetbrains.kotlin.resolve.calls.checkers package org.jetbrains.kotlin.resolve.calls.checkers
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.config.LanguageFeatureSettings
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.diagnostics.DiagnosticSink import org.jetbrains.kotlin.diagnostics.DiagnosticSink
import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.calls.CallTransformer import org.jetbrains.kotlin.resolve.calls.CallTransformer
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isConventionCall import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isConventionCall
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic
@@ -36,17 +34,13 @@ import org.jetbrains.kotlin.util.OperatorNameConventions.UNARY_MINUS
import org.jetbrains.kotlin.util.OperatorNameConventions.UNARY_PLUS import org.jetbrains.kotlin.util.OperatorNameConventions.UNARY_PLUS
class OperatorCallChecker : CallChecker { class OperatorCallChecker : CallChecker {
override fun check(resolvedCall: ResolvedCall<*>, context: BasicCallResolutionContext, languageFeatureSettings: LanguageFeatureSettings) { override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
val functionDescriptor = resolvedCall.resultingDescriptor as? FunctionDescriptor ?: return val functionDescriptor = resolvedCall.resultingDescriptor as? FunctionDescriptor ?: return
if (!checkNotErrorOrDynamic(functionDescriptor)) return if (!checkNotErrorOrDynamic(functionDescriptor)) return
val element = resolvedCall.call.calleeExpression ?: resolvedCall.call.callElement val element = resolvedCall.call.calleeExpression ?: resolvedCall.call.callElement
val call = resolvedCall.call val call = resolvedCall.call
fun isInvokeCall(): Boolean = call is CallTransformer.CallForImplicitInvoke
fun isMultiDeclaration(): Boolean = call.callElement is KtDestructuringDeclarationEntry
if (resolvedCall is VariableAsFunctionResolvedCall && if (resolvedCall is VariableAsFunctionResolvedCall &&
call is CallTransformer.CallForImplicitInvoke && call.itIsVariableAsFunctionCall) { call is CallTransformer.CallForImplicitInvoke && call.itIsVariableAsFunctionCall) {
val outerCall = call.outerCall val outerCall = call.outerCall
@@ -56,7 +50,7 @@ class OperatorCallChecker : CallChecker {
} }
} }
if (isMultiDeclaration() || isInvokeCall()) { if (call.callElement is KtDestructuringDeclarationEntry || call is CallTransformer.CallForImplicitInvoke) {
if (!functionDescriptor.isOperator) { if (!functionDescriptor.isOperator) {
report(call.callElement, functionDescriptor, context.trace) report(call.callElement, functionDescriptor, context.trace)
} }
@@ -66,7 +60,7 @@ class OperatorCallChecker : CallChecker {
val isConventionOperator = element is KtOperationReferenceExpression && element.getNameForConventionalOperation() != null val isConventionOperator = element is KtOperationReferenceExpression && element.getNameForConventionalOperation() != null
if (isConventionOperator || element is KtArrayAccessExpression) { if (isConventionOperator || element is KtArrayAccessExpression) {
if (!functionDescriptor.isOperator) { if (!functionDescriptor.isOperator) {
report(element, functionDescriptor, context.trace) report(reportOn, functionDescriptor, context.trace)
} }
if (isConventionOperator) { if (isConventionOperator) {
checkDeprecatedUnaryConventions(call, functionDescriptor, context.trace) checkDeprecatedUnaryConventions(call, functionDescriptor, context.trace)
@@ -85,16 +79,16 @@ class OperatorCallChecker : CallChecker {
} }
companion object { companion object {
fun report(element: PsiElement, descriptor: FunctionDescriptor, sink: DiagnosticSink) { fun report(reportOn: PsiElement, descriptor: FunctionDescriptor, sink: DiagnosticSink) {
if (!checkNotErrorOrDynamic(descriptor)) return if (!checkNotErrorOrDynamic(descriptor)) return
val containingDeclaration = descriptor.containingDeclaration val containingDeclaration = descriptor.containingDeclaration
val containingDeclarationName = containingDeclaration.fqNameUnsafe.asString() val containingDeclarationName = containingDeclaration.fqNameUnsafe.asString()
sink.report(Errors.OPERATOR_MODIFIER_REQUIRED.on(element, descriptor, containingDeclarationName)) sink.report(Errors.OPERATOR_MODIFIER_REQUIRED.on(reportOn, descriptor, containingDeclarationName))
} }
private fun checkNotErrorOrDynamic(functionDescriptor: FunctionDescriptor): Boolean { private fun checkNotErrorOrDynamic(functionDescriptor: FunctionDescriptor): Boolean {
return (!functionDescriptor.isDynamic() && !ErrorUtils.isError(functionDescriptor)) return !functionDescriptor.isDynamic() && !ErrorUtils.isError(functionDescriptor)
} }
} }
} }
@@ -16,18 +16,18 @@
package org.jetbrains.kotlin.resolve.calls.checkers package org.jetbrains.kotlin.resolve.calls.checkers
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.psi.KtConstructorCalleeExpression import org.jetbrains.kotlin.psi.KtConstructorCalleeExpression
import org.jetbrains.kotlin.psi.KtConstructorDelegationReferenceExpression import org.jetbrains.kotlin.psi.KtConstructorDelegationReferenceExpression
import org.jetbrains.kotlin.psi.KtSuperTypeCallEntry import org.jetbrains.kotlin.psi.KtSuperTypeCallEntry
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf
object ProtectedConstructorCallChecker : SimpleCallChecker { object ProtectedConstructorCallChecker : CallChecker {
override fun check(resolvedCall: ResolvedCall<*>, context: BasicCallResolutionContext) { override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
val descriptor = resolvedCall.resultingDescriptor as? ConstructorDescriptor ?: return val descriptor = resolvedCall.resultingDescriptor as? ConstructorDescriptor ?: return
val constructorOwner = descriptor.containingDeclaration.original val constructorOwner = descriptor.containingDeclaration.original
val scopeOwner = context.scope.ownerDescriptor val scopeOwner = context.scope.ownerDescriptor
@@ -36,7 +36,7 @@ object ProtectedConstructorCallChecker : SimpleCallChecker {
// Error already reported // Error already reported
if (!Visibilities.isVisibleWithAnyReceiver(descriptor, scopeOwner)) return if (!Visibilities.isVisibleWithAnyReceiver(descriptor, scopeOwner)) return
val calleeExpression = resolvedCall.call.calleeExpression ?: return val calleeExpression = resolvedCall.call.calleeExpression
// Permit constructor super-calls // Permit constructor super-calls
when (calleeExpression) { when (calleeExpression) {
@@ -53,7 +53,7 @@ object ProtectedConstructorCallChecker : SimpleCallChecker {
// of constructor owner // of constructor owner
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
if (Visibilities.findInvisibleMember(Visibilities.FALSE_IF_PROTECTED, descriptor, scopeOwner) == descriptor) { if (Visibilities.findInvisibleMember(Visibilities.FALSE_IF_PROTECTED, descriptor, scopeOwner) == descriptor) {
context.trace.report(Errors.PROTECTED_CONSTRUCTOR_NOT_IN_SUPER_CALL.on(calleeExpression, descriptor)) context.trace.report(Errors.PROTECTED_CONSTRUCTOR_NOT_IN_SUPER_CALL.on(reportOn, descriptor))
} }
} }
} }
@@ -17,35 +17,24 @@
package org.jetbrains.kotlin.resolve.calls.checkers; package org.jetbrains.kotlin.resolve.calls.checkers;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import kotlin.collections.CollectionsKt;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.config.LanguageFeatureSettings;
import org.jetbrains.kotlin.descriptors.ClassDescriptor; import org.jetbrains.kotlin.descriptors.ClassDescriptor;
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor; import org.jetbrains.kotlin.descriptors.ClassifierDescriptor;
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor; import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
import org.jetbrains.kotlin.diagnostics.Errors; import org.jetbrains.kotlin.diagnostics.Errors;
import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.psi.KtTypeProjection;
import org.jetbrains.kotlin.psi.KtExpression;
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.types.KotlinType; import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt; import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt;
import java.util.Map; import java.util.Map;
public class ReifiedTypeParameterSubstitutionChecker implements SimpleCallChecker { public class ReifiedTypeParameterSubstitutionChecker implements CallChecker {
@Override @Override
public void check( public void check(@NotNull ResolvedCall<?> resolvedCall, @NotNull PsiElement reportOn, @NotNull CallCheckerContext context) {
@NotNull ResolvedCall<?> resolvedCall,
@NotNull BasicCallResolutionContext context,
@NotNull LanguageFeatureSettings languageFeatureSettings
) {
SimpleCallChecker.DefaultImpls.check(this, resolvedCall, context, languageFeatureSettings);
}
@Override
public void check(@NotNull ResolvedCall<?> resolvedCall, @NotNull BasicCallResolutionContext context) {
Map<TypeParameterDescriptor, KotlinType> typeArguments = resolvedCall.getTypeArguments(); Map<TypeParameterDescriptor, KotlinType> typeArguments = resolvedCall.getTypeArguments();
for (Map.Entry<TypeParameterDescriptor, KotlinType> entry : typeArguments.entrySet()) { for (Map.Entry<TypeParameterDescriptor, KotlinType> entry : typeArguments.entrySet()) {
TypeParameterDescriptor parameter = entry.getKey(); TypeParameterDescriptor parameter = entry.getKey();
@@ -56,42 +45,34 @@ public class ReifiedTypeParameterSubstitutionChecker implements SimpleCallChecke
continue; continue;
} }
KtTypeProjection typeProjection = CollectionsKt.getOrNull(resolvedCall.getCall().getTypeArguments(), parameter.getIndex());
PsiElement reportErrorOn = typeProjection != null ? typeProjection : reportOn;
if (argumentDeclarationDescriptor instanceof TypeParameterDescriptor && if (argumentDeclarationDescriptor instanceof TypeParameterDescriptor &&
!((TypeParameterDescriptor) argumentDeclarationDescriptor).isReified()) { !((TypeParameterDescriptor) argumentDeclarationDescriptor).isReified()) {
context.trace.report( context.getTrace().report(Errors.TYPE_PARAMETER_AS_REIFIED.on(reportErrorOn, parameter));
Errors.TYPE_PARAMETER_AS_REIFIED.on(getElementToReport(context, parameter.getIndex()), parameter)
);
} }
else if (TypeUtilsKt.cannotBeReified(argument)) { else if (TypeUtilsKt.cannotBeReified(argument)) {
context.trace.report( context.getTrace().report(Errors.REIFIED_TYPE_FORBIDDEN_SUBSTITUTION.on(reportErrorOn, argument));
Errors.REIFIED_TYPE_FORBIDDEN_SUBSTITUTION.on(getElementToReport(context, parameter.getIndex()), argument));
} }
// REIFIED_TYPE_UNSAFE_SUBSTITUTION is temporary disabled because it seems too strict now (see KT-10847) // REIFIED_TYPE_UNSAFE_SUBSTITUTION is temporary disabled because it seems too strict now (see KT-10847)
//else if (TypeUtilsKt.unsafeAsReifiedArgument(argument) && !hasPureReifiableAnnotation(parameter)) { //else if (TypeUtilsKt.unsafeAsReifiedArgument(argument) && !hasPureReifiableAnnotation(parameter)) {
// context.trace.report( // context.getTrace().report(Errors.REIFIED_TYPE_UNSAFE_SUBSTITUTION.on(reportErrorOn, argument));
// Errors.REIFIED_TYPE_UNSAFE_SUBSTITUTION.on(getElementToReport(context, parameter.getIndex()), argument));
//} //}
} }
} }
/*
private static final FqName PURE_REIFIABLE_ANNOTATION_FQ_NAME = new FqName("kotlin.internal.PureReifiable"); private static final FqName PURE_REIFIABLE_ANNOTATION_FQ_NAME = new FqName("kotlin.internal.PureReifiable");
private static boolean hasPureReifiableAnnotation(@NotNull TypeParameterDescriptor parameter) { private static boolean hasPureReifiableAnnotation(@NotNull TypeParameterDescriptor parameter) {
return parameter.getAnnotations().hasAnnotation(PURE_REIFIABLE_ANNOTATION_FQ_NAME) || return parameter.getAnnotations().hasAnnotation(PURE_REIFIABLE_ANNOTATION_FQ_NAME) ||
isTypeParameterOfKotlinArray(parameter); isTypeParameterOfKotlinArray(parameter);
} }
*/
private static boolean isTypeParameterOfKotlinArray(@NotNull TypeParameterDescriptor parameter) { private static boolean isTypeParameterOfKotlinArray(@NotNull TypeParameterDescriptor parameter) {
DeclarationDescriptor container = parameter.getContainingDeclaration(); DeclarationDescriptor container = parameter.getContainingDeclaration();
return container instanceof ClassDescriptor && KotlinBuiltIns.isNonPrimitiveArray((ClassDescriptor) container); return container instanceof ClassDescriptor && KotlinBuiltIns.isNonPrimitiveArray((ClassDescriptor) container);
} }
@NotNull
private static PsiElement getElementToReport(@NotNull BasicCallResolutionContext context, int parameterIndex) {
if (context.call.getTypeArguments().size() > parameterIndex) {
return context.call.getTypeArguments().get(parameterIndex);
}
KtExpression callee = context.call.getCalleeExpression();
return callee != null ? callee : context.call.getCallElement();
}
} }
@@ -16,17 +16,18 @@
package org.jetbrains.kotlin.resolve.calls.checkers package org.jetbrains.kotlin.resolve.calls.checkers
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
class SafeCallChecker : SimpleCallChecker { class SafeCallChecker : CallChecker {
override fun check(resolvedCall: ResolvedCall<*>, context: BasicCallResolutionContext) { override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
val operationNode = resolvedCall.call.callOperationNode ?: return val operationNode = resolvedCall.call.callOperationNode ?: return
if (operationNode.elementType == KtTokens.SAFE_ACCESS && resolvedCall.explicitReceiverKind == ExplicitReceiverKind.NO_EXPLICIT_RECEIVER) { if (operationNode.elementType == KtTokens.SAFE_ACCESS &&
resolvedCall.explicitReceiverKind == ExplicitReceiverKind.NO_EXPLICIT_RECEIVER) {
context.trace.report(Errors.UNEXPECTED_SAFE_CALL.on(operationNode.psi)) context.trace.report(Errors.UNEXPECTED_SAFE_CALL.on(operationNode.psi))
} }
} }
@@ -16,18 +16,17 @@
package org.jetbrains.kotlin.resolve.calls.checkers package org.jetbrains.kotlin.resolve.calls.checkers
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageFeatureSettings
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.coroutine.CoroutineReceiverValue import org.jetbrains.kotlin.resolve.coroutine.CoroutineReceiverValue
import org.jetbrains.kotlin.resolve.inline.InlineUtil import org.jetbrains.kotlin.resolve.inline.InlineUtil
object CoroutineSuspendCallChecker : SimpleCallChecker { object CoroutineSuspendCallChecker : CallChecker {
override fun check(resolvedCall: ResolvedCall<*>, context: BasicCallResolutionContext) { override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
val descriptor = resolvedCall.candidateDescriptor as? FunctionDescriptor ?: return val descriptor = resolvedCall.candidateDescriptor as? FunctionDescriptor ?: return
if (!descriptor.isSuspend || descriptor.initialSignatureDescriptor == null) return if (!descriptor.isSuspend || descriptor.initialSignatureDescriptor == null) return
@@ -35,23 +34,17 @@ object CoroutineSuspendCallChecker : SimpleCallChecker {
val callElement = resolvedCall.call.callElement as KtExpression val callElement = resolvedCall.call.callElement as KtExpression
if (!InlineUtil.checkNonLocalReturnUsage(dispatchReceiverOwner, callElement, context.trace)) { if (!InlineUtil.checkNonLocalReturnUsage(dispatchReceiverOwner, callElement, context.trace)) {
context.trace.report(Errors.NON_LOCAL_SUSPENSION_POINT.on(resolvedCall.call.calleeExpression ?: callElement)) context.trace.report(Errors.NON_LOCAL_SUSPENSION_POINT.on(reportOn))
} }
} }
} }
object BuilderFunctionsCallChecker : CallChecker { object BuilderFunctionsCallChecker : CallChecker {
override fun check( override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
resolvedCall: ResolvedCall<*>,
context: BasicCallResolutionContext,
languageFeatureSettings: LanguageFeatureSettings
) {
val descriptor = resolvedCall.candidateDescriptor as? FunctionDescriptor ?: return val descriptor = resolvedCall.candidateDescriptor as? FunctionDescriptor ?: return
if (descriptor.valueParameters.any { it.isCoroutine } if (descriptor.valueParameters.any { it.isCoroutine } &&
&& !languageFeatureSettings.supportsFeature(LanguageFeature.Coroutines)) { !context.languageFeatureSettings.supportsFeature(LanguageFeature.Coroutines)) {
context.trace.report( context.trace.report(Errors.UNSUPPORTED_FEATURE.on(reportOn, LanguageFeature.Coroutines))
Errors.UNSUPPORTED_FEATURE.on(
resolvedCall.call.calleeExpression ?: resolvedCall.call.callElement, LanguageFeature.Coroutines))
} }
} }
} }
@@ -39,8 +39,7 @@ import org.jetbrains.kotlin.resolve.bindingContextUtil.BindingContextUtilsKt;
import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver; import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver;
import org.jetbrains.kotlin.resolve.calls.CallExpressionResolver; import org.jetbrains.kotlin.resolve.calls.CallExpressionResolver;
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker; import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker;
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext; import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext;
import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode;
import org.jetbrains.kotlin.resolve.calls.model.DataFlowInfoForArgumentsImpl; import org.jetbrains.kotlin.resolve.calls.model.DataFlowInfoForArgumentsImpl;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCallImpl; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCallImpl;
@@ -586,10 +585,9 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
trace.record(RESOLVED_CALL, call, resolvedCall); trace.record(RESOLVED_CALL, call, resolvedCall);
trace.record(CALL, expression, call); trace.record(CALL, expression, call);
BasicCallResolutionContext resolutionContext = CallCheckerContext callCheckerContext = new CallCheckerContext(context, components.languageFeatureSettings);
BasicCallResolutionContext.create(context, call, CheckArgumentTypesMode.CHECK_CALLABLE_TYPE);
for (CallChecker checker : components.callCheckers) { for (CallChecker checker : components.callCheckers) {
checker.check(resolvedCall, resolutionContext, components.languageFeatureSettings); checker.check(resolvedCall, expression, callCheckerContext);
} }
for (SymbolUsageValidator validator : components.symbolUsageValidators) { for (SymbolUsageValidator validator : components.symbolUsageValidators) {
validator.validateCall(resolvedCall, trace, expression); validator.validateCall(resolvedCall, trace, expression);
@@ -894,11 +892,11 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
if (resolvedCall != null) { if (resolvedCall != null) {
// Call must be validated with the actual, not temporary trace in order to report operator diagnostic // Call must be validated with the actual, not temporary trace in order to report operator diagnostic
// Only unary assignment expressions (++, --) and +=/... must be checked, normal assignments have the proper trace // Only unary assignment expressions (++, --) and +=/... must be checked, normal assignments have the proper trace
BasicCallResolutionContext callResolutionContext = BasicCallResolutionContext.create( CallCheckerContext callCheckerContext = new CallCheckerContext(
context.replaceBindingTrace(trace), resolvedCall.getCall(), CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS trace, context.scope, components.languageFeatureSettings, context.dataFlowInfo, context.isAnnotationContext
); );
for (CallChecker checker : components.callCheckers) { for (CallChecker checker : components.callCheckers) {
checker.check(resolvedCall, callResolutionContext, components.languageFeatureSettings); checker.check(resolvedCall, expression, callCheckerContext);
} }
} }
} }
@@ -13,13 +13,13 @@ abstract class A {
open class B : A() { open class B : A() {
fun test() { fun test() {
super.foo("123") super.foo("123")
<!SUPER_CALL_WITH_DEFAULT_PARAMETERS!>super.foo()<!> super.<!SUPER_CALL_WITH_DEFAULT_PARAMETERS!>foo<!>()
super.foo2("123") super.foo2("123")
<!SUPER_CALL_WITH_DEFAULT_PARAMETERS!>super.foo2()<!> super.<!SUPER_CALL_WITH_DEFAULT_PARAMETERS!>foo2<!>()
super.foo3("123") super.foo3("123")
<!SUPER_CALL_WITH_DEFAULT_PARAMETERS!>super.foo3()<!> super.<!SUPER_CALL_WITH_DEFAULT_PARAMETERS!>foo3<!>()
} }
override fun foo3(a: String) { override fun foo3(a: String) {
@@ -19,7 +19,7 @@ class F {
// FILE: main.kt // FILE: main.kt
fun main(x: A) { fun main(x: A) {
x.b().bar() x.b().bar()
x.<!MISSING_DEPENDENCY_CLASS!>f()<!>.<!UNRESOLVED_REFERENCE!>foobaz<!>() x.<!MISSING_DEPENDENCY_CLASS!>f<!>().<!UNRESOLVED_REFERENCE!>foobaz<!>()
<!UNRESOLVED_REFERENCE!>D<!>().<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>baz<!>() <!UNRESOLVED_REFERENCE!>D<!>().<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>baz<!>()
} }
@@ -8,7 +8,7 @@ public interface Test {
// FILE: test.kt // FILE: test.kt
interface KTrait : Test { interface KTrait : Test {
fun ktest() { fun ktest() {
<!INTERFACE_CANT_CALL_DEFAULT_METHOD_VIA_SUPER!>super.test()<!> super.<!INTERFACE_CANT_CALL_DEFAULT_METHOD_VIA_SUPER!>test<!>()
test() test()
} }
@@ -0,0 +1,13 @@
open class C(val x: Int)
class D : C {
constructor() : super(
{
val s = ""
<!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>s<!>()
""() // TODO: see KT-12875
42
}())
operator fun String.invoke() { }
}
@@ -0,0 +1,18 @@
package
public open class C {
public constructor C(/*0*/ x: kotlin.Int)
public final val x: kotlin.Int
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class D : C {
public constructor D()
public final override /*1*/ /*fake_override*/ val x: kotlin.Int
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
public final operator fun kotlin.String.invoke(): kotlin.Unit
}
@@ -38,17 +38,17 @@ fun test4(
) {} ) {}
fun test5() { fun test5() {
<!UNSUPPORTED!>arrayOf<<!REIFIED_TYPE_FORBIDDEN_SUBSTITUTION!>Nothing<!>>()<!> <!UNSUPPORTED!>arrayOf<!><<!REIFIED_TYPE_FORBIDDEN_SUBSTITUTION!>Nothing<!>>()
<!UNSUPPORTED!>Array<<!REIFIED_TYPE_FORBIDDEN_SUBSTITUTION!>Nothing<!>>(10) { throw Exception() }<!> <!UNSUPPORTED!>Array<!><<!REIFIED_TYPE_FORBIDDEN_SUBSTITUTION!>Nothing<!>>(10) { throw Exception() }
} }
fun <T> foo(): Array<T> = (object {} as Any) as Array<T> fun <T> foo(): Array<T> = (object {} as Any) as Array<T>
fun test6() = <!UNSUPPORTED!>foo<Nothing>()<!> fun test6() = <!UNSUPPORTED!>foo<!><Nothing>()
class B<T>(val array: Array<T>) class B<T>(val array: Array<T>)
fun <T> bar() = B<Array<T>>(arrayOf()) fun <T> bar() = B<Array<T>>(arrayOf())
fun test7() = <!UNSUPPORTED!>bar<Nothing>()<!> fun test7() = <!UNSUPPORTED!>bar<!><Nothing>()
@@ -44,24 +44,24 @@ class Derived : Base() {
fun test() { fun test() {
foo() // Ok foo() // Ok
gav() // Ok gav() // Ok
<!SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC!>bar()<!> <!SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC!>bar<!>()
<!SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC!>baz()<!> <!SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC!>baz<!>()
} }
inner class DerivedInner { inner class DerivedInner {
fun fromDerivedInner() { fun fromDerivedInner() {
foo() // Ok foo() // Ok
gav() // Ok gav() // Ok
<!SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC!>bar()<!> <!SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC!>bar<!>()
<!SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC!>baz()<!> <!SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC!>baz<!>()
} }
} }
companion object { companion object {
fun test2() { fun test2() {
gav() // Ok gav() // Ok
<!SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC!>bar()<!> <!SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC!>bar<!>()
<!SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC!>baz()<!> <!SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC!>baz<!>()
} }
} }
} }
@@ -5,8 +5,8 @@ inline fun<reified T> foo(block: () -> T): String = block().toString()
inline fun <reified T: Any> javaClass(): Class<T> = T::class.java inline fun <reified T: Any> javaClass(): Class<T> = T::class.java
fun box() { fun box() {
val a = <!UNSUPPORTED!><!REIFIED_TYPE_FORBIDDEN_SUBSTITUTION!>arrayOf<!>(null!!)<!> val a = <!REIFIED_TYPE_FORBIDDEN_SUBSTITUTION, UNSUPPORTED!>arrayOf<!>(null!!)
val b = <!UNSUPPORTED!>Array<<!REIFIED_TYPE_FORBIDDEN_SUBSTITUTION!>Nothing?<!>>(5) { null!! }<!> val b = <!UNSUPPORTED!>Array<!><<!REIFIED_TYPE_FORBIDDEN_SUBSTITUTION!>Nothing?<!>>(5) { null!! }
val c = <!REIFIED_TYPE_FORBIDDEN_SUBSTITUTION!>foo<!>() { null!! } val c = <!REIFIED_TYPE_FORBIDDEN_SUBSTITUTION!>foo<!>() { null!! }
val d = foo<Any> { null!! } val d = foo<Any> { null!! }
val e = <!REIFIED_TYPE_FORBIDDEN_SUBSTITUTION!>foo<!> { "1" as Nothing } val e = <!REIFIED_TYPE_FORBIDDEN_SUBSTITUTION!>foo<!> { "1" as Nothing }
@@ -16703,6 +16703,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("operatorCall.kt")
public void testOperatorCall() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/operatorCall.kt");
doTest(fileName);
}
@TestMetadata("passingInstance.kt") @TestMetadata("passingInstance.kt")
public void testPassingInstance() throws Exception { public void testPassingInstance() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/passingInstance.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/passingInstance.kt");
@@ -24,6 +24,7 @@ import com.google.gwt.dev.js.rhino.CodePosition
import com.google.gwt.dev.js.rhino.ErrorReporter import com.google.gwt.dev.js.rhino.ErrorReporter
import com.google.gwt.dev.js.rhino.Utils.isEndOfLine import com.google.gwt.dev.js.rhino.Utils.isEndOfLine
import com.intellij.openapi.util.TextRange import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory1 import org.jetbrains.kotlin.diagnostics.DiagnosticFactory1
@@ -36,8 +37,8 @@ import org.jetbrains.kotlin.psi.KtLiteralStringTemplateEntry
import org.jetbrains.kotlin.psi.KtStringTemplateExpression import org.jetbrains.kotlin.psi.KtStringTemplateExpression
import org.jetbrains.kotlin.resolve.BindingTrace import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace import org.jetbrains.kotlin.resolve.TemporaryBindingTrace
import org.jetbrains.kotlin.resolve.calls.checkers.SimpleCallChecker import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant
import org.jetbrains.kotlin.resolve.constants.StringValue import org.jetbrains.kotlin.resolve.constants.StringValue
@@ -47,7 +48,7 @@ import org.jetbrains.kotlin.types.TypeUtils
class JsCallChecker( class JsCallChecker(
private val constantExpressionEvaluator: ConstantExpressionEvaluator private val constantExpressionEvaluator: ConstantExpressionEvaluator
) : SimpleCallChecker { ) : CallChecker {
companion object { companion object {
private val JS_PATTERN: DescriptorPredicate = PatternBuilder.pattern("kotlin.js.js(String)") private val JS_PATTERN: DescriptorPredicate = PatternBuilder.pattern("kotlin.js.js(String)")
@@ -62,7 +63,7 @@ class JsCallChecker(
} }
} }
override fun check(resolvedCall: ResolvedCall<*>, context: BasicCallResolutionContext) { override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
if (context.isAnnotationContext || !resolvedCall.isJsCall()) return if (context.isAnnotationContext || !resolvedCall.isJsCall()) return
val expression = resolvedCall.call.callElement val expression = resolvedCall.call.callElement
@@ -16,27 +16,28 @@
package org.jetbrains.kotlin.android.synthetic.diagnostic package org.jetbrains.kotlin.android.synthetic.diagnostic
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.android.synthetic.descriptors.AndroidSyntheticPackageFragmentDescriptor import org.jetbrains.kotlin.android.synthetic.descriptors.AndroidSyntheticPackageFragmentDescriptor
import org.jetbrains.kotlin.android.synthetic.diagnostic.ErrorsAndroid.* import org.jetbrains.kotlin.android.synthetic.diagnostic.ErrorsAndroid.*
import org.jetbrains.kotlin.android.synthetic.res.AndroidSyntheticProperty import org.jetbrains.kotlin.android.synthetic.res.AndroidSyntheticProperty
import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.diagnostics.DiagnosticSink import org.jetbrains.kotlin.diagnostics.DiagnosticSink
import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.resolve.calls.checkers.SimpleCallChecker import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
class AndroidExtensionPropertiesCallChecker : SimpleCallChecker { class AndroidExtensionPropertiesCallChecker : CallChecker {
override fun check(resolvedCall: ResolvedCall<*>, context: BasicCallResolutionContext) { override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
val expression = context.call.calleeExpression ?: return reportOn as? KtExpression ?: return
val propertyDescriptor = resolvedCall.resultingDescriptor as? PropertyDescriptor ?: return val propertyDescriptor = resolvedCall.resultingDescriptor as? PropertyDescriptor ?: return
val containingPackage = propertyDescriptor.containingDeclaration as? AndroidSyntheticPackageFragmentDescriptor ?: return val containingPackage = propertyDescriptor.containingDeclaration as? AndroidSyntheticPackageFragmentDescriptor ?: return
val androidSyntheticProperty = propertyDescriptor as? AndroidSyntheticProperty ?: return val androidSyntheticProperty = propertyDescriptor as? AndroidSyntheticProperty ?: return
with (context.trace) { with(context.trace) {
checkUnresolvedWidgetType(expression, androidSyntheticProperty) checkUnresolvedWidgetType(reportOn, androidSyntheticProperty)
checkDeprecated(expression, containingPackage) checkDeprecated(reportOn, containingPackage)
} }
} }