[ULC] Add annotations for PsiTypes in UltraLight classes

WIP on KT-41148, KT-41406, KT-41420
This commit is contained in:
Igor Yakovlev
2020-09-04 11:58:32 +03:00
parent b82d8cd4f4
commit e08763f3dd
13 changed files with 224 additions and 24 deletions
@@ -145,7 +145,7 @@ internal open class KtUltraLightFieldImpl protected constructor(
val kotlinType = declaration.getKotlinType() ?: return@lazyPub PsiType.NULL
val descriptor = variableDescriptor ?: return@lazyPub PsiType.NULL
support.mapType(this) { typeMapper, sw ->
support.mapType(kotlinType, this) { typeMapper, sw ->
typeMapper.writeFieldSignature(kotlinType, descriptor, sw)
}
}
@@ -243,7 +243,7 @@ internal class UltraLightMembersCreator(
ktDeclaration.resolve()?.getterIfProperty() as? CallableDescriptor
?: return PsiType.NULL
return support.mapType(wrapper) { typeMapper, signatureWriter ->
return support.mapType(desc.returnType, wrapper) { typeMapper, signatureWriter ->
typeMapper.mapReturnType(desc, signatureWriter)
}
}
@@ -258,7 +258,7 @@ internal class KtUltraLightMethodForDescriptor(
delegate.isConstructor = true
PsiType.VOID
} else {
support.mapType(this) { typeMapper, signatureWriter ->
support.mapType(methodDescriptor.returnType, this) { typeMapper, signatureWriter ->
typeMapper.mapReturnType(methodDescriptor, signatureWriter)
}
}
@@ -9,6 +9,8 @@ import com.intellij.navigation.ItemPresentation
import com.intellij.navigation.ItemPresentationProviders
import com.intellij.openapi.util.TextRange
import com.intellij.psi.*
import com.intellij.psi.impl.compiled.ClsTypeElementImpl
import com.intellij.psi.impl.source.PsiClassReferenceType
import com.intellij.psi.search.LocalSearchScope
import com.intellij.psi.search.SearchScope
import com.intellij.psi.util.TypeConversionUtil
@@ -108,7 +110,6 @@ internal abstract class KtUltraLightParameter(
override val psiTypeForNullabilityAnnotation: PsiType?
get() = type
protected fun computeParameterType(kotlinType: KotlinType?, containingDeclaration: CallableDescriptor?): PsiType {
kotlinType ?: return PsiType.NULL
@@ -116,9 +117,10 @@ internal abstract class KtUltraLightParameter(
return kotlinType.asPsiType(support, TypeMappingMode.DEFAULT, this)
} else {
val containingDescriptor = containingDeclaration ?: return PsiType.NULL
val mappedType = support.mapType(this) { typeMapper, sw ->
val mappedType = support.mapType(kotlinType, this) { typeMapper, sw ->
typeMapper.writeParameterType(sw, kotlinType, containingDescriptor)
}
return if (ultraLightMethod.checkNeedToErasureParametersTypes) TypeConversionUtil.erasure(mappedType) else mappedType
}
}
@@ -14,8 +14,10 @@ import com.intellij.psi.impl.cache.ModifierFlags
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.psi.impl.light.*
import com.intellij.psi.impl.compiled.StubBuildingVisitor.GUESSING_MAPPER
import com.intellij.psi.impl.light.LightMethodBuilder
import com.intellij.psi.impl.light.LightModifierList
import com.intellij.psi.impl.light.LightParameterListBuilder
import com.intellij.psi.util.TypeConversionUtil
import com.intellij.util.BitUtil.isSet
import com.intellij.util.IncorrectOperationException
@@ -23,9 +25,7 @@ import com.intellij.util.containers.ContainerUtil
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
import org.jetbrains.kotlin.asJava.UltraLightClassModifierExtension
import org.jetbrains.kotlin.asJava.builder.LightMemberOriginForDeclaration
import org.jetbrains.kotlin.asJava.elements.KotlinLightTypeParameterListBuilder
import org.jetbrains.kotlin.asJava.elements.KtLightAnnotationForSourceEntry
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.asJava.elements.*
import org.jetbrains.kotlin.asJava.elements.psiType
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.StandardNames
@@ -39,8 +39,8 @@ import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.psi.*
@@ -163,31 +163,95 @@ internal fun KotlinType.asPsiType(
support: KtUltraLightSupport,
mode: TypeMappingMode,
psiContext: PsiElement,
): PsiType = support.mapType(psiContext) { typeMapper, signatureWriter ->
): PsiType = support.mapType(this, psiContext) { typeMapper, signatureWriter ->
typeMapper.mapType(this, signatureWriter, mode)
}
internal fun KtUltraLightSupport.mapType(
// There is no other known way found to make PSI types annotated for now.
// It seems we need for platform changes to do it more convenient way (KTIJ-141).
private val setPsiTypeAnnotationProvider: (PsiType, TypeAnnotationProvider) -> Unit by lazyPub {
val klass = PsiType::class.java
val providerField = try {
klass.getDeclaredField("myAnnotationProvider")
.also { it.isAccessible = true }
} catch (e: NoSuchFieldException) {
if (ApplicationManager.getApplication().isInternal) throw e
null
} catch (e: SecurityException) {
if (ApplicationManager.getApplication().isInternal) throw e
null
}
{ psiType, provider ->
providerField?.set(psiType, provider)
}
}
private fun annotateByKotlinType(
psiType: PsiType,
kotlinType: KotlinType,
psiContext: PsiElement,
mapTypeToSignatureWriter: (KotlinTypeMapper, JvmSignatureWriter) -> Unit,
ultraLightSupport: KtUltraLightSupport
) {
fun KotlinType.getAnnotationsSequence(): Sequence<List<PsiAnnotation>> =
sequence {
yield(annotations.mapNotNull { it.toLightAnnotation(ultraLightSupport, psiContext) })
for (argument in arguments) {
yieldAll(argument.type.getAnnotationsSequence())
}
}
val annotationsIterator = kotlinType.getAnnotationsSequence().iterator()
fun recursiveAnnotator(psiType: PsiType) {
if (!annotationsIterator.hasNext()) return
val typeAnnotations = annotationsIterator.next()
if (psiType is PsiClassType) {
for (parameterType in psiType.parameters) {
recursiveAnnotator(parameterType)
}
} else if (psiType is PsiArrayType) {
recursiveAnnotator(psiType.componentType)
}
if (typeAnnotations.isEmpty()) return
val provider = TypeAnnotationProvider.Static.create(typeAnnotations.toTypedArray())
setPsiTypeAnnotationProvider(psiType, provider)
}
recursiveAnnotator(psiType)
}
internal fun KtUltraLightSupport.mapType(
kotlinType: KotlinType?,
psiContext: PsiElement,
mapTypeToSignatureWriter: (KotlinTypeMapper, JvmSignatureWriter) -> Unit
): PsiType {
val signatureWriter = BothSignatureWriter(BothSignatureWriter.Mode.SKIP_CHECKS)
mapTypeToSignatureWriter(typeMapper, signatureWriter)
val canonicalSignature = signatureWriter.toString()
return createTypeFromCanonicalText(canonicalSignature, psiContext)
return createTypeFromCanonicalText(kotlinType, canonicalSignature, psiContext)
}
fun createTypeFromCanonicalText(
private fun KtUltraLightSupport.createTypeFromCanonicalText(
kotlinType: KotlinType?,
canonicalSignature: String,
psiContext: PsiElement,
): PsiType {
val signature = StringCharacterIterator(canonicalSignature)
val javaType = SignatureParsing.parseTypeString(signature, StubBuildingVisitor.GUESSING_MAPPER)
val javaType = SignatureParsing.parseTypeString(signature, GUESSING_MAPPER)
val typeInfo = TypeInfo.fromString(javaType, false)
val typeText = TypeInfo.createTypeText(typeInfo) ?: return PsiType.NULL
val type = ClsTypeElementImpl(psiContext, typeText, '\u0000').type
val typeElement = ClsTypeElementImpl(psiContext, typeText, '\u0000')
val type = typeElement.type
if (kotlinType != null) {
annotateByKotlinType(type, kotlinType, typeElement, this)
}
if (type is PsiArrayType && psiContext is KtUltraLightParameter && psiContext.isVarArgs) {
return PsiEllipsisType(type.componentType, type.annotationProvider)
}