add ultra-light classes/members that work without backend in simple cases
This commit is contained in:
@@ -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) {
|
||||
|
||||
+27
-27
@@ -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
|
||||
)
|
||||
+7
-2
@@ -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? = ""
|
||||
}
|
||||
|
||||
+14
-22
@@ -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
|
||||
|
||||
+31
-26
@@ -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 }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user