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 = fun boundTypeFor(expression: KtExpression): BoundType =
cache.getOrPut(expression) { cache.getOrPut(expression) {
if (expression is KtParenthesizedExpression) return@getOrPut boundTypeFor(expression.expression!!)
val boundType = val boundType =
when (expression) { when (expression) {
is KtParenthesizedExpression -> expression.expression?.let { boundTypeFor(it) } is KtParenthesizedExpression -> expression.expression?.let { boundTypeFor(it) }
@@ -131,13 +130,18 @@ internal class BoundTypeStorage(private val analysisAnalysisContext: AnalysisCon
val descriptor = val descriptor =
getResolvedCall(bindingContext)?.candidateDescriptor?.original?.safeAs<CallableDescriptor>() ?: return null getResolvedCall(bindingContext)?.candidateDescriptor?.original?.safeAs<CallableDescriptor>() ?: return null
val typeParameters = val typeParameters =
if (this is KtCallElement) { run {
typeArguments.mapIndexed { index, typeArgument -> if (this is KtCallElement) {
//TODO better check typeArguments.mapIndexed { index, typeArgument ->
descriptor.typeParameters[index] to //TODO better check
analysisAnalysisContext.typeElementToTypeVariable.getValue(typeArgument.typeReference?.typeElement!!) val typeParameter = descriptor.typeParameters.getOrNull(index) ?: return@run null
}.toMap() val typeVariable =
} else emptyMap() analysisAnalysisContext.typeElementToTypeVariable[typeArgument.typeReference?.typeElement ?: return@run null]
?: return@run null
typeParameter to typeVariable
}.toMap()
} else emptyMap()
} ?: emptyMap()
return descriptor.returnType?.toBoundType(contextBoundType, typeParameters) return descriptor.returnType?.toBoundType(contextBoundType, typeParameters)
} }
@@ -80,7 +80,7 @@ internal class ConstraintsCollector(
} }
expression is KtBinaryExpression && expression.asAssignment() != null -> { 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() -> { expression is KtBinaryExpression && expression.isComaprationWithNull() -> {
@@ -152,7 +152,7 @@ internal class ConstraintsCollector(
analysisContext.typeElementToTypeVariable[typeElement] analysisContext.typeElementToTypeVariable[typeElement]
} }
if (loopParameterTypeVariable != null) { 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 loopRangeType = expression.loopRange?.getType(expression.analyze()) ?: return
val loopRangeItemType = loopRangeType val loopRangeItemType = loopRangeType
.constructor .constructor
@@ -280,7 +280,7 @@ internal class ConstraintsCollector(
} }
}?.let { type -> }?.let { type ->
boundTypeStorage 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> = private fun KtCallExpression.typeArgumentsDescriptors(descriptor: CallableDescriptor): Map<TypeParameterDescriptor, TypeVariable>? {
descriptor.typeParameters.zip(typeArguments) { typeParameter, typeArgument -> return descriptor.typeParameters.zip(typeArguments) { typeParameter, typeArgument ->
typeParameter to val typeVariable =
this@ConstraintsCollector.analysisContext.typeElementToTypeVariable.getValue(typeArgument.typeReference?.typeElement!!) analysisContext.typeElementToTypeVariable[typeArgument.typeReference?.typeElement ?: return null]
?: return null
typeParameter to typeVariable
}.toMap() }.toMap()
}
} }
@@ -50,7 +50,7 @@ internal class ContextCreator(
if (typeArguments.isNotEmpty()) if (typeArguments.isNotEmpty())
FunctionCallTypeArgumentTarget( FunctionCallTypeArgumentTarget(
this, this,
typeArguments.map { it.typeReference?.typeElement?.asTypeVariable()!! } typeArguments.map { it.typeReference?.typeElement?.asTypeVariable() ?: return null }
) )
else null else null
else -> null else -> null
@@ -11,7 +11,6 @@ import com.intellij.psi.PsiClass
import com.intellij.psi.PsiComment import com.intellij.psi.PsiComment
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.PsiElementVisitor import com.intellij.psi.PsiElementVisitor
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext
import org.jetbrains.kotlin.nj2k.asLabel import org.jetbrains.kotlin.nj2k.asLabel
import org.jetbrains.kotlin.nj2k.parentOfType import org.jetbrains.kotlin.nj2k.parentOfType
@@ -29,10 +28,10 @@ internal fun TypeVariable.changeNullability(toNullable: Boolean) {
internal fun KtTypeElement.changeNullability(toNullable: Boolean) { internal fun KtTypeElement.changeNullability(toNullable: Boolean) {
val factory = KtPsiFactory(this) val factory = KtPsiFactory(this)
if (this is KtNullableType && !toNullable) { if (this is KtNullableType && !toNullable) {
replace(factory.createType(innerType!!.text).typeElement!!) replace(factory.createType(innerType?.text ?: return).typeElement ?: return)
} }
if (this !is KtNullableType && toNullable) { 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) { return when (target) {
is KtClassOrObject -> KtClassReference(target) is KtClassOrObject -> KtClassReference(target)
is PsiClass -> JavaClassReference(target) is PsiClass -> JavaClassReference(target)
is KtTypeAlias -> target.getTypeReference()?.typeElement?.classReference()!! is KtTypeAlias -> target.getTypeReference()?.typeElement?.classReference()
is KtTypeParameter -> TypeParameterClassReference(target) is KtTypeParameter -> TypeParameterClassReference(target)
else -> UnknownClassReference(text) else -> null
} } ?: UnknownClassReference(text)
} }
class NullabilityAnalysisFacade( 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.DataFlowValue
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactoryImpl import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactoryImpl
import org.jetbrains.kotlin.resolve.jvm.checkers.mustNotBeNull 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 import org.jetbrains.kotlin.util.javaslang.getOrNull
internal fun KtExpression.deepestReceiver(): KtExpression = 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() mustNotBeNull()?.isFromJava == true && dataFlowInfo.getStableNullability(dataFlowValue).canBeNull()
private fun IElementType.isEqualsToken() = private fun IElementType.isEqualsToken() =