[FIR IDE] HL API Better support of nullability and modality

This commit is contained in:
Igor Yakovlev
2020-11-17 15:00:02 +03:00
parent 4c69043a15
commit 2a8f783393
22 changed files with 115 additions and 56 deletions

View File

@@ -34,7 +34,7 @@ fun ConeClassLikeType.isByte(): Boolean = lookupTag.classId == StandardClassIds.
fun ConeClassLikeType.isBoolean(): Boolean = lookupTag.classId == StandardClassIds.Boolean
fun ConeClassLikeType.isChar(): Boolean = lookupTag.classId == StandardClassIds.Char
fun ConeClassLikeType.isPrimitiveType(): Boolean = isPrimitiveNumberOrUnsignedNumberType() || isBoolean() || isByte() || isShort()
fun ConeClassLikeType.isPrimitiveType(): Boolean = isPrimitiveNumberOrUnsignedNumberType() || isBoolean() || isByte() || isShort() || isChar()
fun ConeClassLikeType.isPrimitiveNumberType(): Boolean = lookupTag.classId in PRIMITIVE_NUMBER_CLASS_IDS
fun ConeClassLikeType.isPrimitiveUnsignedNumberType(): Boolean = lookupTag.classId in PRIMITIVE_UNSIGNED_NUMBER_CLASS_IDS
fun ConeClassLikeType.isPrimitiveNumberOrUnsignedNumberType(): Boolean = isPrimitiveNumberType() || isPrimitiveUnsignedNumberType()

View File

@@ -9,4 +9,6 @@ enum class E {
Entry2,
@Deprecated("b")
Entry3
}
}
// FIR_COMPARISON

View File

@@ -9,3 +9,5 @@ interface Bar : Foo {
}
enum class EnumNameOverride : Bar
// FIR_COMPARISON

View File

@@ -44,4 +44,6 @@ class Container {
TODO("not implemented")
}
}
}
}
// FIR_COMPARISON

View File

@@ -13,4 +13,5 @@ class C : A(), I {
override fun if() = 5
}
// LAZINESS:NoLaziness
// LAZINESS:NoLaziness
// FIR_COMPARISON

View File

@@ -20,4 +20,6 @@ interface Primitives {
val long: Long
val float: Float
val double: Double
}
}
// FIR_COMPARISON

View File

@@ -29,3 +29,5 @@ private class Private {
override val overridesNothing: Boolean
get() = false
}
// FIR_COMPARISON

View File

@@ -2,3 +2,5 @@
val a: Collection<*> = emptyList()
@JvmField
var b: Int = 1
// FIR_COMPARISON

View File

@@ -14,6 +14,7 @@ sealed class KtPropertyAccessorSymbol : KtCallableSymbol(),
abstract val isDefault: Boolean
abstract val isInline: Boolean
abstract val isOverride: Boolean
abstract val hasBody: Boolean
abstract val symbolKind: KtSymbolKind

View File

@@ -53,6 +53,8 @@ abstract class KtPropertySymbol : KtVariableSymbol(),
abstract val hasBackingField: Boolean
abstract val isLateInit: Boolean
abstract val isConst: Boolean
abstract val isOverride: Boolean

View File

