Add support UL for FileFacade
This commit is contained in:
+10
@@ -16,13 +16,16 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.cli.jvm.compiler
|
package org.jetbrains.kotlin.cli.jvm.compiler
|
||||||
|
|
||||||
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
import org.jetbrains.kotlin.asJava.LightClassBuilder
|
import org.jetbrains.kotlin.asJava.LightClassBuilder
|
||||||
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
|
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
|
||||||
import org.jetbrains.kotlin.asJava.builder.InvalidLightClassDataHolder
|
import org.jetbrains.kotlin.asJava.builder.InvalidLightClassDataHolder
|
||||||
import org.jetbrains.kotlin.asJava.builder.LightClassConstructionContext
|
import org.jetbrains.kotlin.asJava.builder.LightClassConstructionContext
|
||||||
import org.jetbrains.kotlin.asJava.builder.LightClassDataHolder
|
import org.jetbrains.kotlin.asJava.builder.LightClassDataHolder
|
||||||
import org.jetbrains.kotlin.asJava.builder.LightClassDataHolderImpl
|
import org.jetbrains.kotlin.asJava.builder.LightClassDataHolderImpl
|
||||||
|
import org.jetbrains.kotlin.asJava.classes.KtUltraLightClassForFacade
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
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
|
* To mitigate this, CliLightClassGenerationSupport hold a trace that is shared between the analyzer and JetLightClasses
|
||||||
*/
|
*/
|
||||||
class CliLightClassGenerationSupport(private val traceHolder: CliTraceHolder) : LightClassGenerationSupport() {
|
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 createUltraLightClass(element: KtClassOrObject) = null
|
||||||
|
|
||||||
override fun createDataHolderForClass(classOrObject: KtClassOrObject, builder: LightClassBuilder): LightClassDataHolder.ForClass {
|
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.components.ServiceManager
|
||||||
import com.intellij.openapi.project.Project
|
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.LightClassBuilderResult
|
||||||
import org.jetbrains.kotlin.asJava.builder.LightClassConstructionContext
|
import org.jetbrains.kotlin.asJava.builder.LightClassConstructionContext
|
||||||
import org.jetbrains.kotlin.asJava.builder.LightClassDataHolder
|
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.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.descriptors.DeclarationDescriptor
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
|
|
||||||
@@ -43,6 +48,12 @@ abstract class LightClassGenerationSupport {
|
|||||||
|
|
||||||
abstract fun createUltraLightClass(element: KtClassOrObject): KtUltraLightClass?
|
abstract fun createUltraLightClass(element: KtClassOrObject): KtUltraLightClass?
|
||||||
|
|
||||||
|
abstract fun createUltraLightClassForFacade(
|
||||||
|
facadeClassFqName: FqName,
|
||||||
|
searchScope: GlobalSearchScope,
|
||||||
|
facadeFile: KtFile
|
||||||
|
): KtUltraLightClassForFacade?
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun getInstance(project: Project): LightClassGenerationSupport {
|
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.components.ServiceManager
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.util.Comparing
|
import com.intellij.openapi.util.Comparing
|
||||||
|
import com.intellij.openapi.util.registry.Registry
|
||||||
import com.intellij.psi.*
|
import com.intellij.psi.*
|
||||||
import com.intellij.psi.impl.light.LightEmptyImplementsList
|
import com.intellij.psi.impl.light.LightEmptyImplementsList
|
||||||
import com.intellij.psi.impl.light.LightModifierList
|
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.psi.util.PsiModificationTracker
|
||||||
import com.intellij.util.containers.SLRUCache
|
import com.intellij.util.containers.SLRUCache
|
||||||
import org.jetbrains.annotations.NonNls
|
import org.jetbrains.annotations.NonNls
|
||||||
|
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
|
||||||
import org.jetbrains.kotlin.asJava.builder.LightClassDataHolder
|
import org.jetbrains.kotlin.asJava.builder.LightClassDataHolder
|
||||||
import org.jetbrains.kotlin.asJava.builder.LightClassDataProviderForFileFacade
|
import org.jetbrains.kotlin.asJava.builder.LightClassDataProviderForFileFacade
|
||||||
import org.jetbrains.kotlin.asJava.elements.FakeFileForLightClass
|
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 org.jetbrains.kotlin.psi.psiUtil.siblings
|
||||||
import javax.swing.Icon
|
import javax.swing.Icon
|
||||||
|
|
||||||
class KtLightClassForFacade private constructor(
|
open class KtLightClassForFacade protected constructor(
|
||||||
manager: PsiManager,
|
manager: PsiManager,
|
||||||
private val facadeClassFqName: FqName,
|
protected val facadeClassFqName: FqName,
|
||||||
private val lightClassDataCache: CachedValue<LightClassDataHolder.ForFacade>,
|
protected open val lightClassDataCache: CachedValue<LightClassDataHolder.ForFacade>,
|
||||||
files: Collection<KtFile>
|
files: Collection<KtFile>
|
||||||
) : KtLazyLightClass(manager) {
|
) : KtLazyLightClass(manager) {
|
||||||
|
|
||||||
private data class StubCacheKey(val fqName: FqName, val searchScope: GlobalSearchScope)
|
private data class StubCacheKey(val fqName: FqName, val searchScope: GlobalSearchScope)
|
||||||
|
|
||||||
class FacadeStubCache(private val project: Project) {
|
class FacadeStubCache(private val project: Project) {
|
||||||
@@ -58,17 +61,18 @@ class KtLightClassForFacade private constructor(
|
|||||||
val cache = object : SLRUCache<StubCacheKey, CachedValue<LightClassDataHolder.ForFacade>>(20, 30) {
|
val cache = object : SLRUCache<StubCacheKey, CachedValue<LightClassDataHolder.ForFacade>>(20, 30) {
|
||||||
override fun createValue(key: StubCacheKey): CachedValue<LightClassDataHolder.ForFacade> {
|
override fun createValue(key: StubCacheKey): CachedValue<LightClassDataHolder.ForFacade> {
|
||||||
val stubProvider = LightClassDataProviderForFileFacade.ByProjectSource(project, key.fqName, key.searchScope)
|
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>(
|
private val cachedValue: CachedValue<FacadeCacheData> = CachedValuesManager.getManager(project).createCachedValue<FacadeCacheData>(
|
||||||
{ CachedValueProvider.Result.create(FacadeCacheData(), PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT) },
|
{ CachedValueProvider.Result.create(FacadeCacheData(), PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT) }, false
|
||||||
/*trackValue = */ false)
|
)
|
||||||
|
|
||||||
operator fun get(qualifiedName: FqName, searchScope: GlobalSearchScope): CachedValue<LightClassDataHolder.ForFacade> {
|
operator fun get(qualifiedName: FqName, searchScope: GlobalSearchScope): CachedValue<LightClassDataHolder.ForFacade> {
|
||||||
synchronized (cachedValue) {
|
synchronized(cachedValue) {
|
||||||
return cachedValue.value.cache.get(StubCacheKey(qualifiedName, searchScope))
|
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
|
val files: Collection<KtFile> = files.toSet() // needed for hashCode
|
||||||
|
|
||||||
private val hashCode: Int =
|
private val hashCode: Int =
|
||||||
computeHashCode()
|
computeHashCode()
|
||||||
|
|
||||||
private val packageFqName: FqName =
|
private val packageFqName: FqName =
|
||||||
facadeClassFqName.parent()
|
facadeClassFqName.parent()
|
||||||
|
|
||||||
private val modifierList: PsiModifierList =
|
private val modifierList: PsiModifierList =
|
||||||
LightModifierList(manager, KotlinLanguage.INSTANCE, PsiModifier.PUBLIC, PsiModifier.FINAL)
|
LightModifierList(manager, KotlinLanguage.INSTANCE, PsiModifier.PUBLIC, PsiModifier.FINAL)
|
||||||
|
|
||||||
private val implementsList: LightEmptyImplementsList =
|
private val implementsList: LightEmptyImplementsList =
|
||||||
LightEmptyImplementsList(manager)
|
LightEmptyImplementsList(manager)
|
||||||
|
|
||||||
private val packageClsFile = FakeFileForLightClass(
|
private val packageClsFile = FakeFileForLightClass(
|
||||||
files.first(),
|
files.first(),
|
||||||
lightClass = { this },
|
lightClass = { this },
|
||||||
stub = { lightClassDataCache.value.javaFileStub },
|
stub = { lightClassDataCache.value.javaFileStub },
|
||||||
packageFqName = packageFqName
|
packageFqName = packageFqName
|
||||||
)
|
)
|
||||||
|
|
||||||
override val kotlinOrigin: KtClassOrObject? get() = null
|
override val kotlinOrigin: KtClassOrObject? get() = null
|
||||||
@@ -171,8 +175,7 @@ class KtLightClassForFacade private constructor(
|
|||||||
val annotationList = file.fileAnnotationList
|
val annotationList = file.fileAnnotationList
|
||||||
if (annotationList != null) {
|
if (annotationList != null) {
|
||||||
annotationList.add(newFileAnnotationList.annotationEntries.first())
|
annotationList.add(newFileAnnotationList.annotationEntries.first())
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val anchor = file.firstChild.siblings().firstOrNull { it !is PsiWhiteSpace && it !is PsiComment }
|
val anchor = file.firstChild.siblings().firstOrNull { it !is PsiWhiteSpace && it !is PsiComment }
|
||||||
file.addBefore(newFileAnnotationList, anchor)
|
file.addBefore(newFileAnnotationList, anchor)
|
||||||
}
|
}
|
||||||
@@ -180,7 +183,7 @@ class KtLightClassForFacade private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val jvmNameExpression = jvmNameEntry.valueArguments.firstOrNull()?.getArgumentExpression() as? KtStringTemplateExpression
|
val jvmNameExpression = jvmNameEntry.valueArguments.firstOrNull()?.getArgumentExpression() as? KtStringTemplateExpression
|
||||||
?: continue
|
?: continue
|
||||||
ElementManipulators.handleContentChange(jvmNameExpression, name)
|
ElementManipulators.handleContentChange(jvmNameExpression, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,29 +250,37 @@ class KtLightClassForFacade private constructor(
|
|||||||
|
|
||||||
override fun toString() = "${KtLightClassForFacade::class.java.simpleName}:$facadeClassFqName"
|
override fun toString() = "${KtLightClassForFacade::class.java.simpleName}:$facadeClassFqName"
|
||||||
|
|
||||||
companion object Factory {
|
companion object {
|
||||||
fun createForFacade(
|
fun createForFacade(
|
||||||
manager: PsiManager,
|
manager: PsiManager,
|
||||||
facadeClassFqName: FqName,
|
facadeClassFqName: FqName,
|
||||||
searchScope: GlobalSearchScope,
|
searchScope: GlobalSearchScope,
|
||||||
files: Collection<KtFile>
|
files: Collection<KtFile>
|
||||||
): KtLightClassForFacade {
|
): KtLightClassForFacade {
|
||||||
assert(files.isNotEmpty()) { "No files for facade $facadeClassFqName" }
|
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)
|
val lightClassDataCache = FacadeStubCache.getInstance(manager.project).get(facadeClassFqName, searchScope)
|
||||||
return KtLightClassForFacade(manager, facadeClassFqName, lightClassDataCache, files)
|
return KtLightClassForFacade(manager, facadeClassFqName, lightClassDataCache, files)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createForSyntheticFile(
|
fun createForSyntheticFile(
|
||||||
manager: PsiManager,
|
manager: PsiManager,
|
||||||
facadeClassFqName: FqName,
|
facadeClassFqName: FqName,
|
||||||
file: KtFile
|
file: KtFile
|
||||||
): KtLightClassForFacade {
|
): KtLightClassForFacade {
|
||||||
// TODO: refactor, using cached value doesn't make sense for this case
|
// TODO: refactor, using cached value doesn't make sense for this case
|
||||||
val cachedValue = CachedValuesManager.getManager(manager.project).
|
val cachedValue = CachedValuesManager.getManager(manager.project).createCachedValue<LightClassDataHolder.ForFacade>(
|
||||||
createCachedValue<LightClassDataHolder.ForFacade>(
|
LightClassDataProviderForFileFacade.ByFile(manager.project, facadeClassFqName, file), /*trackValue = */false
|
||||||
LightClassDataProviderForFileFacade.ByFile(manager.project, facadeClassFqName, file), /*trackValue = */false
|
)
|
||||||
)
|
|
||||||
return KtLightClassForFacade(manager, facadeClassFqName, cachedValue, listOf(file))
|
return KtLightClassForFacade(manager, facadeClassFqName, cachedValue, listOf(file))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-1
@@ -339,7 +339,10 @@ abstract class KtLightClassForSourceDeclaration(
|
|||||||
fun create(classOrObject: KtClassOrObject): KtLightClassForSourceDeclaration? =
|
fun create(classOrObject: KtClassOrObject): KtLightClassForSourceDeclaration? =
|
||||||
CachedValuesManager.getCachedValue(classOrObject) {
|
CachedValuesManager.getCachedValue(classOrObject) {
|
||||||
CachedValueProvider.Result
|
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? {
|
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.PsiClassImplUtil
|
||||||
import com.intellij.psi.impl.PsiSuperMethodImplUtil
|
import com.intellij.psi.impl.PsiSuperMethodImplUtil
|
||||||
import com.intellij.psi.impl.light.LightMethodBuilder
|
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.builder.LightClassData
|
||||||
import org.jetbrains.kotlin.asJava.elements.KtLightField
|
import org.jetbrains.kotlin.asJava.elements.KtLightField
|
||||||
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
|
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.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.codegen.JvmCodegenUtil
|
import org.jetbrains.kotlin.codegen.JvmCodegenUtil
|
||||||
import org.jetbrains.kotlin.codegen.kotlinType
|
import org.jetbrains.kotlin.codegen.kotlinType
|
||||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.Annotated
|
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens.*
|
import org.jetbrains.kotlin.lexer.KtTokens.*
|
||||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||||
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
|
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.SpecialNames
|
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
|
||||||
import org.jetbrains.kotlin.resolve.DelegationResolver
|
import org.jetbrains.kotlin.resolve.DelegationResolver
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
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.JVM_STATIC_ANNOTATION_FQ_NAME
|
||||||
import org.jetbrains.kotlin.resolve.annotations.argumentValue
|
import org.jetbrains.kotlin.resolve.annotations.argumentValue
|
||||||
import org.jetbrains.kotlin.resolve.constants.EnumValue
|
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_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.KotlinType
|
||||||
import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny
|
import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny
|
||||||
|
|
||||||
open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val support: KtUltraLightSupport) :
|
open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val support: KtUltraLightSupport) :
|
||||||
KtLightClassImpl(classOrObject) {
|
KtLightClassImpl(classOrObject) {
|
||||||
companion object {
|
|
||||||
|
|
||||||
// This property may be removed once IntelliJ versions earlier than 2018.3 become unsupported
|
private val methodsBuilder by lazyPub {
|
||||||
// And usages of that property may be replaced with relevant registry key
|
UltraLightMembersCreator(this, isNamedObject(), classOrObject.hasModifier(SEALED_KEYWORD), support)
|
||||||
@Volatile
|
|
||||||
@get:TestOnly
|
|
||||||
var forceUsingOldLightClasses = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val tooComplex: Boolean by lazyPub { support.isTooComplexForUltraLightGeneration(classOrObject) }
|
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 result = arrayListOf<KtLightField>()
|
||||||
val usedNames = hashSetOf<String>()
|
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()) {
|
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 ->
|
this.classOrObject.companionObjects.firstOrNull()?.let { companion ->
|
||||||
result.add(
|
result.add(
|
||||||
KtUltraLightField(
|
KtUltraLightField(
|
||||||
companion,
|
companion,
|
||||||
generateUniqueName(companion.name.orEmpty()),
|
methodsBuilder.generateUniqueFieldName(companion.name.orEmpty(), usedNames),
|
||||||
this,
|
this,
|
||||||
support,
|
support,
|
||||||
setOf(PsiModifier.STATIC, PsiModifier.FINAL, PsiModifier.PUBLIC)
|
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>()) {
|
for (property in companion.declarations.filterIsInstance<KtProperty>()) {
|
||||||
if (isInterface && !property.isConstOrJvmField()) continue
|
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)
|
// 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
|
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 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
|
override fun getOwnFields(): List<KtLightField> = if (tooComplex) super.getOwnFields() else _ownFields
|
||||||
|
|
||||||
private fun propertyParameters() = classOrObject.primaryConstructorParameters.filter { it.hasValOrVar() }
|
private fun propertyParameters() = classOrObject.primaryConstructorParameters.filter { it.hasValOrVar() }
|
||||||
@@ -273,16 +197,16 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor
|
|||||||
|
|
||||||
val result = arrayListOf<KtLightMethod>()
|
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
|
if (declaration.hasModifier(PRIVATE_KEYWORD) && isInterface) continue
|
||||||
when (declaration) {
|
when (declaration) {
|
||||||
is KtNamedFunction -> result.addAll(asJavaMethods(declaration, false))
|
is KtNamedFunction -> result.addAll(methodsBuilder.createMethods(declaration, false))
|
||||||
is KtProperty -> result.addAll(propertyAccessors(declaration, declaration.isVar, false))
|
is KtProperty -> result.addAll(methodsBuilder.propertyAccessors(declaration, declaration.isVar, false,false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (parameter in propertyParameters()) {
|
for (parameter in propertyParameters()) {
|
||||||
result.addAll(propertyAccessors(parameter, parameter.isMutable, false))
|
result.addAll(methodsBuilder.propertyAccessors(parameter, parameter.isMutable, false,false))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isInterface) {
|
if (!isInterface) {
|
||||||
@@ -292,8 +216,8 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor
|
|||||||
this.classOrObject.companionObjects.firstOrNull()?.let { companion ->
|
this.classOrObject.companionObjects.firstOrNull()?.let { companion ->
|
||||||
for (declaration in companion.declarations.filterNot { isHiddenByDeprecation(it) }) {
|
for (declaration in companion.declarations.filterNot { isHiddenByDeprecation(it) }) {
|
||||||
when (declaration) {
|
when (declaration) {
|
||||||
is KtNamedFunction -> if (isJvmStatic(declaration)) result.addAll(asJavaMethods(declaration, true))
|
is KtNamedFunction -> if (isJvmStatic(declaration)) result.addAll(methodsBuilder.createMethods(declaration, true))
|
||||||
is KtProperty -> result.addAll(propertyAccessors(declaration, declaration.isVar, 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())
|
result.add(defaultConstructor())
|
||||||
}
|
}
|
||||||
for (constructor in constructors.filterNot { isHiddenByDeprecation(it) }) {
|
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
|
val primary = classOrObject.primaryConstructor
|
||||||
if (primary != null && shouldGenerateNoArgOverload(primary)) {
|
if (primary != null && shouldGenerateNoArgOverload(primary)) {
|
||||||
result.add(noArgConstructor(simpleVisibility(primary), primary))
|
result.add(noArgConstructor(primary.simpleVisibility(), primary))
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@@ -403,12 +327,6 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor
|
|||||||
return noArgConstructor(visibility, classOrObject)
|
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 =
|
private fun noArgConstructor(visibility: String, declaration: KtDeclaration): KtUltraLightMethod =
|
||||||
KtUltraLightMethodForSourceDeclaration(
|
KtUltraLightMethodForSourceDeclaration(
|
||||||
LightMethodBuilder(manager, language, name.orEmpty()).setConstructor(true).addModifier(visibility),
|
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
|
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 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() =
|
private fun KtCallableDeclaration.isConstOrJvmField() =
|
||||||
hasModifier(CONST_KEYWORD) || isJvmField()
|
hasModifier(CONST_KEYWORD) || isJvmField()
|
||||||
|
|
||||||
private fun KtCallableDeclaration.isJvmField() = hasAnnotation(JvmAbi.JVM_FIELD_ANNOTATION_FQ_NAME)
|
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 getInitializers(): Array<PsiClassInitializer> = emptyArray()
|
||||||
|
|
||||||
override fun getContainingClass(): PsiClass? =
|
override fun getContainingClass(): PsiClass? =
|
||||||
|
|||||||
+2
-2
@@ -11,7 +11,7 @@ import org.jetbrains.kotlin.psi.KtEnumEntry
|
|||||||
internal class KtUltraLightEnumEntry(
|
internal class KtUltraLightEnumEntry(
|
||||||
declaration: KtEnumEntry,
|
declaration: KtEnumEntry,
|
||||||
name: String,
|
name: String,
|
||||||
containingClass: KtUltraLightClass,
|
containingClass: KtLightClass,
|
||||||
support: KtUltraLightSupport,
|
support: KtUltraLightSupport,
|
||||||
modifiers: Set<String>
|
modifiers: Set<String>
|
||||||
) : KtUltraLightField(declaration, name, containingClass, support, modifiers), PsiEnumConstant {
|
) : KtUltraLightField(declaration, name, containingClass, support, modifiers), PsiEnumConstant {
|
||||||
@@ -19,7 +19,7 @@ internal class KtUltraLightEnumEntry(
|
|||||||
private val enumEntry get() = declaration as KtEnumEntry
|
private val enumEntry get() = declaration as KtEnumEntry
|
||||||
|
|
||||||
private val _initializingClass by lazyPub {
|
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
|
override fun getInitializingClass(): PsiEnumConstantInitializer? = _initializingClass
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ import org.jetbrains.kotlin.types.KotlinType
|
|||||||
internal open class KtUltraLightField(
|
internal open class KtUltraLightField(
|
||||||
protected val declaration: KtNamedDeclaration,
|
protected val declaration: KtNamedDeclaration,
|
||||||
name: String,
|
name: String,
|
||||||
private val containingClass: KtUltraLightClass,
|
private val containingClass: KtLightClass,
|
||||||
private val support: KtUltraLightSupport,
|
private val support: KtUltraLightSupport,
|
||||||
modifiers: Set<String>
|
modifiers: Set<String>
|
||||||
) : LightFieldBuilder(name, PsiType.NULL, declaration), KtLightField,
|
) : LightFieldBuilder(name, PsiType.NULL, declaration), KtLightField,
|
||||||
@@ -75,7 +75,7 @@ internal open class KtUltraLightField(
|
|||||||
declaration is KtObjectDeclaration ->
|
declaration is KtObjectDeclaration ->
|
||||||
(declaration.resolve() as? ClassDescriptor)?.defaultType
|
(declaration.resolve() as? ClassDescriptor)?.defaultType
|
||||||
declaration is KtEnumEntry -> {
|
declaration is KtEnumEntry -> {
|
||||||
(containingClass.kotlinOrigin.resolve() as? ClassDescriptor)?.defaultType
|
(containingClass.kotlinOrigin?.resolve() as? ClassDescriptor)?.defaultType
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
declaration.getKotlinType()
|
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,
|
internal val delegate: LightMethodBuilder,
|
||||||
closestDeclarationForOrigin: KtDeclaration?,
|
closestDeclarationForOrigin: KtDeclaration?,
|
||||||
protected val support: KtUltraLightSupport,
|
protected val support: KtUltraLightSupport,
|
||||||
containingClass: KtUltraLightClass
|
containingClass: KtLightClass
|
||||||
) : KtLightMethodImpl(
|
) : KtLightMethodImpl(
|
||||||
{ delegate },
|
{ delegate },
|
||||||
closestDeclarationForOrigin?.let {
|
closestDeclarationForOrigin?.let {
|
||||||
@@ -101,7 +101,7 @@ internal class KtUltraLightMethodForSourceDeclaration(
|
|||||||
delegate: LightMethodBuilder,
|
delegate: LightMethodBuilder,
|
||||||
declaration: KtDeclaration,
|
declaration: KtDeclaration,
|
||||||
support: KtUltraLightSupport,
|
support: KtUltraLightSupport,
|
||||||
containingClass: KtUltraLightClass
|
containingClass: KtLightClass
|
||||||
) : KtUltraLightMethod(
|
) : KtUltraLightMethod(
|
||||||
delegate,
|
delegate,
|
||||||
declaration,
|
declaration,
|
||||||
|
|||||||
+11
-2
@@ -5,20 +5,29 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.asJava.classes
|
package org.jetbrains.kotlin.asJava.classes
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.TestOnly
|
||||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.psi.KtAnnotated
|
import org.jetbrains.kotlin.psi.KtAnnotated
|
||||||
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
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
|
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
|
||||||
|
|
||||||
interface KtUltraLightSupport {
|
interface KtUltraLightSupport {
|
||||||
val moduleName: String
|
val moduleName: String
|
||||||
fun findAnnotation(owner: KtAnnotated, fqName: FqName): Pair<KtAnnotationEntry, AnnotationDescriptor>?
|
fun findAnnotation(owner: KtAnnotated, fqName: FqName): Pair<KtAnnotationEntry, AnnotationDescriptor>?
|
||||||
fun isTooComplexForUltraLightGeneration(element: KtClassOrObject): Boolean
|
fun isTooComplexForUltraLightGeneration(element: KtDeclaration): Boolean
|
||||||
val deprecationResolver: DeprecationResolver
|
val deprecationResolver: DeprecationResolver
|
||||||
val typeMapper: KotlinTypeMapper
|
val typeMapper: KotlinTypeMapper
|
||||||
val moduleDescriptor: ModuleDescriptor
|
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.signature.JvmSignatureWriter
|
||||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
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.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.*
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
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.KotlinType
|
||||||
import org.jetbrains.kotlin.types.TypeProjectionImpl
|
import org.jetbrains.kotlin.types.TypeProjectionImpl
|
||||||
import org.jetbrains.kotlin.types.replace
|
import org.jetbrains.kotlin.types.replace
|
||||||
@@ -286,3 +300,16 @@ private fun packMethodFlags(access: Int, isInterface: Boolean): Int {
|
|||||||
|
|
||||||
return flags
|
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
|
package org.jetbrains.kotlin.idea.caches.resolve
|
||||||
|
|
||||||
import com.intellij.openapi.diagnostic.debug
|
import com.intellij.openapi.diagnostic.debug
|
||||||
|
import com.intellij.openapi.module.Module
|
||||||
import com.intellij.openapi.module.ModuleUtilCore
|
import com.intellij.openapi.module.ModuleUtilCore
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.util.text.StringUtil
|
import com.intellij.openapi.util.text.StringUtil
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.PsiManager
|
||||||
import com.intellij.psi.search.GlobalSearchScope
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
import com.intellij.psi.util.CachedValueProvider
|
import com.intellij.psi.util.CachedValueProvider
|
||||||
import com.intellij.psi.util.CachedValuesManager
|
import com.intellij.psi.util.CachedValuesManager
|
||||||
@@ -60,6 +62,142 @@ import org.jetbrains.kotlin.types.KotlinType
|
|||||||
import java.util.concurrent.ConcurrentMap
|
import java.util.concurrent.ConcurrentMap
|
||||||
|
|
||||||
class IDELightClassGenerationSupport(private val project: Project) : LightClassGenerationSupport() {
|
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? {
|
override fun createUltraLightClass(element: KtClassOrObject): KtUltraLightClass? {
|
||||||
if (element.shouldNotBeVisibleAsLightClass() ||
|
if (element.shouldNotBeVisibleAsLightClass() ||
|
||||||
element is KtObjectDeclaration && element.isObjectLiteral() ||
|
element is KtObjectDeclaration && element.isObjectLiteral() ||
|
||||||
@@ -71,113 +209,8 @@ class IDELightClassGenerationSupport(private val project: Project) : LightClassG
|
|||||||
}
|
}
|
||||||
|
|
||||||
val module = ModuleUtilCore.findModuleForPsiElement(element) ?: return null
|
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 {
|
private fun implementsKotlinCollection(classOrObject: KtClassOrObject): Boolean {
|
||||||
|
|||||||
Reference in New Issue
Block a user