From c1e24d818b6a2c066d9047e04c533353743a7494 Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Wed, 5 Jun 2019 17:21:35 +0300 Subject: [PATCH] New J2K: fix NPEs in nullability analysis #KT-31817 fixed --- .../nullabilityAnalysis/BoundTypeStorage.kt | 20 +++++++++++-------- .../constraintsCollector.kt | 17 +++++++++------- .../nj2k/nullabilityAnalysis/context.kt | 2 +- .../nullabilityAnalysis.kt | 11 +++++----- .../kotlin/nj2k/nullabilityAnalysis/utils.kt | 5 +++-- 5 files changed, 31 insertions(+), 24 deletions(-) diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/nullabilityAnalysis/BoundTypeStorage.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/nullabilityAnalysis/BoundTypeStorage.kt index 4c9ce357c70..9a40f2724e2 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/nullabilityAnalysis/BoundTypeStorage.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/nullabilityAnalysis/BoundTypeStorage.kt @@ -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() ?: 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) } diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/nullabilityAnalysis/constraintsCollector.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/nullabilityAnalysis/constraintsCollector.kt index 178e76d37c0..0386136e9e2 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/nullabilityAnalysis/constraintsCollector.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/nullabilityAnalysis/constraintsCollector.kt @@ -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 = - descriptor.typeParameters.zip(typeArguments) { typeParameter, typeArgument -> - typeParameter to - this@ConstraintsCollector.analysisContext.typeElementToTypeVariable.getValue(typeArgument.typeReference?.typeElement!!) + private fun KtCallExpression.typeArgumentsDescriptors(descriptor: CallableDescriptor): Map? { + return descriptor.typeParameters.zip(typeArguments) { typeParameter, typeArgument -> + val typeVariable = + analysisContext.typeElementToTypeVariable[typeArgument.typeReference?.typeElement ?: return null] + ?: return null + typeParameter to typeVariable }.toMap() + } } \ No newline at end of file diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/nullabilityAnalysis/context.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/nullabilityAnalysis/context.kt index c7f177ce377..efd0fd66c10 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/nullabilityAnalysis/context.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/nullabilityAnalysis/context.kt @@ -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 diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/nullabilityAnalysis/nullabilityAnalysis.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/nullabilityAnalysis/nullabilityAnalysis.kt index 142b5ee7800..5b0643fdf21 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/nullabilityAnalysis/nullabilityAnalysis.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/nullabilityAnalysis/nullabilityAnalysis.kt @@ -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( diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/nullabilityAnalysis/utils.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/nullabilityAnalysis/utils.kt index 0be9d801552..c265fb81a97 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/nullabilityAnalysis/utils.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/nullabilityAnalysis/utils.kt @@ -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() =