diff --git a/compiler/frontend/src/org/jetbrains/kotlin/extensions/LightClassApplicabilityCheckExtension.kt b/compiler/frontend/src/org/jetbrains/kotlin/extensions/LightClassApplicabilityCheckExtension.kt deleted file mode 100644 index 8ddd5cf3473..00000000000 --- a/compiler/frontend/src/org/jetbrains/kotlin/extensions/LightClassApplicabilityCheckExtension.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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.extensions - -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.psi.KtDeclaration - -enum class LightClassApplicabilityType { - LightClass, - UltraLightClass -} - -/** - * This extension point needs to be implemented by the Kotlin compiler plugins in case they change the requested declaration (i.e. producing synthetic parts) - * with backend extension points. The light class provider will request this EP to check either to create LightClass or UltraLight class implementations. - * @see org.jetbrains.kotlin.extensions.DeclarationAttributeAltererExtension - * @see org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension - */ -interface LightClassApplicabilityCheckExtension { - companion object : ProjectExtensionDescriptor( - "org.jetbrains.kotlin.lightClassApplicabilityCheckExtension", - LightClassApplicabilityCheckExtension::class.java - ) - - /** - * This method should return LightClass if any changes in Kotlin declarations is going to be produced during JVM-backend code generation. - * This method ought to be as fast as possible but never return UltraLightClass when not sure. - * Next advice could be given to make best: - * 1) Try to cover as much cases as possible without forcing descriptor evaluation - * 2) After you've forced descriptor evaluation, ideally, you should never return LightClass while in fact no synthetic parts going to be generated - * 3) So, you should force descriptor evaluation only if you're sure that you will be able to return UltraLightClass significantly more often - * @see org.jetbrains.kotlin.noarg.ide.IdeNoArgApplicabilityExtension - * @see org.jetbrains.kotlin.android.parcel.IDEParcelableApplicabilityExtension - */ - fun checkApplicabilityType(declaration: KtDeclaration, descriptor: Lazy): LightClassApplicabilityType -} \ No newline at end of file diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/UltraLightClassCodegenSupport.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/UltraLightClassModifierExtension.kt similarity index 72% rename from compiler/light-classes/src/org/jetbrains/kotlin/asJava/UltraLightClassCodegenSupport.kt rename to compiler/light-classes/src/org/jetbrains/kotlin/asJava/UltraLightClassModifierExtension.kt index 0655ec862f6..0b4dd8ed678 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/UltraLightClassCodegenSupport.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/UltraLightClassModifierExtension.kt @@ -9,9 +9,16 @@ import org.jetbrains.kotlin.asJava.classes.KtUltraLightClass import org.jetbrains.kotlin.asJava.elements.KtLightField import org.jetbrains.kotlin.asJava.elements.KtLightMethod import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.extensions.ProjectExtensionDescriptor import org.jetbrains.kotlin.psi.KtDeclaration -interface UltraLightClassCodegenSupport { +interface UltraLightClassModifierExtension { + + companion object : ProjectExtensionDescriptor( + "org.jetbrains.kotlin.ultraLightClassModifierExtension", + UltraLightClassModifierExtension::class.java + ) + fun interceptMethodsBuilding( declaration: KtDeclaration, descriptor: Lazy, @@ -23,6 +30,6 @@ interface UltraLightClassCodegenSupport { declaration: KtDeclaration, descriptor: Lazy, containingDeclaration: KtUltraLightClass, - methodsList: MutableList + fieldsList: MutableList ) = Unit } 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 03738e6dd73..aa86253e14d 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 @@ -14,7 +14,7 @@ import com.intellij.psi.impl.light.LightMethodBuilder import com.intellij.psi.util.CachedValue import com.intellij.psi.util.CachedValueProvider import com.intellij.psi.util.CachedValuesManager -import org.jetbrains.kotlin.asJava.UltraLightClassCodegenSupport +import org.jetbrains.kotlin.asJava.UltraLightClassModifierExtension import org.jetbrains.kotlin.asJava.builder.LightClassData import org.jetbrains.kotlin.asJava.elements.KtLightField import org.jetbrains.kotlin.asJava.elements.KtLightMethod @@ -340,10 +340,8 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor return result } - private inline fun applyCompilerPlugins(body: (UltraLightClassCodegenSupport) -> Unit) { - ExpressionCodegenExtension.getInstances(project) - .filterIsInstance() - .forEach { body(it) } + private inline fun applyCompilerPlugins(body: (UltraLightClassModifierExtension) -> Unit) { + UltraLightClassModifierExtension.getInstances(project).forEach { body(it) } } private val _ownMethods: CachedValue> = CachedValuesManager.getManager(project).createCachedValue( 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 6c772a8903d..1df5a9f0bc8 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 @@ -29,6 +29,7 @@ import com.intellij.psi.util.PsiModificationTracker import com.intellij.util.containers.ConcurrentFactoryMap import org.jetbrains.kotlin.asJava.LightClassBuilder import org.jetbrains.kotlin.asJava.LightClassGenerationSupport +import org.jetbrains.kotlin.asJava.UltraLightClassModifierExtension import org.jetbrains.kotlin.asJava.builder.InvalidLightClassDataHolder import org.jetbrains.kotlin.asJava.builder.LightClassDataHolder import org.jetbrains.kotlin.asJava.classes.* @@ -40,8 +41,6 @@ import org.jetbrains.kotlin.config.JvmTarget import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor -import org.jetbrains.kotlin.extensions.LightClassApplicabilityCheckExtension -import org.jetbrains.kotlin.extensions.LightClassApplicabilityType import org.jetbrains.kotlin.idea.caches.lightClasses.IDELightClassContexts import org.jetbrains.kotlin.idea.caches.lightClasses.LazyLightClassDataHolder import org.jetbrains.kotlin.idea.facet.KotlinFacet @@ -69,33 +68,7 @@ class IDELightClassGenerationSupport(private val project: Project) : LightClassG override val isReleasedCoroutine get() = module?.languageVersionSettings?.supportsFeature(LanguageFeature.ReleaseCoroutines) ?: true - private fun KtDeclaration.mayBeModifiedByCompilerPlugins(): Boolean { - - module?.let { - val facet = KotlinFacet.get(it) - val pluginClasspaths = facet?.configuration?.settings?.compilerArguments?.pluginClasspaths - if (pluginClasspaths.isNullOrEmpty()) return false - } - - val resolvedDescriptor = lazy(LazyThreadSafetyMode.NONE) { - resolveToDescriptorIfAny( - getResolutionFacade(), - bodyResolveMode = BodyResolveMode.PARTIAL - ) - } - - return LightClassApplicabilityCheckExtension.getInstances(project).any { - it.checkApplicabilityType(this, resolvedDescriptor) == LightClassApplicabilityType.LightClass - } - } - override fun isTooComplexForUltraLightGeneration(element: KtDeclaration): Boolean { - - val codegenExtensionsEnabled = element.mayBeModifiedByCompilerPlugins() - if (codegenExtensionsEnabled) { - LOG.debug { "Using heavy light classes because of compiler plugins" } - return true - } return false } diff --git a/idea/resources/META-INF/android.xml b/idea/resources/META-INF/android.xml index 9f021ecda0b..3dec20142a8 100644 --- a/idea/resources/META-INF/android.xml +++ b/idea/resources/META-INF/android.xml @@ -96,7 +96,7 @@ - + diff --git a/idea/resources/META-INF/extensions/ide.xml b/idea/resources/META-INF/extensions/ide.xml index f0bf2e5699c..e1e07ff592f 100644 --- a/idea/resources/META-INF/extensions/ide.xml +++ b/idea/resources/META-INF/extensions/ide.xml @@ -13,8 +13,8 @@ - diff --git a/idea/resources/META-INF/extensions/ide.xml.183 b/idea/resources/META-INF/extensions/ide.xml.183 index adae3b3a6ab..f1f34485a46 100644 --- a/idea/resources/META-INF/extensions/ide.xml.183 +++ b/idea/resources/META-INF/extensions/ide.xml.183 @@ -21,8 +21,8 @@ - diff --git a/idea/resources/META-INF/jvm.xml b/idea/resources/META-INF/jvm.xml index eed12b6c756..26fad8bca9e 100644 --- a/idea/resources/META-INF/jvm.xml +++ b/idea/resources/META-INF/jvm.xml @@ -198,11 +198,10 @@ - - + diff --git a/idea/resources/META-INF/jvm.xml.183 b/idea/resources/META-INF/jvm.xml.183 index c42f0b7c995..7bd461223b7 100644 --- a/idea/resources/META-INF/jvm.xml.183 +++ b/idea/resources/META-INF/jvm.xml.183 @@ -198,11 +198,10 @@ - - + diff --git a/idea/resources/META-INF/kotlinx-serialization.xml b/idea/resources/META-INF/kotlinx-serialization.xml index fafe0401264..4ad16af7a6a 100644 --- a/idea/resources/META-INF/kotlinx-serialization.xml +++ b/idea/resources/META-INF/kotlinx-serialization.xml @@ -5,6 +5,5 @@ - diff --git a/plugins/allopen/allopen-ide/src/IdeAllOpenDeclarationAttributeAltererExtension.kt b/plugins/allopen/allopen-ide/src/IdeAllOpenDeclarationAttributeAltererExtension.kt index 312d03e36f7..c681e38e1b7 100644 --- a/plugins/allopen/allopen-ide/src/IdeAllOpenDeclarationAttributeAltererExtension.kt +++ b/plugins/allopen/allopen-ide/src/IdeAllOpenDeclarationAttributeAltererExtension.kt @@ -21,16 +21,12 @@ import com.intellij.openapi.project.Project import org.jetbrains.kotlin.allopen.AbstractAllOpenDeclarationAttributeAltererExtension import org.jetbrains.kotlin.allopen.AllOpenCommandLineProcessor.Companion.ANNOTATION_OPTION import org.jetbrains.kotlin.allopen.AllOpenCommandLineProcessor.Companion.PLUGIN_ID -import org.jetbrains.kotlin.annotation.plugin.ide.AnnotationBasedLightClassApplicabilityExtension import org.jetbrains.kotlin.annotation.plugin.ide.CachedAnnotationNames import org.jetbrains.kotlin.annotation.plugin.ide.getAnnotationNames import org.jetbrains.kotlin.psi.KtModifierListOwner internal val ALL_OPEN_ANNOTATION_OPTION_PREFIX = "plugin:$PLUGIN_ID:${ANNOTATION_OPTION.optionName}=" -class IdeAllOpenApplicabilityExtension(project: Project) : - AnnotationBasedLightClassApplicabilityExtension(project, ALL_OPEN_ANNOTATION_OPTION_PREFIX) - class IdeAllOpenDeclarationAttributeAltererExtension(val project: Project) : AbstractAllOpenDeclarationAttributeAltererExtension() { diff --git a/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/parcel/ParcelableCodegenExtension.kt b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/parcel/ParcelableCodegenExtension.kt index a823843cfb0..d72df10b1a5 100644 --- a/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/parcel/ParcelableCodegenExtension.kt +++ b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/parcel/ParcelableCodegenExtension.kt @@ -7,7 +7,6 @@ package org.jetbrains.kotlin.android.parcel import kotlinx.android.parcel.TypeParceler import org.jetbrains.kotlin.android.parcel.ParcelableResolveExtension.Companion.createMethod -import org.jetbrains.kotlin.android.parcel.ParcelableSyntheticComponent.* import org.jetbrains.kotlin.android.parcel.serializers.* import org.jetbrains.kotlin.android.parcel.ParcelableSyntheticComponent.ComponentKind.* import org.jetbrains.kotlin.builtins.KotlinBuiltIns @@ -44,13 +43,10 @@ import org.jetbrains.org.objectweb.asm.Opcodes.* import org.jetbrains.org.objectweb.asm.Type import java.io.FileDescriptor -open class ParcelableCodegenExtension : ExpressionCodegenExtension { +open class ParcelableCodegenExtension : ParcelableExtensionBase, ExpressionCodegenExtension { - private companion object { + companion object { private val FILE_DESCRIPTOR_FQNAME = FqName(FileDescriptor::class.java.canonicalName) - private val CREATOR_NAME = Name.identifier("CREATOR") - - private val ALLOWED_CLASS_KINDS = listOf(ClassKind.CLASS, ClassKind.OBJECT, ClassKind.ENUM_CLASS) } @Deprecated( @@ -60,8 +56,6 @@ open class ParcelableCodegenExtension : ExpressionCodegenExtension { ) protected open fun isExperimental(element: KtElement) = true - protected val ClassDescriptor.isParcelableClassDescriptor get() = kind in ALLOWED_CLASS_KINDS && isParcelize - override val shouldGenerateClassSyntheticPartsInLightClassesMode: Boolean get() = true @@ -99,32 +93,6 @@ open class ParcelableCodegenExtension : ExpressionCodegenExtension { } } - protected fun ClassDescriptor.hasCreatorField(): Boolean { - val companionObject = companionObjectDescriptor ?: return false - - if (companionObject.name == CREATOR_NAME) { - return true - } - - return companionObject.unsubstitutedMemberScope - .getContributedVariables(CREATOR_NAME, NoLookupLocation.FROM_BACKEND) - .isNotEmpty() - } - - protected fun ClassDescriptor.hasSyntheticDescribeContents() = hasParcelizeSyntheticMethod(ComponentKind.DESCRIBE_CONTENTS) - - protected fun ClassDescriptor.hasSyntheticWriteToParcel() = hasParcelizeSyntheticMethod(ComponentKind.WRITE_TO_PARCEL) - - protected fun ClassDescriptor.hasParcelizeSyntheticMethod(componentKind: ParcelableSyntheticComponent.ComponentKind): Boolean { - val methodName = Name.identifier(componentKind.methodName) - - val writeToParcelMethods = unsubstitutedMemberScope - .getContributedFunctions(methodName, NoLookupLocation.FROM_BACKEND) - .filter { it is ParcelableSyntheticComponent && it.componentKind == componentKind } - - return writeToParcelMethods.size == 1 - } - private fun getCompanionClassType(containerAsmType: Type, parcelerObject: ClassDescriptor): Pair { val shortName = parcelerObject.name return Pair(Type.getObjectType(containerAsmType.internalName + "\$$shortName"), shortName.asString()) @@ -411,12 +379,6 @@ open class ParcelableCodegenExtension : ExpressionCodegenExtension { } }) } - - protected fun ClassDescriptor.findFunction(componentKind: ParcelableSyntheticComponent.ComponentKind): SimpleFunctionDescriptor? { - return unsubstitutedMemberScope - .getContributedFunctions(Name.identifier(componentKind.methodName), WHEN_GET_ALL_DESCRIPTORS) - .firstOrNull { (it as? ParcelableSyntheticComponent)?.componentKind == componentKind } - } } internal fun getTypeParcelers(annotations: Annotations): List { diff --git a/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/parcel/serializers/ParcelableExtensionBase.kt b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/parcel/serializers/ParcelableExtensionBase.kt new file mode 100644 index 00000000000..8285ba06fd3 --- /dev/null +++ b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/parcel/serializers/ParcelableExtensionBase.kt @@ -0,0 +1,58 @@ +/* + * 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.android.parcel.serializers + +import org.jetbrains.kotlin.android.parcel.ParcelableSyntheticComponent +import org.jetbrains.kotlin.android.parcel.isParcelize +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.incremental.components.NoLookupLocation +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.android.parcel.ParcelableSyntheticComponent.ComponentKind.* +import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor + +interface ParcelableExtensionBase { + + companion object { + private val CREATOR_NAME = Name.identifier("CREATOR") + + private val ALLOWED_CLASS_KINDS = listOf(ClassKind.CLASS, ClassKind.OBJECT, ClassKind.ENUM_CLASS) + } + + fun ClassDescriptor.hasCreatorField(): Boolean { + val companionObject = companionObjectDescriptor ?: return false + + if (companionObject.name == CREATOR_NAME) { + return true + } + + return companionObject.unsubstitutedMemberScope + .getContributedVariables(CREATOR_NAME, NoLookupLocation.FROM_BACKEND) + .isNotEmpty() + } + + val ClassDescriptor.isParcelableClassDescriptor get() = kind in ALLOWED_CLASS_KINDS && isParcelize + + fun ClassDescriptor.hasSyntheticDescribeContents() = hasParcelizeSyntheticMethod(DESCRIBE_CONTENTS) + + fun ClassDescriptor.hasSyntheticWriteToParcel() = hasParcelizeSyntheticMethod(WRITE_TO_PARCEL) + + fun ClassDescriptor.findFunction(componentKind: ParcelableSyntheticComponent.ComponentKind): SimpleFunctionDescriptor? { + return unsubstitutedMemberScope + .getContributedFunctions(Name.identifier(componentKind.methodName), NoLookupLocation.WHEN_GET_ALL_DESCRIPTORS) + .firstOrNull { (it as? ParcelableSyntheticComponent)?.componentKind == componentKind } + } + + private fun ClassDescriptor.hasParcelizeSyntheticMethod(componentKind: ParcelableSyntheticComponent.ComponentKind): Boolean { + val methodName = Name.identifier(componentKind.methodName) + + val writeToParcelMethods = unsubstitutedMemberScope + .getContributedFunctions(methodName, NoLookupLocation.FROM_BACKEND) + .filter { it is ParcelableSyntheticComponent && it.componentKind == componentKind } + + return writeToParcelMethods.size == 1 + } +} \ No newline at end of file diff --git a/plugins/android-extensions/android-extensions-idea/src/org/jetbrains/kotlin/android/parcel/IDEParcelableApplicabilityExtension.kt b/plugins/android-extensions/android-extensions-idea/src/org/jetbrains/kotlin/android/parcel/IDEParcelableApplicabilityExtension.kt deleted file mode 100644 index a2ef9c0a619..00000000000 --- a/plugins/android-extensions/android-extensions-idea/src/org/jetbrains/kotlin/android/parcel/IDEParcelableApplicabilityExtension.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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.android.parcel - -import org.jetbrains.kotlin.util.isAnnotated -import org.jetbrains.kotlin.util.isOrdinaryClass -import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.extensions.LightClassApplicabilityCheckExtension -import org.jetbrains.kotlin.extensions.LightClassApplicabilityType -import org.jetbrains.kotlin.psi.KtDeclaration -import org.jetbrains.kotlin.extensions.LightClassApplicabilityType.LightClass -import org.jetbrains.kotlin.extensions.LightClassApplicabilityType.UltraLightClass - -class IDEParcelableApplicabilityExtension : LightClassApplicabilityCheckExtension { - - override fun checkApplicabilityType(declaration: KtDeclaration, descriptor: Lazy): LightClassApplicabilityType { - - return UltraLightClass -// if (!declaration.isOrdinaryClass || !declaration.isAnnotated) return UltraLightClass -// -// val descriptorValue = descriptor.value ?: return UltraLightClass -// -// val classDescriptor = (descriptorValue as? ClassDescriptor) -// ?: descriptorValue.containingDeclaration as? ClassDescriptor -// ?: return UltraLightClass -// -// return if (classDescriptor.isParcelize) LightClass else UltraLightClass - } -} \ No newline at end of file diff --git a/plugins/android-extensions/android-extensions-idea/src/org/jetbrains/kotlin/android/parcel/IDEParcelableCodegenExtension.kt b/plugins/android-extensions/android-extensions-idea/src/org/jetbrains/kotlin/android/parcel/IDEParcelableCodegenExtension.kt index 8c0fc7d0faf..50d9c66c709 100644 --- a/plugins/android-extensions/android-extensions-idea/src/org/jetbrains/kotlin/android/parcel/IDEParcelableCodegenExtension.kt +++ b/plugins/android-extensions/android-extensions-idea/src/org/jetbrains/kotlin/android/parcel/IDEParcelableCodegenExtension.kt @@ -5,100 +5,13 @@ package org.jetbrains.kotlin.android.parcel -import com.intellij.psi.impl.light.LightFieldBuilder import org.jetbrains.kotlin.android.synthetic.idea.androidExtensionsIsExperimental -import org.jetbrains.kotlin.asJava.UltraLightClassCodegenSupport -import org.jetbrains.kotlin.asJava.classes.KtUltraLightClass -import org.jetbrains.kotlin.asJava.classes.createGeneratedMethodFromDescriptor -import org.jetbrains.kotlin.asJava.elements.* -import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.idea.caches.project.getModuleInfo -import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtElement -import org.jetbrains.kotlin.util.isAnnotated -import org.jetbrains.kotlin.util.isOrdinaryClass -class IDEParcelableCodegenExtension : ParcelableCodegenExtension(), UltraLightClassCodegenSupport { +class IDEParcelableCodegenExtension : ParcelableCodegenExtension() { override fun isExperimental(element: KtElement): Boolean { val moduleInfo = element.getModuleInfo() return moduleInfo.androidExtensionsIsExperimental } - - private fun tryGetParcelableClass( - declaration: KtDeclaration, - descriptor: Lazy - ): ClassDescriptor? { - - if (!declaration.isOrdinaryClass || !declaration.isAnnotated) return null - - val descriptorValue = descriptor.value ?: return null - - val parcelableClass = (descriptorValue as? ClassDescriptor) - ?: descriptorValue.containingDeclaration as? ClassDescriptor - ?: return null - - if (!parcelableClass.isParcelableClassDescriptor) return null - - return parcelableClass - } - - override fun interceptFieldsBuilding( - declaration: KtDeclaration, - descriptor: Lazy, - containingDeclaration: KtUltraLightClass, - fieldsList: MutableList - ) { - - val parcelableClass = tryGetParcelableClass( - declaration = declaration, - descriptor = descriptor - ) ?: return - - if (parcelableClass.hasCreatorField()) return - - val fieldWrapper = KtLightFieldImpl.KtLightFieldForSourceDeclaration( - origin = null, - computeDelegate = { - LightFieldBuilder("CREATOR", "android.os.Parcelable.Creator", containingDeclaration).also { - it.setModifiers("public", "static", "final") - } - }, - containingClass = containingDeclaration, - dummyDelegate = null - ) - - fieldsList.add(fieldWrapper) - } - - override fun interceptMethodsBuilding( - declaration: KtDeclaration, - descriptor: Lazy, - containingDeclaration: KtUltraLightClass, - methodsList: MutableList - ) { - - val parcelableClass = tryGetParcelableClass( - declaration = declaration, - descriptor = descriptor - ) ?: return - - with(parcelableClass) { - if (hasSyntheticDescribeContents()) { - findFunction(ParcelableSyntheticComponent.ComponentKind.DESCRIBE_CONTENTS)?.let { - methodsList.add( - containingDeclaration.createGeneratedMethodFromDescriptor(it) - ) - } - } - - if (hasSyntheticWriteToParcel()) { - findFunction(ParcelableSyntheticComponent.ComponentKind.WRITE_TO_PARCEL)?.let { - methodsList.add( - containingDeclaration.createGeneratedMethodFromDescriptor(it) - ) - } - } - } - } } \ No newline at end of file diff --git a/plugins/android-extensions/android-extensions-idea/src/org/jetbrains/kotlin/android/parcel/ParcelableUltraLightClassModifierExtension.kt b/plugins/android-extensions/android-extensions-idea/src/org/jetbrains/kotlin/android/parcel/ParcelableUltraLightClassModifierExtension.kt new file mode 100644 index 00000000000..3283c11ab97 --- /dev/null +++ b/plugins/android-extensions/android-extensions-idea/src/org/jetbrains/kotlin/android/parcel/ParcelableUltraLightClassModifierExtension.kt @@ -0,0 +1,101 @@ +/* + * 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.android.parcel + +import com.intellij.psi.impl.light.LightFieldBuilder +import org.jetbrains.kotlin.android.parcel.serializers.ParcelableExtensionBase +import org.jetbrains.kotlin.asJava.UltraLightClassModifierExtension +import org.jetbrains.kotlin.asJava.classes.KtUltraLightClass +import org.jetbrains.kotlin.asJava.classes.createGeneratedMethodFromDescriptor +import org.jetbrains.kotlin.asJava.elements.KtLightField +import org.jetbrains.kotlin.asJava.elements.KtLightFieldImpl +import org.jetbrains.kotlin.asJava.elements.KtLightMethod +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.util.isAnnotated +import org.jetbrains.kotlin.util.isOrdinaryClass + +class ParcelableUltraLightClassModifierExtension : ParcelableExtensionBase, UltraLightClassModifierExtension { + + private fun tryGetParcelableClass( + declaration: KtDeclaration, + descriptor: Lazy + ): ClassDescriptor? { + + if (!declaration.isOrdinaryClass || !declaration.isAnnotated) return null + + val descriptorValue = descriptor.value ?: return null + + val parcelableClass = (descriptorValue as? ClassDescriptor) + ?: descriptorValue.containingDeclaration as? ClassDescriptor + ?: return null + + if (!parcelableClass.isParcelableClassDescriptor) return null + + return parcelableClass + } + + override fun interceptFieldsBuilding( + declaration: KtDeclaration, + descriptor: Lazy, + containingDeclaration: KtUltraLightClass, + fieldsList: MutableList + ) { + + val parcelableClass = tryGetParcelableClass( + declaration = declaration, + descriptor = descriptor + ) ?: return + + if (parcelableClass.hasCreatorField()) return + + val fieldWrapper = KtLightFieldImpl.KtLightFieldForSourceDeclaration( + origin = null, + computeDelegate = { + LightFieldBuilder("CREATOR", "android.os.Parcelable.Creator", containingDeclaration).also { + it.setModifiers("public", "static", "final") + } + }, + containingClass = containingDeclaration, + dummyDelegate = null + ) + + fieldsList.add(fieldWrapper) + } + + override fun interceptMethodsBuilding( + declaration: KtDeclaration, + descriptor: Lazy, + containingDeclaration: KtUltraLightClass, + methodsList: MutableList + ) { + + val parcelableClass = tryGetParcelableClass( + declaration = declaration, + descriptor = descriptor + ) ?: return + + with(parcelableClass) { + if (hasSyntheticDescribeContents()) { + findFunction(ParcelableSyntheticComponent.ComponentKind.DESCRIBE_CONTENTS)?.let { + methodsList.add( + containingDeclaration.createGeneratedMethodFromDescriptor(it) + ) + } + } + + if (hasSyntheticWriteToParcel()) { + findFunction(ParcelableSyntheticComponent.ComponentKind.WRITE_TO_PARCEL)?.let { + methodsList.add( + containingDeclaration.createGeneratedMethodFromDescriptor(it) + ) + } + } + } + } + +} \ No newline at end of file diff --git a/plugins/annotation-based-compiler-plugins-ide-support/src/AnnotationBasedLightClassApplicabilityExtension.kt b/plugins/annotation-based-compiler-plugins-ide-support/src/AnnotationBasedLightClassApplicabilityExtension.kt deleted file mode 100644 index c1674e14ad7..00000000000 --- a/plugins/annotation-based-compiler-plugins-ide-support/src/AnnotationBasedLightClassApplicabilityExtension.kt +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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.annotation.plugin.ide - -import org.jetbrains.kotlin.util.isAnnotated -import org.jetbrains.kotlin.util.isOrdinaryClass -import com.intellij.openapi.project.Project -import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.extensions.AnnotationBasedExtension -import org.jetbrains.kotlin.extensions.LightClassApplicabilityCheckExtension -import org.jetbrains.kotlin.extensions.LightClassApplicabilityType -import org.jetbrains.kotlin.psi.KtDeclaration -import org.jetbrains.kotlin.psi.KtModifierListOwner -import org.jetbrains.kotlin.extensions.LightClassApplicabilityType.LightClass -import org.jetbrains.kotlin.extensions.LightClassApplicabilityType.UltraLightClass - -abstract class AnnotationBasedLightClassApplicabilityExtension(project: Project, annotationOptionPrefix: String) : - LightClassApplicabilityCheckExtension, - AnnotationBasedExtension -{ - private val cachedAnnotationsNames = CachedAnnotationNames(project, annotationOptionPrefix) - - override fun getAnnotationFqNames(modifierListOwner: KtModifierListOwner?): List = - cachedAnnotationsNames.getAnnotationNames(modifierListOwner) - - override fun checkApplicabilityType(declaration: KtDeclaration, descriptor: Lazy): LightClassApplicabilityType { - - return UltraLightClass -// -// if (!declaration.isOrdinaryClass || !declaration.isAnnotated) return UltraLightClass -// -// if (cachedAnnotationsNames.getAnnotationNames(declaration).isEmpty()) return UltraLightClass -// -// val descriptorValue = descriptor.value ?: return UltraLightClass -// -// val classDescriptor = (descriptorValue as? ClassDescriptor) -// ?: descriptorValue.containingDeclaration as? ClassDescriptor -// ?: return UltraLightClass -// -// val hasSpecialAnnotation = run { classDescriptor.hasSpecialAnnotation(declaration) } -// -// return if (hasSpecialAnnotation) LightClass else UltraLightClass - } -} \ No newline at end of file diff --git a/plugins/kotlin-serialization/kotlin-serialization-ide/src/org/jetbrains/kotlinx/serialization/idea/IdeSerializationPluginApplicabilityExtension.kt b/plugins/kotlin-serialization/kotlin-serialization-ide/src/org/jetbrains/kotlinx/serialization/idea/IdeSerializationPluginApplicabilityExtension.kt deleted file mode 100644 index 26b5d4d7c39..00000000000 --- a/plugins/kotlin-serialization/kotlin-serialization-ide/src/org/jetbrains/kotlinx/serialization/idea/IdeSerializationPluginApplicabilityExtension.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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.kotlinx.serialization.idea - -import org.jetbrains.kotlin.util.isAnnotated -import org.jetbrains.kotlin.util.isOrdinaryClass -import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.extensions.LightClassApplicabilityCheckExtension -import org.jetbrains.kotlin.extensions.LightClassApplicabilityType -import org.jetbrains.kotlin.psi.KtDeclaration -import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations.serializableAnnotationFqName -import org.jetbrains.kotlin.extensions.LightClassApplicabilityType.LightClass -import org.jetbrains.kotlin.extensions.LightClassApplicabilityType.UltraLightClass - -class IdeSerializationPluginApplicabilityExtension : LightClassApplicabilityCheckExtension { - override fun checkApplicabilityType(declaration: KtDeclaration, descriptor: Lazy): LightClassApplicabilityType { - - if (!declaration.isOrdinaryClass || !declaration.isAnnotated) return UltraLightClass - - return (descriptor.value as? ClassDescriptor)?.let { - getIfEnabledOn(it) { - if (it.annotations.hasAnnotation(serializableAnnotationFqName)) LightClass - else UltraLightClass - } - } ?: UltraLightClass - } -} \ No newline at end of file diff --git a/plugins/noarg/noarg-cli/src/AbstractNoArgExpressionCodegenExtension.kt b/plugins/noarg/noarg-cli/src/AbstractNoArgExpressionCodegenExtension.kt index 4c95a08c217..21b18c1f19d 100644 --- a/plugins/noarg/noarg-cli/src/AbstractNoArgExpressionCodegenExtension.kt +++ b/plugins/noarg/noarg-cli/src/AbstractNoArgExpressionCodegenExtension.kt @@ -30,7 +30,8 @@ class CliNoArgExpressionCodegenExtension(private val annotations: List, override fun getAnnotationFqNames(modifierListOwner: KtModifierListOwner?): List = annotations } -abstract class AbstractNoArgExpressionCodegenExtension(val invokeInitializers: Boolean) : ExpressionCodegenExtension, AnnotationBasedExtension { +abstract class AbstractNoArgExpressionCodegenExtension(val invokeInitializers: Boolean) : ExpressionCodegenExtension, + AnnotationBasedExtension { override fun generateClassSyntheticParts(codegen: ImplementationBodyCodegen) = with(codegen) { if (shouldGenerateNoArgConstructor()) { @@ -48,7 +49,7 @@ abstract class AbstractNoArgExpressionCodegenExtension(val invokeInitializers: B // If a parent sealed class has not a zero-parameter constructor, user must write @NoArg annotation for the parent class as well, // and then we generate ()V val isParentASealedClassWithDefaultConstructor = - superClass.modality == Modality.SEALED && superClass.constructors.any { it.isZeroParameterConstructor() } + superClass.modality == Modality.SEALED && superClass.constructors.any { isZeroParameterConstructor(it) } functionCodegen.generateMethod(JvmDeclarationOrigin.NO_ORIGIN, constructorDescriptor, object : CodegenBased(state) { override fun doGenerateBody(codegen: ExpressionCodegen, signature: JvmMethodSignature) { @@ -72,15 +73,6 @@ abstract class AbstractNoArgExpressionCodegenExtension(val invokeInitializers: B }) } - protected fun createNoArgConstructorDescriptor(containingClass: ClassDescriptor): ConstructorDescriptor { - return ClassConstructorDescriptorImpl.createSynthesized(containingClass, Annotations.EMPTY, false, SourceElement.NO_SOURCE).apply { - initialize( - null, calculateDispatchReceiverParameter(), emptyList(), emptyList(), - containingClass.builtIns.unitType, Modality.OPEN, Visibilities.PUBLIC - ) - } - } - private fun ImplementationBodyCodegen.shouldGenerateNoArgConstructor(): Boolean { val origin = myClass as? KtClass ?: return false @@ -88,14 +80,30 @@ abstract class AbstractNoArgExpressionCodegenExtension(val invokeInitializers: B return false } - return descriptor.constructors.none { it.isZeroParameterConstructor() } - } - - private fun ClassConstructorDescriptor.isZeroParameterConstructor(): Boolean { - val parameters = this.valueParameters - return parameters.isEmpty() || - (parameters.all { it.declaresDefaultValue() } && (isPrimary || findJvmOverloadsAnnotation() != null)) + return descriptor.constructors.none { isZeroParameterConstructor(it) } } override val shouldGenerateClassSyntheticPartsInLightClassesMode = true + + companion object { + + fun isZeroParameterConstructor(constructor: ClassConstructorDescriptor): Boolean { + val parameters = constructor.valueParameters + return parameters.isEmpty() || + (parameters.all { it.declaresDefaultValue() } && (constructor.isPrimary || constructor.findJvmOverloadsAnnotation() != null)) + } + + fun createNoArgConstructorDescriptor(containingClass: ClassDescriptor): ConstructorDescriptor = + ClassConstructorDescriptorImpl.createSynthesized(containingClass, Annotations.EMPTY, false, SourceElement.NO_SOURCE).apply { + initialize( + null, + calculateDispatchReceiverParameter(), + emptyList(), + emptyList(), + containingClass.builtIns.unitType, + Modality.OPEN, + Visibilities.PUBLIC + ) + } + } } diff --git a/plugins/noarg/noarg-ide/src/IdeArgExpressionCodegenExtension.kt b/plugins/noarg/noarg-ide/src/IdeArgExpressionCodegenExtension.kt index 5523480858b..032792e5b94 100644 --- a/plugins/noarg/noarg-ide/src/IdeArgExpressionCodegenExtension.kt +++ b/plugins/noarg/noarg-ide/src/IdeArgExpressionCodegenExtension.kt @@ -8,49 +8,13 @@ package org.jetbrains.kotlin.noarg.ide import com.intellij.openapi.project.Project import org.jetbrains.kotlin.annotation.plugin.ide.CachedAnnotationNames import org.jetbrains.kotlin.annotation.plugin.ide.getAnnotationNames -import org.jetbrains.kotlin.asJava.UltraLightClassCodegenSupport -import org.jetbrains.kotlin.asJava.classes.KtUltraLightClass -import org.jetbrains.kotlin.asJava.classes.createGeneratedMethodFromDescriptor -import org.jetbrains.kotlin.asJava.elements.KtLightMethod -import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.noarg.AbstractNoArgExpressionCodegenExtension -import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtModifierListOwner -import org.jetbrains.kotlin.util.isAnnotated -import org.jetbrains.kotlin.util.isOrdinaryClass -class IdeNoArgExpressionCodegenExtension(project: Project) : - AbstractNoArgExpressionCodegenExtension(invokeInitializers = false), - UltraLightClassCodegenSupport { +class IdeNoArgExpressionCodegenExtension(project: Project) : AbstractNoArgExpressionCodegenExtension(invokeInitializers = false) { private val cachedAnnotationsNames = CachedAnnotationNames(project, NO_ARG_ANNOTATION_OPTION_PREFIX) override fun getAnnotationFqNames(modifierListOwner: KtModifierListOwner?): List = cachedAnnotationsNames.getAnnotationNames(modifierListOwner) - - override fun interceptMethodsBuilding( - declaration: KtDeclaration, - descriptor: Lazy, - containingDeclaration: KtUltraLightClass, - methodsList: MutableList - ) { - if (!declaration.isOrdinaryClass || !declaration.isAnnotated) return - - if (cachedAnnotationsNames.getAnnotationNames(declaration).isEmpty()) return - - val descriptorValue = descriptor.value ?: return - - val classDescriptor = (descriptorValue as? ClassDescriptor) - ?: descriptorValue.containingDeclaration as? ClassDescriptor - ?: return - - if (!run { classDescriptor.hasSpecialAnnotation(declaration) }) return - - val parentClass = containingDeclaration as? KtUltraLightClass ?: return - - val constructorDescriptor = createNoArgConstructorDescriptor(classDescriptor) - - methodsList.add(parentClass.createGeneratedMethodFromDescriptor(constructorDescriptor)) - } } diff --git a/plugins/noarg/noarg-ide/src/IdeNoArgDeclarationChecker.kt b/plugins/noarg/noarg-ide/src/IdeNoArgDeclarationChecker.kt index 01538f18e3c..8c770b17c53 100644 --- a/plugins/noarg/noarg-ide/src/IdeNoArgDeclarationChecker.kt +++ b/plugins/noarg/noarg-ide/src/IdeNoArgDeclarationChecker.kt @@ -1,23 +1,11 @@ /* - * Copyright 2010-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * 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.noarg.ide import com.intellij.openapi.project.Project -import org.jetbrains.kotlin.annotation.plugin.ide.AnnotationBasedLightClassApplicabilityExtension import org.jetbrains.kotlin.annotation.plugin.ide.CachedAnnotationNames import org.jetbrains.kotlin.annotation.plugin.ide.getAnnotationNames import org.jetbrains.kotlin.noarg.NoArgCommandLineProcessor @@ -27,9 +15,6 @@ import org.jetbrains.kotlin.psi.KtModifierListOwner internal val NO_ARG_ANNOTATION_OPTION_PREFIX = "plugin:${NoArgCommandLineProcessor.PLUGIN_ID}:${NoArgCommandLineProcessor.ANNOTATION_OPTION.optionName}=" -class IdeNoArgApplicabilityExtension(project: Project) : - AnnotationBasedLightClassApplicabilityExtension(project, NO_ARG_ANNOTATION_OPTION_PREFIX) - class IdeNoArgDeclarationChecker(project: Project) : AbstractNoArgDeclarationChecker() { private val cachedAnnotationNames = CachedAnnotationNames(project, NO_ARG_ANNOTATION_OPTION_PREFIX) diff --git a/plugins/noarg/noarg-ide/src/NoArgUltraLightClassModifierExtension.kt b/plugins/noarg/noarg-ide/src/NoArgUltraLightClassModifierExtension.kt new file mode 100644 index 00000000000..bb3cc9dd149 --- /dev/null +++ b/plugins/noarg/noarg-ide/src/NoArgUltraLightClassModifierExtension.kt @@ -0,0 +1,73 @@ +/* + * 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.noarg.ide + +import com.intellij.openapi.project.Project +import org.jetbrains.kotlin.annotation.plugin.ide.CachedAnnotationNames +import org.jetbrains.kotlin.annotation.plugin.ide.getAnnotationNames +import org.jetbrains.kotlin.asJava.UltraLightClassModifierExtension +import org.jetbrains.kotlin.asJava.classes.KtUltraLightClass +import org.jetbrains.kotlin.asJava.classes.createGeneratedMethodFromDescriptor +import org.jetbrains.kotlin.asJava.elements.KtLightMethod +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.extensions.AnnotationBasedExtension +import org.jetbrains.kotlin.noarg.AbstractNoArgExpressionCodegenExtension +import org.jetbrains.kotlin.noarg.AbstractNoArgExpressionCodegenExtension.Companion.isZeroParameterConstructor +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.util.isAnnotated +import org.jetbrains.kotlin.util.isOrdinaryClass + +class NoArgUltraLightClassModifierExtension(project: Project) : + AnnotationBasedExtension, + UltraLightClassModifierExtension { + + private val cachedAnnotationsNames = CachedAnnotationNames(project, NO_ARG_ANNOTATION_OPTION_PREFIX) + + override fun getAnnotationFqNames(modifierListOwner: KtModifierListOwner?): List = + cachedAnnotationsNames.getAnnotationNames(modifierListOwner) + + private fun isSuitableDeclaration(declaration: KtDeclaration): Boolean { + if (getAnnotationFqNames(declaration).isEmpty()) return false + + if (!declaration.isOrdinaryClass || declaration !is KtClassOrObject) return false + + if (declaration.allConstructors.isEmpty()) return false + + if (declaration.allConstructors.any { it.getValueParameters().isEmpty() }) return false + + if (declaration.superTypeListEntries.isEmpty() && !declaration.isAnnotated) return false + + return true + } + + override fun interceptMethodsBuilding( + declaration: KtDeclaration, + descriptor: Lazy, + containingDeclaration: KtUltraLightClass, + methodsList: MutableList + ) { + val parentClass = containingDeclaration as? KtUltraLightClass ?: return + + if (methodsList.any { it.isConstructor && it.parameters.isEmpty() }) return + + if (!isSuitableDeclaration(declaration)) return + + val descriptorValue = descriptor.value ?: return + + val classDescriptor = (descriptorValue as? ClassDescriptor) + ?: descriptorValue.containingDeclaration as? ClassDescriptor + ?: return + + if (!classDescriptor.hasSpecialAnnotation(declaration)) return + + if (classDescriptor.constructors.any { isZeroParameterConstructor(it) }) return + + val constructorDescriptor = AbstractNoArgExpressionCodegenExtension.createNoArgConstructorDescriptor(classDescriptor) + + methodsList.add(parentClass.createGeneratedMethodFromDescriptor(constructorDescriptor)) + } +} \ No newline at end of file diff --git a/plugins/noarg/noarg-ide/test/org/jetbrains/kotlin/noarg/TestNoArgForLightClass.kt b/plugins/noarg/noarg-ide/test/org/jetbrains/kotlin/noarg/TestNoArgForLightClass.kt index f0d40021e7f..0bb7858e39a 100644 --- a/plugins/noarg/noarg-ide/test/org/jetbrains/kotlin/noarg/TestNoArgForLightClass.kt +++ b/plugins/noarg/noarg-ide/test/org/jetbrains/kotlin/noarg/TestNoArgForLightClass.kt @@ -16,6 +16,7 @@ import org.jetbrains.kotlin.test.JUnit3WithIdeaConfigurationRunner import org.junit.runner.RunWith private const val targetClassName = "TargetClassName" +private const val baseClassName = "BaseClassName" private const val noArgAnnotationName = "HelloNoArg" @RunWith(JUnit3WithIdeaConfigurationRunner::class) @@ -51,4 +52,23 @@ class TestNoArgForLightClass : KotlinLightCodeInsightFixtureTestCase() { assertEquals(constructors.size, 2) assertTrue(constructors.any { it.parameters.isEmpty() }) } + + fun testNoArgDerivedAnnotation() { + val file = myFixture.configureByText( + "A.kt", + "annotation class $noArgAnnotationName\n" + + "@$noArgAnnotationName class $baseClassName(val e: Int)\n" + + "class $targetClassName(val k: Int) : $baseClassName(k)" + ) as KtFile + + val classes = file.classes + assertEquals(3, classes.size) + + val targetClass = classes.firstOrNull { it.name == targetClassName } + ?: error { "Expected class $targetClassName not found" } + + val constructors = targetClass.constructors + assertEquals(constructors.size, 2) + assertTrue(constructors.any { it.parameters.isEmpty() }) + } } \ No newline at end of file