@@ -87,7 +87,8 @@ internal fun KtAnnotatedSymbol.hasAnnotation(classIdString: String, annotationUs
internal fun KtAnnotatedSymbol.computeAnnotations(
parent: PsiElement,
nullability: NullabilityType,
annotationUseSiteTarget: AnnotationUseSiteTarget?
annotationUseSiteTarget: AnnotationUseSiteTarget?,
includeAnnotationsWithoutSite: Boolean = true
): List<PsiAnnotation> {
if (nullability == NullabilityType.Unknown && annotations.isEmpty()) return emptyList()
@@ -108,7 +109,10 @@ internal fun KtAnnotatedSymbol.computeAnnotations(
for (annotation in annotations) {
val siteTarget = annotation.useSiteTarget
if (siteTarget == null || siteTarget == annotationUseSiteTarget) {
if ((includeAnnotationsWithoutSite && siteTarget == null) ||
siteTarget == annotationUseSiteTarget
) {
result.add(FirLightAnnotationForAnnotationCall(annotation, parent))
}
}

View File

@@ -13,9 +13,15 @@ import com.intellij.psi.impl.light.LightModifierList
import org.jetbrains.annotations.NonNls
import org.jetbrains.kotlin.asJava.classes.*
import org.jetbrains.kotlin.asJava.elements.*
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
import org.jetbrains.kotlin.asJava.classes.lazyPub
import org.jetbrains.kotlin.asJava.elements.FakeFileForLightClass
import org.jetbrains.kotlin.asJava.elements.KtLightField
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.isConst
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.asJava.classes.createFields
import org.jetbrains.kotlin.idea.asJava.classes.createMethods
@@ -23,7 +29,9 @@ import org.jetbrains.kotlin.idea.frontend.api.analyze
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtCallableSymbol
import org.jetbrains.kotlin.load.java.structure.LightClassOriginKind
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.psi.psiUtil.isPrivate
class FirLightClassForFacade(

View File

@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.idea.frontend.api.analyze
import org.jetbrains.kotlin.idea.frontend.api.symbols.*
import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtAnnotatedSymbol
import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtCommonSymbolModality
import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSymbolVisibility
import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSymbolWithVisibility
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
@@ -147,11 +148,17 @@ internal fun FirLightClassBase.createMethods(
is KtPropertySymbol -> {
if (declaration.hasJvmFieldAnnotation()) continue
if (declaration.visibility == KtSymbolVisibility.PRIVATE) continue
fun KtPropertyAccessorSymbol.needToCreateAccessor(siteTarget: AnnotationUseSiteTarget): Boolean {
if (isInline) return false
if (!hasBody && visibility == KtSymbolVisibility.PRIVATE) return false
return !declaration.hasJvmSyntheticAnnotation(siteTarget)
&& !declaration.isHiddenByDeprecation(siteTarget)
}
val getter = declaration.getter?.takeIf {
!declaration.hasJvmSyntheticAnnotation(AnnotationUseSiteTarget.PROPERTY_GETTER) &&
!it.isInline &&
!declaration.isHiddenByDeprecation(AnnotationUseSiteTarget.PROPERTY_GETTER)
it.needToCreateAccessor(AnnotationUseSiteTarget.PROPERTY_GETTER)
}
if (getter != null) {
@@ -167,10 +174,7 @@ internal fun FirLightClassBase.createMethods(
}
val setter = declaration.setter?.takeIf {
!isAnnotationType &&
!declaration.hasJvmSyntheticAnnotation(AnnotationUseSiteTarget.PROPERTY_SETTER) &&
!it.isInline &&
!declaration.isHiddenByDeprecation(AnnotationUseSiteTarget.PROPERTY_GETTER)
!isAnnotationType && it.needToCreateAccessor(AnnotationUseSiteTarget.PROPERTY_SETTER)
}
if (setter != null) {
@@ -194,13 +198,19 @@ internal fun FirLightClassBase.createFields(
isTopLevel: Boolean,
result: MutableList<KtLightField>
) {
fun hasBackingField(property: KtPropertySymbol): Boolean {
if (property.modality == KtCommonSymbolModality.ABSTRACT) return false
if (property.isLateInit) return true
//IS PARAMETER -> true
if (property.getter == null && property.setter == null) return true
if (property.hasJvmSyntheticAnnotation(AnnotationUseSiteTarget.FIELD)) return false
return property.hasBackingField
}
//TODO isHiddenByDeprecation
for (declaration in declarations) {
if (declaration !is KtPropertySymbol) continue
if (!declaration.hasBackingField) continue
if (declaration.hasJvmSyntheticAnnotation(AnnotationUseSiteTarget.FIELD)) continue
if (declaration.modality == KtCommonSymbolModality.ABSTRACT) continue
if (!hasBackingField(declaration)) continue
result.add(
FirLightFieldForPropertySymbol(

View File

@@ -42,7 +42,7 @@ internal class FirLightFieldForPropertySymbol(
private val _modifierList: PsiModifierList by lazyPub {
val isJvmField = propertySymbol.hasJvmFieldAnnotation()
val suppressFinal = !isJvmField && !propertySymbol.isVal
val suppressFinal = !propertySymbol.isVal
val modifiersFromSymbol = propertySymbol.computeModalityForMethod(
isTopLevel = isTopLevel,
@@ -64,9 +64,13 @@ internal class FirLightFieldForPropertySymbol(
`if` = !suppressFinal
)
val nullability = if (visibility != PsiModifier.PRIVATE)
propertySymbol.type.getTypeNullability(propertySymbol, FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE)
else NullabilityType.Unknown
val annotations = propertySymbol.computeAnnotations(
parent = this,
nullability = propertySymbol.type.getTypeNullability(propertySymbol, FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE),
nullability = nullability,
annotationUseSiteTarget = AnnotationUseSiteTarget.FIELD,
)

View File

@@ -45,7 +45,7 @@ internal class FirLightAccessorMethodForSymbol(
val defaultName = containingPropertySymbol.name.identifier.let {
if (containingClass.isAnnotationType) it else it.abiName(propertyAccessorSymbol)
}
containingPropertySymbol.computeJvmMethodName(defaultName, accessorSite)
containingPropertySymbol.computeJvmMethodName(defaultName, containingClass, accessorSite)
}
override fun getName(): String = _name
@@ -61,9 +61,11 @@ internal class FirLightAccessorMethodForSymbol(
else AnnotationUseSiteTarget.PROPERTY_SETTER
private val _annotations: List<PsiAnnotation> by lazyPub {
val nullabilityType = containingPropertySymbol.type
.getTypeNullability(containingPropertySymbol, FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE)
containingPropertySymbol.computeAnnotations(
parent = this,
nullability = NullabilityType.Unknown,
nullability = nullabilityType,
annotationUseSiteTarget = accessorSite,
)
}

View File

@@ -17,9 +17,11 @@ import org.jetbrains.kotlin.asJava.classes.cannotModify
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtCallableSymbol
import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtAnnotatedSymbol
import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSymbolVisibility
import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSymbolWithVisibility
import org.jetbrains.kotlin.idea.util.ifTrue
import org.jetbrains.kotlin.idea.util.module
internal abstract class FirLightMethod(
@@ -83,11 +85,16 @@ internal abstract class FirLightMethod(
protected fun <T> T.computeJvmMethodName(
defaultName: String,
containingClass: FirLightClassBase,
annotationUseSiteTarget: AnnotationUseSiteTarget? = null
): String where T : KtAnnotatedSymbol, T : KtSymbolWithVisibility {
): String where T : KtAnnotatedSymbol, T : KtSymbolWithVisibility, T : KtCallableSymbol {
getJvmNameFromAnnotation(annotationUseSiteTarget)?.let { return it }
if (visibility != KtSymbolVisibility.INTERNAL) return defaultName
val effectiveVisibilityIfNotInternal = (visibility != KtSymbolVisibility.INTERNAL).ifTrue {
(containingClass as? FirLightClassForSymbol)?.tryGetEffectiveVisibility(this)
} ?: this.visibility
if (effectiveVisibilityIfNotInternal != KtSymbolVisibility.INTERNAL) return defaultName
val moduleName = module?.name ?: return defaultName

View File

@@ -34,14 +34,16 @@ internal class FirLightSimpleMethodForSymbol(
) {
private val _name: String by lazyPub {
functionSymbol.computeJvmMethodName(functionSymbol.name.asString())
functionSymbol.computeJvmMethodName(functionSymbol.name.asString(), containingClass)
}
override fun getName(): String = _name
private val _annotations: List<PsiAnnotation> by lazyPub {
val nullability = if (functionSymbol.type.isUnit) NullabilityType.Unknown else functionSymbol.type.getTypeNullability(
val needUnknownNullability = functionSymbol.type.isUnit || (_visibility == PsiModifier.PRIVATE)
val nullability = if (needUnknownNullability) NullabilityType.Unknown else functionSymbol.type.getTypeNullability(
functionSymbol,
FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE
)
@@ -53,29 +55,24 @@ internal class FirLightSimpleMethodForSymbol(
)
}
open class X {
open val x: Int = 2
open fun u() = 2
private val _visibility: String by lazyPub {
functionSymbol.isOverride.ifTrue {
(containingClass as? FirLightClassForSymbol)
?.tryGetEffectiveVisibility(functionSymbol)
?.toPsiVisibility(isTopLevel)
} ?: functionSymbol.computeVisibility(isTopLevel = isTopLevel)
}
private val _modifiers: Set<String> by lazyPub {
if (functionSymbol.hasInlineOnlyAnnotation()) return@lazyPub setOf(PsiModifier.FINAL, PsiModifier.PRIVATE)
val isOverrideMethod = functionSymbol.isOverride
val visibility = isOverrideMethod.ifTrue {
(containingClass as? FirLightClassForSymbol)
?.tryGetEffectiveVisibility(functionSymbol)
?.toPsiVisibility(isTopLevel)
} ?: functionSymbol.computeVisibility(isTopLevel = isTopLevel)
val finalModifier = kotlinOrigin?.hasModifier(KtTokens.FINAL_KEYWORD) == true
val modifiers = functionSymbol.computeModalityForMethod(
isTopLevel = isTopLevel,
suppressFinal = !finalModifier && isOverrideMethod
) + visibility
suppressFinal = !finalModifier && functionSymbol.isOverride
) + _visibility
modifiers.add(
what = PsiModifier.STATIC,

View File

@@ -7,8 +7,11 @@ package org.jetbrains.kotlin.idea.asJava
import com.intellij.psi.*
import org.jetbrains.kotlin.asJava.classes.lazyPub
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtParameterSymbol
import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSymbolKind
import org.jetbrains.kotlin.idea.util.ifTrue
import org.jetbrains.kotlin.psi.KtParameter
internal class FirLightParameterForSymbol(
@@ -26,10 +29,15 @@ internal class FirLightParameterForSymbol(
override val kotlinOrigin: KtParameter? = parameterSymbol.psi as? KtParameter
private val _annotations: List<PsiAnnotation> by lazyPub {
val annotationSite = (containingMethod.isConstructor && parameterSymbol.symbolKind == KtSymbolKind.MEMBER).ifTrue {
AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER
}
parameterSymbol.computeAnnotations(
parent = this,
nullability = parameterSymbol.type.getTypeNullability(parameterSymbol, FirResolvePhase.TYPES),
annotationUseSiteTarget = null,
annotationUseSiteTarget = annotationSite,
includeAnnotationsWithoutSite = false
)
}
@@ -50,9 +58,7 @@ internal class FirLightParameterForSymbol(
override fun equals(other: Any?): Boolean =
this === other ||
(other is FirLightParameterForSymbol &&
kotlinOrigin == other.kotlinOrigin &&
parameterSymbol == other.parameterSymbol)
(other is FirLightParameterForSymbol && parameterSymbol == other.parameterSymbol)
override fun hashCode(): Int = kotlinOrigin.hashCode()
}

View File

@@ -39,6 +39,7 @@ internal class KtFirPropertyGetterSymbol(
override val isDefault: Boolean get() = firRef.withFir { it is FirDefaultPropertyAccessor }
override val isInline: Boolean get() = firRef.withFir { it.isInline }
override val isOverride: Boolean get() = firRef.withFir { it.isOverride }
override val hasBody: Boolean get() = firRef.withFir { it.body != null }
override val symbolKind: KtSymbolKind
get() = firRef.withFir { fir ->

View File

@@ -39,6 +39,8 @@ internal class KtFirPropertySetterSymbol(
override val isDefault: Boolean get() = firRef.withFir { it is FirDefaultPropertyAccessor }
override val isInline: Boolean get() = firRef.withFir { it.isInline }
override val isOverride: Boolean get() = firRef.withFir { it.isOverride }
override val hasBody: Boolean get() = firRef.withFir { it.body != null }
override val modality: KtCommonSymbolModality get() = firRef.withFir(FirResolvePhase.STATUS) { it.modality.getSymbolModality() }
override val visibility: KtSymbolVisibility get() = firRef.withFir(FirResolvePhase.STATUS) { it.visibility.getSymbolVisibility() }
override val parameter: KtSetterParameterSymbol by firRef.withFirAndCache { fir ->

View File

@@ -80,6 +80,8 @@ internal class KtFirPropertySymbol(
override val hasBackingField: Boolean get() = firRef.withFir { it.hasBackingField }
override val isLateInit: Boolean get() = firRef.withFir { it.isLateInit }
override val isConst: Boolean get() = firRef.withFir { it.isConst }
override val isOverride: Boolean get() = firRef.withFir { it.isOverride }

View File

@@ -151,12 +151,10 @@ fun findClass(fqName: String, ktFile: KtFile?, project: Project): PsiClass? {
return it.toLightClass()
}
return JavaPsiFacade.getInstance(project).findClass(fqName, GlobalSearchScope.allScope(project)) ?: PsiTreeUtil.findChildrenOfType(
ktFile,
KtClassOrObject::class.java
)
.find { fqName.endsWith(it.nameAsName!!.asString()) }
?.let { KtLightClassForSourceDeclaration.create(it) }
return JavaPsiFacade.getInstance(project).findClass(fqName, GlobalSearchScope.allScope(project))
?: PsiTreeUtil.findChildrenOfType(ktFile, KtClassOrObject::class.java)
.find { fqName.endsWith(it.nameAsName!!.asString()) }
?.toLightClass()
}
object LightClassLazinessChecker {
@@ -276,11 +274,13 @@ object LightClassLazinessChecker {
// see KtLightNullabilityAnnotation
assertTrue(
lightAnnotations.isNotEmpty(),
"Missing $fqName annotation in '${modifierListOwner}' have only ${annotations?.joinToString(
", ",
"[",
"]"
) { it.toString() }}"
"Missing $fqName annotation in '${modifierListOwner}' have only ${
annotations?.joinToString(
", ",
"[",
"]"
) { it.toString() }
}"
)
}
clsAnnotations.zip(lightAnnotations).forEach { (clsAnnotation, lightAnnotation) ->