From cc6389d39478414d6e51e774b326b15255119b3f Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Mon, 16 Aug 2021 17:18:48 +0300 Subject: [PATCH] FIR LC: do not use fir directly to create PSI types --- .../api/components/KtPsiTypeProvider.kt | 2 +- .../classes/FirLightClassForEnumEntry.kt | 10 +- .../idea/asJava/classes/firLightClassUtils.kt | 8 +- .../asJava/fields/FirLightFieldEnumEntry.kt | 5 +- .../fields/FirLightFieldForObjectSymbol.kt | 6 +- .../fields/FirLightFieldForPropertySymbol.kt | 9 +- .../kotlin/idea/asJava/firLightUtils.kt | 175 ++---------------- .../FirLightAccessorMethodForSymbol.kt | 9 +- .../methods/FirLightSimpleMethodForSymbol.kt | 5 +- .../FirLightParameterBaseForSymbol.kt | 6 +- .../FirLightParameterForReceiver.kt | 5 +- .../parameters/FirLightTypeParameter.kt | 24 +-- .../fir/components/KtFirPsiTypeProvider.kt | 103 ++++++++++- 13 files changed, 175 insertions(+), 192 deletions(-) diff --git a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/components/KtPsiTypeProvider.kt b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/components/KtPsiTypeProvider.kt index eaea81950a5..807456414a5 100644 --- a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/components/KtPsiTypeProvider.kt +++ b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/components/KtPsiTypeProvider.kt @@ -18,6 +18,6 @@ public interface KtPsiTypeProviderMixIn : KtAnalysisSessionMixIn { public fun KtType.asPsiType( context: PsiElement, mode: TypeMappingMode = TypeMappingMode.DEFAULT - ): PsiType? = + ): PsiType = analysisSession.psiTypeProvider.asPsiType(this, context, mode) } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightClassForEnumEntry.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightClassForEnumEntry.kt index 53be1051f40..8bc8d11108e 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightClassForEnumEntry.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/FirLightClassForEnumEntry.kt @@ -17,6 +17,7 @@ import org.jetbrains.kotlin.idea.frontend.api.fir.analyzeWithSymbolAsContext import org.jetbrains.kotlin.idea.frontend.api.isValid import org.jetbrains.kotlin.idea.frontend.api.symbols.KtEnumEntrySymbol import org.jetbrains.kotlin.load.java.structure.LightClassOriginKind +import org.jetbrains.kotlin.load.kotlin.TypeMappingMode import org.jetbrains.kotlin.psi.KtClassOrObject internal class FirLightClassForEnumEntry( @@ -83,10 +84,11 @@ internal class FirLightClassForEnumEntry( override fun isEnum(): Boolean = false private val _extendsList: PsiReferenceList? by lazyPub { - - val mappedType = enumEntrySymbol.annotatedType - .mapSupertype(this@FirLightClassForEnumEntry) - ?: return@lazyPub null + val mappedType = analyzeWithSymbolAsContext(enumEntrySymbol) { + enumEntrySymbol.annotatedType + .type.asPsiType(this@FirLightClassForEnumEntry, TypeMappingMode.SUPER_TYPE) as? PsiClassType + ?: return@lazyPub null + } KotlinSuperTypeListBuilder( kotlinOrigin = enumClass.kotlinOrigin?.getSuperTypeList(), diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/firLightClassUtils.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/firLightClassUtils.kt index e29bd25113a..21293353588 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/firLightClassUtils.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/classes/firLightClassUtils.kt @@ -315,7 +315,13 @@ internal fun FirLightClassBase.createInheritanceList(forExtendsList: Boolean, su //TODO Add support for kotlin.collections. superTypes.asSequence() .filter { it.type.needToAddTypeIntoList() } - .mapNotNull { it.mapSupertype(this, kotlinCollectionAsIs = true) } + .mapNotNull { typeAnnotated -> + val type = typeAnnotated.type + if (type !is KtNonErrorClassType) return@mapNotNull null + analyzeWithSymbolAsContext(type.classSymbol) { + mapSuperType(type, this@createInheritanceList, kotlinCollectionAsIs = true) + } + } .forEach { listBuilder.addReference(it) } return listBuilder diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/fields/FirLightFieldEnumEntry.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/fields/FirLightFieldEnumEntry.kt index 9e8c81379bb..aab6c041e18 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/fields/FirLightFieldEnumEntry.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/fields/FirLightFieldEnumEntry.kt @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.asJava.classes.* import org.jetbrains.kotlin.asJava.elements.FirLightIdentifier import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.idea.asJava.* +import org.jetbrains.kotlin.idea.frontend.api.fir.analyzeWithSymbolAsContext import org.jetbrains.kotlin.idea.frontend.api.isValid import org.jetbrains.kotlin.idea.frontend.api.symbols.KtEnumEntrySymbol import org.jetbrains.kotlin.psi.KtEnumEntry @@ -65,7 +66,9 @@ internal class FirLightFieldForEnumEntry( override fun getName(): String = enumEntrySymbol.name.asString() private val _type: PsiType by lazyPub { - enumEntrySymbol.annotatedType.asPsiType(enumEntrySymbol, this@FirLightFieldForEnumEntry, FirResolvePhase.TYPES) + analyzeWithSymbolAsContext(enumEntrySymbol) { + enumEntrySymbol.annotatedType.type.asPsiType(this@FirLightFieldForEnumEntry) + } } override fun getType(): PsiType = _type diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/fields/FirLightFieldForObjectSymbol.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/fields/FirLightFieldForObjectSymbol.kt index 83812eaf7d0..b7fa27eb86b 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/fields/FirLightFieldForObjectSymbol.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/fields/FirLightFieldForObjectSymbol.kt @@ -10,8 +10,10 @@ import org.jetbrains.kotlin.asJava.builder.LightMemberOrigin import org.jetbrains.kotlin.asJava.classes.KtLightClass import org.jetbrains.kotlin.asJava.classes.lazyPub import org.jetbrains.kotlin.asJava.elements.FirLightIdentifier +import org.jetbrains.kotlin.idea.frontend.api.fir.analyzeWithSymbolAsContext import org.jetbrains.kotlin.idea.frontend.api.isValid import org.jetbrains.kotlin.idea.frontend.api.symbols.KtNamedClassOrObjectSymbol +import org.jetbrains.kotlin.load.kotlin.TypeMappingMode import org.jetbrains.kotlin.psi.KtDeclaration internal class FirLightFieldForObjectSymbol( @@ -40,7 +42,9 @@ internal class FirLightFieldForObjectSymbol( override fun getModifierList(): PsiModifierList? = _modifierList private val _type: PsiType by lazyPub { - objectSymbol.typeForClassSymbol(this@FirLightFieldForObjectSymbol) + analyzeWithSymbolAsContext(objectSymbol) { + objectSymbol.buildSelfClassType().asPsiType(this@FirLightFieldForObjectSymbol) + } } private val _identifier: PsiIdentifier by lazyPub { diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/fields/FirLightFieldForPropertySymbol.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/fields/FirLightFieldForPropertySymbol.kt index 74284f0e601..08c0d6dd3d4 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/fields/FirLightFieldForPropertySymbol.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/fields/FirLightFieldForPropertySymbol.kt @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.asJava.classes.lazyPub import org.jetbrains.kotlin.asJava.elements.FirLightIdentifier import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget import org.jetbrains.kotlin.fir.declarations.FirResolvePhase +import org.jetbrains.kotlin.idea.frontend.api.fir.analyzeWithSymbolAsContext import org.jetbrains.kotlin.idea.frontend.api.isValid import org.jetbrains.kotlin.idea.frontend.api.symbols.KtKotlinPropertySymbol import org.jetbrains.kotlin.idea.frontend.api.symbols.KtPropertySymbol @@ -30,11 +31,9 @@ internal class FirLightFieldForPropertySymbol( override val kotlinOrigin: KtDeclaration? = propertySymbol.psi as? KtDeclaration private val _returnedType: PsiType by lazyPub { - propertySymbol.annotatedType.asPsiType( - propertySymbol, - this@FirLightFieldForPropertySymbol, - FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE - ) + analyzeWithSymbolAsContext(propertySymbol) { + propertySymbol.annotatedType.type.asPsiType(this@FirLightFieldForPropertySymbol) + } } private val _isDeprecated: Boolean by lazyPub { diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/firLightUtils.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/firLightUtils.kt index 6990f90fa88..9880673337c 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/firLightUtils.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/firLightUtils.kt @@ -6,40 +6,25 @@ package org.jetbrains.kotlin.idea.asJava import com.intellij.psi.* -import com.intellij.psi.impl.cache.TypeInfo -import com.intellij.psi.impl.compiled.ClsTypeElementImpl -import com.intellij.psi.impl.compiled.SignatureParsing -import com.intellij.psi.impl.compiled.StubBuildingVisitor import com.intellij.util.IncorrectOperationException import org.jetbrains.kotlin.asJava.elements.KtLightElement import org.jetbrains.kotlin.asJava.elements.KtLightMember -import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter -import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.backend.jvm.jvmTypeMapper -import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirConstructor import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.declarations.utils.modality -import org.jetbrains.kotlin.fir.declarations.utils.superConeTypes import org.jetbrains.kotlin.fir.isPrimitiveType -import org.jetbrains.kotlin.fir.resolve.fullyExpandedType -import org.jetbrains.kotlin.fir.resolve.substitution.AbstractConeSubstitutor -import org.jetbrains.kotlin.fir.resolve.toSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol -import org.jetbrains.kotlin.fir.typeContext import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState -import org.jetbrains.kotlin.idea.fir.low.level.api.api.withFirDeclaration +import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession import org.jetbrains.kotlin.idea.frontend.api.components.DefaultTypeClassIds -import org.jetbrains.kotlin.idea.frontend.api.fir.analyzeWithSymbolAsContext import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirSymbol import org.jetbrains.kotlin.idea.frontend.api.fir.types.KtFirType -import org.jetbrains.kotlin.idea.frontend.api.fir.types.PublicTypeApproximator import org.jetbrains.kotlin.idea.frontend.api.symbols.* import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSimpleConstantValue import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSymbolWithModality @@ -52,158 +37,34 @@ import org.jetbrains.kotlin.idea.frontend.api.types.KtTypeWithNullability import org.jetbrains.kotlin.load.kotlin.TypeMappingMode import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.SpecialNames -import org.jetbrains.kotlin.types.model.SimpleTypeMarker -import java.text.StringCharacterIterator import java.util.* internal fun L.invalidAccess(): Nothing = error("Cls delegate shouldn't be accessed for fir light classes! Qualified name: ${javaClass.name}") -private fun PsiElement.nonExistentType() = JavaPsiFacade.getElementFactory(project) - .createTypeFromText("error.NonExistentClass", this) - -internal fun KtCallableSymbol.asPsiType(parent: PsiElement, phase: FirResolvePhase): PsiType = - annotatedType.asPsiType(this, parent, phase) - -internal fun KtTypeAndAnnotations.asPsiType( - context: KtSymbol, - parent: PsiElement, - phase: FirResolvePhase -): PsiType { - val type = this.type - require(type is KtFirType) - require(context is KtFirSymbol<*>) - val session = context.firRef.withFir(phase) { it.moduleData.session } - return type.coneType.asPsiType(session, context.firRef.resolveState, TypeMappingMode.DEFAULT, parent) -} - -internal fun KtNamedClassOrObjectSymbol.typeForClassSymbol(psiElement: PsiElement): PsiType { - require(this is KtFirSymbol<*>) - - val types = analyzeWithSymbolAsContext(this) { - this@typeForClassSymbol.buildSelfClassType() - } - require(types is KtFirType) - - val session = firRef.withFir { it.moduleData.session } - return types.coneType.asPsiType(session, firRef.resolveState, TypeMappingMode.DEFAULT, psiElement) -} - -private class AnonymousTypesSubstitutor( - private val session: FirSession, - private val state: FirModuleResolveState, -) : AbstractConeSubstitutor(session.typeContext) { - override fun substituteType(type: ConeKotlinType): ConeKotlinType? { - - if (type !is ConeClassLikeType) return null - - val isAnonymous = type.classId.let { it?.shortClassName?.asString() == SpecialNames.ANONYMOUS_STRING } - if (!isAnonymous) return null - - fun ConeClassLikeType.isNotInterface(): Boolean { - val firClassNode = lookupTag.toSymbol(session)?.fir as? FirClass ?: return false - return firClassNode.withFirDeclaration(state) { firSuperClass -> - firSuperClass.classKind != ClassKind.INTERFACE - } - } - - val firClassNode = (type.lookupTag.toSymbol(session) as? FirClassSymbol)?.fir - if (firClassNode != null) { - val superTypesCones = firClassNode.withFirDeclaration(state, FirResolvePhase.SUPER_TYPES) { - (it as? FirClass)?.superConeTypes - } - val superClass = superTypesCones?.firstOrNull { it.isNotInterface() } - if (superClass != null) return superClass - } - - return if (type.nullability.isNullable) session.builtinTypes.nullableAnyType.type - else session.builtinTypes.anyType.type - } -} - -private fun ConeKotlinType.simplifyType(session: FirSession, state: FirModuleResolveState): ConeKotlinType { - val substitutor = AnonymousTypesSubstitutor(session, state) - var currentType = this - do { - val oldType = currentType - currentType = currentType.fullyExpandedType(session) - currentType = currentType.upperBoundIfFlexible() - currentType = substitutor.substituteOrSelf(currentType) - currentType = PublicTypeApproximator.approximateTypeToPublicDenotable(currentType, session) ?: currentType - } while (oldType !== currentType) - return currentType -} - -internal fun ConeKotlinType.asPsiType( - session: FirSession, - state: FirModuleResolveState, - mode: TypeMappingMode, - psiContext: PsiElement, -): 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() - - val signatureWriter = BothSignatureWriter(BothSignatureWriter.Mode.SKIP_CHECKS) - - //TODO Check thread safety - session.jvmTypeMapper.mapType(correctedType, mode, signatureWriter) - - val canonicalSignature = signatureWriter.toString() - - if (canonicalSignature.contains("L")) return psiContext.nonExistentType() - 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 typeElement = ClsTypeElementImpl(psiContext, typeText, '\u0000') - return typeElement.type -} - -private fun mapSupertype( - psiContext: PsiElement, - session: FirSession, - firResolvePhase: FirModuleResolveState, - supertype: ConeKotlinType, - kotlinCollectionAsIs: Boolean = false -) = - supertype.asPsiType( - session, - firResolvePhase, - if (kotlinCollectionAsIs) TypeMappingMode.SUPER_TYPE_KOTLIN_COLLECTIONS_AS_IS else TypeMappingMode.SUPER_TYPE, - psiContext - ) as? PsiClassType - -internal fun KtTypeAndAnnotations.mapSupertype( +internal fun KtAnalysisSession.mapSuperType( + type: KtTypeAndAnnotations, psiContext: PsiElement, kotlinCollectionAsIs: Boolean = false -): PsiClassType? = type.mapSupertype(psiContext, kotlinCollectionAsIs) - -internal fun KtType.mapSupertype( - psiContext: PsiElement, - kotlinCollectionAsIs: Boolean = false, ): PsiClassType? { - if (this !is KtNonErrorClassType) return null - require(this is KtFirType) - val contextSymbol = classSymbol - require(contextSymbol is KtFirSymbol<*>) - - val session = contextSymbol.firRef.withFir { it.moduleData.session } - - return mapSupertype( - psiContext, - session, - contextSymbol.firRef.resolveState, - coneType, - kotlinCollectionAsIs, - ) + return mapSuperType(type.type, psiContext, kotlinCollectionAsIs) } +internal fun KtAnalysisSession.mapSuperType( + type: KtType, + psiContext: PsiElement, + kotlinCollectionAsIs: Boolean = false +): PsiClassType? { + if (type !is KtNonErrorClassType) return null + val psiType = type.asPsiType( + psiContext, + if (kotlinCollectionAsIs) TypeMappingMode.SUPER_TYPE_KOTLIN_COLLECTIONS_AS_IS else TypeMappingMode.SUPER_TYPE, + ) + return psiType as? PsiClassType +} + + internal enum class NullabilityType { Nullable, NotNull, diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/methods/FirLightAccessorMethodForSymbol.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/methods/FirLightAccessorMethodForSymbol.kt index 655ed346ac9..3136eb37aea 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/methods/FirLightAccessorMethodForSymbol.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/methods/FirLightAccessorMethodForSymbol.kt @@ -15,6 +15,7 @@ import org.jetbrains.kotlin.asJava.elements.FirLightIdentifier import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.idea.asJava.parameters.FirLightSetterParameterForSymbol +import org.jetbrains.kotlin.idea.frontend.api.fir.analyzeWithSymbolAsContext import org.jetbrains.kotlin.idea.frontend.api.isValid import org.jetbrains.kotlin.idea.frontend.api.symbols.* import org.jetbrains.kotlin.load.java.JvmAbi.getterName @@ -144,11 +145,9 @@ internal class FirLightAccessorMethodForSymbol( private val _returnedType: PsiType? by lazyPub { if (!isGetter) return@lazyPub PsiType.VOID - return@lazyPub containingPropertySymbol.annotatedType.asPsiType( - context = containingPropertySymbol, - parent = this@FirLightAccessorMethodForSymbol, - phase = FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE - ) + analyzeWithSymbolAsContext(containingPropertySymbol) { + containingPropertySymbol.annotatedType.type.asPsiType(this@FirLightAccessorMethodForSymbol) + } } override fun getReturnType(): PsiType? = _returnedType diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/methods/FirLightSimpleMethodForSymbol.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/methods/FirLightSimpleMethodForSymbol.kt index b1e6cfa4775..bd6dec1d7fc 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/methods/FirLightSimpleMethodForSymbol.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/methods/FirLightSimpleMethodForSymbol.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.asJava.builder.LightMemberOrigin import org.jetbrains.kotlin.asJava.classes.lazyPub import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.idea.asJava.elements.FirLightTypeParameterListForSymbol +import org.jetbrains.kotlin.idea.frontend.api.fir.analyzeWithSymbolAsContext import org.jetbrains.kotlin.idea.frontend.api.isValid import org.jetbrains.kotlin.idea.frontend.api.symbols.KtFunctionSymbol import org.jetbrains.kotlin.lexer.KtTokens @@ -127,7 +128,9 @@ internal class FirLightSimpleMethodForSymbol( private val _returnedType: PsiType by lazyPub { if (isVoidReturnType) return@lazyPub PsiType.VOID - functionSymbol.asPsiType(this@FirLightSimpleMethodForSymbol, FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE) + analyzeWithSymbolAsContext(functionSymbol) { + functionSymbol.annotatedType.type.asPsiType(this@FirLightSimpleMethodForSymbol) + } } override fun getReturnType(): PsiType = _returnedType diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/parameters/FirLightParameterBaseForSymbol.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/parameters/FirLightParameterBaseForSymbol.kt index 1866ec23ca1..c9cfa8d81dd 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/parameters/FirLightParameterBaseForSymbol.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/parameters/FirLightParameterBaseForSymbol.kt @@ -9,6 +9,7 @@ import com.intellij.psi.* import org.jetbrains.kotlin.asJava.classes.lazyPub import org.jetbrains.kotlin.asJava.elements.FirLightIdentifier import org.jetbrains.kotlin.fir.declarations.FirResolvePhase +import org.jetbrains.kotlin.idea.frontend.api.fir.analyzeWithSymbolAsContext import org.jetbrains.kotlin.idea.frontend.api.symbols.* import org.jetbrains.kotlin.psi.KtParameter @@ -45,8 +46,9 @@ internal abstract class FirLightParameterBaseForSymbol( override fun getNameIdentifier(): PsiIdentifier = _identifier private val _type by lazyPub { - val convertedType = parameterSymbol.asPsiType(this, FirResolvePhase.TYPES) - + val convertedType = analyzeWithSymbolAsContext(parameterSymbol) { + parameterSymbol.annotatedType.type.asPsiType(this@FirLightParameterBaseForSymbol) + } if (convertedType is PsiArrayType && parameterSymbol.isVararg) { PsiEllipsisType(convertedType.componentType, convertedType.annotationProvider) } else convertedType diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/parameters/FirLightParameterForReceiver.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/parameters/FirLightParameterForReceiver.kt index 4842c38d27b..141c6c43ce2 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/parameters/FirLightParameterForReceiver.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/parameters/FirLightParameterForReceiver.kt @@ -12,6 +12,7 @@ import com.intellij.psi.PsiType import org.jetbrains.kotlin.asJava.classes.lazyPub import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.fir.declarations.FirResolvePhase +import org.jetbrains.kotlin.idea.frontend.api.fir.analyzeWithSymbolAsContext import org.jetbrains.kotlin.idea.frontend.api.isValid import org.jetbrains.kotlin.idea.frontend.api.symbols.KtCallableSymbol import org.jetbrains.kotlin.idea.frontend.api.symbols.KtSymbol @@ -71,7 +72,9 @@ internal class FirLightParameterForReceiver private constructor( } private val _type: PsiType by lazyPub { - receiverTypeAndAnnotations.asPsiType(context, method, FirResolvePhase.TYPES) + analyzeWithSymbolAsContext(context) { + receiverTypeAndAnnotations.type.asPsiType(this@FirLightParameterForReceiver) + } } override fun getType(): PsiType = _type diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/parameters/FirLightTypeParameter.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/parameters/FirLightTypeParameter.kt index e864ad9c4fb..f86e987d957 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/parameters/FirLightTypeParameter.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/parameters/FirLightTypeParameter.kt @@ -21,10 +21,12 @@ import org.jetbrains.kotlin.asJava.elements.KtLightDeclaration import org.jetbrains.kotlin.idea.KotlinLanguage import org.jetbrains.kotlin.idea.asJava.basicIsEquivalentTo import org.jetbrains.kotlin.idea.asJava.invalidAccess -import org.jetbrains.kotlin.idea.asJava.mapSupertype +import org.jetbrains.kotlin.idea.asJava.mapSuperType +import org.jetbrains.kotlin.idea.frontend.api.fir.analyzeWithSymbolAsContext import org.jetbrains.kotlin.idea.frontend.api.isValid import org.jetbrains.kotlin.idea.frontend.api.symbols.KtTypeParameterSymbol import org.jetbrains.kotlin.idea.frontend.api.types.KtNonErrorClassType +import org.jetbrains.kotlin.load.kotlin.TypeMappingMode import org.jetbrains.kotlin.name.StandardClassIds import org.jetbrains.kotlin.psi.KtTypeParameter import org.jetbrains.kotlin.psi.psiUtil.startOffset @@ -61,17 +63,15 @@ internal class FirLightTypeParameter( language = language, role = PsiReferenceList.Role.EXTENDS_LIST ) - - typeParameterSymbol.upperBounds - .filterIsInstance() - .filter { it.classId != StandardClassIds.Any } - .mapNotNull { - it.mapSupertype( - psiContext = this, - kotlinCollectionAsIs = true, - ) - } - .forEach { listBuilder.addReference(it) } + analyzeWithSymbolAsContext(typeParameterSymbol) { + typeParameterSymbol.upperBounds + .filterIsInstance() + .filter { it.classId != StandardClassIds.Any } + .mapNotNull { + mapSuperType(it, this@FirLightTypeParameter, kotlinCollectionAsIs = true) + } + .forEach { listBuilder.addReference(it) } + } listBuilder } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirPsiTypeProvider.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirPsiTypeProvider.kt index a6fd56c5d10..ea6eb6a68d6 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirPsiTypeProvider.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirPsiTypeProvider.kt @@ -5,15 +5,38 @@ package org.jetbrains.kotlin.idea.frontend.api.fir.components +import com.intellij.psi.JavaPsiFacade import com.intellij.psi.PsiElement import com.intellij.psi.PsiType -import org.jetbrains.kotlin.idea.asJava.asPsiType +import com.intellij.psi.impl.cache.TypeInfo +import com.intellij.psi.impl.compiled.ClsTypeElementImpl +import com.intellij.psi.impl.compiled.SignatureParsing +import com.intellij.psi.impl.compiled.StubBuildingVisitor +import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter +import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.backend.jvm.jvmTypeMapper +import org.jetbrains.kotlin.fir.declarations.FirClass +import org.jetbrains.kotlin.fir.declarations.FirResolvePhase +import org.jetbrains.kotlin.fir.declarations.utils.superConeTypes +import org.jetbrains.kotlin.fir.resolve.fullyExpandedType +import org.jetbrains.kotlin.fir.resolve.substitution.AbstractConeSubstitutor +import org.jetbrains.kotlin.fir.resolve.toSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol +import org.jetbrains.kotlin.fir.typeContext +import org.jetbrains.kotlin.fir.types.* +import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState +import org.jetbrains.kotlin.idea.fir.low.level.api.api.withFirDeclaration import org.jetbrains.kotlin.idea.frontend.api.components.KtPsiTypeProvider import org.jetbrains.kotlin.idea.frontend.api.fir.KtFirAnalysisSession +import org.jetbrains.kotlin.idea.frontend.api.fir.types.PublicTypeApproximator import org.jetbrains.kotlin.idea.frontend.api.tokens.ValidityToken import org.jetbrains.kotlin.idea.frontend.api.types.KtType import org.jetbrains.kotlin.idea.frontend.api.withValidityAssertion import org.jetbrains.kotlin.load.kotlin.TypeMappingMode +import org.jetbrains.kotlin.name.SpecialNames +import org.jetbrains.kotlin.types.model.SimpleTypeMarker +import java.text.StringCharacterIterator internal class KtFirPsiTypeProvider( override val analysisSession: KtFirAnalysisSession, @@ -24,3 +47,81 @@ internal class KtFirPsiTypeProvider( 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 + do { + val oldType = currentType + currentType = currentType.fullyExpandedType(session) + currentType = currentType.upperBoundIfFlexible() + currentType = substitutor.substituteOrSelf(currentType) + currentType = PublicTypeApproximator.approximateTypeToPublicDenotable(currentType, session) ?: currentType + } while (oldType !== currentType) + return currentType +} + +internal fun ConeKotlinType.asPsiType( + session: FirSession, + state: FirModuleResolveState, + mode: TypeMappingMode, + psiContext: PsiElement, +): 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() + + val signatureWriter = BothSignatureWriter(BothSignatureWriter.Mode.SKIP_CHECKS) + + //TODO Check thread safety + session.jvmTypeMapper.mapType(correctedType, mode, signatureWriter) + + val canonicalSignature = signatureWriter.toString() + + if (canonicalSignature.contains("L")) return psiContext.nonExistentType() + 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 typeElement = ClsTypeElementImpl(psiContext, typeText, '\u0000') + return typeElement.type +} + +private class AnonymousTypesSubstitutor( + private val session: FirSession, + private val state: FirModuleResolveState, +) : AbstractConeSubstitutor(session.typeContext) { + override fun substituteType(type: ConeKotlinType): ConeKotlinType? { + if (type !is ConeClassLikeType) return null + + val isAnonymous = type.classId.let { it?.shortClassName?.asString() == SpecialNames.ANONYMOUS_STRING } + if (!isAnonymous) return null + + fun ConeClassLikeType.isNotInterface(): Boolean { + val firClassNode = lookupTag.toSymbol(session)?.fir as? FirClass ?: return false + return firClassNode.withFirDeclaration(state) { firSuperClass -> + firSuperClass.classKind != ClassKind.INTERFACE + } + } + + val firClassNode = (type.lookupTag.toSymbol(session) as? FirClassSymbol)?.fir + if (firClassNode != null) { + val superTypesCones = firClassNode.withFirDeclaration(state, FirResolvePhase.SUPER_TYPES) { + (it as? FirClass)?.superConeTypes + } + val superClass = superTypesCones?.firstOrNull { it.isNotInterface() } + if (superClass != null) return superClass + } + + return if (type.nullability.isNullable) session.builtinTypes.nullableAnyType.type + else session.builtinTypes.anyType.type + } +} \ No newline at end of file