New J2K: fix NPEs in nullability analysis

#KT-31817 fixed
This commit is contained in:
Ilya Kirillov
2019-06-05 17:21:35 +03:00
parent 1a9deed5d8
commit c1e24d818b
5 changed files with 31 additions and 24 deletions
@@ -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)
}
@@ -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
@@ -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() =