[ULC] Better nullability annotations for light classes

This commit is contained in:
Igor Yakovlev
2020-06-23 16:25:12 +03:00
parent c3810dc223
commit a5e304f520
3 changed files with 49 additions and 13 deletions
@@ -10,6 +10,7 @@ import com.intellij.util.IncorrectOperationException
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
import org.jetbrains.kotlin.asJava.builder.LightMemberOriginForDeclaration
import org.jetbrains.kotlin.asJava.classes.*
import org.jetbrains.kotlin.asJava.fastCheckIsNullabilityApplied
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
@@ -76,12 +77,16 @@ abstract class KtLightModifierList<out T : KtLightElement<KtModifierListOwner, P
if ((modifierListOwner is KtLightMember<*> && modifierListOwner !is KtLightFieldImpl.KtLightEnumConstant)
|| modifierListOwner is LightParameter
) {
val nullabilityAnnotation = when (modifierListOwner) {
is KtUltraLightElementWithNullabilityAnnotation<*, *> -> KtUltraLightNullabilityAnnotation(modifierListOwner, this)
else -> KtLightNullabilityAnnotation(modifierListOwner as KtLightElement<*, PsiModifierListOwner>, this)
}
return annotationsForEntries + listOf(nullabilityAnnotation)
if (fastCheckIsNullabilityApplied(modifierListOwner)) {
val nullabilityAnnotation = when (modifierListOwner) {
is KtUltraLightElementWithNullabilityAnnotation<*, *> -> KtUltraLightNullabilityAnnotation(modifierListOwner, this)
else -> KtLightNullabilityAnnotation(modifierListOwner as KtLightElement<*, PsiModifierListOwner>, this)
}
return annotationsForEntries + listOf(nullabilityAnnotation)
}
}
return annotationsForEntries
}
@@ -26,6 +26,7 @@ import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
import org.jetbrains.kotlin.asJava.classes.cannotModify
import org.jetbrains.kotlin.asJava.classes.lazyPub
import org.jetbrains.kotlin.asJava.fastCheckIsNullabilityApplied
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
@@ -37,6 +38,7 @@ import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
import org.jetbrains.kotlin.psi.psiUtil.hasSuspendModifier
import org.jetbrains.kotlin.psi.psiUtil.isPrivate
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.CompileTimeConstantUtils
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
@@ -308,14 +310,15 @@ open class KtLightNullabilityAnnotation<D : KtLightElement<*, PsiModifierListOwn
?: // it is out of our hands
return getClsNullabilityAnnotation(member)?.qualifiedName
if (!fastCheckIsNullabilityApplied(member)) return null
// all data-class generated members are not-null
if (annotatedElement is KtClass && annotatedElement.isData()) return NotNull::class.java.name
// objects and companion objects are not null
if (annotatedElement is KtObjectDeclaration) return NotNull::class.java.name
if (annotatedElement is KtParameter) {
if (annotatedElement.containingClassOrObject?.isAnnotation() == true) return null
// objects and companion objects are not null but ctor that does not annotated
if (annotatedElement is KtObjectDeclaration) {
if ((parent.parent as? PsiMethod)?.isConstructor == true) return null
return NotNull::class.java.name
}
// don't annotate property setters
@@ -20,6 +20,7 @@ import com.intellij.psi.*
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
import org.jetbrains.kotlin.asJava.classes.KtUltraLightElementWithNullabilityAnnotation
import org.jetbrains.kotlin.asJava.elements.PsiElementWithOrigin
import org.jetbrains.kotlin.asJava.elements.*
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
@@ -30,9 +31,7 @@ import org.jetbrains.kotlin.load.java.propertyNameBySetMethodName
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.isExtensionDeclaration
import org.jetbrains.kotlin.psi.psiUtil.*
/**
* Can be null in scripts and for elements from non-jvm modules.
@@ -220,4 +219,33 @@ fun KtLightMethod.checkIsMangled(): Boolean {
val demangledName = KotlinTypeMapper.InternalNameMapper.demangleInternalName(name) ?: return false
val originalName = propertyNameByAccessor(demangledName, this) ?: demangledName
return originalName == kotlinOrigin?.name
}
fun fastCheckIsNullabilityApplied(lightElement: KtLightElement<*, PsiModifierListOwner>): Boolean {
val annotatedElement = lightElement.kotlinOrigin ?: return true
// all data-class generated members are not-null
if (annotatedElement is KtClass && annotatedElement.isData()) return true
if (annotatedElement is KtParameter && lightElement !is PsiField) { //KtParameter but not it's backing field
val containingClassOrObject = annotatedElement.containingClassOrObject
if (containingClassOrObject?.isAnnotation() == true) return false
if ((containingClassOrObject as? KtClass)?.isEnum() == true) {
if (annotatedElement.parent.parent is KtPrimaryConstructor) return false
}
val parent = annotatedElement.parent.parent
if (parent is KtModifierListOwner && parent.isPrivate()) return false
if (parent is KtPropertyAccessor) {
val propertyOfAccessor = parent.parent
if (propertyOfAccessor is KtProperty && propertyOfAccessor.isPrivate()) return false
}
} else {
// private properties
if ((annotatedElement as? KtModifierListOwner)?.isPrivate() == true) return false
}
return true
}