KTIJ-34123 KTIJ-34014 [kotlin] Introduce temporary KtTypeReference.typeIfSafeToResolve workaround to avoid frequent exceptions

Put it into common utils so it can be readily used in other places.
Should probably be removed after KT-77222 is fixed.

Use it in `JavaCollectionWithNullableTypeArgumentInspection`
locations which currently produce many such exceptions.

In `JavaCollectionWithNullableTypeArgumentInspection`, remove the
previous workaround for KTIJ-34009 and KT-77333 to avoid
confusion.

^KTIJ-34123 Fixed
^KTIJ-34014 Fixed

GitOrigin-RevId: 8c70d520398fcc794cbd903e9b268459e09f2b03
This commit is contained in:
Roman Golyshev
2025-05-09 18:12:48 +02:00
committed by intellij-monorepo-bot
parent 8afa145acd
commit ebcda8f493
5 changed files with 58 additions and 5 deletions

View File

@@ -8,7 +8,6 @@ import com.intellij.codeInspection.util.IntentionFamilyName
import com.intellij.modcommand.ActionContext
import com.intellij.modcommand.ModPsiUpdater
import com.intellij.openapi.util.TextRange
import com.intellij.psi.util.PsiTreeUtil
import org.jdom.Element
import org.jetbrains.kotlin.analysis.api.KaSession
import org.jetbrains.kotlin.analysis.api.resolution.KaFunctionCall
@@ -22,6 +21,7 @@ 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
import org.jetbrains.kotlin.idea.codeinsight.api.applicators.ApplicabilityRange
import org.jetbrains.kotlin.idea.codeinsight.utils.typeIfSafeToResolve
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.FqNameUnsafe
@@ -104,8 +104,6 @@ internal class JavaCollectionWithNullableTypeArgumentInspection :
}
override fun KaSession.prepareContext(element: KtElement): Context? {
if (PsiTreeUtil.hasErrorElements(element)) return null // Temporary check until KT-77222 is fixed
if (element is KtTypeReference && element.parent is KtSuperExpression) return null // super type qualifier `super<Foo>`
val typeArguments = element.getTypeArguments() ?: return null
val canMakeNonNullable: Boolean
@@ -124,7 +122,7 @@ internal class JavaCollectionWithNullableTypeArgumentInspection :
}
is KtTypeReference -> {
collectionName = element.type.symbol?.importableFqName ?: return null
collectionName = element.typeIfSafeToResolve?.symbol?.importableFqName ?: return null
canMakeNonNullable = canMakeNonNullable(typeArguments) ?: return null
}

View File

@@ -15700,6 +15700,11 @@ public abstract class K2LocalInspectionTestGenerated extends AbstractK2LocalInsp
runTest("../../../idea/tests/testData/inspectionsLocal/javaCollectionsWithNullableTypes/contextParam.kt");
}
@TestMetadata("contextParamPartial.kt")
public void testContextParamPartial() throws Exception {
runTest("../../../idea/tests/testData/inspectionsLocal/javaCollectionsWithNullableTypes/contextParamPartial.kt");
}
@TestMetadata("contextParamWithAngleBracketsBeforeDot.kt")
public void testContextParamWithAngleBracketsBeforeDot() throws Exception {
runTest("../../../idea/tests/testData/inspectionsLocal/javaCollectionsWithNullableTypes/contextParamWithAngleBracketsBeforeDot.kt");
@@ -15740,6 +15745,11 @@ public abstract class K2LocalInspectionTestGenerated extends AbstractK2LocalInsp
runTest("../../../idea/tests/testData/inspectionsLocal/javaCollectionsWithNullableTypes/nullableTypealias.kt");
}
@TestMetadata("recursiveTypeAlias.kt")
public void testRecursiveTypeAlias() throws Exception {
runTest("../../../idea/tests/testData/inspectionsLocal/javaCollectionsWithNullableTypes/recursiveTypeAlias.kt");
}
@TestMetadata("superTypeQualifier.kt")
public void testSuperTypeQualifier() throws Exception {
runTest("../../../idea/tests/testData/inspectionsLocal/javaCollectionsWithNullableTypes/superTypeQualifier.kt");

View File

@@ -1,11 +1,13 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.codeinsight.utils
import org.jetbrains.annotations.ApiStatus
import org.jetbrains.kotlin.analysis.api.KaSession
import org.jetbrains.kotlin.analysis.api.analyze
import org.jetbrains.kotlin.analysis.api.resolution.*
import org.jetbrains.kotlin.analysis.api.symbols.*
import org.jetbrains.kotlin.analysis.api.types.KaFunctionType
import org.jetbrains.kotlin.analysis.api.types.KaType
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.idea.references.KtReference
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
@@ -13,6 +15,7 @@ import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClass
import org.jetbrains.kotlin.psi.psiUtil.unwrapNullability
import org.jetbrains.kotlin.resolve.ArrayFqNames
import org.jetbrains.kotlin.util.OperatorNameConventions
@@ -115,4 +118,36 @@ fun KtExpression.resolveExpression(): KaSymbol? {
reference?.resolveToSymbol()?.let { return it }
val call = resolveToCall()?.calls?.singleOrNull() ?: return null
return if (call is KaCallableMemberCall<*, *>) call.symbol else null
}
}
/**
* A less fragile alternative to [KaSession.type] which should be safer to use on incomplete code.
*
* Can be used now in cases when exceptions occur too frequently, but should eventually become obsolete,
* as [KaSession.type] becomes less fragile.
*
* See KT-77222 for more information.
*
* N.B. This function should NOT be used everywhere - only in cases where exceptions are too frequent.
*/
context(KaSession)
@get:ApiStatus.Internal
val KtTypeReference.typeIfSafeToResolve: KaType?
get() {
val typeElement = this.typeElement?.unwrapNullability() ?: return null
if (typeElement !is KtUserType) {
// We currently do a generous assumption that only `KtUserType`s are really fragile.
// If proved otherwise, this condition should become more restrictive.
return this.type
}
val typeNameExpression = typeElement.referenceExpression
if (typeNameExpression?.mainReference?.resolveToSymbols().isNullOrEmpty()) {
// resolveToSymbols failed, no point in calling type, it may produce/log exceptions
return null
}
return this.type
}

View File

@@ -0,0 +1,6 @@
// WITH_STDLIB
// COMPILER_ARGUMENTS: -Xcontext-parameters
// K2_ERROR: Context parameters are unsupported in this position.
// PROBLEM: none
context(string: <caret>String)

View File

@@ -0,0 +1,4 @@
// WITH_STDLIB
// PROBLEM: none
// K2_ERROR: Recursive type alias in expansion.
typealias RecursiveTATopLevelB = <caret>List<RecursiveTATopLevelB>