add ultra-light classes/members that work without backend in simple cases

This commit is contained in:
peter
2018-10-25 17:58:05 +02:00
parent 387efc3791
commit ebc998d710
48 changed files with 2502 additions and 98 deletions
@@ -21,6 +21,7 @@ import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.asJava.builder.LightClassBuilderResult
import org.jetbrains.kotlin.asJava.builder.LightClassConstructionContext
import org.jetbrains.kotlin.asJava.builder.LightClassDataHolder
import org.jetbrains.kotlin.asJava.classes.KtUltraLightClass
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
@@ -40,6 +41,8 @@ abstract class LightClassGenerationSupport {
abstract fun analyzeWithContent(element: KtClassOrObject): BindingContext
abstract fun createUltraLightClass(element: KtClassOrObject): KtUltraLightClass?
companion object {
@JvmStatic
fun getInstance(project: Project): LightClassGenerationSupport {
@@ -209,7 +209,7 @@ object LightClassUtil {
fun buildLightTypeParameterList(
owner: PsiTypeParameterListOwner,
declaration: KtDeclaration): PsiTypeParameterList {
val builder = KotlinLightTypeParameterListBuilder(owner.manager)
val builder = KotlinLightTypeParameterListBuilder(owner)
if (declaration is KtTypeParameterListOwner) {
val parameters = declaration.typeParameters
for (i in parameters.indices) {
@@ -22,6 +22,7 @@ import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Comparing
import com.intellij.openapi.util.Key
import com.intellij.openapi.util.registry.Registry
import com.intellij.psi.*
import com.intellij.psi.impl.PsiSubstitutorImpl
import com.intellij.psi.impl.java.stubs.PsiJavaFileStub
@@ -37,6 +38,7 @@ import com.intellij.psi.util.CachedValuesManager
import com.intellij.psi.util.PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT
import com.intellij.psi.util.PsiUtilCore
import com.intellij.util.IncorrectOperationException
import com.intellij.util.SystemProperties
import com.intellij.util.containers.ContainerUtil
import org.jetbrains.annotations.NonNls
import org.jetbrains.kotlin.asJava.ImpreciseResolveResult
@@ -73,15 +75,11 @@ abstract class KtLightClassForSourceDeclaration(protected val classOrObject: KtC
: KtLazyLightClass(classOrObject.manager), StubBasedPsiElement<KotlinClassOrObjectStub<out KtClassOrObject>> {
private val lightIdentifier = KtLightIdentifier(this, classOrObject)
private val _extendsList by lazyPub {
val listDelegate = super.getExtendsList() ?: return@lazyPub null
KtLightPsiReferenceList(listDelegate, this)
}
private val _extendsList by lazyPub { createExtendsList() }
private val _implementsList by lazyPub { createImplementsList() }
private val _implementsList by lazyPub {
val listDelegate = super.getImplementsList() ?: return@lazyPub null
KtLightPsiReferenceList(listDelegate, this)
}
protected open fun createExtendsList(): PsiReferenceList? = super.getExtendsList()?.let { KtLightPsiReferenceList(it, this) }
protected open fun createImplementsList(): PsiReferenceList? = super.getImplementsList()?.let { KtLightPsiReferenceList(it, this) }
override val kotlinOrigin: KtClassOrObject = classOrObject
@@ -92,7 +90,7 @@ abstract class KtLightClassForSourceDeclaration(protected val classOrObject: KtC
override val lightClassData: LightClassData
get() = findLightClassData()
open protected fun findLightClassData() = getLightClassDataHolder().findDataForClassOrObject(classOrObject)
protected open fun findLightClassData() = getLightClassDataHolder().findDataForClassOrObject(classOrObject)
private fun getJavaFileStub(): PsiJavaFileStub = getLightClassDataHolder().javaFileStub
@@ -110,9 +108,9 @@ abstract class KtLightClassForSourceDeclaration(protected val classOrObject: KtC
private val _containingFile: PsiFile by lazyPub {
object : FakeFileForLightClass(
classOrObject.containingKtFile,
{ if (classOrObject.isTopLevel()) this else create(getOutermostClassOrObject(classOrObject))!! },
{ getJavaFileStub() }
classOrObject.containingKtFile,
{ if (classOrObject.isTopLevel()) this else create(getOutermostClassOrObject(classOrObject))!! },
{ getJavaFileStub() }
) {
override fun findReferenceAt(offset: Int) = ktFile.findReferenceAt(offset)
@@ -173,9 +171,9 @@ abstract class KtLightClassForSourceDeclaration(protected val classOrObject: KtC
return super.getContainingClass()
}
private val _typeParameterList: PsiTypeParameterList by lazyPub {
LightClassUtil.buildLightTypeParameterList(this, classOrObject)
}
private val _typeParameterList: PsiTypeParameterList by lazyPub { buildTypeParameterList() }
open protected fun buildTypeParameterList() = LightClassUtil.buildLightTypeParameterList(this, classOrObject)
override fun getTypeParameterList(): PsiTypeParameterList? = _typeParameterList
@@ -322,9 +320,8 @@ abstract class KtLightClassForSourceDeclaration(protected val classOrObject: KtC
override fun getNameIdentifier(): KtLightIdentifier? = lightIdentifier
override fun getExtendsList() = _extendsList
override fun getImplementsList() = _implementsList
override fun getExtendsList(): PsiReferenceList? = _extendsList
override fun getImplementsList(): PsiReferenceList? = _implementsList
companion object {
private val JAVA_API_STUB = Key.create<CachedValue<LightClassDataHolder.ForClass>>("JAVA_API_STUB")
@@ -347,6 +344,10 @@ abstract class KtLightClassForSourceDeclaration(protected val classOrObject: KtC
return null
}
if (Registry.`is`("kotlin.use.ultra.light.classes", false)) {
LightClassGenerationSupport.getInstance(classOrObject.project).createUltraLightClass(classOrObject)?.let { return it }
}
return when {
classOrObject is KtObjectDeclaration && classOrObject.isObjectLiteral() ->
KtLightClassForAnonymousDeclaration(classOrObject)
@@ -456,17 +457,16 @@ abstract class KtLightClassForSourceDeclaration(protected val classOrObject: KtC
private val modifiers by lazyPub { containingClass.computeModifiers() }
override fun hasModifierProperty(name: String): Boolean {
if (name != PsiModifier.FINAL) {
return name in modifiers
}
override fun hasModifierProperty(name: String): Boolean =
if (name != PsiModifier.FINAL) name in modifiers else owner.isFinal(PsiModifier.FINAL in modifiers)
val isFinalByPsi = PsiModifier.FINAL in modifiers
// annotations can make class open via 'allopen' plugin
if (!owner.isPossiblyAffectedByAllOpen() || !isFinalByPsi) return isFinalByPsi
}
return clsDelegate.hasModifierProperty(PsiModifier.FINAL)
}
open fun isFinal(isFinalByPsi: Boolean): Boolean {
// annotations can make class open via 'allopen' plugin
if (!isPossiblyAffectedByAllOpen() || !isFinalByPsi) return isFinalByPsi
return clsDelegate.hasModifierProperty(PsiModifier.FINAL)
}
}
@@ -19,7 +19,7 @@ package org.jetbrains.kotlin.asJava.classes
import org.jetbrains.kotlin.psi.KtClassOrObject
// light class for top level or (inner/nested of top level) source declarations
class KtLightClassImpl(classOrObject: KtClassOrObject) : KtLightClassForSourceDeclaration(classOrObject) {
open class KtLightClassImpl(classOrObject: KtClassOrObject) : KtLightClassForSourceDeclaration(classOrObject) {
override fun getQualifiedName() = classOrObject.fqName?.asString()
override fun getParent() = if (classOrObject.isTopLevel())
@@ -0,0 +1,657 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.asJava.classes
import com.google.common.annotations.VisibleForTesting
import com.intellij.lang.Language
import com.intellij.psi.*
import com.intellij.psi.impl.PsiClassImplUtil
import com.intellij.psi.impl.PsiImplUtil
import com.intellij.psi.impl.light.*
import com.intellij.psi.util.TypeConversionUtil
import org.jetbrains.annotations.NonNls
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
import org.jetbrains.kotlin.asJava.builder.LightClassData
import org.jetbrains.kotlin.asJava.builder.LightMemberOriginForDeclaration
import org.jetbrains.kotlin.asJava.elements.*
import org.jetbrains.kotlin.codegen.FunctionCodegen
import org.jetbrains.kotlin.codegen.PropertyCodegen
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.idea.KotlinLanguage
import org.jetbrains.kotlin.lexer.KtTokens.*
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClass
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.annotations.JVM_STATIC_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.resolve.annotations.argumentValue
import org.jetbrains.kotlin.resolve.constants.EnumValue
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.isPublishedApi
import org.jetbrains.kotlin.resolve.jvm.annotations.STRICTFP_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.resolve.jvm.annotations.SYNCHRONIZED_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.resolve.jvm.annotations.TRANSIENT_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.resolve.jvm.annotations.VOLATILE_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind
import org.jetbrains.kotlin.types.KotlinType
class KtUltraLightClass(classOrObject: KtClassOrObject, private val support: UltraLightSupport) :
KtLightClassImpl(classOrObject) {
private val tooComplex: Boolean by lazyPub { support.isTooComplexForUltraLightGeneration(classOrObject) }
override fun isFinal(isFinalByPsi: Boolean) = if (tooComplex) super.isFinal(isFinalByPsi) else isFinalByPsi
@Volatile
@VisibleForTesting
var isClsDelegateLoaded = false
override fun findLightClassData(): LightClassData = super.findLightClassData().also {
if (!isClsDelegateLoaded) {
isClsDelegateLoaded = true
check(tooComplex) { "Cls delegate shouldn't be loaded for not too complex ultra-light classes!" }
}
}
private fun allSuperTypes() =
getDescriptor()?.typeConstructor?.supertypes?.mapNotNull {
it.asPsiType(classOrObject, support, TypeMappingMode.SUPER_TYPE) as? PsiClassType
}.orEmpty()
override fun createExtendsList(): PsiReferenceList? =
if (tooComplex) super.createExtendsList()
else LightReferenceListBuilder(manager, language, PsiReferenceList.Role.EXTENDS_LIST).also { list ->
allSuperTypes()
.filter { (isInterface || it.resolve()?.isInterface == false) && !it.equalsToText(CommonClassNames.JAVA_LANG_OBJECT) }
.forEach(list::addReference)
}
override fun createImplementsList(): PsiReferenceList? =
if (tooComplex) super.createImplementsList()
else LightReferenceListBuilder(manager, language, PsiReferenceList.Role.IMPLEMENTS_LIST).also { list ->
if (!isInterface) {
allSuperTypes()
.filter { it.resolve()?.isInterface == true }
.forEach(list::addReference)
}
}
override fun buildTypeParameterList(): PsiTypeParameterList =
if (tooComplex) super.buildTypeParameterList() else buildTypeParameterList(classOrObject, this, support)
// the following logic should be in the platform (super), overrides can be removed once that happens
override fun getInterfaces(): Array<PsiClass> = PsiClassImplUtil.getInterfaces(this)
override fun getSuperClass(): PsiClass? = PsiClassImplUtil.getSuperClass(this)
override fun getSupers(): Array<PsiClass> = PsiClassImplUtil.getSupers(this)
override fun getSuperTypes(): Array<PsiClassType> = PsiClassImplUtil.getSuperTypes(this)
override fun getRBrace(): PsiElement? = null
override fun getLBrace(): PsiElement? = null
private val _ownFields: List<KtLightField> by lazyPub {
val result = arrayListOf<KtLightField>()
val usedNames = hashSetOf<String>()
fun generateUniqueName(base: String): String {
if (usedNames.add(base)) return base
var i = 1
while (true) {
val suggestion = "$base$$i"
if (usedNames.add(suggestion)) return suggestion
i++
}
}
for (parameter in propertyParameters()) {
val modifiers = hashSetOf<String>()
modifiers.add(PsiModifier.PRIVATE)
if (!parameter.isMutable) {
modifiers.add(PsiModifier.FINAL)
}
result.add(KtUltraLightField(parameter, generateUniqueName(parameter.name.orEmpty()), this, support, modifiers))
}
this.classOrObject.companionObjects.firstOrNull()?.let { companion ->
result.add(
KtUltraLightField(
companion,
generateUniqueName(companion.name.orEmpty()),
this,
support,
setOf(PsiModifier.STATIC, PsiModifier.FINAL, PsiModifier.PUBLIC)
)
)
for (property in companion.declarations.filterIsInstance<KtProperty>()) {
if (isInterface && !property.hasModifier(CONST_KEYWORD)) continue
propertyField(property, ::generateUniqueName, true)?.let(result::add)
}
}
if (!isInterface &&
!(this.classOrObject is KtObjectDeclaration && this.classOrObject.isCompanion() && containingClass?.isInterface == false)
) {
for (property in this.classOrObject.declarations.filterIsInstance<KtProperty>()) {
propertyField(property, ::generateUniqueName, forceStatic = this.classOrObject is KtObjectDeclaration)?.let(result::add)
}
}
if (isNamedObject()) {
result.add(
KtUltraLightField(
this.classOrObject,
JvmAbi.INSTANCE_FIELD,
this,
support,
setOf(PsiModifier.STATIC, PsiModifier.FINAL, PsiModifier.PUBLIC)
)
)
}
result
}
private fun isNamedObject() = classOrObject is KtObjectDeclaration && !classOrObject.isCompanion()
private fun propertyField(property: KtProperty, generateUniqueName: (String) -> String, forceStatic: Boolean): KtLightField? {
if (!hasBackingField(property)) return null
val hasDelegate = property.hasDelegate()
val fieldName = generateUniqueName((property.name ?: "") + (if (hasDelegate) "\$delegate" else ""))
val visibility = when {
property.hasModifier(PRIVATE_KEYWORD) -> PsiModifier.PRIVATE
property.hasModifier(PROTECTED_KEYWORD) && property.hasModifier(LATEINIT_KEYWORD) -> PsiModifier.PROTECTED
property.hasModifier(CONST_KEYWORD) || (property.hasModifier(LATEINIT_KEYWORD) && property.setter == null) -> PsiModifier.PUBLIC
else -> PsiModifier.PRIVATE
}
val modifiers = hashSetOf(visibility)
if (!property.isVar || property.hasModifier(CONST_KEYWORD) || hasDelegate) {
modifiers.add(PsiModifier.FINAL)
}
if (forceStatic || isNamedObject() && isJvmStatic(property)) {
modifiers.add(PsiModifier.STATIC)
}
return KtUltraLightField(property, fieldName, this, support, modifiers)
}
private fun hasBackingField(property: KtProperty): Boolean {
if (property.hasModifier(ABSTRACT_KEYWORD)) return false
if (property.hasModifier(LATEINIT_KEYWORD) || property.accessors.isEmpty()) return true
val context = LightClassGenerationSupport.getInstance(project).analyze(property)
val descriptor = context.get(BindingContext.DECLARATION_TO_DESCRIPTOR, property)
return descriptor is PropertyDescriptor && context[BindingContext.BACKING_FIELD_REQUIRED, descriptor] == true
}
override fun getOwnFields(): List<KtLightField> = if (tooComplex) super.getOwnFields() else _ownFields
private fun propertyParameters() = classOrObject.primaryConstructorParameters.filter { it.hasValOrVar() }
private val _ownMethods: List<KtLightMethod> by lazyPub {
val result = arrayListOf<KtLightMethod>()
for (declaration in this.classOrObject.declarations.filterNot { isHiddenByDeprecation(it) }) {
if (declaration.hasModifier(PRIVATE_KEYWORD) && isInterface) continue
when (declaration) {
is KtNamedFunction -> result.add(asJavaMethod(declaration, false))
is KtProperty -> result.addAll(propertyAccessors(declaration, declaration.isVar, false))
}
}
for (parameter in propertyParameters()) {
result.addAll(propertyAccessors(parameter, parameter.isMutable, false))
}
if (!isInterface) {
result.addAll(createConstructors())
}
this.classOrObject.companionObjects.firstOrNull()?.let { companion ->
for (declaration in companion.declarations.filterNot { isHiddenByDeprecation(it) }) {
when (declaration) {
is KtNamedFunction -> if (isJvmStatic(declaration)) result.add(asJavaMethod(declaration, true))
is KtProperty -> result.addAll(propertyAccessors(declaration, declaration.isVar, true))
}
}
}
result
}
private fun createConstructors(): List<KtLightMethod> {
val result = arrayListOf<KtLightMethod>()
val constructors = classOrObject.allConstructors
if (constructors.isEmpty()) {
result.add(defaultConstructor())
}
for (constructor in constructors.filterNot { isHiddenByDeprecation(it) }) {
result.add(asJavaMethod(constructor, false))
}
val primary = classOrObject.primaryConstructor
if (primary != null && shouldGenerateNoArgOverload(primary)) {
result.add(noArgConstructor(simpleVisibility(primary), primary))
}
return result
}
private fun shouldGenerateNoArgOverload(primary: KtPrimaryConstructor): Boolean {
return !primary.hasModifier(PRIVATE_KEYWORD) &&
primary.valueParameters.isNotEmpty() &&
primary.valueParameters.all { it.defaultValue != null } &&
classOrObject.allConstructors.none { it.valueParameters.isEmpty() }
}
private fun defaultConstructor(): KtUltraLightMethod {
val visibility =
if (classOrObject is KtObjectDeclaration || classOrObject.hasModifier(SEALED_KEYWORD)) PsiModifier.PRIVATE
else PsiModifier.PUBLIC
return noArgConstructor(visibility, classOrObject)
}
private fun simpleVisibility(declaration: KtDeclaration): String = when {
declaration.hasModifier(PRIVATE_KEYWORD) -> PsiModifier.PRIVATE
declaration.hasModifier(PROTECTED_KEYWORD) -> PsiModifier.PROTECTED
else -> PsiModifier.PUBLIC
}
private fun noArgConstructor(visibility: String, declaration: KtDeclaration): KtUltraLightMethod = KtUltraLightMethod(
LightMethodBuilder(manager, language, name.orEmpty()).setConstructor(true).addModifier(visibility),
declaration,
support,
this
)
private fun isHiddenByDeprecation(declaration: KtDeclaration): Boolean {
val deprecated = support.findAnnotation(declaration, FqName("kotlin.Deprecated"))?.second
return (deprecated?.argumentValue("level") as? EnumValue)?.enumEntryName?.asString() == "HIDDEN"
}
private fun isJvmStatic(declaration: KtAnnotated): Boolean = declaration.hasAnnotation(JVM_STATIC_ANNOTATION_FQ_NAME)
override fun getOwnMethods(): List<KtLightMethod> = if (tooComplex) super.getOwnMethods() else _ownMethods
private fun asJavaMethod(f: KtFunction, forceStatic: Boolean): KtLightMethod {
val isConstructor = f is KtConstructor<*>
val name = if (isConstructor) this.name else mangleIfNeeded(listOf(f), f.name ?: SpecialNames.NO_NAME_PROVIDED.asString())
val method = lightMethod(name.orEmpty(), f, forceStatic)
val wrapper = KtUltraLightMethod(method, f, support, this)
addReceiverParameter(f, wrapper)
for (parameter in f.valueParameters) {
method.addParameter(KtUltraLightParameter(parameter.name.orEmpty(), parameter, support, wrapper, null))
}
val returnType: PsiType? by lazyPub {
if (isConstructor) null
else methodReturnType(f)
}
method.setMethodReturnType { returnType }
return wrapper
}
private fun addReceiverParameter(f: KtDeclaration, method: KtUltraLightMethod) {
val receiver = (f as? KtCallableDeclaration)?.receiverTypeReference
if (receiver != null) {
method.delegate.addParameter(KtUltraLightParameter("\$self", f, support, method, receiver))
}
}
private fun methodReturnType(f: KtDeclaration): PsiType {
val desc = f.resolve()?.let { if (it is PropertyDescriptor) it.getter else it }
val kotlinType = (desc as? FunctionDescriptor)?.returnType ?: return PsiType.NULL
val mode = when {
typeMapper(support).forceBoxedReturnType(desc) -> TypeMappingMode.RETURN_TYPE_BOXED
else -> TypeMappingMode.getOptimalModeForReturnType(kotlinType, false)
}
return kotlinType.asPsiType(f, support, mode)
}
private fun lightMethod(name: String, declaration: KtDeclaration, forceStatic: Boolean): LightMethodBuilder {
val accessedProperty = if (declaration is KtPropertyAccessor) declaration.property else null
val outer = accessedProperty ?: declaration
return LightMethodBuilder(
manager, language, name,
LightParameterListBuilder(manager, language),
object : LightModifierList(manager, language) {
override fun hasModifierProperty(name: String): Boolean {
if (name == PsiModifier.PUBLIC || name == PsiModifier.PROTECTED || name == PsiModifier.PRIVATE) {
if (declaration.isPrivate() || accessedProperty?.isPrivate() == true) {
return name == PsiModifier.PRIVATE
}
if (declaration.hasModifier(PROTECTED_KEYWORD) || accessedProperty?.hasModifier(PROTECTED_KEYWORD) == true) {
return name == PsiModifier.PROTECTED
}
if (outer.hasModifier(OVERRIDE_KEYWORD)) {
when ((outer.resolve() as? CallableDescriptor)?.visibility) {
Visibilities.PUBLIC -> return name == PsiModifier.PUBLIC
Visibilities.PRIVATE -> return name == PsiModifier.PRIVATE
Visibilities.PROTECTED -> return name == PsiModifier.PROTECTED
}
}
return name == PsiModifier.PUBLIC
}
return when (name) {
PsiModifier.FINAL -> !isInterface && outer !is KtConstructor<*> && isFinal(outer)
PsiModifier.ABSTRACT -> isInterface || outer.hasModifier(ABSTRACT_KEYWORD)
PsiModifier.STATIC -> forceStatic || isNamedObject() && isJvmStatic(outer)
PsiModifier.STRICTFP -> declaration is KtFunction && declaration.hasAnnotation(STRICTFP_ANNOTATION_FQ_NAME)
PsiModifier.SYNCHRONIZED -> declaration is KtFunction && declaration.hasAnnotation(SYNCHRONIZED_ANNOTATION_FQ_NAME)
else -> false
}
}
fun KtDeclaration.isPrivate() =
hasModifier(PRIVATE_KEYWORD) ||
this is KtConstructor<*> && classOrObject.hasModifier(SEALED_KEYWORD) ||
this is KtFunction && typeParameters.any { it.hasModifier(REIFIED_KEYWORD) }
}
).setConstructor(declaration is KtConstructor<*>)
}
private fun mangleIfNeeded(declarations: List<KtDeclaration>, name: String): String {
for (declaration in declarations) {
if (declaration.hasModifier(PRIVATE_KEYWORD) ||
declaration.hasModifier(PROTECTED_KEYWORD) ||
declaration.hasModifier(PUBLIC_KEYWORD)
) {
return name
}
if (isInternal(declaration) && declaration.resolve()?.isPublishedApi() != true) {
return KotlinTypeMapper.InternalNameMapper.mangleInternalName(name, support.moduleName)
}
}
return name
}
private fun KtAnnotated.hasAnnotation(name: FqName) = support.findAnnotation(this, name) != null
private fun isInternal(f: KtDeclaration): Boolean {
if (f.hasModifier(OVERRIDE_KEYWORD)) {
val desc = f.resolve()
return desc is CallableDescriptor &&
desc.visibility.effectiveVisibility(desc, false) == EffectiveVisibility.Internal
}
return f.hasModifier(INTERNAL_KEYWORD)
}
private fun propertyAccessors(declaration: KtNamedDeclaration, mutable: Boolean, onlyJvmStatic: Boolean): List<KtLightMethod> {
val propertyName = declaration.name
if (declaration.hasModifier(CONST_KEYWORD) || propertyName == null) return emptyList()
val ktGetter = (declaration as? KtProperty)?.getter
val ktSetter = (declaration as? KtProperty)?.setter
val isPrivate = declaration.hasModifier(PRIVATE_KEYWORD)
if (isPrivate && declaration !is KtProperty) return emptyList()
fun needsAccessor(accessor: KtPropertyAccessor?): Boolean {
if (!onlyJvmStatic || isJvmStatic(declaration) || accessor != null && isJvmStatic(accessor)) {
if (declaration is KtProperty && declaration.hasDelegate()) {
return true
}
if (accessor?.hasModifier(PRIVATE_KEYWORD) == true) {
return false
}
if (!isPrivate || accessor?.hasBody() == true) {
return true
}
}
return false
}
val result = arrayListOf<KtLightMethod>()
if (needsAccessor(ktGetter)) {
val getterName = mangleIfNeeded(listOfNotNull(ktGetter, declaration), JvmAbi.getterName(propertyName))
val getterType: PsiType by lazyPub { methodReturnType(declaration) }
val getterPrototype = lightMethod(getterName, ktGetter ?: declaration, onlyJvmStatic)
.setMethodReturnType { getterType }
val getterWrapper = KtUltraLightMethod(getterPrototype, declaration, support, this)
addReceiverParameter(declaration, getterWrapper)
result.add(getterWrapper)
}
if (mutable && needsAccessor(ktSetter)) {
val setterName = mangleIfNeeded(listOfNotNull(ktSetter, declaration), JvmAbi.setterName(propertyName))
val setterPrototype = lightMethod(setterName, ktSetter ?: declaration, onlyJvmStatic)
.setMethodReturnType(PsiType.VOID)
val setterWrapper = KtUltraLightMethod(setterPrototype, declaration, support, this)
addReceiverParameter(declaration, setterWrapper)
val parameterOrigin = ktSetter?.parameter ?: declaration
setterPrototype.addParameter(KtUltraLightParameter(propertyName, parameterOrigin, support, setterWrapper, null))
result.add(setterWrapper)
}
return result
}
private fun isFinal(declaration: KtDeclaration): Boolean {
if (declaration.hasModifier(FINAL_KEYWORD)) return true
return declaration !is KtPropertyAccessor &&
!declaration.hasModifier(OPEN_KEYWORD) &&
!declaration.hasModifier(OVERRIDE_KEYWORD) &&
!declaration.hasModifier(ABSTRACT_KEYWORD)
}
override fun getInitializers(): Array<PsiClassInitializer> = emptyArray()
override fun getContainingClass(): PsiClass? =
if (tooComplex) super.getContainingClass() else classOrObject.containingClass()?.let(KtLightClassForSourceDeclaration::create)
override fun getParent(): PsiElement? = if (tooComplex) super.getParent() else containingClass ?: containingFile
override fun getScope(): PsiElement? = if (tooComplex) super.getScope() else parent
override fun copy(): KtLightClassImpl = KtUltraLightClass(classOrObject.copy() as KtClassOrObject, support)
}
private class KtUltraLightField(
private val declaration: KtNamedDeclaration,
name: String,
private val containingClass: KtUltraLightClass,
private val support: UltraLightSupport,
modifiers: Set<String>
) : LightFieldBuilder(name, PsiType.NULL, declaration), KtLightField {
private val modList = object : KtLightSimpleModifierList(this, modifiers) {
override fun hasModifierProperty(name: String): Boolean = when (name) {
PsiModifier.VOLATILE -> hasFieldAnnotation(VOLATILE_ANNOTATION_FQ_NAME)
PsiModifier.TRANSIENT -> hasFieldAnnotation(TRANSIENT_ANNOTATION_FQ_NAME)
else -> super.hasModifierProperty(name)
}
private fun hasFieldAnnotation(fqName: FqName): Boolean {
val annotation = support.findAnnotation(declaration, fqName)?.first ?: return false
val target = annotation.useSiteTarget?.getAnnotationUseSiteTarget() ?: return true
val expectedTarget =
if (declaration is KtProperty && declaration.hasDelegate()) AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD
else AnnotationUseSiteTarget.FIELD
return target == expectedTarget
}
}
override fun getModifierList(): PsiModifierList = modList
override fun hasModifierProperty(name: String): Boolean =
modifierList.hasModifierProperty(name) //can be removed after IDEA platform does the same
override fun getLanguage(): Language = KotlinLanguage.INSTANCE
private val _type: PsiType by lazyPub {
fun nonExistent() = JavaPsiFacade.getElementFactory(project).createTypeFromText("error.NonExistentClass", declaration)
when {
declaration is KtProperty && declaration.hasDelegate() ->
(declaration.resolve() as? PropertyDescriptor)
?.let {
val context = LightClassGenerationSupport.getInstance(project).analyze(declaration)
PropertyCodegen.getDelegateTypeForProperty(declaration, it, context)
}
?.let { it.asPsiType(declaration, support, TypeMappingMode.getOptimalModeForValueParameter(it), this) }
?.let(TypeConversionUtil::erasure)
?: nonExistent()
declaration is KtObjectDeclaration ->
KtLightClassForSourceDeclaration.create(declaration)?.let { JavaPsiFacade.getElementFactory(project).createType(it) }
?: nonExistent()
else ->
declaration.getKotlinType()?.let {
val mode = when {
(declaration.resolve() as? PropertyDescriptor)?.isVar == true -> TypeMappingMode.getOptimalModeForValueParameter(it)
else -> TypeMappingMode.getOptimalModeForReturnType(it, false)
}
it.asPsiType(declaration, support, mode, this)
} ?: PsiType.NULL
}
}
override fun getType(): PsiType = _type
override fun getParent() = containingClass
override fun getContainingClass() = containingClass
override fun getContainingFile(): PsiFile? = containingClass.containingFile
override fun computeConstantValue(): Any? =
if (hasModifierProperty(PsiModifier.FINAL) &&
(TypeConversionUtil.isPrimitiveAndNotNull(_type) || _type.equalsToText(CommonClassNames.JAVA_LANG_STRING))
)
(declaration.resolve() as? VariableDescriptor)?.compileTimeInitializer?.value
else null
override fun computeConstantValue(visitedVars: MutableSet<PsiVariable>?): Any? = computeConstantValue()
override val kotlinOrigin = declaration
override val clsDelegate: PsiField
get() = throw IllegalStateException("Cls delegate shouldn't be loaded for ultra-light PSI!")
override val lightMemberOrigin = LightMemberOriginForDeclaration(declaration, JvmDeclarationOriginKind.OTHER)
override fun setName(@NonNls name: String): PsiElement {
(kotlinOrigin as? KtNamedDeclaration)?.setName(name)
return this
}
override fun setInitializer(initializer: PsiExpression?) = cannotModify()
}
internal class KtUltraLightMethod(
internal val delegate: LightMethodBuilder,
originalElement: KtDeclaration,
private val support: UltraLightSupport,
containingClass: KtUltraLightClass
) : KtLightMethodImpl({ delegate }, LightMemberOriginForDeclaration(originalElement, JvmDeclarationOriginKind.OTHER), containingClass) {
override fun getReturnTypeElement(): PsiTypeElement? = null
override fun getReturnType(): PsiType? = clsDelegate.returnType
override fun getParameterList(): PsiParameterList = clsDelegate.parameterList
// should be in super
override fun isVarArgs() = PsiImplUtil.isVarArgs(this)
override fun buildTypeParameterList(): PsiTypeParameterList {
val origin = kotlinOrigin
return if (origin is KtFunction || origin is KtProperty)
buildTypeParameterList(origin as KtTypeParameterListOwner, this, support)
else LightTypeParameterListBuilder(manager, language)
}
private val _throwsList: PsiReferenceList by lazyPub {
val list = LightReferenceListBuilder(manager, language, PsiReferenceList.Role.THROWS_LIST)
(kotlinOrigin?.resolve() as? FunctionDescriptor)?.let {
for (ex in FunctionCodegen.getThrownExceptions(it)) {
list.addReference(ex.fqNameSafe.asString())
}
}
list
}
override fun getThrowsList(): PsiReferenceList = _throwsList
}
internal class KtUltraLightParameter(
name: String,
override val kotlinOrigin: KtDeclaration,
private val support: UltraLightSupport,
method: KtLightMethod,
private val receiver: KtTypeReference?
) : org.jetbrains.kotlin.asJava.elements.LightParameter(
name,
PsiType.NULL,
method,
method.language
),
KtLightDeclaration<KtDeclaration, PsiParameter> {
override val clsDelegate: PsiParameter
get() = throw IllegalStateException("Cls delegate shouldn't be loaded for ultra-light PSI!")
private val lightModifierList by lazyPub { KtLightSimpleModifierList(this, emptySet()) }
override fun isVarArgs(): Boolean =
kotlinOrigin is KtParameter && kotlinOrigin.isVarArg && method.parameterList.parameters.last() == this
override fun getModifierList(): PsiModifierList = lightModifierList
override fun getNavigationElement(): PsiElement = kotlinOrigin
private val kotlinType: KotlinType? by lazyPub {
when {
receiver != null -> (kotlinOrigin.resolve() as? CallableMemberDescriptor)?.extensionReceiverParameter?.type
else -> kotlinOrigin.getKotlinType()
}
}
private val _type: PsiType by lazyPub {
kotlinType?.let { it.asPsiType(kotlinOrigin, support, TypeMappingMode.getOptimalModeForValueParameter(it), this) } ?: PsiType.NULL
}
override fun getType(): PsiType = _type
override fun setName(@NonNls name: String): PsiElement {
(kotlinOrigin as? KtVariableDeclaration)?.setName(name)
return this
}
override fun getContainingFile(): PsiFile = method.containingFile
override fun getParent(): PsiElement = method.parameterList
override fun equals(other: Any?): Boolean = other is KtUltraLightParameter && other.kotlinOrigin == this.kotlinOrigin
override fun hashCode(): Int = kotlinOrigin.hashCode()
internal fun annotatedOrigin(): KtAnnotated? {
if (receiver != null) return receiver
if (kotlinOrigin is KtProperty) {
return null // we're a setter of a property with no explicit declaration, so we don't have annotation
}
return kotlinOrigin
}
internal fun getTypeForNullability(): KotlinType? {
if (receiver != null) return kotlinType
if (kotlinOrigin is KtProperty) {
if (kotlinOrigin.setter?.hasModifier(PRIVATE_KEYWORD) == true) return null
return kotlinType
}
if (kotlinOrigin is KtParameter) {
val reference = kotlinOrigin.typeReference
if (kotlinOrigin.isVarArg && reference != null) {
LightClassGenerationSupport.getInstance(project).analyze(reference)[BindingContext.TYPE, reference]?.let { return it }
}
if (reference != null || kotlinOrigin.parent?.parent is KtPropertyAccessor) {
return kotlinType
}
}
return null
}
}
interface UltraLightSupport {
val moduleName: String
fun findAnnotation(owner: KtAnnotated, fqName: FqName): Pair<KtAnnotationEntry, AnnotationDescriptor>?
fun isTooComplexForUltraLightGeneration(element: KtClassOrObject): Boolean
}
@@ -0,0 +1,105 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.asJava.classes
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.psi.impl.light.LightReferenceListBuilder
import com.intellij.psi.impl.light.LightTypeParameterBuilder
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
import org.jetbrains.kotlin.asJava.elements.KotlinLightTypeParameterListBuilder
import org.jetbrains.kotlin.codegen.ClassBuilderMode
import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter
import org.jetbrains.kotlin.codegen.state.IncompatibleClassTracker
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.config.JvmTarget
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.ValueDescriptor
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.KtTypeParameterListOwner
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.types.KotlinType
import java.text.StringCharacterIterator
internal fun buildTypeParameterList(
declaration: KtTypeParameterListOwner,
owner: PsiTypeParameterListOwner,
support: UltraLightSupport
): PsiTypeParameterList {
val tpList = KotlinLightTypeParameterListBuilder(owner)
for ((i, ktParam) in declaration.typeParameters.withIndex()) {
tpList.addParameter(object : LightTypeParameterBuilder(ktParam.name.orEmpty(), owner, i) {
private val superList: LightReferenceListBuilder by lazyPub {
val boundList = LightReferenceListBuilder(manager, PsiReferenceList.Role.EXTENDS_BOUNDS_LIST)
if (ktParam.extendsBound != null || declaration.typeConstraints.isNotEmpty()) {
val boundTypes = (ktParam.resolve() as? TypeParameterDescriptor)?.upperBounds.orEmpty()
.mapNotNull { it.asPsiType(ktParam, support, TypeMappingMode.DEFAULT, this) as? PsiClassType }
val hasDefaultBound = boundTypes.size == 1 && boundTypes[0].equalsToText(CommonClassNames.JAVA_LANG_OBJECT)
if (!hasDefaultBound) {
boundTypes.forEach(boundList::addReference)
}
}
boundList
}
override fun getExtendsList(): LightReferenceListBuilder = superList
override fun getParent(): PsiElement = tpList
override fun getContainingFile(): PsiFile = owner.containingFile
})
}
return tpList
}
internal fun KtDeclaration.getKotlinType(): KotlinType? {
val descriptor = resolve()
return when (descriptor) {
is ValueDescriptor -> descriptor.type
is CallableDescriptor -> descriptor.returnType
else -> null
}
}
internal fun KtDeclaration.resolve() = LightClassGenerationSupport.getInstance(project).resolveToDescriptor(this)
// copy-pasted from kotlinInternalUastUtils.kt and post-processed
internal fun KotlinType.asPsiType(
declaration: KtDeclaration,
support: UltraLightSupport,
mode: TypeMappingMode,
psiContext: PsiElement = declaration
): PsiType {
val typeFqName = constructor.declarationDescriptor?.fqNameSafe?.asString()
if (typeFqName == "kotlin.Unit" && declaration is KtFunction) return PsiType.VOID
val signatureWriter = BothSignatureWriter(BothSignatureWriter.Mode.TYPE)
typeMapper(support).mapType(this, signatureWriter, mode)
val signature = StringCharacterIterator(signatureWriter.toString())
val javaType = SignatureParsing.parseTypeString(signature, StubBuildingVisitor.GUESSING_MAPPER)
val typeInfo = TypeInfo.fromString(javaType, false)
val typeText = TypeInfo.createTypeText(typeInfo) ?: return PsiType.NULL
val type = ClsTypeElementImpl(psiContext, typeText, '\u0000').type
if (type is PsiArrayType && psiContext is KtUltraLightParameter && psiContext.isVarArgs) {
return PsiEllipsisType(type.componentType, type.annotationProvider)
}
return type
}
internal fun typeMapper(support: UltraLightSupport): KotlinTypeMapper = KotlinTypeMapper(
BindingContext.EMPTY, ClassBuilderMode.LIGHT_CLASSES,
IncompatibleClassTracker.DoNothing, support.moduleName,
JvmTarget.JVM_1_8,
true, false
)
@@ -17,16 +17,21 @@
package org.jetbrains.kotlin.asJava.elements
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiManager
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiTypeParameterListOwner
import com.intellij.psi.ResolveState
import com.intellij.psi.impl.light.LightTypeParameterListBuilder
import com.intellij.psi.scope.PsiScopeProcessor
import org.jetbrains.kotlin.idea.KotlinLanguage
class KotlinLightTypeParameterListBuilder(manager: PsiManager): LightTypeParameterListBuilder(manager, KotlinLanguage.INSTANCE) {
class KotlinLightTypeParameterListBuilder(private val owner: PsiTypeParameterListOwner) :
LightTypeParameterListBuilder(owner.manager, KotlinLanguage.INSTANCE) {
override fun processDeclarations(processor: PsiScopeProcessor, state: ResolveState, lastParent: PsiElement?, place: PsiElement): Boolean {
return typeParameters.all { processor.execute(it, state) }
}
override fun getParent(): PsiElement = owner
override fun getContainingFile(): PsiFile = owner.containingFile
override fun getText(): String? = ""
}
@@ -19,7 +19,9 @@ package org.jetbrains.kotlin.asJava.elements
import com.intellij.psi.*
import com.intellij.psi.impl.compiled.ClsTypeElementImpl
import com.intellij.psi.scope.PsiScopeProcessor
import com.intellij.psi.util.*
import com.intellij.psi.util.MethodSignature
import com.intellij.psi.util.MethodSignatureBackedByPsiMethod
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.asJava.LightClassUtil
import org.jetbrains.kotlin.asJava.builder.LightMemberOrigin
import org.jetbrains.kotlin.asJava.builder.LightMemberOriginForDeclaration
@@ -36,7 +38,7 @@ import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.jvm.KotlinJavaPsiFacade
class KtLightMethodImpl private constructor(
open class KtLightMethodImpl protected constructor(
computeRealDelegate: () -> PsiMethod,
lightMemberOrigin: LightMemberOrigin?,
containingClass: KtLightClass,
@@ -55,25 +57,15 @@ class KtLightMethodImpl private constructor(
}
}
private val typeParamsList: CachedValue<PsiTypeParameterList> by lazyPub {
val cacheManager = CachedValuesManager.getManager(clsDelegate.project)
cacheManager.createCachedValue<PsiTypeParameterList>(
{
val origin = (lightMemberOrigin as? LightMemberOriginForDeclaration)?.originalElement
val list = if (origin != null) {
if (origin is KtClassOrObject) {
KotlinLightTypeParameterListBuilder(manager)
}
else {
LightClassUtil.buildLightTypeParameterList(this@KtLightMethodImpl, origin)
}
}
else {
clsDelegate.typeParameterList
}
CachedValueProvider.Result.create(list, PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT)
}, false
)
private val typeParamsList: PsiTypeParameterList? by lazyPub { buildTypeParameterList() }
protected open fun buildTypeParameterList(): PsiTypeParameterList? {
val origin = (lightMemberOrigin as? LightMemberOriginForDeclaration)?.originalElement
return when {
origin is KtClassOrObject -> KotlinLightTypeParameterListBuilder(this)
origin != null -> LightClassUtil.buildLightTypeParameterList(this, origin)
else -> clsDelegate.typeParameterList
}
}
override fun accept(visitor: PsiElementVisitor) {
@@ -128,7 +120,7 @@ class KtLightMethodImpl private constructor(
override fun getParameterList() = paramsList
override fun getTypeParameterList() = typeParamsList.value
override fun getTypeParameterList() = typeParamsList
override fun getTypeParameters(): Array<PsiTypeParameter> =
typeParameterList?.typeParameters ?: PsiTypeParameter.EMPTY_ARRAY
@@ -23,6 +23,7 @@ import com.intellij.psi.PsiModifierListOwner
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
import org.jetbrains.kotlin.asJava.builder.LightMemberOriginForDeclaration
import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration
import org.jetbrains.kotlin.asJava.classes.KtUltraLightParameter
import org.jetbrains.kotlin.asJava.classes.lazyPub
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
@@ -37,7 +38,7 @@ import org.jetbrains.kotlin.resolve.source.getPsi
abstract class KtLightModifierList<out T : KtLightElement<KtModifierListOwner, PsiModifierListOwner>>(protected val owner: T)
: KtLightElementBase(owner), PsiModifierList, KtLightElement<KtModifierList, PsiModifierList> {
override val clsDelegate by lazyPub { owner.clsDelegate.modifierList!! }
private val _annotations by lazyPub { computeAnnotations(this) }
private val _annotations by lazyPub { computeAnnotations() }
override val kotlinOrigin: KtModifierList?
get() = owner.kotlinOrigin?.modifierList
@@ -61,9 +62,28 @@ abstract class KtLightModifierList<out T : KtLightElement<KtModifierListOwner, P
override fun isWritable() = false
override fun toString() = "Light modifier list of $owner"
protected open fun computeAnnotations(): List<KtLightAbstractAnnotation> {
val annotationsForEntries = lightAnnotationsForEntries(this)
val modifierListOwner = parent
if (modifierListOwner is KtLightClassForSourceDeclaration && modifierListOwner.isAnnotationType) {
val sourceAnnotationNames = annotationsForEntries.mapTo(mutableSetOf()) { it.qualifiedName }
val specialAnnotationsOnAnnotationClass = modifierListOwner.clsDelegate.modifierList?.annotations.orEmpty().filter {
it.qualifiedName !in sourceAnnotationNames
}.map { KtLightNonSourceAnnotation(this, it) }
return annotationsForEntries + specialAnnotationsOnAnnotationClass
}
if ((modifierListOwner is KtLightMember<*> && modifierListOwner !is KtLightFieldImpl.KtLightEnumConstant)
|| modifierListOwner is LightParameter) {
return annotationsForEntries +
listOf(KtLightNullabilityAnnotation(modifierListOwner as KtLightElement<*, PsiModifierListOwner>, this))
}
return annotationsForEntries
}
}
class KtLightSimpleModifierList(
open class KtLightSimpleModifierList(
owner: KtLightElement<KtModifierListOwner, PsiModifierListOwner>, private val modifiers: Set<String>
) : KtLightModifierList<KtLightElement<KtModifierListOwner, PsiModifierListOwner>>(owner) {
override fun hasModifierProperty(name: String) = name in modifiers
@@ -71,31 +91,14 @@ class KtLightSimpleModifierList(
override fun copy() = KtLightSimpleModifierList(owner, modifiers)
}
private fun computeAnnotations(lightModifierList: KtLightModifierList<*>): List<KtLightAbstractAnnotation> {
val annotationsForEntries = lightAnnotationsForEntries(lightModifierList)
val modifierListOwner = lightModifierList.parent
if (modifierListOwner is KtLightClassForSourceDeclaration && modifierListOwner.isAnnotationType) {
val sourceAnnotationNames = annotationsForEntries.mapTo(mutableSetOf()) { it.qualifiedName }
val specialAnnotationsOnAnnotationClass = modifierListOwner.clsDelegate.modifierList?.annotations.orEmpty().filter {
it.qualifiedName !in sourceAnnotationNames
}.map { KtLightNonSourceAnnotation(lightModifierList, it) }
return annotationsForEntries + specialAnnotationsOnAnnotationClass
}
if ((modifierListOwner is KtLightMember<*> && modifierListOwner !is KtLightFieldImpl.KtLightEnumConstant)
|| modifierListOwner is KtLightParameter) {
return annotationsForEntries +
@Suppress("UNCHECKED_CAST")
listOf(KtLightNullabilityAnnotation(modifierListOwner as KtLightElement<*, PsiModifierListOwner>, lightModifierList))
}
return annotationsForEntries
}
private fun lightAnnotationsForEntries(lightModifierList: KtLightModifierList<*>): List<KtLightAnnotationForSourceEntry> {
val lightModifierListOwner = lightModifierList.parent
if (!isFromSources(lightModifierList)) return emptyList()
val annotatedKtDeclaration = lightModifierListOwner.kotlinOrigin as? KtDeclaration
val annotatedKtDeclaration =
if (lightModifierListOwner is KtUltraLightParameter) lightModifierListOwner.annotatedOrigin()
else lightModifierListOwner.kotlinOrigin as? KtDeclaration
if (annotatedKtDeclaration == null || !annotatedKtDeclaration.isValid || !hasAnnotationsInSource(annotatedKtDeclaration)) {
return emptyList()
@@ -128,11 +131,11 @@ fun isFromSources(lightElement: KtLightElement<*, *>): Boolean {
return true
}
private fun getAnnotationDescriptors(declaration: KtDeclaration, annotatedLightElement: KtLightElement<*, *>): List<AnnotationDescriptor> {
private fun getAnnotationDescriptors(declaration: KtAnnotated, annotatedLightElement: KtLightElement<*, *>): List<AnnotationDescriptor> {
val context = LightClassGenerationSupport.getInstance(declaration.project).analyze(declaration)
val descriptor = if (declaration is KtParameter && declaration.isPropertyParameter()) {
if (annotatedLightElement is KtLightParameter && annotatedLightElement.method.isConstructor)
if (annotatedLightElement is LightParameter && annotatedLightElement.method.isConstructor)
context[BindingContext.VALUE_PARAMETER, declaration]
else
context[BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, declaration]
@@ -145,7 +148,8 @@ private fun getAnnotationDescriptors(declaration: KtDeclaration, annotatedLightE
descriptor is ClassDescriptor && annotatedLightElement is KtLightMethod && annotatedLightElement.isConstructor ->
descriptor.unsubstitutedPrimaryConstructor
descriptor !is PropertyDescriptor -> descriptor
annotatedLightElement is KtLightFieldImpl.KtLightFieldForDeclaration -> descriptor.backingField
annotatedLightElement is KtLightFieldImpl.KtLightEnumConstant -> descriptor
annotatedLightElement is KtLightField -> descriptor.backingField
annotatedLightElement !is KtLightMethod -> descriptor
annotatedLightElement.isGetter -> descriptor.getter
annotatedLightElement.isSetter -> descriptor.setter
@@ -164,7 +168,7 @@ private fun getAnnotationDescriptors(declaration: KtDeclaration, annotatedLightE
return annotations
}
private fun hasAnnotationsInSource(declaration: KtDeclaration): Boolean {
private fun hasAnnotationsInSource(declaration: KtAnnotated): Boolean {
if (declaration.annotationEntries.isNotEmpty()) {
return true
}
@@ -175,3 +179,4 @@ private fun hasAnnotationsInSource(declaration: KtDeclaration): Boolean {
return false
}
@@ -25,7 +25,7 @@ import org.jetbrains.kotlin.psi.psiUtil.isExtensionDeclaration
class KtLightParameter(
override val clsDelegate: PsiParameter,
private val index: Int,
val method: KtLightMethod
method: KtLightMethod
) : LightParameter(clsDelegate.name ?: "p$index", clsDelegate.type, method, KotlinLanguage.INSTANCE),
KtLightDeclaration<KtParameter, PsiParameter> {
@@ -25,14 +25,14 @@ public class LightParameter extends LightVariableBuilder implements PsiParameter
public static final LightParameter[] EMPTY_ARRAY = new LightParameter[0];
private final String myName;
private final PsiElement myDeclarationScope;
private final KtLightMethod myDeclarationScope;
private final boolean myVarArgs;
public LightParameter(@NotNull String name, @NotNull PsiType type, PsiElement declarationScope, Language language) {
public LightParameter(@NotNull String name, @NotNull PsiType type, @NotNull KtLightMethod declarationScope, Language language) {
this(name, type, declarationScope, language, type instanceof PsiEllipsisType);
}
public LightParameter(@NotNull String name, @NotNull PsiType type, PsiElement declarationScope, Language language, boolean isVarArgs) {
public LightParameter(@NotNull String name, @NotNull PsiType type, @NotNull KtLightMethod declarationScope, Language language, boolean isVarArgs) {
super(declarationScope.getManager(), name, type, language);
myName = name;
myDeclarationScope = declarationScope;
@@ -41,7 +41,11 @@ public class LightParameter extends LightVariableBuilder implements PsiParameter
@NotNull
@Override
public PsiElement getDeclarationScope() {
public KtLightMethod getDeclarationScope() {
return myDeclarationScope;
}
public KtLightMethod getMethod() {
return myDeclarationScope;
}
@@ -24,6 +24,7 @@ import org.jetbrains.annotations.NotNull
import org.jetbrains.annotations.Nullable
import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
import org.jetbrains.kotlin.asJava.classes.KtUltraLightParameter
import org.jetbrains.kotlin.asJava.classes.cannotModify
import org.jetbrains.kotlin.asJava.classes.lazyPub
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
@@ -298,6 +299,10 @@ class KtLightNullabilityAnnotation(val member: KtLightElement<*, PsiModifierList
internal fun KtTypeReference.getType(): KotlinType? = analyze()[BindingContext.TYPE, this]
private fun getTargetType(annotatedElement: PsiElement): KotlinType? {
if (member is KtUltraLightParameter) {
return member.getTypeForNullability()
}
if (annotatedElement is KtTypeReference) {
annotatedElement.getType()?.let { return it }
}