FIR IDE: null out for erroneous PsiType conversion

This commit is contained in:
Jinseong Jeon
2021-08-27 16:53:27 -07:00
committed by Ilya Kirillov
parent 8e242655f9
commit 5446a8ad10
10 changed files with 44 additions and 22 deletions
@@ -11,13 +11,21 @@ import org.jetbrains.kotlin.idea.frontend.api.types.KtType
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
public abstract class KtPsiTypeProvider : KtAnalysisSessionComponent() {
public abstract fun asPsiType(type: KtType, context: PsiElement, mode: TypeMappingMode): PsiType
public abstract fun asPsiType(type: KtType, context: PsiElement, mode: TypeMappingMode): PsiType?
}
public interface KtPsiTypeProviderMixIn : KtAnalysisSessionMixIn {
/**
* Converts the given [KtType] to [PsiType].
*
* Returns `null` if the conversion encounters any erroneous cases, e.g., errors in type arguments.
* A client can handle such case in its own way. For instance,
* * UAST will return `UastErrorType` as a default error type.
* * LC will return `NonExistentClass` from the [context].
*/
public fun KtType.asPsiType(
context: PsiElement,
mode: TypeMappingMode = TypeMappingMode.DEFAULT
): PsiType =
mode: TypeMappingMode = TypeMappingMode.DEFAULT,
): PsiType? =
analysisSession.psiTypeProvider.asPsiType(this, context, mode)
}
@@ -43,15 +43,15 @@ internal class KtFirPsiTypeProvider(
override val token: ValidityToken,
) : KtPsiTypeProvider(), KtFirAnalysisSessionComponent {
override fun asPsiType(type: KtType, context: PsiElement, mode: TypeMappingMode): PsiType = withValidityAssertion {
override fun asPsiType(
type: KtType,
context: PsiElement,
mode: TypeMappingMode,
): PsiType? = withValidityAssertion {
type.coneType.asPsiType(rootModuleSession, analysisSession.firResolveState, mode, context)
}
}
private fun PsiElement.nonExistentType() = JavaPsiFacade.getElementFactory(project)
.createTypeFromText("error.NonExistentClass", this)
private fun ConeKotlinType.simplifyType(session: FirSession, state: FirModuleResolveState): ConeKotlinType {
val substitutor = AnonymousTypesSubstitutor(session, state)
var currentType = this
@@ -70,11 +70,12 @@ internal fun ConeKotlinType.asPsiType(
state: FirModuleResolveState,
mode: TypeMappingMode,
psiContext: PsiElement,
): PsiType {
): PsiType? {
val correctedType = simplifyType(session, state)
if (correctedType is ConeClassErrorType || correctedType !is SimpleTypeMarker) return psiContext.nonExistentType()
if (correctedType.typeArguments.any { it is ConeClassErrorType }) return psiContext.nonExistentType()
if (correctedType is ConeClassErrorType || correctedType !is SimpleTypeMarker) return null
if (correctedType.typeArguments.any { it is ConeClassErrorType }) return null
val signatureWriter = BothSignatureWriter(BothSignatureWriter.Mode.SKIP_CHECKS)
@@ -83,13 +84,14 @@ internal fun ConeKotlinType.asPsiType(
val canonicalSignature = signatureWriter.toString()
if (canonicalSignature.contains("L<error>")) return psiContext.nonExistentType()
if (canonicalSignature.contains("L<error>")) return null
require(!canonicalSignature.contains(SpecialNames.ANONYMOUS_STRING))
val signature = StringCharacterIterator(canonicalSignature)
val javaType = SignatureParsing.parseTypeString(signature, StubBuildingVisitor.GUESSING_MAPPER)
val typeInfo = TypeInfo.fromString(javaType, false)
val typeText = TypeInfo.createTypeText(typeInfo) ?: return psiContext.nonExistentType()
val typeText = TypeInfo.createTypeText(typeInfo) ?: return null
val typeElement = ClsTypeElementImpl(psiContext, typeText, '\u0000')
return typeElement.type
@@ -124,4 +126,4 @@ private class AnonymousTypesSubstitutor(
return if (type.nullability.isNullable) session.builtinTypes.nullableAnyType.type
else session.builtinTypes.anyType.type
}
}
}