Fix parameters nullability for generated overloads in light classes

When making KtLightNullabilityAnnotation after test org.jetbrains.kotlin.idea.caches.resolve.IdeLightClassTestGenerated.NullabilityAnnotations#testJvmOverloads
started failing the wrong assumption was made that for
@JvmOverloads-generated overloads their last parameter is always nullable
(see removed isNullableInJvmOverloads function) and that lead to a bug,
namely KT-28556.

The actual problem of this test started failing was incorrect definition
of kotlinOrigin in KtLightParameter for case of JvmOverloads:
wrong KtParameter was being chosen before

This commit fixes the issue by propagating how actually generated
parameters in codegen relate to source KtParameters'

^KT-28556 Fixed
This commit is contained in:
Denis Zharkov
2018-11-30 15:17:35 +03:00
parent ac19cc9376
commit d7d0407afb
9 changed files with 40 additions and 31 deletions
@@ -231,7 +231,9 @@ public abstract class ClassBodyCodegen extends MemberCodegen<KtPureClassOrObject
private void generateDelegationToDefaultImpl(@NotNull FunctionDescriptor interfaceFun, @NotNull FunctionDescriptor inheritedFun) {
functionCodegen.generateMethod(
new JvmDeclarationOrigin(CLASS_MEMBER_DELEGATION_TO_DEFAULT_IMPL, descriptorToDeclaration(interfaceFun), interfaceFun),
new JvmDeclarationOrigin(
CLASS_MEMBER_DELEGATION_TO_DEFAULT_IMPL, descriptorToDeclaration(interfaceFun), interfaceFun, null
),
inheritedFun,
new FunctionGenerationStrategy.CodegenBased(state) {
@Override
@@ -21,13 +21,16 @@ import org.jetbrains.kotlin.codegen.binding.CodegenBinding
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.psi.KtPureClassOrObject
import org.jetbrains.kotlin.psi.KtPureElement
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.calls.components.hasDefaultValue
import org.jetbrains.kotlin.resolve.isInlineClass
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.jvm.annotations.findJvmOverloadsAnnotation
import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOriginFromPure
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind
import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
@@ -126,6 +129,9 @@ class DefaultParameterValueSubstitutor(val state: GenerationState) {
val isStatic = AsmUtil.isStaticMethod(contextKind, functionDescriptor)
val baseMethodFlags = AsmUtil.getCommonCallableFlags(functionDescriptor, state) and Opcodes.ACC_VARARGS.inv()
val remainingParameters = getRemainingParameters(functionDescriptor.original, substituteCount)
val remainingParametersDeclarations =
remainingParameters.map { DescriptorToSourceUtils.descriptorToDeclaration(it) as? KtParameter }
val flags =
baseMethodFlags or
(if (isStatic) Opcodes.ACC_STATIC else 0) or
@@ -133,7 +139,11 @@ class DefaultParameterValueSubstitutor(val state: GenerationState) {
(if (remainingParameters.lastOrNull()?.varargElementType != null) Opcodes.ACC_VARARGS else 0)
val signature = typeMapper.mapSignatureWithCustomParameters(functionDescriptor, contextKind, remainingParameters, false)
val mv = classBuilder.newMethod(
OtherOriginFromPure(methodElement, functionDescriptor), flags,
JvmDeclarationOrigin(
JvmDeclarationOriginKind.JVM_OVERLOADS, methodElement?.psiOrParent, functionDescriptor,
remainingParametersDeclarations
),
flags,
signature.asmMethod.name,
signature.asmMethod.descriptor,
signature.genericsSignature,
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.resolve.jvm.diagnostics
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.psi.KtPureElement
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind.*
@@ -31,13 +32,15 @@ enum class JvmDeclarationOriginKind {
COLLECTION_STUB,
AUGMENTED_BUILTIN_API,
ERASED_INLINE_CLASS,
UNBOX_METHOD_OF_INLINE_CLASS
UNBOX_METHOD_OF_INLINE_CLASS,
JVM_OVERLOADS
}
class JvmDeclarationOrigin(
val originKind: JvmDeclarationOriginKind,
val element: PsiElement?,
val descriptor: DeclarationDescriptor?
val descriptor: DeclarationDescriptor?,
val parametersForJvmOverload: List<KtParameter?>? = null
) {
companion object {
@JvmField
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.asJava.builder
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.psi.KtAnnotationEntry
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind
@@ -41,7 +42,7 @@ fun JvmDeclarationOrigin.toLightMemberOrigin(): LightElementOrigin {
val originalElement = element
return when (originalElement) {
is KtAnnotationEntry -> DefaultLightElementOrigin(originalElement)
is KtDeclaration -> LightMemberOriginForDeclaration(originalElement, originKind)
is KtDeclaration -> LightMemberOriginForDeclaration(originalElement, originKind, parametersForJvmOverload)
else -> LightElementOrigin.None
}
}
@@ -49,19 +50,24 @@ fun JvmDeclarationOrigin.toLightMemberOrigin(): LightElementOrigin {
interface LightMemberOrigin : LightElementOrigin {
override val originalElement: KtDeclaration?
override val originKind: JvmDeclarationOriginKind
val parametersForJvmOverloads: List<KtParameter?>? get() = null
fun isEquivalentTo(other: LightMemberOrigin?): Boolean
fun copy(): LightMemberOrigin
}
data class LightMemberOriginForDeclaration(override val originalElement: KtDeclaration, override val originKind: JvmDeclarationOriginKind) : LightMemberOrigin {
data class LightMemberOriginForDeclaration(
override val originalElement: KtDeclaration,
override val originKind: JvmDeclarationOriginKind,
override val parametersForJvmOverloads: List<KtParameter?>? = null
) : LightMemberOrigin {
override fun isEquivalentTo(other: LightMemberOrigin?): Boolean {
if (other !is LightMemberOriginForDeclaration) return false
return originalElement.isEquivalentTo(other.originalElement)
}
override fun copy(): LightMemberOrigin {
return LightMemberOriginForDeclaration(originalElement.copy() as KtDeclaration, originKind)
return LightMemberOriginForDeclaration(originalElement.copy() as KtDeclaration, originKind, parametersForJvmOverloads)
}
}
@@ -71,4 +77,4 @@ data class DefaultLightElementOrigin(override val originalElement: PsiElement?)
fun PsiElement?.toLightClassOrigin(): LightElementOrigin {
return if (this != null) DefaultLightElementOrigin(this) else LightElementOrigin.None
}
}
@@ -41,7 +41,7 @@ class KtLightParameter(
if (jetIndex < 0) return null
if (declaration is KtFunction) {
val paramList = declaration.valueParameters
val paramList = method.lightMemberOrigin?.parametersForJvmOverloads ?: declaration.valueParameters
return if (jetIndex < paramList.size) paramList[jetIndex] else null
}
@@ -44,7 +44,6 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getType
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument
import org.jetbrains.kotlin.resolve.descriptorUtil.declaresOrInheritsDefaultValue
import org.jetbrains.kotlin.resolve.jvm.annotations.findJvmOverloadsAnnotation
import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
@@ -260,7 +259,6 @@ class KtLightNullabilityAnnotation(val member: KtLightElement<*, PsiModifierList
if (annotatedElement is KtParameter) {
if (annotatedElement.containingClassOrObject?.isAnnotation() == true) return null
if (isNullableInJvmOverloads(annotatedElement)) return Nullable::class.java.name
}
// don't annotate property setters
@@ -289,13 +287,6 @@ class KtLightNullabilityAnnotation(val member: KtLightElement<*, PsiModifierList
}
}
private fun isNullableInJvmOverloads(annotatedElement: KtParameter): Boolean {
if (annotatedElement.ownerFunction?.let { it.analyze()[BindingContext.DECLARATION_TO_DESCRIPTOR, it]?.findJvmOverloadsAnnotation() } == null) return false
val lightParameterList = (member as? PsiParameter)?.parent as? PsiParameterList ?: return false
val lastParameter = (lightParameterList.parameters.lastOrNull() as? KtLightElement<*, *>)?.kotlinOrigin
return lastParameter == annotatedElement
}
internal fun KtTypeReference.getType(): KotlinType? = analyze()[BindingContext.TYPE, this]
private fun getTargetType(annotatedElement: PsiElement): KotlinType? {
@@ -430,4 +421,4 @@ fun <T> withAllowedAnnotationsClsDelegate(body: () -> T): T {
} finally {
accessAnnotationsClsDelegateIsAllowed = prev
}
}
}
@@ -43,7 +43,6 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getType
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument
import org.jetbrains.kotlin.resolve.descriptorUtil.declaresOrInheritsDefaultValue
import org.jetbrains.kotlin.resolve.jvm.annotations.findJvmOverloadsAnnotation
import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
@@ -261,7 +260,6 @@ class KtLightNullabilityAnnotation(val member: KtLightElement<*, PsiModifierList
if (annotatedElement is KtParameter) {
if (annotatedElement.containingClassOrObject?.isAnnotation() == true) return null
if (isNullableInJvmOverloads(annotatedElement)) return Nullable::class.java.name
}
// don't annotate property setters
@@ -290,13 +288,6 @@ class KtLightNullabilityAnnotation(val member: KtLightElement<*, PsiModifierList
}
}
private fun isNullableInJvmOverloads(annotatedElement: KtParameter): Boolean {
if (annotatedElement.ownerFunction?.let { it.analyze()[BindingContext.DECLARATION_TO_DESCRIPTOR, it]?.findJvmOverloadsAnnotation() } == null) return false
val lightParameterList = (member as? PsiParameter)?.parent as? PsiParameterList ?: return false
val lastParameter = (lightParameterList.parameters.lastOrNull() as? KtLightElement<*, *>)?.kotlinOrigin
return lastParameter == annotatedElement
}
internal fun KtTypeReference.getType(): KotlinType? = analyze()[BindingContext.TYPE, this]
private fun getTargetType(annotatedElement: PsiElement): KotlinType? {
@@ -427,4 +418,4 @@ fun <T> withAllowedAnnotationsClsDelegate(body: () -> T): T {
} finally {
accessAnnotationsClsDelegateIsAllowed = prev
}
}
}
@@ -9,5 +9,10 @@ class JvmOverloadsFunctions {
foo(a.getClass(), a, true, "Some");
foo(a.getClass(), a, true);
foo(a.getClass(), a);
// Before KT-28556 is fixed the second not-nullable parameter wasn't marked as it shoud, so there were no warnings on it
foo(<warning descr="Passing 'null' argument to parameter annotated as @NotNull">null</warning>, <warning descr="Passing 'null' argument to parameter annotated as @NotNull">null</warning>, true, <warning descr="Passing 'null' argument to parameter annotated as @NotNull">null</warning>);
foo(<warning descr="Passing 'null' argument to parameter annotated as @NotNull">null</warning>, <warning descr="Passing 'null' argument to parameter annotated as @NotNull">null</warning>, true);
foo(<warning descr="Passing 'null' argument to parameter annotated as @NotNull">null</warning>, <warning descr="Passing 'null' argument to parameter annotated as @NotNull">null</warning>);
}
}
@@ -1 +1,2 @@
// WITH_RUNTIME
// WITH_RUNTIME
// TOOL: DataFlowInspection