From 852a4bc0ca4e6f491fbd6b709d4a02b6ffa45172 Mon Sep 17 00:00:00 2001 From: Igor Yakovlev Date: Wed, 22 May 2019 17:35:24 +0300 Subject: [PATCH] Add support UL for FileFacade --- .../CliLightClassGenerationSupport.kt | 10 + .../asJava/LightClassGenerationSupport.kt | 11 + .../asJava/classes/KtLightClassForFacade.kt | 75 ++-- .../KtLightClassForSourceDeclaration.kt | 5 +- .../classes/ultraKtLightClassForFacade.kt | 82 ++++ .../kotlin/asJava/classes/ultraLightClass.kt | 390 +----------------- .../asJava/classes/ultraLightEnumEntry.kt | 4 +- .../kotlin/asJava/classes/ultraLightField.kt | 4 +- .../classes/ultraLightMembersCreator.kt | 384 +++++++++++++++++ .../asJava/classes/ultraLightMethods.kt | 4 +- .../asJava/classes/ultraLightSupport.kt | 13 +- .../kotlin/asJava/classes/ultraLightUtils.kt | 27 ++ .../resolve/IDELightClassGenerationSupport.kt | 245 ++++++----- 13 files changed, 735 insertions(+), 519 deletions(-) create mode 100644 compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraKtLightClassForFacade.kt create mode 100644 compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMembersCreator.kt diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/CliLightClassGenerationSupport.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/CliLightClassGenerationSupport.kt index e266e0e3433..e6818aa8953 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/CliLightClassGenerationSupport.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/CliLightClassGenerationSupport.kt @@ -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 { diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/LightClassGenerationSupport.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/LightClassGenerationSupport.kt index 6e4a0a7f2fe..f2d5587627f 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/LightClassGenerationSupport.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/LightClassGenerationSupport.kt @@ -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 { diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForFacade.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForFacade.kt index 69eb4ea77c3..07c05ea71c4 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForFacade.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForFacade.kt @@ -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, - files: Collection +open class KtLightClassForFacade protected constructor( + manager: PsiManager, + protected val facadeClassFqName: FqName, + protected open val lightClassDataCache: CachedValue, + files: Collection ) : 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>(20, 30) { override fun createValue(key: StubCacheKey): CachedValue { val stubProvider = LightClassDataProviderForFileFacade.ByProjectSource(project, key.fqName, key.searchScope) - return CachedValuesManager.getManager(project).createCachedValue(stubProvider, /*trackValue = */false) + return CachedValuesManager.getManager(project) + .createCachedValue(stubProvider, /*trackValue = */false) } } } private val cachedValue: CachedValue = CachedValuesManager.getManager(project).createCachedValue( - { 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 { - synchronized (cachedValue) { + synchronized(cachedValue) { return cachedValue.value.cache.get(StubCacheKey(qualifiedName, searchScope)) } } @@ -83,22 +87,22 @@ class KtLightClassForFacade private constructor( val files: Collection = 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 + manager: PsiManager, + facadeClassFqName: FqName, + searchScope: GlobalSearchScope, + files: Collection ): 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( - LightClassDataProviderForFileFacade.ByFile(manager.project, facadeClassFqName, file), /*trackValue = */false - ) + val cachedValue = CachedValuesManager.getManager(manager.project).createCachedValue( + LightClassDataProviderForFileFacade.ByFile(manager.project, facadeClassFqName, file), /*trackValue = */false + ) return KtLightClassForFacade(manager, facadeClassFqName, cachedValue, listOf(file)) } } diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForSourceDeclaration.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForSourceDeclaration.kt index 01690623b05..0455e287cad 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForSourceDeclaration.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForSourceDeclaration.kt @@ -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? { diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraKtLightClassForFacade.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraKtLightClassForFacade.kt new file mode 100644 index 00000000000..758148f67ce --- /dev/null +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraKtLightClassForFacade.kt @@ -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, + 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 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 + 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 by lazyPub { + + val result = arrayListOf() + + 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 by lazyPub { + hashSetOf().run { + file.declarations.filterIsInstance().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 +} \ No newline at end of file diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightClass.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightClass.kt index 899a7533c8f..54f8b42dd6e 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightClass.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightClass.kt @@ -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() val usedNames = hashSetOf() - 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()) { 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 = 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() - 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 = if (tooComplex) super.getOwnMethods() else _ownMethods - private fun asJavaMethods( - ktFunction: KtFunction, - forceStatic: Boolean, - forcePrivate: Boolean = false - ): Collection { - 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 { - - 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() - - 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 = emptyArray() override fun getContainingClass(): PsiClass? = diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightEnumEntry.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightEnumEntry.kt index c7d4150f71a..3ec76fdda92 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightEnumEntry.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightEnumEntry.kt @@ -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 ) : 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 diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightField.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightField.kt index 9ad3e2cf3db..ccc28adfe53 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightField.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightField.kt @@ -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 ) : 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() diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMembersCreator.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMembersCreator.kt new file mode 100644 index 00000000000..2d9fccf9d0e --- /dev/null +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMembersCreator.kt @@ -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 { + 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, + 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 { + + 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 { + + 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() + + 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) + } +} diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMethods.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMethods.kt index b165800ac45..834c4e4915f 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMethods.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMethods.kt @@ -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, diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightSupport.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightSupport.kt index 3cccb834ef5..68e76ee1d11 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightSupport.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightSupport.kt @@ -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? - 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 + } } diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightUtils.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightUtils.kt index 2ae639447de..1d0109c1749 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightUtils.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightUtils.kt @@ -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 +} \ No newline at end of file diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.kt index ebfd05f2557..8c04ae41635 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.kt @@ -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? { + 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? { - 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 {