[kotlin] Unpack a user type from a nullable type

KTIJ-33942


(cherry picked from commit 72a2140d5a328d1089e1aab4e01d14bd2fba43b4)

IJ-CR-167086

GitOrigin-RevId: 2500d2b33b4590184749570d499dccbcf12a6edb
This commit is contained in:
Victoria.Petrakovich
2025-06-23 12:45:55 +02:00
committed by intellij-monorepo-bot
parent b5064e7047
commit b32d59990e
4 changed files with 31 additions and 3 deletions

View File

@@ -19,7 +19,6 @@ import org.jetbrains.kotlin.analysis.api.symbols.KaClassifierSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KaConstructorSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KaTypeAliasSymbol
import org.jetbrains.kotlin.analysis.api.types.symbol
import org.jetbrains.kotlin.idea.base.psi.typeArguments
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
import org.jetbrains.kotlin.idea.codeinsight.api.applicable.inspections.KotlinApplicableInspectionBase
import org.jetbrains.kotlin.idea.codeinsight.api.applicable.intentions.KotlinApplicableModCommandAction
@@ -197,7 +196,7 @@ internal class JavaCollectionWithNullableTypeArgumentInspection :
private fun KtTypeProjection.removeQuestionMark() {
val initialNullableType = this.typeReference?.typeElement as? KtNullableType ?: return
val deepestNullableType = generateSequence(initialNullableType) { it.innerType as? KtNullableType }.last()
val deepestNullableType = getDeepestNullableType(initialNullableType)
val innerType = deepestNullableType.innerType ?: return
innerType.let { initialNullableType.replace(innerType) }
}
@@ -300,7 +299,13 @@ private fun KtTypeProjection.isTypeAlias(): Boolean {
private fun KtElement.getTypeArguments(): List<KtTypeProjection>? {
return when (this) {
is KtTypeReference -> {
this.typeArguments()
val typeElement = this.typeElement
val userType = if (typeElement is KtNullableType) {
getDeepestNullableType(typeElement).innerType
} else {
typeElement
} as? KtUserType
userType?.typeArguments.orEmpty()
}
is KtCallExpression -> {
@@ -310,3 +315,7 @@ private fun KtElement.getTypeArguments(): List<KtTypeProjection>? {
else -> null
}
}
private fun getDeepestNullableType(initialNullableType: KtNullableType): KtNullableType {
return generateSequence(initialNullableType) { it.innerType as? KtNullableType }.last()
}

View File

@@ -16551,6 +16551,11 @@ public abstract class K2LocalInspectionTestGenerated extends AbstractK2LocalInsp
runTest("../../../idea/tests/testData/inspectionsLocal/javaCollectionsWithNullableTypes/nullableGeneric.kt");
}
@TestMetadata("nullableTypeReference.kt")
public void testNullableTypeReference() throws Exception {
runTest("../../../idea/tests/testData/inspectionsLocal/javaCollectionsWithNullableTypes/nullableTypeReference.kt");
}
@TestMetadata("nullableTypealias.kt")
public void testNullableTypealias() throws Exception {
runTest("../../../idea/tests/testData/inspectionsLocal/javaCollectionsWithNullableTypes/nullableTypealias.kt");

View File

@@ -0,0 +1,7 @@
// WITH_STDLIB
// PROBLEM: Java collection 'ConcurrentLinkedQueue' is parameterized with a nullable type
import java.util.concurrent.ConcurrentLinkedQueue
fun typeUsage() {
val queue: ConcurrentLinkedQueue<<caret>String?>???? = null
}

View File

@@ -0,0 +1,7 @@
// WITH_STDLIB
// PROBLEM: Java collection 'ConcurrentLinkedQueue' is parameterized with a nullable type
import java.util.concurrent.ConcurrentLinkedQueue
fun typeUsage() {
val queue: ConcurrentLinkedQueue<String>???? = null
}