New J2K: fix NPEs in nullability analysis
#KT-31817 fixed
This commit is contained in:
+12
-8
@@ -30,7 +30,6 @@ internal class BoundTypeStorage(private val analysisAnalysisContext: AnalysisCon
|
||||
|
||||
fun boundTypeFor(expression: KtExpression): BoundType =
|
||||
cache.getOrPut(expression) {
|
||||
if (expression is KtParenthesizedExpression) return@getOrPut boundTypeFor(expression.expression!!)
|
||||
val boundType =
|
||||
when (expression) {
|
||||
is KtParenthesizedExpression -> expression.expression?.let { boundTypeFor(it) }
|
||||
@@ -131,13 +130,18 @@ internal class BoundTypeStorage(private val analysisAnalysisContext: AnalysisCon
|
||||
val descriptor =
|
||||
getResolvedCall(bindingContext)?.candidateDescriptor?.original?.safeAs<CallableDescriptor>() ?: return null
|
||||
val typeParameters =
|
||||
if (this is KtCallElement) {
|
||||
typeArguments.mapIndexed { index, typeArgument ->
|
||||
//TODO better check
|
||||
descriptor.typeParameters[index] to
|
||||
analysisAnalysisContext.typeElementToTypeVariable.getValue(typeArgument.typeReference?.typeElement!!)
|
||||
}.toMap()
|
||||
} else emptyMap()
|
||||
run {
|
||||
if (this is KtCallElement) {
|
||||
typeArguments.mapIndexed { index, typeArgument ->
|
||||
//TODO better check
|
||||
val typeParameter = descriptor.typeParameters.getOrNull(index) ?: return@run null
|
||||
val typeVariable =
|
||||
analysisAnalysisContext.typeElementToTypeVariable[typeArgument.typeReference?.typeElement ?: return@run null]
|
||||
?: return@run null
|
||||
typeParameter to typeVariable
|
||||
}.toMap()
|
||||
} else emptyMap()
|
||||
} ?: emptyMap()
|
||||
return descriptor.returnType?.toBoundType(contextBoundType, typeParameters)
|
||||
}
|
||||
|
||||
|
||||
+10
-7
@@ -80,7 +80,7 @@ internal class ConstraintsCollector(
|
||||
}
|
||||
|
||||
expression is KtBinaryExpression && expression.asAssignment() != null -> {
|
||||
expression.right?.addSubtypeNullabilityConstraint(expression.left!!, ConstraintCameFrom.ASSIGNMENT_TARGET)
|
||||
expression.right?.addSubtypeNullabilityConstraint(expression.left ?: return, ConstraintCameFrom.ASSIGNMENT_TARGET)
|
||||
}
|
||||
|
||||
expression is KtBinaryExpression && expression.isComaprationWithNull() -> {
|
||||
@@ -152,7 +152,7 @@ internal class ConstraintsCollector(
|
||||
analysisContext.typeElementToTypeVariable[typeElement]
|
||||
}
|
||||
if (loopParameterTypeVariable != null) {
|
||||
val loopRangeBoundType = boundTypeStorage.boundTypeFor(expression.loopRange!!)
|
||||
val loopRangeBoundType = boundTypeStorage.boundTypeFor(expression.loopRange ?: return)
|
||||
val loopRangeType = expression.loopRange?.getType(expression.analyze()) ?: return
|
||||
val loopRangeItemType = loopRangeType
|
||||
.constructor
|
||||
@@ -280,7 +280,7 @@ internal class ConstraintsCollector(
|
||||
}
|
||||
}?.let { type ->
|
||||
boundTypeStorage
|
||||
.boundTypeForType(type, receiverBoundType, callExpression.typeArgumentsDescriptors(descriptor))
|
||||
.boundTypeForType(type, receiverBoundType, callExpression.typeArgumentsDescriptors(descriptor).orEmpty())
|
||||
}
|
||||
|
||||
|
||||
@@ -299,9 +299,12 @@ internal class ConstraintsCollector(
|
||||
}
|
||||
}
|
||||
|
||||
private fun KtCallExpression.typeArgumentsDescriptors(descriptor: CallableDescriptor): Map<TypeParameterDescriptor, TypeVariable> =
|
||||
descriptor.typeParameters.zip(typeArguments) { typeParameter, typeArgument ->
|
||||
typeParameter to
|
||||
this@ConstraintsCollector.analysisContext.typeElementToTypeVariable.getValue(typeArgument.typeReference?.typeElement!!)
|
||||
private fun KtCallExpression.typeArgumentsDescriptors(descriptor: CallableDescriptor): Map<TypeParameterDescriptor, TypeVariable>? {
|
||||
return descriptor.typeParameters.zip(typeArguments) { typeParameter, typeArgument ->
|
||||
val typeVariable =
|
||||
analysisContext.typeElementToTypeVariable[typeArgument.typeReference?.typeElement ?: return null]
|
||||
?: return null
|
||||
typeParameter to typeVariable
|
||||
}.toMap()
|
||||
}
|
||||
}
|
||||
@@ -50,7 +50,7 @@ internal class ContextCreator(
|
||||
if (typeArguments.isNotEmpty())
|
||||
FunctionCallTypeArgumentTarget(
|
||||
this,
|
||||
typeArguments.map { it.typeReference?.typeElement?.asTypeVariable()!! }
|
||||
typeArguments.map { it.typeReference?.typeElement?.asTypeVariable() ?: return null }
|
||||
)
|
||||
else null
|
||||
else -> null
|
||||
|
||||
+5
-6
@@ -11,7 +11,6 @@ import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.PsiComment
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiElementVisitor
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext
|
||||
import org.jetbrains.kotlin.nj2k.asLabel
|
||||
import org.jetbrains.kotlin.nj2k.parentOfType
|
||||
@@ -29,10 +28,10 @@ internal fun TypeVariable.changeNullability(toNullable: Boolean) {
|
||||
internal fun KtTypeElement.changeNullability(toNullable: Boolean) {
|
||||
val factory = KtPsiFactory(this)
|
||||
if (this is KtNullableType && !toNullable) {
|
||||
replace(factory.createType(innerType!!.text).typeElement!!)
|
||||
replace(factory.createType(innerType?.text ?: return).typeElement ?: return)
|
||||
}
|
||||
if (this !is KtNullableType && toNullable) {
|
||||
replace(factory.createType("$text?").typeElement!!)
|
||||
replace(factory.createType("$text?").typeElement ?: return)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,10 +69,10 @@ internal fun KtTypeElement.classReference(): ClassReference {
|
||||
return when (target) {
|
||||
is KtClassOrObject -> KtClassReference(target)
|
||||
is PsiClass -> JavaClassReference(target)
|
||||
is KtTypeAlias -> target.getTypeReference()?.typeElement?.classReference()!!
|
||||
is KtTypeAlias -> target.getTypeReference()?.typeElement?.classReference()
|
||||
is KtTypeParameter -> TypeParameterClassReference(target)
|
||||
else -> UnknownClassReference(text)
|
||||
}
|
||||
else -> null
|
||||
} ?: UnknownClassReference(text)
|
||||
}
|
||||
|
||||
class NullabilityAnalysisFacade(
|
||||
|
||||
@@ -18,7 +18,8 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactoryImpl
|
||||
import org.jetbrains.kotlin.resolve.jvm.checkers.mustNotBeNull
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.isNullable
|
||||
import org.jetbrains.kotlin.util.javaslang.getOrNull
|
||||
|
||||
internal fun KtExpression.deepestReceiver(): KtExpression =
|
||||
@@ -52,7 +53,7 @@ internal fun KtExpression.getForcedNullability(): Nullability? {
|
||||
}
|
||||
|
||||
|
||||
private fun KotlinType.isExternallyAnnotatedNotNull(dataFlowInfo: DataFlowInfo, dataFlowValue: DataFlowValue): Boolean=
|
||||
private fun KotlinType.isExternallyAnnotatedNotNull(dataFlowInfo: DataFlowInfo, dataFlowValue: DataFlowValue): Boolean =
|
||||
mustNotBeNull()?.isFromJava == true && dataFlowInfo.getStableNullability(dataFlowValue).canBeNull()
|
||||
|
||||
private fun IElementType.isEqualsToken() =
|
||||
|
||||
Reference in New Issue
Block a user