[AA LC] Create proper Psi types for types with errors inside

This commit is contained in:
Dmitriy Novozhilov
2022-09-21 16:13:30 +03:00
committed by Space Team
parent 3a536bb32f
commit a3b9f15ecc
18 changed files with 51 additions and 26 deletions
@@ -41,6 +41,7 @@ internal class KtFe10PsiTypeProvider(
useSitePosition: PsiElement, useSitePosition: PsiElement,
mode: KtTypeMappingMode, mode: KtTypeMappingMode,
isAnnotationMethod: Boolean, isAnnotationMethod: Boolean,
allowErrorTypes: Boolean
): PsiType? { ): PsiType? {
val kotlinType = (type as KtFe10Type).fe10Type val kotlinType = (type as KtFe10Type).fe10Type
@@ -51,17 +51,18 @@ internal class KtFirPsiTypeProvider(
useSitePosition: PsiElement, useSitePosition: PsiElement,
mode: KtTypeMappingMode, mode: KtTypeMappingMode,
isAnnotationMethod: Boolean, isAnnotationMethod: Boolean,
allowErrorTypes: Boolean
): PsiType? { ): PsiType? {
val coneType = type.coneType val coneType = type.coneType
with(rootModuleSession.typeContext) { with(rootModuleSession.typeContext) {
if (coneType.contains { it.isError() }) { if (!allowErrorTypes && coneType.contains { it.isError() }) {
return null return null
} }
} }
return coneType.simplifyType(rootModuleSession, useSitePosition) return coneType.simplifyType(rootModuleSession, useSitePosition)
.asPsiType(rootModuleSession, mode.toTypeMappingMode(type, isAnnotationMethod), useSitePosition) .asPsiType(rootModuleSession, mode.toTypeMappingMode(type, isAnnotationMethod), useSitePosition, allowErrorTypes)
} }
private fun KtTypeMappingMode.toTypeMappingMode(type: KtType, isAnnotationMethod: Boolean): TypeMappingMode { private fun KtTypeMappingMode.toTypeMappingMode(type: KtType, isAnnotationMethod: Boolean): TypeMappingMode {
@@ -186,9 +187,12 @@ private fun ConeKotlinType.asPsiType(
session: FirSession, session: FirSession,
mode: TypeMappingMode, mode: TypeMappingMode,
useSitePosition: PsiElement, useSitePosition: PsiElement,
allowErrorTypes: Boolean
): PsiType? { ): PsiType? {
if (this !is SimpleTypeMarker) return null if (this !is SimpleTypeMarker) return null
if (!allowErrorTypes && (this is ConeErrorType)) return null
val signatureWriter = BothSignatureWriter(BothSignatureWriter.Mode.SKIP_CHECKS) val signatureWriter = BothSignatureWriter(BothSignatureWriter.Mode.SKIP_CHECKS)
//TODO Check thread safety //TODO Check thread safety
@@ -30,7 +30,7 @@ abstract class AbstractAnalysisApiExpressionPsiTypeProviderTest : AbstractAnalys
val actual = analyze(ktFile) { val actual = analyze(ktFile) {
val returnType = declarationAtCaret.getKtType() val returnType = declarationAtCaret.getKtType()
?: error("Not a typable expression ${declarationAtCaret::class} ${declarationAtCaret.text}") ?: error("Not a typable expression ${declarationAtCaret::class} ${declarationAtCaret.text}")
val psiType = returnType.asPsiType(psiContext) val psiType = returnType.asPsiType(psiContext, allowErrorTypes = false)
buildString { buildString {
appendLine("KtType: ${returnType.render(position = Variance.INVARIANT)}") appendLine("KtType: ${returnType.render(position = Variance.INVARIANT)}")
appendLine("PsiType: $psiType") appendLine("PsiType: $psiType")
@@ -39,11 +39,11 @@ abstract class AbstractAnalysisApiPsiTypeProviderTest : AbstractAnalysisApiBased
analyze(declaration) { analyze(declaration) {
val ktType = declaration.getReturnKtType() val ktType = declaration.getReturnKtType()
appendLine("KtType: ${ktType.render(position = Variance.INVARIANT)}") appendLine("KtType: ${ktType.render(position = Variance.INVARIANT)}")
appendLine("PsiType: ${ktType.asPsiType(psiContext)}") appendLine("PsiType: ${ktType.asPsiType(psiContext, allowErrorTypes = false)}")
} }
} }
} }
testServices.assertions.assertEqualsToTestDataFileSibling(actual) testServices.assertions.assertEqualsToTestDataFileSibling(actual)
} }
} }
@@ -17,6 +17,7 @@ public abstract class KtPsiTypeProvider : KtAnalysisSessionComponent() {
useSitePosition: PsiElement, useSitePosition: PsiElement,
mode: KtTypeMappingMode, mode: KtTypeMappingMode,
isAnnotationMethod: Boolean, isAnnotationMethod: Boolean,
allowErrorTypes: Boolean
): PsiType? ): PsiType?
} }
@@ -32,16 +33,19 @@ public interface KtPsiTypeProviderMixIn : KtAnalysisSessionMixIn {
* still use such local type. Otherwise, e.g., exposed to public as a return type, the resulting * still use such local type. Otherwise, e.g., exposed to public as a return type, the resulting
* type will be approximated accordingly. * type will be approximated accordingly.
* *
* Returns `null` if the conversion encounters any erroneous cases, e.g., errors in type arguments. * If [allowErrorTypes] set to false then method 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, * A client can handle such case in its own way. For instance,
* * UAST will return `UastErrorType` as a default error type. * * UAST will return `UastErrorType` as a default error type.
* * LC will return `NonExistentClass` created from the [useSitePosition]. *
* If [allowErrorTypes] set to true then erroneous types will be replaced with `error.NonExistentClass` type
*/ */
public fun KtType.asPsiType( public fun KtType.asPsiType(
useSitePosition: PsiElement, useSitePosition: PsiElement,
allowErrorTypes: Boolean,
mode: KtTypeMappingMode = KtTypeMappingMode.DEFAULT, mode: KtTypeMappingMode = KtTypeMappingMode.DEFAULT,
isAnnotationMethod: Boolean = false, isAnnotationMethod: Boolean = false
): PsiType? = ): PsiType? = withValidityAssertion {
withValidityAssertion { analysisSession.psiTypeProvider.asPsiType(this, useSitePosition, mode, isAnnotationMethod) } analysisSession.psiTypeProvider.asPsiType(this, useSitePosition, mode, isAnnotationMethod, allowErrorTypes)
}
} }
@@ -80,8 +80,8 @@ internal object PsiDeclarationAndKtSymbolEqualityChecker {
): Boolean { ): Boolean {
// Shortcut: primitive void == Unit as a function return type // Shortcut: primitive void == Unit as a function return type
if (psi == PsiType.VOID && ktType.isUnit) return true if (psi == PsiType.VOID && ktType.isUnit) return true
val ktTypeRendered = ktType.asPsiType(context, mode) ?: return false val ktTypeRendered = ktType.asPsiType(context, allowErrorTypes = true, mode) ?: return false
val rendered = if (isVararg) ktTypeRendered.createArrayType() else ktTypeRendered val rendered = if (isVararg) ktTypeRendered.createArrayType() else ktTypeRendered
return rendered == psi return rendered == psi
} }
} }
@@ -309,8 +309,9 @@ internal fun KtAnnotatedSymbol.computeThrowsList(
is KtNonLocalKClassAnnotationValue -> { is KtNonLocalKClassAnnotationValue -> {
val psiType = buildClassType(annotationValue.classId).asPsiType( val psiType = buildClassType(annotationValue.classId).asPsiType(
useSitePosition, useSitePosition,
allowErrorTypes = true,
KtTypeMappingMode.DEFAULT, KtTypeMappingMode.DEFAULT,
containingClass.isAnnotationType containingClass.isAnnotationType,
) )
(psiType as? PsiClassType)?.let { (psiType as? PsiClassType)?.let {
builder.addReference(it) builder.addReference(it)
@@ -72,8 +72,11 @@ internal class SymbolLightClassForEnumEntry(
private val _extendsList: PsiReferenceList? by lazyPub { private val _extendsList: PsiReferenceList? by lazyPub {
val mappedType = enumConstant.withEnumEntrySymbol { symbol -> val mappedType = enumConstant.withEnumEntrySymbol { symbol ->
symbol.returnType.asPsiType(this@SymbolLightClassForEnumEntry, KtTypeMappingMode.SUPER_TYPE) as? PsiClassType symbol.returnType.asPsiType(
} ?: return@lazyPub null this@SymbolLightClassForEnumEntry,
allowErrorTypes = true,
KtTypeMappingMode.SUPER_TYPE
) as? PsiClassType} ?: return@lazyPub null
KotlinSuperTypeListBuilder( KotlinSuperTypeListBuilder(
kotlinOrigin = enumClass.kotlinOrigin?.getSuperTypeList(), kotlinOrigin = enumClass.kotlinOrigin?.getSuperTypeList(),
@@ -85,7 +85,7 @@ internal class SymbolLightFieldForEnumEntry(
private val _type: PsiType by lazyPub { private val _type: PsiType by lazyPub {
withEnumEntrySymbol { enumEntrySymbol -> withEnumEntrySymbol { enumEntrySymbol ->
enumEntrySymbol.returnType.asPsiType(this@SymbolLightFieldForEnumEntry) ?: nonExistentType() enumEntrySymbol.returnType.asPsiType(this@SymbolLightFieldForEnumEntry, allowErrorTypes = true) ?: nonExistentType()
} }
} }
@@ -84,7 +84,8 @@ internal class SymbolLightFieldForObject private constructor(
private val _type: PsiType by lazyPub { private val _type: PsiType by lazyPub {
withObjectDeclarationSymbol { objectSymbol -> withObjectDeclarationSymbol { objectSymbol ->
objectSymbol.buildSelfClassType().asPsiType(this@SymbolLightFieldForObject) objectSymbol.buildSelfClassType()
.asPsiType(this@SymbolLightFieldForObject, allowErrorTypes = true)
} ?: nonExistentType() } ?: nonExistentType()
} }
@@ -70,10 +70,18 @@ internal class SymbolLightFieldForProperty private constructor(
when { when {
isDelegated -> isDelegated ->
(kotlinOrigin as? KtProperty)?.delegateExpression?.let { (kotlinOrigin as? KtProperty)?.delegateExpression?.let {
it.getKtType()?.asPsiType(this@SymbolLightFieldForProperty, KtTypeMappingMode.RETURN_TYPE) it.getKtType()?.asPsiType(
this@SymbolLightFieldForProperty,
allowErrorTypes = true,
KtTypeMappingMode.RETURN_TYPE
)
} }
else -> propertySymbol.returnType.asPsiType(this@SymbolLightFieldForProperty, KtTypeMappingMode.RETURN_TYPE) else -> propertySymbol.returnType.asPsiType(
this@SymbolLightFieldForProperty,
allowErrorTypes = true,
KtTypeMappingMode.RETURN_TYPE
)
} ?: nonExistentType() } ?: nonExistentType()
} }
} }
@@ -233,8 +233,9 @@ internal class SymbolLightAccessorMethod private constructor(
analyzeForLightClasses(ktModule) { analyzeForLightClasses(ktModule) {
propertySymbol().returnType.asPsiType( propertySymbol().returnType.asPsiType(
this@SymbolLightAccessorMethod, this@SymbolLightAccessorMethod,
KtTypeMappingMode.RETURN_TYPE, allowErrorTypes = true,
containingClass.isAnnotationType, KtTypeMappingMode.RETURN_TYPE,
containingClass.isAnnotationType,
) )
} ?: nonExistentType() } ?: nonExistentType()
} }
@@ -185,6 +185,7 @@ internal class SymbolLightSimpleMethod(
ktType.asPsiType( ktType.asPsiType(
this@SymbolLightSimpleMethod, this@SymbolLightSimpleMethod,
allowErrorTypes = true,
KtTypeMappingMode.RETURN_TYPE, KtTypeMappingMode.RETURN_TYPE,
containingClass.isAnnotationType, containingClass.isAnnotationType,
) )
@@ -75,7 +75,7 @@ internal abstract class SymbolLightParameterCommon(
else -> KtTypeMappingMode.VALUE_PARAMETER else -> KtTypeMappingMode.VALUE_PARAMETER
} }
ktType.asPsiType(this@SymbolLightParameterCommon, typeMappingMode) ktType.asPsiType(this@SymbolLightParameterCommon, allowErrorTypes = true, typeMappingMode)
} ?: nonExistentType() } ?: nonExistentType()
if (parameterSymbol.isVararg) { if (parameterSymbol.isVararg) {
@@ -85,7 +85,7 @@ internal class SymbolLightParameterForReceiver private constructor(
private val _type: PsiType by lazyPub { private val _type: PsiType by lazyPub {
withReceiverSymbol { receiver -> withReceiverSymbol { receiver ->
receiver.type.asPsiType(this) receiver.type.asPsiType(this, allowErrorTypes = true)
} ?: nonExistentType() } ?: nonExistentType()
} }
@@ -41,7 +41,7 @@ internal class SymbolLightSuspendContinuationParameter(
private val _type by lazyPub { private val _type by lazyPub {
withFunctionSymbol { functionSymbol -> withFunctionSymbol { functionSymbol ->
buildClassType(StandardClassIds.Continuation) { argument(functionSymbol.returnType) }.asPsiType(this) ?: nonExistentType() buildClassType(StandardClassIds.Continuation) { argument(functionSymbol.returnType) }.asPsiType(this, allowErrorTypes = true) ?: nonExistentType()
} }
} }
@@ -46,6 +46,7 @@ internal fun KtAnalysisSession.mapType(
if (type is KtClassErrorType) return null if (type is KtClassErrorType) return null
val psiType = type.asPsiType( val psiType = type.asPsiType(
psiContext, psiContext,
allowErrorTypes = true,
mode, mode,
) )
return psiType as? PsiClassType return psiType as? PsiClassType
@@ -24,7 +24,7 @@ public final class JvmWildcardAnnotationsKt /* JvmWildcardAnnotationsKt*/ {
@kotlin.jvm.JvmSuppressWildcards(suppress = true) @kotlin.jvm.JvmSuppressWildcards(suppress = true)
@org.jetbrains.annotations.NotNull() @org.jetbrains.annotations.NotNull()
public static final error.NonExistentClass foo2();// foo2() public static final Out<error.NonExistentClass> foo2();// foo2()
@kotlin.jvm.JvmSuppressWildcards(suppress = true) @kotlin.jvm.JvmSuppressWildcards(suppress = true)
public static final int bar(boolean, @org.jetbrains.annotations.NotNull() In<? super java.lang.Long>, long);// bar(boolean, In<? super java.lang.Long>, long) public static final int bar(boolean, @org.jetbrains.annotations.NotNull() In<? super java.lang.Long>, long);// bar(boolean, In<? super java.lang.Long>, long)