Add support UL for FileFacade
This commit is contained in:
+10
@@ -16,13 +16,16 @@
|
||||
|
||||
package org.jetbrains.kotlin.cli.jvm.compiler
|
||||
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.kotlin.asJava.LightClassBuilder
|
||||
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
|
||||
import org.jetbrains.kotlin.asJava.builder.InvalidLightClassDataHolder
|
||||
import org.jetbrains.kotlin.asJava.builder.LightClassConstructionContext
|
||||
import org.jetbrains.kotlin.asJava.builder.LightClassDataHolder
|
||||
import org.jetbrains.kotlin.asJava.builder.LightClassDataHolderImpl
|
||||
import org.jetbrains.kotlin.asJava.classes.KtUltraLightClassForFacade
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
|
||||
@@ -39,6 +42,13 @@ import org.jetbrains.kotlin.resolve.BindingContext
|
||||
* To mitigate this, CliLightClassGenerationSupport hold a trace that is shared between the analyzer and JetLightClasses
|
||||
*/
|
||||
class CliLightClassGenerationSupport(private val traceHolder: CliTraceHolder) : LightClassGenerationSupport() {
|
||||
|
||||
override fun createUltraLightClassForFacade(
|
||||
facadeClassFqName: FqName,
|
||||
searchScope: GlobalSearchScope,
|
||||
facadeFile: KtFile
|
||||
): KtUltraLightClassForFacade? = null
|
||||
|
||||
override fun createUltraLightClass(element: KtClassOrObject) = null
|
||||
|
||||
override fun createDataHolderForClass(classOrObject: KtClassOrObject, builder: LightClassBuilder): LightClassDataHolder.ForClass {
|
||||
|
||||
@@ -18,11 +18,16 @@ package org.jetbrains.kotlin.asJava
|
||||
|
||||
import com.intellij.openapi.components.ServiceManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
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.KtLightClassForFacade
|
||||
import org.jetbrains.kotlin.asJava.classes.KtUltraLightClass
|
||||
import org.jetbrains.kotlin.asJava.classes.KtUltraLightClassForFacade
|
||||
import org.jetbrains.kotlin.asJava.classes.KtUltraLightSupport
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
|
||||
@@ -43,6 +48,12 @@ abstract class LightClassGenerationSupport {
|
||||
|
||||
abstract fun createUltraLightClass(element: KtClassOrObject): KtUltraLightClass?
|
||||
|
||||
abstract fun createUltraLightClassForFacade(
|
||||
facadeClassFqName: FqName,
|
||||
searchScope: GlobalSearchScope,
|
||||
facadeFile: KtFile
|
||||
): KtUltraLightClassForFacade?
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun getInstance(project: Project): LightClassGenerationSupport {
|
||||
|
||||
+43
-32
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.asJava.classes
|
||||
import com.intellij.openapi.components.ServiceManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.Comparing
|
||||
import com.intellij.openapi.util.registry.Registry
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.impl.light.LightEmptyImplementsList
|
||||
import com.intellij.psi.impl.light.LightModifierList
|
||||
@@ -29,6 +30,7 @@ import com.intellij.psi.util.CachedValuesManager
|
||||
import com.intellij.psi.util.PsiModificationTracker
|
||||
import com.intellij.util.containers.SLRUCache
|
||||
import org.jetbrains.annotations.NonNls
|
||||
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
|
||||
import org.jetbrains.kotlin.asJava.builder.LightClassDataHolder
|
||||
import org.jetbrains.kotlin.asJava.builder.LightClassDataProviderForFileFacade
|
||||
import org.jetbrains.kotlin.asJava.elements.FakeFileForLightClass
|
||||
@@ -45,12 +47,13 @@ import org.jetbrains.kotlin.psi.KtStringTemplateExpression
|
||||
import org.jetbrains.kotlin.psi.psiUtil.siblings
|
||||
import javax.swing.Icon
|
||||
|
||||
class KtLightClassForFacade private constructor(
|
||||
manager: PsiManager,
|
||||
private val facadeClassFqName: FqName,
|
||||
private val lightClassDataCache: CachedValue<LightClassDataHolder.ForFacade>,
|
||||
files: Collection<KtFile>
|
||||
open class KtLightClassForFacade protected constructor(
|
||||
manager: PsiManager,
|
||||
protected val facadeClassFqName: FqName,
|
||||
protected open val lightClassDataCache: CachedValue<LightClassDataHolder.ForFacade>,
|
||||
files: Collection<KtFile>
|
||||
) : KtLazyLightClass(manager) {
|
||||
|
||||
private data class StubCacheKey(val fqName: FqName, val searchScope: GlobalSearchScope)
|
||||
|
||||
class FacadeStubCache(private val project: Project) {
|
||||
@@ -58,17 +61,18 @@ class KtLightClassForFacade private constructor(
|
||||
val cache = object : SLRUCache<StubCacheKey, CachedValue<LightClassDataHolder.ForFacade>>(20, 30) {
|
||||
override fun createValue(key: StubCacheKey): CachedValue<LightClassDataHolder.ForFacade> {
|
||||
val stubProvider = LightClassDataProviderForFileFacade.ByProjectSource(project, key.fqName, key.searchScope)
|
||||
return CachedValuesManager.getManager(project).createCachedValue<LightClassDataHolder.ForFacade>(stubProvider, /*trackValue = */false)
|
||||
return CachedValuesManager.getManager(project)
|
||||
.createCachedValue<LightClassDataHolder.ForFacade>(stubProvider, /*trackValue = */false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val cachedValue: CachedValue<FacadeCacheData> = CachedValuesManager.getManager(project).createCachedValue<FacadeCacheData>(
|
||||
{ CachedValueProvider.Result.create(FacadeCacheData(), PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT) },
|
||||
/*trackValue = */ false)
|
||||
{ CachedValueProvider.Result.create(FacadeCacheData(), PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT) }, false
|
||||
)
|
||||
|
||||
operator fun get(qualifiedName: FqName, searchScope: GlobalSearchScope): CachedValue<LightClassDataHolder.ForFacade> {
|
||||
synchronized (cachedValue) {
|
||||
synchronized(cachedValue) {
|
||||
return cachedValue.value.cache.get(StubCacheKey(qualifiedName, searchScope))
|
||||
}
|
||||
}
|
||||
@@ -83,22 +87,22 @@ class KtLightClassForFacade private constructor(
|
||||
val files: Collection<KtFile> = files.toSet() // needed for hashCode
|
||||
|
||||
private val hashCode: Int =
|
||||
computeHashCode()
|
||||
computeHashCode()
|
||||
|
||||
private val packageFqName: FqName =
|
||||
facadeClassFqName.parent()
|
||||
facadeClassFqName.parent()
|
||||
|
||||
private val modifierList: PsiModifierList =
|
||||
LightModifierList(manager, KotlinLanguage.INSTANCE, PsiModifier.PUBLIC, PsiModifier.FINAL)
|
||||
LightModifierList(manager, KotlinLanguage.INSTANCE, PsiModifier.PUBLIC, PsiModifier.FINAL)
|
||||
|
||||
private val implementsList: LightEmptyImplementsList =
|
||||
LightEmptyImplementsList(manager)
|
||||
LightEmptyImplementsList(manager)
|
||||
|
||||
private val packageClsFile = FakeFileForLightClass(
|
||||
files.first(),
|
||||
lightClass = { this },
|
||||
stub = { lightClassDataCache.value.javaFileStub },
|
||||
packageFqName = packageFqName
|
||||
files.first(),
|
||||
lightClass = { this },
|
||||
stub = { lightClassDataCache.value.javaFileStub },
|
||||
packageFqName = packageFqName
|
||||
)
|
||||
|
||||
override val kotlinOrigin: KtClassOrObject? get() = null
|
||||
@@ -171,8 +175,7 @@ class KtLightClassForFacade private constructor(
|
||||
val annotationList = file.fileAnnotationList
|
||||
if (annotationList != null) {
|
||||
annotationList.add(newFileAnnotationList.annotationEntries.first())
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
val anchor = file.firstChild.siblings().firstOrNull { it !is PsiWhiteSpace && it !is PsiComment }
|
||||
file.addBefore(newFileAnnotationList, anchor)
|
||||
}
|
||||
@@ -180,7 +183,7 @@ class KtLightClassForFacade private constructor(
|
||||
}
|
||||
|
||||
val jvmNameExpression = jvmNameEntry.valueArguments.firstOrNull()?.getArgumentExpression() as? KtStringTemplateExpression
|
||||
?: continue
|
||||
?: continue
|
||||
ElementManipulators.handleContentChange(jvmNameExpression, name)
|
||||
}
|
||||
|
||||
@@ -247,29 +250,37 @@ class KtLightClassForFacade private constructor(
|
||||
|
||||
override fun toString() = "${KtLightClassForFacade::class.java.simpleName}:$facadeClassFqName"
|
||||
|
||||
companion object Factory {
|
||||
companion object {
|
||||
fun createForFacade(
|
||||
manager: PsiManager,
|
||||
facadeClassFqName: FqName,
|
||||
searchScope: GlobalSearchScope,
|
||||
files: Collection<KtFile>
|
||||
manager: PsiManager,
|
||||
facadeClassFqName: FqName,
|
||||
searchScope: GlobalSearchScope,
|
||||
files: Collection<KtFile>
|
||||
): KtLightClassForFacade {
|
||||
assert(files.isNotEmpty()) { "No files for facade $facadeClassFqName" }
|
||||
|
||||
val ultraLightEnabled =
|
||||
!KtUltraLightSupport.forceUsingOldLightClasses && Registry.`is`("kotlin.use.ultra.light.classes", true)
|
||||
|
||||
if (ultraLightEnabled && files.count() == 1) {
|
||||
val facadeFile = files.first()
|
||||
LightClassGenerationSupport.getInstance(facadeFile.project)
|
||||
.createUltraLightClassForFacade(facadeClassFqName, searchScope, facadeFile)?.let { return it }
|
||||
}
|
||||
|
||||
val lightClassDataCache = FacadeStubCache.getInstance(manager.project).get(facadeClassFqName, searchScope)
|
||||
return KtLightClassForFacade(manager, facadeClassFqName, lightClassDataCache, files)
|
||||
}
|
||||
|
||||
fun createForSyntheticFile(
|
||||
manager: PsiManager,
|
||||
facadeClassFqName: FqName,
|
||||
file: KtFile
|
||||
manager: PsiManager,
|
||||
facadeClassFqName: FqName,
|
||||
file: KtFile
|
||||
): KtLightClassForFacade {
|
||||
// TODO: refactor, using cached value doesn't make sense for this case
|
||||
val cachedValue = CachedValuesManager.getManager(manager.project).
|
||||
createCachedValue<LightClassDataHolder.ForFacade>(
|
||||
LightClassDataProviderForFileFacade.ByFile(manager.project, facadeClassFqName, file), /*trackValue = */false
|
||||
)
|
||||
val cachedValue = CachedValuesManager.getManager(manager.project).createCachedValue<LightClassDataHolder.ForFacade>(
|
||||
LightClassDataProviderForFileFacade.ByFile(manager.project, facadeClassFqName, file), /*trackValue = */false
|
||||
)
|
||||
return KtLightClassForFacade(manager, facadeClassFqName, cachedValue, listOf(file))
|
||||
}
|
||||
}
|
||||
|
||||
+4
-1
@@ -339,7 +339,10 @@ abstract class KtLightClassForSourceDeclaration(
|
||||
fun create(classOrObject: KtClassOrObject): KtLightClassForSourceDeclaration? =
|
||||
CachedValuesManager.getCachedValue(classOrObject) {
|
||||
CachedValueProvider.Result
|
||||
.create(createNoCache(classOrObject, KtUltraLightClass.forceUsingOldLightClasses), OUT_OF_CODE_BLOCK_MODIFICATION_COUNT)
|
||||
.create(
|
||||
createNoCache(classOrObject, KtUltraLightSupport.forceUsingOldLightClasses),
|
||||
OUT_OF_CODE_BLOCK_MODIFICATION_COUNT
|
||||
)
|
||||
}
|
||||
|
||||
fun createNoCache(classOrObject: KtClassOrObject, forceUsingOldLightClasses: Boolean): KtLightClassForSourceDeclaration? {
|
||||
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* 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.PsiClass
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiManager
|
||||
import com.intellij.psi.util.CachedValue
|
||||
import org.jetbrains.kotlin.asJava.builder.LightClassDataHolder
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightField
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||
import org.jetbrains.kotlin.psi.KtProperty
|
||||
|
||||
class KtUltraLightClassForFacade(
|
||||
manager: PsiManager,
|
||||
facadeClassFqName: FqName,
|
||||
lightClassDataCache: CachedValue<LightClassDataHolder.ForFacade>,
|
||||
private val file: KtFile,
|
||||
private val support: KtUltraLightSupport
|
||||
) : KtLightClassForFacade(manager, facadeClassFqName, lightClassDataCache, listOf(file)) {
|
||||
|
||||
private val methodsBuilder by lazyPub { UltraLightMembersCreator(this, false, true, support) }
|
||||
|
||||
private inline fun <T> forTooComplex(getter: () -> T): T {
|
||||
check(tooComplex) {
|
||||
"Cls delegate shouldn't be loaded for not too complex ultra-light classes! Qualified name: $qualifiedName"
|
||||
}
|
||||
return getter()
|
||||
}
|
||||
|
||||
override val lightClassDataCache: CachedValue<LightClassDataHolder.ForFacade>
|
||||
get() = forTooComplex { super.lightClassDataCache }
|
||||
|
||||
override val clsDelegate: PsiClass
|
||||
get() = forTooComplex { super.clsDelegate }
|
||||
|
||||
private val tooComplex: Boolean by lazyPub { file.declarations.any { support.isTooComplexForUltraLightGeneration(it) } }
|
||||
|
||||
private val ownMethodsForNotTooComplex: List<KtLightMethod> by lazyPub {
|
||||
|
||||
val result = arrayListOf<KtLightMethod>()
|
||||
|
||||
for (declaration in file.declarations.filterNot { it.isHiddenByDeprecation(support) }) {
|
||||
if (declaration.hasModifier(KtTokens.PRIVATE_KEYWORD)) continue
|
||||
when (declaration) {
|
||||
is KtNamedFunction -> result.addAll(methodsBuilder.createMethods(declaration, true))
|
||||
is KtProperty -> result.addAll(methodsBuilder.propertyAccessors(declaration, declaration.isVar, true, false))
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
private val ownFieldsForNotTooComplex: List<KtLightField> by lazyPub {
|
||||
hashSetOf<String>().run {
|
||||
file.declarations.filterIsInstance<KtProperty>().mapNotNull {
|
||||
methodsBuilder.createPropertyField(it, this, forceStatic = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getOwnFields() = if (!tooComplex) ownFieldsForNotTooComplex else super.getOwnFields()
|
||||
|
||||
override fun getOwnMethods() = if (!tooComplex) ownMethodsForNotTooComplex else super.getOwnMethods()
|
||||
|
||||
override fun hashCode(): Int = file.hashCode()
|
||||
|
||||
override fun toString(): String = "UltraLight class for file facade"
|
||||
|
||||
override fun equals(other: Any?): Boolean = this === other
|
||||
|
||||
override fun copy(): KtLightClassForFacade = KtUltraLightClassForFacade(manager, facadeClassFqName, lightClassDataCache, file, support)
|
||||
|
||||
override fun setName(name: String): PsiElement? = this
|
||||
}
|
||||
+18
-372
@@ -10,10 +10,6 @@ import com.intellij.psi.*
|
||||
import com.intellij.psi.impl.PsiClassImplUtil
|
||||
import com.intellij.psi.impl.PsiSuperMethodImplUtil
|
||||
import com.intellij.psi.impl.light.LightMethodBuilder
|
||||
import com.intellij.psi.impl.light.LightModifierList
|
||||
import com.intellij.psi.impl.light.LightParameterListBuilder
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
|
||||
import org.jetbrains.kotlin.asJava.builder.LightClassData
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightField
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
|
||||
@@ -22,40 +18,29 @@ import org.jetbrains.kotlin.backend.common.DataClassMethodGenerator
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.codegen.JvmCodegenUtil
|
||||
import org.jetbrains.kotlin.codegen.kotlinType
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotated
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
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.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DelegationResolver
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
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.isPublishedApi
|
||||
import org.jetbrains.kotlin.resolve.inline.isInlineOnly
|
||||
import org.jetbrains.kotlin.resolve.jvm.annotations.JVM_OVERLOADS_FQ_NAME
|
||||
import org.jetbrains.kotlin.resolve.jvm.annotations.JVM_SYNTHETIC_ANNOTATION_FQ_NAME
|
||||
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.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny
|
||||
|
||||
open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val support: KtUltraLightSupport) :
|
||||
KtLightClassImpl(classOrObject) {
|
||||
companion object {
|
||||
|
||||
// This property may be removed once IntelliJ versions earlier than 2018.3 become unsupported
|
||||
// And usages of that property may be replaced with relevant registry key
|
||||
@Volatile
|
||||
@get:TestOnly
|
||||
var forceUsingOldLightClasses = false
|
||||
private val methodsBuilder by lazyPub {
|
||||
UltraLightMembersCreator(this, isNamedObject(), classOrObject.hasModifier(SEALED_KEYWORD), support)
|
||||
}
|
||||
|
||||
private val tooComplex: Boolean by lazyPub { support.isTooComplexForUltraLightGeneration(classOrObject) }
|
||||
@@ -142,26 +127,15 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor
|
||||
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()) {
|
||||
propertyField(parameter, ::generateUniqueName, forceStatic = false)?.let(result::add)
|
||||
methodsBuilder.createPropertyField(parameter, usedNames, forceStatic = false)?.let(result::add)
|
||||
}
|
||||
|
||||
this.classOrObject.companionObjects.firstOrNull()?.let { companion ->
|
||||
result.add(
|
||||
KtUltraLightField(
|
||||
companion,
|
||||
generateUniqueName(companion.name.orEmpty()),
|
||||
methodsBuilder.generateUniqueFieldName(companion.name.orEmpty(), usedNames),
|
||||
this,
|
||||
support,
|
||||
setOf(PsiModifier.STATIC, PsiModifier.FINAL, PsiModifier.PUBLIC)
|
||||
@@ -170,7 +144,7 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor
|
||||
|
||||
for (property in companion.declarations.filterIsInstance<KtProperty>()) {
|
||||
if (isInterface && !property.isConstOrJvmField()) continue
|
||||
propertyField(property, ::generateUniqueName, true)?.let(result::add)
|
||||
methodsBuilder.createPropertyField(property, usedNames, true)?.let(result::add)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,7 +156,7 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor
|
||||
// Probably, the same should work for const vals but it doesn't at the moment (see KT-28294)
|
||||
if (isCompanion && (containingClass?.isInterface == false || property.isJvmField())) continue
|
||||
|
||||
propertyField(property, ::generateUniqueName, forceStatic = this.classOrObject is KtObjectDeclaration)?.let(result::add)
|
||||
methodsBuilder.createPropertyField(property, usedNames, forceStatic = this.classOrObject is KtObjectDeclaration)?.let(result::add)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,56 +189,6 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor
|
||||
|
||||
private fun isNamedObject() = classOrObject is KtObjectDeclaration && !classOrObject.isCompanion()
|
||||
|
||||
private fun propertyField(
|
||||
// KtProperty | KtParameter
|
||||
variable: KtCallableDeclaration,
|
||||
generateUniqueName: (String) -> String,
|
||||
forceStatic: Boolean
|
||||
): KtLightField? {
|
||||
val property = variable as? KtProperty
|
||||
if (property != null && !hasBackingField(property)) return null
|
||||
|
||||
if (variable.hasAnnotation(JVM_SYNTHETIC_ANNOTATION_FQ_NAME)) return null
|
||||
|
||||
val hasDelegate = property?.hasDelegate() == true
|
||||
val fieldName = generateUniqueName((variable.name ?: "") + (if (hasDelegate) "\$delegate" else ""))
|
||||
|
||||
val visibility = when {
|
||||
variable.hasModifier(PRIVATE_KEYWORD) -> PsiModifier.PRIVATE
|
||||
variable.hasModifier(LATEINIT_KEYWORD) || variable.isConstOrJvmField() -> {
|
||||
val declaration = property?.setter ?: variable
|
||||
simpleVisibility(declaration)
|
||||
}
|
||||
else -> PsiModifier.PRIVATE
|
||||
}
|
||||
val modifiers = hashSetOf(visibility)
|
||||
|
||||
val isMutable = when (variable) {
|
||||
is KtProperty -> variable.isVar
|
||||
is KtParameter -> variable.isMutable
|
||||
else -> error("Unexpected type of variable: ${variable::class.java}")
|
||||
}
|
||||
|
||||
if (!isMutable || variable.hasModifier(CONST_KEYWORD) || hasDelegate) {
|
||||
modifiers.add(PsiModifier.FINAL)
|
||||
}
|
||||
|
||||
if (forceStatic || isNamedObject() && isJvmStatic(variable)) {
|
||||
modifiers.add(PsiModifier.STATIC)
|
||||
}
|
||||
|
||||
return KtUltraLightField(variable, 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() }
|
||||
@@ -273,16 +197,16 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor
|
||||
|
||||
val result = arrayListOf<KtLightMethod>()
|
||||
|
||||
for (declaration in this.classOrObject.declarations.filterNot { isHiddenByDeprecation(it) }) {
|
||||
for (declaration in this.classOrObject.declarations.filterNot { it.isHiddenByDeprecation(support) }) {
|
||||
if (declaration.hasModifier(PRIVATE_KEYWORD) && isInterface) continue
|
||||
when (declaration) {
|
||||
is KtNamedFunction -> result.addAll(asJavaMethods(declaration, false))
|
||||
is KtProperty -> result.addAll(propertyAccessors(declaration, declaration.isVar, false))
|
||||
is KtNamedFunction -> result.addAll(methodsBuilder.createMethods(declaration, false))
|
||||
is KtProperty -> result.addAll(methodsBuilder.propertyAccessors(declaration, declaration.isVar, false,false))
|
||||
}
|
||||
}
|
||||
|
||||
for (parameter in propertyParameters()) {
|
||||
result.addAll(propertyAccessors(parameter, parameter.isMutable, false))
|
||||
result.addAll(methodsBuilder.propertyAccessors(parameter, parameter.isMutable, false,false))
|
||||
}
|
||||
|
||||
if (!isInterface) {
|
||||
@@ -292,8 +216,8 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor
|
||||
this.classOrObject.companionObjects.firstOrNull()?.let { companion ->
|
||||
for (declaration in companion.declarations.filterNot { isHiddenByDeprecation(it) }) {
|
||||
when (declaration) {
|
||||
is KtNamedFunction -> if (isJvmStatic(declaration)) result.addAll(asJavaMethods(declaration, true))
|
||||
is KtProperty -> result.addAll(propertyAccessors(declaration, declaration.isVar, true))
|
||||
is KtNamedFunction -> if (isJvmStatic(declaration)) result.addAll(methodsBuilder.createMethods(declaration, true))
|
||||
is KtProperty -> result.addAll(methodsBuilder.propertyAccessors(declaration, declaration.isVar, false,true))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -374,11 +298,11 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor
|
||||
result.add(defaultConstructor())
|
||||
}
|
||||
for (constructor in constructors.filterNot { isHiddenByDeprecation(it) }) {
|
||||
result.addAll(asJavaMethods(constructor, false, forcePrivate = isEnum))
|
||||
result.addAll(methodsBuilder.createMethods(constructor, false, forcePrivate = isEnum))
|
||||
}
|
||||
val primary = classOrObject.primaryConstructor
|
||||
if (primary != null && shouldGenerateNoArgOverload(primary)) {
|
||||
result.add(noArgConstructor(simpleVisibility(primary), primary))
|
||||
result.add(noArgConstructor(primary.simpleVisibility(), primary))
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -403,12 +327,6 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor
|
||||
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 =
|
||||
KtUltraLightMethodForSourceDeclaration(
|
||||
LightMethodBuilder(manager, language, name.orEmpty()).setConstructor(true).addModifier(visibility),
|
||||
@@ -426,285 +344,13 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor
|
||||
|
||||
override fun getOwnMethods(): List<KtLightMethod> = if (tooComplex) super.getOwnMethods() else _ownMethods
|
||||
|
||||
private fun asJavaMethods(
|
||||
ktFunction: KtFunction,
|
||||
forceStatic: Boolean,
|
||||
forcePrivate: Boolean = false
|
||||
): Collection<KtLightMethod> {
|
||||
if (ktFunction.hasAnnotation(JVM_SYNTHETIC_ANNOTATION_FQ_NAME) || ktFunction.hasReifiedParameters()) return emptyList()
|
||||
|
||||
val basicMethod = asJavaMethod(ktFunction, forceStatic, forcePrivate)
|
||||
|
||||
val result = mutableListOf(basicMethod)
|
||||
|
||||
if (ktFunction.hasAnnotation(JVM_OVERLOADS_FQ_NAME)) {
|
||||
val numberOfDefaultParameters = ktFunction.valueParameters.count(KtParameter::hasDefaultValue)
|
||||
for (numberOfDefaultParametersToAdd in numberOfDefaultParameters - 1 downTo 0) {
|
||||
result.add(
|
||||
asJavaMethod(
|
||||
ktFunction,
|
||||
forceStatic,
|
||||
forcePrivate,
|
||||
numberOfDefaultParametersToAdd = numberOfDefaultParametersToAdd
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private fun asJavaMethod(
|
||||
ktFunction: KtFunction,
|
||||
forceStatic: Boolean,
|
||||
forcePrivate: Boolean,
|
||||
numberOfDefaultParametersToAdd: Int = -1
|
||||
): KtLightMethod {
|
||||
val isConstructor = ktFunction is KtConstructor<*>
|
||||
val name =
|
||||
if (isConstructor)
|
||||
this.name
|
||||
else computeMethodName(ktFunction, ktFunction.name ?: SpecialNames.NO_NAME_PROVIDED.asString(), MethodType.REGULAR)
|
||||
|
||||
val method = lightMethod(name.orEmpty(), ktFunction, forceStatic, forcePrivate)
|
||||
val wrapper = KtUltraLightMethodForSourceDeclaration(method, ktFunction, support, this)
|
||||
addReceiverParameter(ktFunction, wrapper)
|
||||
|
||||
|
||||
var remainingNumberOfDefaultParametersToAdd =
|
||||
if (numberOfDefaultParametersToAdd >= 0)
|
||||
numberOfDefaultParametersToAdd
|
||||
else
|
||||
// Just to avoid computing the actual number of default parameters, we use an upper bound
|
||||
ktFunction.valueParameters.size
|
||||
|
||||
for (parameter in ktFunction.valueParameters) {
|
||||
if (parameter.hasDefaultValue()) {
|
||||
if (remainingNumberOfDefaultParametersToAdd == 0) continue
|
||||
remainingNumberOfDefaultParametersToAdd--
|
||||
}
|
||||
|
||||
method.addParameter(KtUltraLightParameterForSource(parameter.name.orEmpty(), parameter, support, wrapper, ktFunction))
|
||||
}
|
||||
val returnType: PsiType? by lazyPub {
|
||||
if (isConstructor) null
|
||||
else methodReturnType(ktFunction, wrapper)
|
||||
}
|
||||
method.setMethodReturnType { returnType }
|
||||
return wrapper
|
||||
}
|
||||
|
||||
private fun addReceiverParameter(callable: KtCallableDeclaration, method: KtUltraLightMethod) {
|
||||
if (callable.receiverTypeReference == null) return
|
||||
method.delegate.addParameter(KtUltraLightReceiverParameter(callable, support, method))
|
||||
}
|
||||
|
||||
private fun methodReturnType(ktDeclaration: KtDeclaration, wrapper: KtUltraLightMethod): PsiType {
|
||||
val desc =
|
||||
ktDeclaration.resolve()?.getterIfProperty() as? FunctionDescriptor
|
||||
?: return PsiType.NULL
|
||||
|
||||
return support.mapType(wrapper) { typeMapper, signatureWriter ->
|
||||
typeMapper.mapReturnType(desc, signatureWriter)
|
||||
}
|
||||
}
|
||||
|
||||
private fun DeclarationDescriptor.getterIfProperty() =
|
||||
if (this@getterIfProperty is PropertyDescriptor) this@getterIfProperty.getter else this@getterIfProperty
|
||||
|
||||
private fun lightMethod(
|
||||
name: String,
|
||||
declaration: KtDeclaration,
|
||||
forceStatic: Boolean,
|
||||
forcePrivate: Boolean = false
|
||||
): 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 (forcePrivate || 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) || isJvmStatic(declaration))
|
||||
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) ||
|
||||
isInlineOnly()
|
||||
|
||||
private fun KtDeclaration.isInlineOnly(): Boolean {
|
||||
if (this !is KtCallableDeclaration || !hasModifier(INLINE_KEYWORD)) return false
|
||||
if (annotationEntries.isEmpty()) return false
|
||||
|
||||
val descriptor = resolve() as? CallableMemberDescriptor ?: return false
|
||||
|
||||
return descriptor.isInlineOnly()
|
||||
}
|
||||
}
|
||||
).setConstructor(declaration is KtConstructor<*>)
|
||||
}
|
||||
|
||||
private enum class MethodType {
|
||||
REGULAR,
|
||||
GETTER,
|
||||
SETTER
|
||||
}
|
||||
|
||||
private fun computeMethodName(declaration: KtDeclaration, name: String, type: MethodType): String {
|
||||
|
||||
fun tryCompute(declaration: KtDeclaration, type: MethodType): String? {
|
||||
|
||||
if (!declaration.hasAnnotation(DescriptorUtils.JVM_NAME)) return null
|
||||
|
||||
val annotated = (declaration.resolve() as? Annotated) ?: return null
|
||||
|
||||
val resultName = DescriptorUtils.getJvmName(annotated)
|
||||
if (resultName !== null || type == MethodType.REGULAR) return resultName
|
||||
|
||||
val propertyAnnotated = when (type) {
|
||||
MethodType.GETTER -> (annotated as? PropertyDescriptor)?.getter
|
||||
MethodType.SETTER -> (annotated as? PropertyDescriptor)?.setter
|
||||
else -> throw NotImplementedError()
|
||||
}
|
||||
|
||||
return propertyAnnotated?.let(DescriptorUtils::getJvmName)
|
||||
}
|
||||
|
||||
val computedName = tryCompute(declaration, type)
|
||||
if (computedName !== null) return computedName
|
||||
|
||||
if (isInternalNonPublishedApi(declaration)) return KotlinTypeMapper.InternalNameMapper.mangleInternalName(name, support.moduleName)
|
||||
return name
|
||||
}
|
||||
|
||||
private tailrec fun isInternalNonPublishedApi(declaration: KtDeclaration): Boolean {
|
||||
if (declaration.hasModifier(PRIVATE_KEYWORD) ||
|
||||
declaration.hasModifier(PROTECTED_KEYWORD) ||
|
||||
declaration.hasModifier(PUBLIC_KEYWORD)
|
||||
) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (isInternal(declaration) && declaration.resolve()?.isPublishedApi() != true) return true
|
||||
|
||||
val containingProperty = (declaration as? KtPropertyAccessor)?.property ?: return false
|
||||
return isInternalNonPublishedApi(containingProperty)
|
||||
}
|
||||
|
||||
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: KtCallableDeclaration,
|
||||
mutable: Boolean,
|
||||
onlyJvmStatic: Boolean
|
||||
): List<KtLightMethod> {
|
||||
|
||||
val propertyName = declaration.name ?: return emptyList()
|
||||
if (declaration.isConstOrJvmField() || declaration.hasReifiedParameters()) 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 || accessor?.hasAnnotation(JVM_SYNTHETIC_ANNOTATION_FQ_NAME) == true) {
|
||||
return false
|
||||
}
|
||||
if (!isPrivate || accessor?.hasBody() == true) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
val result = arrayListOf<KtLightMethod>()
|
||||
|
||||
if (needsAccessor(ktGetter)) {
|
||||
val getterName = computeMethodName(ktGetter ?: declaration, JvmAbi.getterName(propertyName), MethodType.GETTER)
|
||||
val getterPrototype = lightMethod(getterName, ktGetter ?: declaration, onlyJvmStatic)
|
||||
val getterWrapper = KtUltraLightMethodForSourceDeclaration(getterPrototype, declaration, support, this)
|
||||
val getterType: PsiType by lazyPub { methodReturnType(declaration, getterWrapper) }
|
||||
getterPrototype.setMethodReturnType { getterType }
|
||||
addReceiverParameter(declaration, getterWrapper)
|
||||
result.add(getterWrapper)
|
||||
}
|
||||
|
||||
if (mutable && needsAccessor(ktSetter)) {
|
||||
val setterName = computeMethodName(ktSetter ?: declaration, JvmAbi.setterName(propertyName), MethodType.SETTER)
|
||||
val setterPrototype = lightMethod(setterName, ktSetter ?: declaration, onlyJvmStatic)
|
||||
.setMethodReturnType(PsiType.VOID)
|
||||
val setterWrapper = KtUltraLightMethodForSourceDeclaration(setterPrototype, declaration, support, this)
|
||||
addReceiverParameter(declaration, setterWrapper)
|
||||
val setterParameter = ktSetter?.parameter
|
||||
setterPrototype.addParameter(
|
||||
if (setterParameter != null)
|
||||
KtUltraLightParameterForSource(propertyName, setterParameter, support, setterWrapper, declaration)
|
||||
else
|
||||
KtUltraLightParameterForSetterParameter(propertyName, declaration, support, setterWrapper, declaration)
|
||||
)
|
||||
result.add(setterWrapper)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun KtCallableDeclaration.isConstOrJvmField() =
|
||||
hasModifier(CONST_KEYWORD) || isJvmField()
|
||||
|
||||
private fun KtCallableDeclaration.isJvmField() = hasAnnotation(JvmAbi.JVM_FIELD_ANNOTATION_FQ_NAME)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
private fun KtCallableDeclaration.hasReifiedParameters(): Boolean =
|
||||
typeParameters.any { it.hasModifier(REIFIED_KEYWORD) }
|
||||
|
||||
override fun getInitializers(): Array<PsiClassInitializer> = emptyArray()
|
||||
|
||||
override fun getContainingClass(): PsiClass? =
|
||||
|
||||
+2
-2
@@ -11,7 +11,7 @@ import org.jetbrains.kotlin.psi.KtEnumEntry
|
||||
internal class KtUltraLightEnumEntry(
|
||||
declaration: KtEnumEntry,
|
||||
name: String,
|
||||
containingClass: KtUltraLightClass,
|
||||
containingClass: KtLightClass,
|
||||
support: KtUltraLightSupport,
|
||||
modifiers: Set<String>
|
||||
) : KtUltraLightField(declaration, name, containingClass, support, modifiers), PsiEnumConstant {
|
||||
@@ -19,7 +19,7 @@ internal class KtUltraLightEnumEntry(
|
||||
private val enumEntry get() = declaration as KtEnumEntry
|
||||
|
||||
private val _initializingClass by lazyPub {
|
||||
enumEntry.body?.let { KtUltraLightClassForEnumEntry(enumEntry, containingClass.support, this) }
|
||||
enumEntry.body?.let { KtUltraLightClassForEnumEntry(enumEntry, support, this) }
|
||||
}
|
||||
|
||||
override fun getInitializingClass(): PsiEnumConstantInitializer? = _initializingClass
|
||||
|
||||
@@ -31,7 +31,7 @@ import org.jetbrains.kotlin.types.KotlinType
|
||||
internal open class KtUltraLightField(
|
||||
protected val declaration: KtNamedDeclaration,
|
||||
name: String,
|
||||
private val containingClass: KtUltraLightClass,
|
||||
private val containingClass: KtLightClass,
|
||||
private val support: KtUltraLightSupport,
|
||||
modifiers: Set<String>
|
||||
) : LightFieldBuilder(name, PsiType.NULL, declaration), KtLightField,
|
||||
@@ -75,7 +75,7 @@ internal open class KtUltraLightField(
|
||||
declaration is KtObjectDeclaration ->
|
||||
(declaration.resolve() as? ClassDescriptor)?.defaultType
|
||||
declaration is KtEnumEntry -> {
|
||||
(containingClass.kotlinOrigin.resolve() as? ClassDescriptor)?.defaultType
|
||||
(containingClass.kotlinOrigin?.resolve() as? ClassDescriptor)?.defaultType
|
||||
}
|
||||
else -> {
|
||||
declaration.getKotlinType()
|
||||
|
||||
+384
@@ -0,0 +1,384 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* 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.PsiModifier
|
||||
import com.intellij.psi.PsiType
|
||||
import com.intellij.psi.impl.light.LightMethodBuilder
|
||||
import com.intellij.psi.impl.light.LightModifierList
|
||||
import com.intellij.psi.impl.light.LightParameterListBuilder
|
||||
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightField
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotated
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.lexer.KtTokens.REIFIED_KEYWORD
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.SpecialNames
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isPublishedApi
|
||||
import org.jetbrains.kotlin.resolve.inline.isInlineOnly
|
||||
import org.jetbrains.kotlin.resolve.jvm.annotations.JVM_OVERLOADS_FQ_NAME
|
||||
import org.jetbrains.kotlin.resolve.jvm.annotations.JVM_SYNTHETIC_ANNOTATION_FQ_NAME
|
||||
import org.jetbrains.kotlin.resolve.jvm.annotations.STRICTFP_ANNOTATION_FQ_NAME
|
||||
import org.jetbrains.kotlin.resolve.jvm.annotations.SYNCHRONIZED_ANNOTATION_FQ_NAME
|
||||
|
||||
internal class UltraLightMembersCreator(
|
||||
private val containingClass: KtLightClass,
|
||||
private val containingClassIsNamedObject: Boolean,
|
||||
private val containingClassIsSealed: Boolean,
|
||||
private val support: KtUltraLightSupport
|
||||
) {
|
||||
|
||||
fun generateUniqueFieldName(base: String, usedNames: HashSet<String>): String {
|
||||
if (usedNames.add(base)) return base
|
||||
var i = 1
|
||||
while (true) {
|
||||
val suggestion = "$base$$i"
|
||||
if (usedNames.add(suggestion)) return suggestion
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
fun createPropertyField(
|
||||
// KtProperty | KtParameter
|
||||
variable: KtCallableDeclaration,
|
||||
usedPropertyNames: HashSet<String>,
|
||||
forceStatic: Boolean
|
||||
): KtLightField? {
|
||||
val property = variable as? KtProperty
|
||||
if (property != null && !hasBackingField(property)) return null
|
||||
|
||||
if (variable.hasAnnotation(JVM_SYNTHETIC_ANNOTATION_FQ_NAME)) return null
|
||||
|
||||
val hasDelegate = property?.hasDelegate() == true
|
||||
val fieldName = generateUniqueFieldName((variable.name ?: "") + (if (hasDelegate) "\$delegate" else ""), usedPropertyNames)
|
||||
|
||||
val visibility = when {
|
||||
variable.hasModifier(KtTokens.PRIVATE_KEYWORD) -> PsiModifier.PRIVATE
|
||||
variable.hasModifier(KtTokens.LATEINIT_KEYWORD) || variable.isConstOrJvmField() -> {
|
||||
val declaration = property?.setter ?: variable
|
||||
declaration.simpleVisibility()
|
||||
}
|
||||
else -> PsiModifier.PRIVATE
|
||||
}
|
||||
val modifiers = hashSetOf(visibility)
|
||||
|
||||
val isMutable = when (variable) {
|
||||
is KtProperty -> variable.isVar
|
||||
is KtParameter -> variable.isMutable
|
||||
else -> error("Unexpected type of variable: ${variable::class.java}")
|
||||
}
|
||||
|
||||
if (!isMutable || variable.hasModifier(KtTokens.CONST_KEYWORD) || hasDelegate) {
|
||||
modifiers.add(PsiModifier.FINAL)
|
||||
}
|
||||
|
||||
if (forceStatic || containingClassIsNamedObject && variable.isJvmStatic(support)) {
|
||||
modifiers.add(PsiModifier.STATIC)
|
||||
}
|
||||
|
||||
return KtUltraLightField(variable, fieldName, containingClass, support, modifiers)
|
||||
}
|
||||
|
||||
private fun hasBackingField(property: KtProperty): Boolean {
|
||||
if (property.hasModifier(KtTokens.ABSTRACT_KEYWORD)) return false
|
||||
if (property.hasModifier(KtTokens.LATEINIT_KEYWORD) || property.accessors.isEmpty()) return true
|
||||
|
||||
val context = LightClassGenerationSupport.getInstance(containingClass.project).analyze(property)
|
||||
val descriptor = context.get(BindingContext.DECLARATION_TO_DESCRIPTOR, property)
|
||||
return descriptor is PropertyDescriptor && context[BindingContext.BACKING_FIELD_REQUIRED, descriptor] == true
|
||||
}
|
||||
|
||||
fun createMethods(
|
||||
ktFunction: KtFunction,
|
||||
forceStatic: Boolean,
|
||||
forcePrivate: Boolean = false
|
||||
): Collection<KtLightMethod> {
|
||||
|
||||
if (ktFunction.hasAnnotation(JVM_SYNTHETIC_ANNOTATION_FQ_NAME) || ktFunction.hasReifiedParameters()) return emptyList()
|
||||
|
||||
val basicMethod = asJavaMethod(ktFunction, forceStatic, forcePrivate)
|
||||
|
||||
val result = mutableListOf(basicMethod)
|
||||
|
||||
if (ktFunction.hasAnnotation(JVM_OVERLOADS_FQ_NAME)) {
|
||||
val numberOfDefaultParameters = ktFunction.valueParameters.count(KtParameter::hasDefaultValue)
|
||||
for (numberOfDefaultParametersToAdd in numberOfDefaultParameters - 1 downTo 0) {
|
||||
result.add(
|
||||
asJavaMethod(
|
||||
ktFunction,
|
||||
forceStatic,
|
||||
forcePrivate,
|
||||
numberOfDefaultParametersToAdd = numberOfDefaultParametersToAdd
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private fun asJavaMethod(
|
||||
ktFunction: KtFunction,
|
||||
forceStatic: Boolean,
|
||||
forcePrivate: Boolean,
|
||||
numberOfDefaultParametersToAdd: Int = -1
|
||||
): KtLightMethod {
|
||||
val isConstructor = ktFunction is KtConstructor<*>
|
||||
val name =
|
||||
if (isConstructor)
|
||||
containingClass.name
|
||||
else computeMethodName(ktFunction, ktFunction.name ?: SpecialNames.NO_NAME_PROVIDED.asString(), MethodType.REGULAR)
|
||||
|
||||
val method = lightMethod(name.orEmpty(), ktFunction, forceStatic, forcePrivate)
|
||||
val wrapper = KtUltraLightMethodForSourceDeclaration(method, ktFunction, support, containingClass)
|
||||
addReceiverParameter(ktFunction, wrapper)
|
||||
|
||||
|
||||
var remainingNumberOfDefaultParametersToAdd =
|
||||
if (numberOfDefaultParametersToAdd >= 0)
|
||||
numberOfDefaultParametersToAdd
|
||||
else
|
||||
// Just to avoid computing the actual number of default parameters, we use an upper bound
|
||||
ktFunction.valueParameters.size
|
||||
|
||||
for (parameter in ktFunction.valueParameters) {
|
||||
if (parameter.hasDefaultValue()) {
|
||||
if (remainingNumberOfDefaultParametersToAdd == 0) continue
|
||||
remainingNumberOfDefaultParametersToAdd--
|
||||
}
|
||||
|
||||
method.addParameter(KtUltraLightParameterForSource(parameter.name.orEmpty(), parameter, support, wrapper, ktFunction))
|
||||
}
|
||||
val returnType: PsiType? by lazyPub {
|
||||
if (isConstructor) null
|
||||
else methodReturnType(ktFunction, wrapper)
|
||||
}
|
||||
method.setMethodReturnType { returnType }
|
||||
return wrapper
|
||||
}
|
||||
|
||||
private fun addReceiverParameter(callable: KtCallableDeclaration, method: KtUltraLightMethod) {
|
||||
if (callable.receiverTypeReference == null) return
|
||||
method.delegate.addParameter(KtUltraLightReceiverParameter(callable, support, method))
|
||||
}
|
||||
|
||||
private fun methodReturnType(ktDeclaration: KtDeclaration, wrapper: KtUltraLightMethod): PsiType {
|
||||
val desc =
|
||||
ktDeclaration.resolve()?.getterIfProperty() as? FunctionDescriptor
|
||||
?: return PsiType.NULL
|
||||
|
||||
return support.mapType(wrapper) { typeMapper, signatureWriter ->
|
||||
typeMapper.mapReturnType(desc, signatureWriter)
|
||||
}
|
||||
}
|
||||
|
||||
private fun DeclarationDescriptor.getterIfProperty() =
|
||||
if (this@getterIfProperty is PropertyDescriptor) this@getterIfProperty.getter else this@getterIfProperty
|
||||
|
||||
private fun lightMethod(
|
||||
name: String,
|
||||
declaration: KtDeclaration,
|
||||
forceStatic: Boolean,
|
||||
forcePrivate: Boolean = false
|
||||
): LightMethodBuilder {
|
||||
val accessedProperty = if (declaration is KtPropertyAccessor) declaration.property else null
|
||||
val outer = accessedProperty ?: declaration
|
||||
|
||||
val manager = declaration.manager
|
||||
val language = declaration.language
|
||||
|
||||
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 (forcePrivate || declaration.isPrivate() || accessedProperty?.isPrivate() == true) {
|
||||
return name == PsiModifier.PRIVATE
|
||||
}
|
||||
if (declaration.hasModifier(KtTokens.PROTECTED_KEYWORD) || accessedProperty?.hasModifier(KtTokens.PROTECTED_KEYWORD) == true) {
|
||||
return name == PsiModifier.PROTECTED
|
||||
}
|
||||
|
||||
if (outer.hasModifier(KtTokens.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 -> !containingClass.isInterface && outer !is KtConstructor<*> && isFinal(outer)
|
||||
PsiModifier.ABSTRACT -> containingClass.isInterface || outer.hasModifier(KtTokens.ABSTRACT_KEYWORD)
|
||||
PsiModifier.STATIC -> forceStatic || containingClassIsNamedObject && (outer.isJvmStatic(support) || declaration.isJvmStatic(support))
|
||||
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(KtTokens.PRIVATE_KEYWORD) ||
|
||||
this is KtConstructor<*> && containingClassIsSealed || isInlineOnly()
|
||||
|
||||
private fun KtDeclaration.isInlineOnly(): Boolean {
|
||||
if (this !is KtCallableDeclaration || !hasModifier(KtTokens.INLINE_KEYWORD)) return false
|
||||
if (annotationEntries.isEmpty()) return false
|
||||
|
||||
val descriptor = resolve() as? CallableMemberDescriptor ?: return false
|
||||
|
||||
return descriptor.isInlineOnly()
|
||||
}
|
||||
}
|
||||
).setConstructor(declaration is KtConstructor<*>)
|
||||
}
|
||||
|
||||
private enum class MethodType {
|
||||
REGULAR,
|
||||
GETTER,
|
||||
SETTER
|
||||
}
|
||||
|
||||
private fun computeMethodName(declaration: KtDeclaration, name: String, type: MethodType): String {
|
||||
|
||||
fun tryCompute(declaration: KtDeclaration, type: MethodType): String? {
|
||||
|
||||
if (!declaration.hasAnnotation(DescriptorUtils.JVM_NAME)) return null
|
||||
|
||||
val annotated = (declaration.resolve() as? Annotated) ?: return null
|
||||
|
||||
val resultName = DescriptorUtils.getJvmName(annotated)
|
||||
if (resultName !== null || type == MethodType.REGULAR) return resultName
|
||||
|
||||
val propertyAnnotated = when (type) {
|
||||
MethodType.GETTER -> (annotated as? PropertyDescriptor)?.getter
|
||||
MethodType.SETTER -> (annotated as? PropertyDescriptor)?.setter
|
||||
else -> throw NotImplementedError()
|
||||
}
|
||||
|
||||
return propertyAnnotated?.let(DescriptorUtils::getJvmName)
|
||||
}
|
||||
|
||||
val computedName = tryCompute(declaration, type)
|
||||
if (computedName !== null) return computedName
|
||||
|
||||
if (isInternalNonPublishedApi(declaration)) return KotlinTypeMapper.InternalNameMapper.mangleInternalName(name, support.moduleName)
|
||||
return name
|
||||
}
|
||||
|
||||
private tailrec fun isInternalNonPublishedApi(declaration: KtDeclaration): Boolean {
|
||||
if (declaration.hasModifier(KtTokens.PRIVATE_KEYWORD) ||
|
||||
declaration.hasModifier(KtTokens.PROTECTED_KEYWORD) ||
|
||||
declaration.hasModifier(KtTokens.PUBLIC_KEYWORD)
|
||||
) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (isInternal(declaration) && declaration.resolve()?.isPublishedApi() != true) return true
|
||||
|
||||
val containingProperty = (declaration as? KtPropertyAccessor)?.property ?: return false
|
||||
return isInternalNonPublishedApi(containingProperty)
|
||||
}
|
||||
|
||||
private fun KtAnnotated.hasAnnotation(name: FqName) = support.findAnnotation(this, name) != null
|
||||
|
||||
private fun isInternal(f: KtDeclaration): Boolean {
|
||||
if (f.hasModifier(KtTokens.OVERRIDE_KEYWORD)) {
|
||||
val desc = f.resolve()
|
||||
return desc is CallableDescriptor &&
|
||||
desc.visibility.effectiveVisibility(desc, false) == EffectiveVisibility.Internal
|
||||
}
|
||||
return f.hasModifier(KtTokens.INTERNAL_KEYWORD)
|
||||
}
|
||||
|
||||
fun propertyAccessors(
|
||||
declaration: KtCallableDeclaration,
|
||||
mutable: Boolean,
|
||||
forceStatic: Boolean,
|
||||
onlyJvmStatic: Boolean
|
||||
): List<KtLightMethod> {
|
||||
|
||||
val propertyName = declaration.name ?: return emptyList()
|
||||
if (declaration.isConstOrJvmField() || declaration.hasReifiedParameters()) return emptyList()
|
||||
|
||||
val ktGetter = (declaration as? KtProperty)?.getter
|
||||
val ktSetter = (declaration as? KtProperty)?.setter
|
||||
|
||||
val isPrivate = !forceStatic && declaration.hasModifier(KtTokens.PRIVATE_KEYWORD)
|
||||
if (isPrivate && declaration !is KtProperty) return emptyList()
|
||||
|
||||
fun needsAccessor(accessor: KtPropertyAccessor?): Boolean {
|
||||
if (!onlyJvmStatic || declaration.isJvmStatic(support) || accessor != null && accessor.isJvmStatic(support)) {
|
||||
if (declaration is KtProperty && declaration.hasDelegate()) {
|
||||
return true
|
||||
}
|
||||
if (accessor?.hasModifier(KtTokens.PRIVATE_KEYWORD) == true || accessor?.hasAnnotation(JVM_SYNTHETIC_ANNOTATION_FQ_NAME) == true) {
|
||||
return false
|
||||
}
|
||||
if (!isPrivate || accessor?.hasBody() == true) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
val result = arrayListOf<KtLightMethod>()
|
||||
|
||||
if (needsAccessor(ktGetter)) {
|
||||
val getterName = computeMethodName(ktGetter ?: declaration, JvmAbi.getterName(propertyName), MethodType.GETTER)
|
||||
val getterPrototype = lightMethod(getterName, ktGetter ?: declaration, onlyJvmStatic || forceStatic)
|
||||
val getterWrapper = KtUltraLightMethodForSourceDeclaration(getterPrototype, declaration, support, containingClass)
|
||||
val getterType: PsiType by lazyPub { methodReturnType(declaration, getterWrapper) }
|
||||
getterPrototype.setMethodReturnType { getterType }
|
||||
addReceiverParameter(declaration, getterWrapper)
|
||||
result.add(getterWrapper)
|
||||
}
|
||||
|
||||
if (mutable && needsAccessor(ktSetter)) {
|
||||
val setterName = computeMethodName(ktSetter ?: declaration, JvmAbi.setterName(propertyName), MethodType.SETTER)
|
||||
val setterPrototype = lightMethod(setterName, ktSetter ?: declaration, onlyJvmStatic || forceStatic)
|
||||
.setMethodReturnType(PsiType.VOID)
|
||||
val setterWrapper = KtUltraLightMethodForSourceDeclaration(setterPrototype, declaration, support, containingClass)
|
||||
addReceiverParameter(declaration, setterWrapper)
|
||||
val setterParameter = ktSetter?.parameter
|
||||
setterPrototype.addParameter(
|
||||
if (setterParameter != null)
|
||||
KtUltraLightParameterForSource(propertyName, setterParameter, support, setterWrapper, declaration)
|
||||
else
|
||||
KtUltraLightParameterForSetterParameter(propertyName, declaration, support, setterWrapper, declaration)
|
||||
)
|
||||
result.add(setterWrapper)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun KtCallableDeclaration.hasReifiedParameters(): Boolean =
|
||||
typeParameters.any { it.hasModifier(REIFIED_KEYWORD) }
|
||||
|
||||
private fun KtCallableDeclaration.isConstOrJvmField() =
|
||||
hasModifier(KtTokens.CONST_KEYWORD) || isJvmField()
|
||||
|
||||
private fun KtCallableDeclaration.isJvmField() = hasAnnotation(JvmAbi.JVM_FIELD_ANNOTATION_FQ_NAME)
|
||||
|
||||
private fun isFinal(declaration: KtDeclaration): Boolean {
|
||||
if (declaration.hasModifier(KtTokens.FINAL_KEYWORD)) return true
|
||||
return declaration !is KtPropertyAccessor &&
|
||||
!declaration.hasModifier(KtTokens.OPEN_KEYWORD) &&
|
||||
!declaration.hasModifier(KtTokens.OVERRIDE_KEYWORD) &&
|
||||
!declaration.hasModifier(KtTokens.ABSTRACT_KEYWORD)
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,7 @@ internal abstract class KtUltraLightMethod(
|
||||
internal val delegate: LightMethodBuilder,
|
||||
closestDeclarationForOrigin: KtDeclaration?,
|
||||
protected val support: KtUltraLightSupport,
|
||||
containingClass: KtUltraLightClass
|
||||
containingClass: KtLightClass
|
||||
) : KtLightMethodImpl(
|
||||
{ delegate },
|
||||
closestDeclarationForOrigin?.let {
|
||||
@@ -101,7 +101,7 @@ internal class KtUltraLightMethodForSourceDeclaration(
|
||||
delegate: LightMethodBuilder,
|
||||
declaration: KtDeclaration,
|
||||
support: KtUltraLightSupport,
|
||||
containingClass: KtUltraLightClass
|
||||
containingClass: KtLightClass
|
||||
) : KtUltraLightMethod(
|
||||
delegate,
|
||||
declaration,
|
||||
|
||||
+11
-2
@@ -5,20 +5,29 @@
|
||||
|
||||
package org.jetbrains.kotlin.asJava.classes
|
||||
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtAnnotated
|
||||
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
|
||||
|
||||
interface KtUltraLightSupport {
|
||||
val moduleName: String
|
||||
fun findAnnotation(owner: KtAnnotated, fqName: FqName): Pair<KtAnnotationEntry, AnnotationDescriptor>?
|
||||
fun isTooComplexForUltraLightGeneration(element: KtClassOrObject): Boolean
|
||||
fun isTooComplexForUltraLightGeneration(element: KtDeclaration): Boolean
|
||||
val deprecationResolver: DeprecationResolver
|
||||
val typeMapper: KotlinTypeMapper
|
||||
val moduleDescriptor: ModuleDescriptor
|
||||
|
||||
companion object {
|
||||
// This property may be removed once IntelliJ versions earlier than 2018.3 become unsupported
|
||||
// And usages of that property may be replaced with relevant registry key
|
||||
@Volatile
|
||||
@get:TestOnly
|
||||
var forceUsingOldLightClasses = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,10 +24,24 @@ import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter
|
||||
import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotated
|
||||
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.resolve.DescriptorToSourceUtils
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
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.isPublishedApi
|
||||
import org.jetbrains.kotlin.resolve.inline.isInlineOnly
|
||||
import org.jetbrains.kotlin.resolve.jvm.annotations.JVM_OVERLOADS_FQ_NAME
|
||||
import org.jetbrains.kotlin.resolve.jvm.annotations.JVM_SYNTHETIC_ANNOTATION_FQ_NAME
|
||||
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.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeProjectionImpl
|
||||
import org.jetbrains.kotlin.types.replace
|
||||
@@ -286,3 +300,16 @@ private fun packMethodFlags(access: Int, isInterface: Boolean): Int {
|
||||
|
||||
return flags
|
||||
}
|
||||
|
||||
internal fun KtDeclaration.isHiddenByDeprecation(support: KtUltraLightSupport): Boolean {
|
||||
val deprecated = support.findAnnotation(this, FqName("kotlin.Deprecated"))?.second
|
||||
return (deprecated?.argumentValue("level") as? EnumValue)?.enumEntryName?.asString() == "HIDDEN"
|
||||
}
|
||||
|
||||
internal fun KtAnnotated.isJvmStatic(support: KtUltraLightSupport): Boolean = support.findAnnotation(this, JVM_STATIC_ANNOTATION_FQ_NAME) !== null
|
||||
|
||||
internal fun KtDeclaration.simpleVisibility(): String = when {
|
||||
hasModifier(KtTokens.PRIVATE_KEYWORD) -> PsiModifier.PRIVATE
|
||||
hasModifier(KtTokens.PROTECTED_KEYWORD) -> PsiModifier.PROTECTED
|
||||
else -> PsiModifier.PUBLIC
|
||||
}
|
||||
+139
-106
@@ -17,10 +17,12 @@
|
||||
package org.jetbrains.kotlin.idea.caches.resolve
|
||||
|
||||
import com.intellij.openapi.diagnostic.debug
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.module.ModuleUtilCore
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiManager
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.psi.util.CachedValueProvider
|
||||
import com.intellij.psi.util.CachedValuesManager
|
||||
@@ -60,6 +62,142 @@ import org.jetbrains.kotlin.types.KotlinType
|
||||
import java.util.concurrent.ConcurrentMap
|
||||
|
||||
class IDELightClassGenerationSupport(private val project: Project) : LightClassGenerationSupport() {
|
||||
|
||||
private inner class KtUltraLightSupportImpl(private val element: KtElement, private val module: Module) : KtUltraLightSupport {
|
||||
|
||||
fun KtDeclaration.forLogString(): String? = when (this) {
|
||||
is KtClassOrObject -> this.fqName?.asString()
|
||||
is KtFile -> this.packageFqNameByTree.asString()
|
||||
else -> this.text
|
||||
}
|
||||
|
||||
override fun isTooComplexForUltraLightGeneration(element: KtDeclaration): Boolean {
|
||||
val facet = KotlinFacet.get(module)
|
||||
val pluginClasspaths = facet?.configuration?.settings?.compilerArguments?.pluginClasspaths
|
||||
if (!pluginClasspaths.isNullOrEmpty()) {
|
||||
val stringifiedClasspaths = pluginClasspaths.joinToString()
|
||||
LOG.debug { "Using heavy light classes for ${element.forLogString()} because of compiler plugins $stringifiedClasspaths" }
|
||||
return true
|
||||
}
|
||||
|
||||
val problem = findTooComplexDeclaration(element)
|
||||
if (problem != null) {
|
||||
LOG.debug {
|
||||
"Using heavy light classes for ${element.forLogString()} because of ${StringUtil.trimLog(problem.text, 100)}"
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override val moduleDescriptor by lazyPub {
|
||||
element.getResolutionFacade().moduleDescriptor
|
||||
}
|
||||
|
||||
override val moduleName: String by lazyPub {
|
||||
JvmCodegenUtil.getModuleName(moduleDescriptor)
|
||||
}
|
||||
|
||||
override fun findAnnotation(owner: KtAnnotated, fqName: FqName): Pair<KtAnnotationEntry, AnnotationDescriptor>? {
|
||||
val candidates = owner.annotationEntries.filter {
|
||||
it.shortName == fqName.shortName() || owner.containingKtFile.hasAlias(it.shortName)
|
||||
}
|
||||
for (entry in candidates) {
|
||||
val descriptor = analyze(entry).get(BindingContext.ANNOTATION, entry)
|
||||
if (descriptor?.fqName == fqName) {
|
||||
return Pair(entry, descriptor)
|
||||
}
|
||||
}
|
||||
|
||||
if (owner is KtPropertyAccessor) {
|
||||
// We might have from the beginning just resolve the descriptor of the accessor
|
||||
// But we trying to avoid analysis in case property doesn't have any relevant annotations at all
|
||||
// (in case of `findAnnotation` returns null)
|
||||
if (findAnnotation(owner.property, fqName) == null) return null
|
||||
|
||||
val accessorDescriptor = owner.resolveToDescriptorIfAny() ?: return null
|
||||
|
||||
// Just reuse the logic of use-site targeted annotation from the compiler
|
||||
val annotationDescriptor = accessorDescriptor.annotations.findAnnotation(fqName) ?: return null
|
||||
val entry = annotationDescriptor.source.getPsi() as? KtAnnotationEntry ?: return null
|
||||
|
||||
return entry to annotationDescriptor
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
override val deprecationResolver: DeprecationResolver by lazyPub {
|
||||
element.getResolutionFacade().getFrontendService(DeprecationResolver::class.java)
|
||||
}
|
||||
|
||||
override val typeMapper: KotlinTypeMapper by lazyPub {
|
||||
KotlinTypeMapper(
|
||||
BindingContext.EMPTY, ClassBuilderMode.LIGHT_CLASSES,
|
||||
moduleName, KotlinTypeMapper.LANGUAGE_VERSION_SETTINGS_DEFAULT, // TODO use proper LanguageVersionSettings
|
||||
jvmTarget = JvmTarget.JVM_1_8,
|
||||
typePreprocessor = KotlinType::cleanFromAnonymousTypes
|
||||
)
|
||||
}
|
||||
|
||||
private fun findTooComplexDeclaration(declaration: KtDeclaration): PsiElement? {
|
||||
if (declaration.hasExpectModifier() ||
|
||||
declaration.hasModifier(KtTokens.ANNOTATION_KEYWORD) ||
|
||||
declaration.hasModifier(KtTokens.INLINE_KEYWORD) && declaration is KtClassOrObject ||
|
||||
declaration.hasModifier(KtTokens.SUSPEND_KEYWORD)
|
||||
) {
|
||||
return declaration
|
||||
}
|
||||
|
||||
if (declaration is KtClassOrObject) {
|
||||
declaration.primaryConstructor?.let { findTooComplexDeclaration(it) }?.let { return it }
|
||||
|
||||
for (d in declaration.declarations) {
|
||||
if (d is KtClassOrObject && !(d is KtObjectDeclaration && d.isCompanion())) continue
|
||||
|
||||
findTooComplexDeclaration(d)?.let { return it }
|
||||
}
|
||||
|
||||
if (implementsKotlinCollection(declaration)) {
|
||||
return declaration.getSuperTypeList()
|
||||
}
|
||||
}
|
||||
if (declaration is KtCallableDeclaration) {
|
||||
declaration.valueParameters.mapNotNull { findTooComplexDeclaration(it) }.firstOrNull()?.let { return it }
|
||||
if (declaration.typeReference?.hasModifier(KtTokens.SUSPEND_KEYWORD) == true) {
|
||||
return declaration.typeReference
|
||||
}
|
||||
}
|
||||
if (declaration is KtProperty) {
|
||||
declaration.accessors.mapNotNull { findTooComplexDeclaration(it) }.firstOrNull()?.let { return it }
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
override fun createUltraLightClassForFacade(
|
||||
facadeClassFqName: FqName,
|
||||
searchScope: GlobalSearchScope,
|
||||
facadeFile: KtFile
|
||||
): KtUltraLightClassForFacade? {
|
||||
|
||||
val lightClassDataCache =
|
||||
KtLightClassForFacade.FacadeStubCache.getInstance(project).get(facadeClassFqName, searchScope)
|
||||
|
||||
if (facadeFile.isScript()) return null
|
||||
|
||||
val module = ModuleUtilCore.findModuleForPsiElement(facadeFile) ?: return null
|
||||
|
||||
return KtUltraLightClassForFacade(
|
||||
facadeFile.manager,
|
||||
facadeClassFqName,
|
||||
lightClassDataCache,
|
||||
facadeFile,
|
||||
KtUltraLightSupportImpl(facadeFile, module)
|
||||
)
|
||||
}
|
||||
|
||||
override fun createUltraLightClass(element: KtClassOrObject): KtUltraLightClass? {
|
||||
if (element.shouldNotBeVisibleAsLightClass() ||
|
||||
element is KtObjectDeclaration && element.isObjectLiteral() ||
|
||||
@@ -71,113 +209,8 @@ class IDELightClassGenerationSupport(private val project: Project) : LightClassG
|
||||
}
|
||||
|
||||
val module = ModuleUtilCore.findModuleForPsiElement(element) ?: return null
|
||||
return KtUltraLightClass(element, object : KtUltraLightSupport {
|
||||
override fun isTooComplexForUltraLightGeneration(element: KtClassOrObject): Boolean {
|
||||
val facet = KotlinFacet.get(module)
|
||||
val pluginClasspaths = facet?.configuration?.settings?.compilerArguments?.pluginClasspaths
|
||||
if (!pluginClasspaths.isNullOrEmpty()) {
|
||||
val stringifiedClasspaths = pluginClasspaths.joinToString()
|
||||
LOG.debug { "Using heavy light classes for ${element.fqName?.asString()} because of compiler plugins $stringifiedClasspaths" }
|
||||
return true
|
||||
}
|
||||
|
||||
val problem = findTooComplexDeclaration(element)
|
||||
if (problem != null) {
|
||||
LOG.debug {
|
||||
"Using heavy light classes for ${element.fqName?.asString()} because of ${StringUtil.trimLog(problem.text, 100)}"
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override val moduleDescriptor by lazyPub {
|
||||
element.getResolutionFacade().moduleDescriptor
|
||||
}
|
||||
|
||||
override val moduleName: String by lazyPub {
|
||||
JvmCodegenUtil.getModuleName(moduleDescriptor)
|
||||
}
|
||||
|
||||
override fun findAnnotation(owner: KtAnnotated, fqName: FqName): Pair<KtAnnotationEntry, AnnotationDescriptor>? {
|
||||
val candidates = owner.annotationEntries.filter {
|
||||
it.shortName == fqName.shortName() || owner.containingKtFile.hasAlias(it.shortName)
|
||||
}
|
||||
for (entry in candidates) {
|
||||
val descriptor = analyze(entry).get(BindingContext.ANNOTATION, entry)
|
||||
if (descriptor?.fqName == fqName) {
|
||||
return Pair(entry, descriptor)
|
||||
}
|
||||
}
|
||||
|
||||
if (owner is KtPropertyAccessor) {
|
||||
// We might have from the beginning just resolve the descriptor of the accessor
|
||||
// But we trying to avoid analysis in case property doesn't have any relevant annotations at all
|
||||
// (in case of `findAnnotation` returns null)
|
||||
if (findAnnotation(owner.property, fqName) == null) return null
|
||||
|
||||
val accessorDescriptor = owner.resolveToDescriptorIfAny() ?: return null
|
||||
|
||||
// Just reuse the logic of use-site targeted annotation from the compiler
|
||||
val annotationDescriptor = accessorDescriptor.annotations.findAnnotation(fqName) ?: return null
|
||||
val entry = annotationDescriptor.source.getPsi() as? KtAnnotationEntry ?: return null
|
||||
|
||||
return entry to annotationDescriptor
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
override val deprecationResolver: DeprecationResolver by lazyPub {
|
||||
element.getResolutionFacade().getFrontendService(DeprecationResolver::class.java)
|
||||
}
|
||||
|
||||
override val typeMapper: KotlinTypeMapper by lazyPub {
|
||||
KotlinTypeMapper(
|
||||
BindingContext.EMPTY, ClassBuilderMode.LIGHT_CLASSES,
|
||||
moduleName, KotlinTypeMapper.LANGUAGE_VERSION_SETTINGS_DEFAULT, // TODO use proper LanguageVersionSettings
|
||||
jvmTarget = JvmTarget.JVM_1_8,
|
||||
typePreprocessor = KotlinType::cleanFromAnonymousTypes
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun findTooComplexDeclaration(declaration: KtDeclaration): PsiElement? {
|
||||
if (declaration.hasExpectModifier() ||
|
||||
declaration.hasModifier(KtTokens.ANNOTATION_KEYWORD) ||
|
||||
declaration.hasModifier(KtTokens.INLINE_KEYWORD) && declaration is KtClassOrObject ||
|
||||
declaration.hasModifier(KtTokens.SUSPEND_KEYWORD)
|
||||
) {
|
||||
return declaration
|
||||
}
|
||||
|
||||
|
||||
if (declaration is KtClassOrObject) {
|
||||
declaration.primaryConstructor?.let { findTooComplexDeclaration(it) }?.let { return it }
|
||||
|
||||
for (d in declaration.declarations) {
|
||||
if (d is KtClassOrObject && !(d is KtObjectDeclaration && d.isCompanion())) continue
|
||||
|
||||
findTooComplexDeclaration(d)?.let { return it }
|
||||
}
|
||||
|
||||
if (implementsKotlinCollection(declaration)) {
|
||||
return declaration.getSuperTypeList()
|
||||
}
|
||||
}
|
||||
if (declaration is KtCallableDeclaration) {
|
||||
declaration.valueParameters.mapNotNull { findTooComplexDeclaration(it) }.firstOrNull()?.let { return it }
|
||||
if (declaration.typeReference?.hasModifier(KtTokens.SUSPEND_KEYWORD) == true) {
|
||||
return declaration.typeReference
|
||||
}
|
||||
}
|
||||
if (declaration is KtProperty) {
|
||||
declaration.accessors.mapNotNull { findTooComplexDeclaration(it) }.firstOrNull()?.let { return it }
|
||||
}
|
||||
|
||||
return null
|
||||
|
||||
return KtUltraLightClass(element, KtUltraLightSupportImpl(element, module))
|
||||
}
|
||||
|
||||
private fun implementsKotlinCollection(classOrObject: KtClassOrObject): Boolean {
|
||||
|
||||
Reference in New Issue
Block a user