diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/AnnotationCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/AnnotationCodegen.java index c0abbf672e6..a1339d07296 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/AnnotationCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/AnnotationCodegen.java @@ -64,7 +64,7 @@ public abstract class AnnotationCodegen { public static final List FIELD_FLAGS = Arrays.asList( new JvmFlagAnnotation(JvmAnnotationUtilKt.VOLATILE_ANNOTATION_FQ_NAME.asString(), Opcodes.ACC_VOLATILE), - new JvmFlagAnnotation("kotlin.jvm.Transient", Opcodes.ACC_TRANSIENT) + new JvmFlagAnnotation(JvmAnnotationUtilKt.TRANSIENT_ANNOTATION_FQ_NAME.asString(), Opcodes.ACC_TRANSIENT) ); public static final List METHOD_FLAGS = Arrays.asList( diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java index 204c941ee16..59602979c6a 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java @@ -1112,34 +1112,37 @@ public class FunctionCodegen { } @NotNull - public static String[] getThrownExceptions(@NotNull FunctionDescriptor function, @NotNull KotlinTypeMapper typeMapper) { + public static String[] getThrownExceptions(@NotNull FunctionDescriptor function, @NotNull KotlinTypeMapper mapper) { + return ArrayUtil.toStringArray(CollectionsKt.map(getThrownExceptions(function), d -> mapper.mapClass(d).getInternalName())); + } + + @NotNull + public static List getThrownExceptions(@NotNull FunctionDescriptor function) { AnnotationDescriptor annotation = function.getAnnotations().findAnnotation(new FqName("kotlin.throws")); if (annotation == null) { annotation = function.getAnnotations().findAnnotation(new FqName("kotlin.jvm.Throws")); } - if (annotation == null) return ArrayUtil.EMPTY_STRING_ARRAY; + if (annotation == null) return Collections.emptyList(); Collection> values = annotation.getAllValueArguments().values(); - if (values.isEmpty()) return ArrayUtil.EMPTY_STRING_ARRAY; + if (values.isEmpty()) return Collections.emptyList(); Object value = values.iterator().next(); - if (!(value instanceof ArrayValue)) return ArrayUtil.EMPTY_STRING_ARRAY; + if (!(value instanceof ArrayValue)) return Collections.emptyList(); ArrayValue arrayValue = (ArrayValue) value; - List strings = CollectionsKt.mapNotNull( + return CollectionsKt.mapNotNull( arrayValue.getValue(), (ConstantValue constant) -> { if (constant instanceof KClassValue) { - ClassDescriptor classDescriptor = DescriptorUtils.getClassDescriptorForType( + return DescriptorUtils.getClassDescriptorForType( ((KClassValue) constant).getArgumentType(DescriptorUtilsKt.getModule(function)) ); - return typeMapper.mapClass(classDescriptor).getInternalName(); } return null; } ); - return ArrayUtil.toStringArray(strings); } void generateDefaultIfNeeded( diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java index d358409b3be..09867966028 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java @@ -398,8 +398,8 @@ public class PropertyCodegen { modifiers |= ACC_SYNTHETIC; } - KotlinType kotlinType = - isDelegate ? getDelegateTypeForProperty((KtProperty) element, propertyDescriptor) : propertyDescriptor.getType(); + KotlinType kotlinType = isDelegate ? getDelegateTypeForProperty((KtProperty) element, propertyDescriptor, bindingContext) + : propertyDescriptor.getType(); Type type = typeMapper.mapType(kotlinType); ClassBuilder builder = v; @@ -438,7 +438,11 @@ public class PropertyCodegen { } @NotNull - private KotlinType getDelegateTypeForProperty(@NotNull KtProperty p, @NotNull PropertyDescriptor propertyDescriptor) { + public static KotlinType getDelegateTypeForProperty( + @NotNull KtProperty p, + @NotNull PropertyDescriptor propertyDescriptor, + @NotNull BindingContext bindingContext + ) { KotlinType delegateType = null; ResolvedCall provideDelegateResolvedCall = diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java index 502984aa29f..477bbdcc35b 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java @@ -1419,7 +1419,7 @@ public class KotlinTypeMapper { * In that case the generated method's return type should be boxed: otherwise it's not possible to use * this class from Java since javac issues errors when loading the class (incompatible return types) */ - private boolean forceBoxedReturnType(@NotNull FunctionDescriptor descriptor) { + public boolean forceBoxedReturnType(@NotNull FunctionDescriptor descriptor) { if (isBoxMethodForInlineClass(descriptor)) return true; //noinspection ConstantConditions 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 a698b88fae7..e266e0e3433 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 @@ -39,6 +39,8 @@ 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 createUltraLightClass(element: KtClassOrObject) = null + override fun createDataHolderForClass(classOrObject: KtClassOrObject, builder: LightClassBuilder): LightClassDataHolder.ForClass { //force resolve companion for light class generation traceHolder.bindingContext.get(BindingContext.CLASS, classOrObject)?.companionObjectDescriptor diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/annotations/jvmAnnotationUtil.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/annotations/jvmAnnotationUtil.kt index c1d7ff180ef..f41b9c26a56 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/annotations/jvmAnnotationUtil.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/annotations/jvmAnnotationUtil.kt @@ -27,6 +27,9 @@ val STRICTFP_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.Strictfp") @JvmField val VOLATILE_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.Volatile") +@JvmField +val TRANSIENT_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.Transient") + fun DeclarationDescriptor.findJvmOverloadsAnnotation(): AnnotationDescriptor? = annotations.findAnnotation(JVM_OVERLOADS_FQ_NAME) 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 ef078ce44ec..6e4a0a7f2fe 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/LightClassGenerationSupport.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/LightClassGenerationSupport.kt @@ -21,6 +21,7 @@ import com.intellij.openapi.project.Project import org.jetbrains.kotlin.asJava.builder.LightClassBuilderResult import org.jetbrains.kotlin.asJava.builder.LightClassConstructionContext import org.jetbrains.kotlin.asJava.builder.LightClassDataHolder +import org.jetbrains.kotlin.asJava.classes.KtUltraLightClass import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.BindingContext @@ -40,6 +41,8 @@ abstract class LightClassGenerationSupport { abstract fun analyzeWithContent(element: KtClassOrObject): BindingContext + abstract fun createUltraLightClass(element: KtClassOrObject): KtUltraLightClass? + companion object { @JvmStatic fun getInstance(project: Project): LightClassGenerationSupport { diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/LightClassUtil.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/LightClassUtil.kt index b3893e12244..86e79855433 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/LightClassUtil.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/LightClassUtil.kt @@ -209,7 +209,7 @@ object LightClassUtil { fun buildLightTypeParameterList( owner: PsiTypeParameterListOwner, declaration: KtDeclaration): PsiTypeParameterList { - val builder = KotlinLightTypeParameterListBuilder(owner.manager) + val builder = KotlinLightTypeParameterListBuilder(owner) if (declaration is KtTypeParameterListOwner) { val parameters = declaration.typeParameters for (i in parameters.indices) { 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 08936a32e94..9dffdf5bf0e 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 @@ -22,6 +22,7 @@ import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.project.Project import com.intellij.openapi.util.Comparing import com.intellij.openapi.util.Key +import com.intellij.openapi.util.registry.Registry import com.intellij.psi.* import com.intellij.psi.impl.PsiSubstitutorImpl import com.intellij.psi.impl.java.stubs.PsiJavaFileStub @@ -37,6 +38,7 @@ import com.intellij.psi.util.CachedValuesManager import com.intellij.psi.util.PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT import com.intellij.psi.util.PsiUtilCore import com.intellij.util.IncorrectOperationException +import com.intellij.util.SystemProperties import com.intellij.util.containers.ContainerUtil import org.jetbrains.annotations.NonNls import org.jetbrains.kotlin.asJava.ImpreciseResolveResult @@ -73,15 +75,11 @@ abstract class KtLightClassForSourceDeclaration(protected val classOrObject: KtC : KtLazyLightClass(classOrObject.manager), StubBasedPsiElement> { private val lightIdentifier = KtLightIdentifier(this, classOrObject) - private val _extendsList by lazyPub { - val listDelegate = super.getExtendsList() ?: return@lazyPub null - KtLightPsiReferenceList(listDelegate, this) - } + private val _extendsList by lazyPub { createExtendsList() } + private val _implementsList by lazyPub { createImplementsList() } - private val _implementsList by lazyPub { - val listDelegate = super.getImplementsList() ?: return@lazyPub null - KtLightPsiReferenceList(listDelegate, this) - } + protected open fun createExtendsList(): PsiReferenceList? = super.getExtendsList()?.let { KtLightPsiReferenceList(it, this) } + protected open fun createImplementsList(): PsiReferenceList? = super.getImplementsList()?.let { KtLightPsiReferenceList(it, this) } override val kotlinOrigin: KtClassOrObject = classOrObject @@ -92,7 +90,7 @@ abstract class KtLightClassForSourceDeclaration(protected val classOrObject: KtC override val lightClassData: LightClassData get() = findLightClassData() - open protected fun findLightClassData() = getLightClassDataHolder().findDataForClassOrObject(classOrObject) + protected open fun findLightClassData() = getLightClassDataHolder().findDataForClassOrObject(classOrObject) private fun getJavaFileStub(): PsiJavaFileStub = getLightClassDataHolder().javaFileStub @@ -110,9 +108,9 @@ abstract class KtLightClassForSourceDeclaration(protected val classOrObject: KtC private val _containingFile: PsiFile by lazyPub { object : FakeFileForLightClass( - classOrObject.containingKtFile, - { if (classOrObject.isTopLevel()) this else create(getOutermostClassOrObject(classOrObject))!! }, - { getJavaFileStub() } + classOrObject.containingKtFile, + { if (classOrObject.isTopLevel()) this else create(getOutermostClassOrObject(classOrObject))!! }, + { getJavaFileStub() } ) { override fun findReferenceAt(offset: Int) = ktFile.findReferenceAt(offset) @@ -173,9 +171,9 @@ abstract class KtLightClassForSourceDeclaration(protected val classOrObject: KtC return super.getContainingClass() } - private val _typeParameterList: PsiTypeParameterList by lazyPub { - LightClassUtil.buildLightTypeParameterList(this, classOrObject) - } + private val _typeParameterList: PsiTypeParameterList by lazyPub { buildTypeParameterList() } + + open protected fun buildTypeParameterList() = LightClassUtil.buildLightTypeParameterList(this, classOrObject) override fun getTypeParameterList(): PsiTypeParameterList? = _typeParameterList @@ -322,9 +320,8 @@ abstract class KtLightClassForSourceDeclaration(protected val classOrObject: KtC override fun getNameIdentifier(): KtLightIdentifier? = lightIdentifier - override fun getExtendsList() = _extendsList - - override fun getImplementsList() = _implementsList + override fun getExtendsList(): PsiReferenceList? = _extendsList + override fun getImplementsList(): PsiReferenceList? = _implementsList companion object { private val JAVA_API_STUB = Key.create>("JAVA_API_STUB") @@ -347,6 +344,10 @@ abstract class KtLightClassForSourceDeclaration(protected val classOrObject: KtC return null } + if (Registry.`is`("kotlin.use.ultra.light.classes", false)) { + LightClassGenerationSupport.getInstance(classOrObject.project).createUltraLightClass(classOrObject)?.let { return it } + } + return when { classOrObject is KtObjectDeclaration && classOrObject.isObjectLiteral() -> KtLightClassForAnonymousDeclaration(classOrObject) @@ -456,17 +457,16 @@ abstract class KtLightClassForSourceDeclaration(protected val classOrObject: KtC private val modifiers by lazyPub { containingClass.computeModifiers() } - override fun hasModifierProperty(name: String): Boolean { - if (name != PsiModifier.FINAL) { - return name in modifiers - } + override fun hasModifierProperty(name: String): Boolean = + if (name != PsiModifier.FINAL) name in modifiers else owner.isFinal(PsiModifier.FINAL in modifiers) - val isFinalByPsi = PsiModifier.FINAL in modifiers - // annotations can make class open via 'allopen' plugin - if (!owner.isPossiblyAffectedByAllOpen() || !isFinalByPsi) return isFinalByPsi + } - return clsDelegate.hasModifierProperty(PsiModifier.FINAL) - } + open fun isFinal(isFinalByPsi: Boolean): Boolean { + // annotations can make class open via 'allopen' plugin + if (!isPossiblyAffectedByAllOpen() || !isFinalByPsi) return isFinalByPsi + + return clsDelegate.hasModifierProperty(PsiModifier.FINAL) } } diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassImpl.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassImpl.kt index 8ae76930cd3..c750b41d366 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassImpl.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassImpl.kt @@ -19,7 +19,7 @@ package org.jetbrains.kotlin.asJava.classes import org.jetbrains.kotlin.psi.KtClassOrObject // light class for top level or (inner/nested of top level) source declarations -class KtLightClassImpl(classOrObject: KtClassOrObject) : KtLightClassForSourceDeclaration(classOrObject) { +open class KtLightClassImpl(classOrObject: KtClassOrObject) : KtLightClassForSourceDeclaration(classOrObject) { override fun getQualifiedName() = classOrObject.fqName?.asString() override fun getParent() = if (classOrObject.isTopLevel()) diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightPsi.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightPsi.kt new file mode 100644 index 00000000000..222fbaeba2a --- /dev/null +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightPsi.kt @@ -0,0 +1,657 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.asJava.classes + +import com.google.common.annotations.VisibleForTesting +import com.intellij.lang.Language +import com.intellij.psi.* +import com.intellij.psi.impl.PsiClassImplUtil +import com.intellij.psi.impl.PsiImplUtil +import com.intellij.psi.impl.light.* +import com.intellij.psi.util.TypeConversionUtil +import org.jetbrains.annotations.NonNls +import org.jetbrains.kotlin.asJava.LightClassGenerationSupport +import org.jetbrains.kotlin.asJava.builder.LightClassData +import org.jetbrains.kotlin.asJava.builder.LightMemberOriginForDeclaration +import org.jetbrains.kotlin.asJava.elements.* +import org.jetbrains.kotlin.codegen.FunctionCodegen +import org.jetbrains.kotlin.codegen.PropertyCodegen +import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor +import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget +import org.jetbrains.kotlin.idea.KotlinLanguage +import org.jetbrains.kotlin.lexer.KtTokens.* +import org.jetbrains.kotlin.load.java.JvmAbi +import org.jetbrains.kotlin.load.kotlin.TypeMappingMode +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.SpecialNames +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.containingClass +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.annotations.JVM_STATIC_ANNOTATION_FQ_NAME +import org.jetbrains.kotlin.resolve.annotations.argumentValue +import org.jetbrains.kotlin.resolve.constants.EnumValue +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe +import org.jetbrains.kotlin.resolve.descriptorUtil.isPublishedApi +import org.jetbrains.kotlin.resolve.jvm.annotations.STRICTFP_ANNOTATION_FQ_NAME +import org.jetbrains.kotlin.resolve.jvm.annotations.SYNCHRONIZED_ANNOTATION_FQ_NAME +import org.jetbrains.kotlin.resolve.jvm.annotations.TRANSIENT_ANNOTATION_FQ_NAME +import org.jetbrains.kotlin.resolve.jvm.annotations.VOLATILE_ANNOTATION_FQ_NAME +import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind +import org.jetbrains.kotlin.types.KotlinType + +class KtUltraLightClass(classOrObject: KtClassOrObject, private val support: UltraLightSupport) : + KtLightClassImpl(classOrObject) { + private val tooComplex: Boolean by lazyPub { support.isTooComplexForUltraLightGeneration(classOrObject) } + + override fun isFinal(isFinalByPsi: Boolean) = if (tooComplex) super.isFinal(isFinalByPsi) else isFinalByPsi + + @Volatile + @VisibleForTesting + var isClsDelegateLoaded = false + + override fun findLightClassData(): LightClassData = super.findLightClassData().also { + if (!isClsDelegateLoaded) { + isClsDelegateLoaded = true + check(tooComplex) { "Cls delegate shouldn't be loaded for not too complex ultra-light classes!" } + } + } + + private fun allSuperTypes() = + getDescriptor()?.typeConstructor?.supertypes?.mapNotNull { + it.asPsiType(classOrObject, support, TypeMappingMode.SUPER_TYPE) as? PsiClassType + }.orEmpty() + + override fun createExtendsList(): PsiReferenceList? = + if (tooComplex) super.createExtendsList() + else LightReferenceListBuilder(manager, language, PsiReferenceList.Role.EXTENDS_LIST).also { list -> + allSuperTypes() + .filter { (isInterface || it.resolve()?.isInterface == false) && !it.equalsToText(CommonClassNames.JAVA_LANG_OBJECT) } + .forEach(list::addReference) + } + + override fun createImplementsList(): PsiReferenceList? = + if (tooComplex) super.createImplementsList() + else LightReferenceListBuilder(manager, language, PsiReferenceList.Role.IMPLEMENTS_LIST).also { list -> + if (!isInterface) { + allSuperTypes() + .filter { it.resolve()?.isInterface == true } + .forEach(list::addReference) + } + } + + override fun buildTypeParameterList(): PsiTypeParameterList = + if (tooComplex) super.buildTypeParameterList() else buildTypeParameterList(classOrObject, this, support) + + // the following logic should be in the platform (super), overrides can be removed once that happens + override fun getInterfaces(): Array = PsiClassImplUtil.getInterfaces(this) + override fun getSuperClass(): PsiClass? = PsiClassImplUtil.getSuperClass(this) + override fun getSupers(): Array = PsiClassImplUtil.getSupers(this) + override fun getSuperTypes(): Array = PsiClassImplUtil.getSuperTypes(this) + + override fun getRBrace(): PsiElement? = null + override fun getLBrace(): PsiElement? = null + + private val _ownFields: List by lazyPub { + 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()) { + val modifiers = hashSetOf() + modifiers.add(PsiModifier.PRIVATE) + if (!parameter.isMutable) { + modifiers.add(PsiModifier.FINAL) + } + result.add(KtUltraLightField(parameter, generateUniqueName(parameter.name.orEmpty()), this, support, modifiers)) + } + + this.classOrObject.companionObjects.firstOrNull()?.let { companion -> + result.add( + KtUltraLightField( + companion, + generateUniqueName(companion.name.orEmpty()), + this, + support, + setOf(PsiModifier.STATIC, PsiModifier.FINAL, PsiModifier.PUBLIC) + ) + ) + + for (property in companion.declarations.filterIsInstance()) { + if (isInterface && !property.hasModifier(CONST_KEYWORD)) continue + + propertyField(property, ::generateUniqueName, true)?.let(result::add) + } + } + + if (!isInterface && + !(this.classOrObject is KtObjectDeclaration && this.classOrObject.isCompanion() && containingClass?.isInterface == false) + ) { + for (property in this.classOrObject.declarations.filterIsInstance()) { + propertyField(property, ::generateUniqueName, forceStatic = this.classOrObject is KtObjectDeclaration)?.let(result::add) + } + } + + if (isNamedObject()) { + result.add( + KtUltraLightField( + this.classOrObject, + JvmAbi.INSTANCE_FIELD, + this, + support, + setOf(PsiModifier.STATIC, PsiModifier.FINAL, PsiModifier.PUBLIC) + ) + ) + } + + result + } + + private fun isNamedObject() = classOrObject is KtObjectDeclaration && !classOrObject.isCompanion() + + private fun propertyField(property: KtProperty, generateUniqueName: (String) -> String, forceStatic: Boolean): KtLightField? { + if (!hasBackingField(property)) return null + + val hasDelegate = property.hasDelegate() + val fieldName = generateUniqueName((property.name ?: "") + (if (hasDelegate) "\$delegate" else "")) + + val visibility = when { + property.hasModifier(PRIVATE_KEYWORD) -> PsiModifier.PRIVATE + property.hasModifier(PROTECTED_KEYWORD) && property.hasModifier(LATEINIT_KEYWORD) -> PsiModifier.PROTECTED + property.hasModifier(CONST_KEYWORD) || (property.hasModifier(LATEINIT_KEYWORD) && property.setter == null) -> PsiModifier.PUBLIC + else -> PsiModifier.PRIVATE + } + val modifiers = hashSetOf(visibility) + + if (!property.isVar || property.hasModifier(CONST_KEYWORD) || hasDelegate) { + modifiers.add(PsiModifier.FINAL) + } + + if (forceStatic || isNamedObject() && isJvmStatic(property)) { + modifiers.add(PsiModifier.STATIC) + } + + return KtUltraLightField(property, fieldName, this, support, modifiers) + } + + private fun hasBackingField(property: KtProperty): Boolean { + if (property.hasModifier(ABSTRACT_KEYWORD)) return false + if (property.hasModifier(LATEINIT_KEYWORD) || property.accessors.isEmpty()) return true + + val context = LightClassGenerationSupport.getInstance(project).analyze(property) + val descriptor = context.get(BindingContext.DECLARATION_TO_DESCRIPTOR, property) + return descriptor is PropertyDescriptor && context[BindingContext.BACKING_FIELD_REQUIRED, descriptor] == true + } + + override fun getOwnFields(): List = if (tooComplex) super.getOwnFields() else _ownFields + + private fun propertyParameters() = classOrObject.primaryConstructorParameters.filter { it.hasValOrVar() } + + private val _ownMethods: List by lazyPub { + val result = arrayListOf() + for (declaration in this.classOrObject.declarations.filterNot { isHiddenByDeprecation(it) }) { + if (declaration.hasModifier(PRIVATE_KEYWORD) && isInterface) continue + when (declaration) { + is KtNamedFunction -> result.add(asJavaMethod(declaration, false)) + is KtProperty -> result.addAll(propertyAccessors(declaration, declaration.isVar, false)) + } + } + for (parameter in propertyParameters()) { + result.addAll(propertyAccessors(parameter, parameter.isMutable, false)) + } + if (!isInterface) { + result.addAll(createConstructors()) + } + this.classOrObject.companionObjects.firstOrNull()?.let { companion -> + for (declaration in companion.declarations.filterNot { isHiddenByDeprecation(it) }) { + when (declaration) { + is KtNamedFunction -> if (isJvmStatic(declaration)) result.add(asJavaMethod(declaration, true)) + is KtProperty -> result.addAll(propertyAccessors(declaration, declaration.isVar, true)) + } + } + } + result + } + + private fun createConstructors(): List { + val result = arrayListOf() + val constructors = classOrObject.allConstructors + if (constructors.isEmpty()) { + result.add(defaultConstructor()) + } + for (constructor in constructors.filterNot { isHiddenByDeprecation(it) }) { + result.add(asJavaMethod(constructor, false)) + } + val primary = classOrObject.primaryConstructor + if (primary != null && shouldGenerateNoArgOverload(primary)) { + result.add(noArgConstructor(simpleVisibility(primary), primary)) + } + return result + } + + private fun shouldGenerateNoArgOverload(primary: KtPrimaryConstructor): Boolean { + return !primary.hasModifier(PRIVATE_KEYWORD) && + primary.valueParameters.isNotEmpty() && + primary.valueParameters.all { it.defaultValue != null } && + classOrObject.allConstructors.none { it.valueParameters.isEmpty() } + } + + private fun defaultConstructor(): KtUltraLightMethod { + val visibility = + if (classOrObject is KtObjectDeclaration || classOrObject.hasModifier(SEALED_KEYWORD)) PsiModifier.PRIVATE + else PsiModifier.PUBLIC + return noArgConstructor(visibility, classOrObject) + } + + private fun simpleVisibility(declaration: KtDeclaration): String = when { + declaration.hasModifier(PRIVATE_KEYWORD) -> PsiModifier.PRIVATE + declaration.hasModifier(PROTECTED_KEYWORD) -> PsiModifier.PROTECTED + else -> PsiModifier.PUBLIC + } + + private fun noArgConstructor(visibility: String, declaration: KtDeclaration): KtUltraLightMethod = KtUltraLightMethod( + LightMethodBuilder(manager, language, name.orEmpty()).setConstructor(true).addModifier(visibility), + declaration, + support, + this + ) + + private fun isHiddenByDeprecation(declaration: KtDeclaration): Boolean { + val deprecated = support.findAnnotation(declaration, FqName("kotlin.Deprecated"))?.second + return (deprecated?.argumentValue("level") as? EnumValue)?.enumEntryName?.asString() == "HIDDEN" + } + + private fun isJvmStatic(declaration: KtAnnotated): Boolean = declaration.hasAnnotation(JVM_STATIC_ANNOTATION_FQ_NAME) + + override fun getOwnMethods(): List = if (tooComplex) super.getOwnMethods() else _ownMethods + + private fun asJavaMethod(f: KtFunction, forceStatic: Boolean): KtLightMethod { + val isConstructor = f is KtConstructor<*> + val name = if (isConstructor) this.name else mangleIfNeeded(listOf(f), f.name ?: SpecialNames.NO_NAME_PROVIDED.asString()) + val method = lightMethod(name.orEmpty(), f, forceStatic) + val wrapper = KtUltraLightMethod(method, f, support, this) + addReceiverParameter(f, wrapper) + for (parameter in f.valueParameters) { + method.addParameter(KtUltraLightParameter(parameter.name.orEmpty(), parameter, support, wrapper, null)) + } + val returnType: PsiType? by lazyPub { + if (isConstructor) null + else methodReturnType(f) + } + method.setMethodReturnType { returnType } + return wrapper + } + + private fun addReceiverParameter(f: KtDeclaration, method: KtUltraLightMethod) { + val receiver = (f as? KtCallableDeclaration)?.receiverTypeReference + if (receiver != null) { + method.delegate.addParameter(KtUltraLightParameter("\$self", f, support, method, receiver)) + } + } + + private fun methodReturnType(f: KtDeclaration): PsiType { + val desc = f.resolve()?.let { if (it is PropertyDescriptor) it.getter else it } + val kotlinType = (desc as? FunctionDescriptor)?.returnType ?: return PsiType.NULL + val mode = when { + typeMapper(support).forceBoxedReturnType(desc) -> TypeMappingMode.RETURN_TYPE_BOXED + else -> TypeMappingMode.getOptimalModeForReturnType(kotlinType, false) + } + return kotlinType.asPsiType(f, support, mode) + } + + private fun lightMethod(name: String, declaration: KtDeclaration, forceStatic: Boolean): LightMethodBuilder { + val accessedProperty = if (declaration is KtPropertyAccessor) declaration.property else null + val outer = accessedProperty ?: declaration + return LightMethodBuilder( + manager, language, name, + LightParameterListBuilder(manager, language), + object : LightModifierList(manager, language) { + override fun hasModifierProperty(name: String): Boolean { + if (name == PsiModifier.PUBLIC || name == PsiModifier.PROTECTED || name == PsiModifier.PRIVATE) { + if (declaration.isPrivate() || accessedProperty?.isPrivate() == true) { + return name == PsiModifier.PRIVATE + } + if (declaration.hasModifier(PROTECTED_KEYWORD) || accessedProperty?.hasModifier(PROTECTED_KEYWORD) == true) { + return name == PsiModifier.PROTECTED + } + + if (outer.hasModifier(OVERRIDE_KEYWORD)) { + when ((outer.resolve() as? CallableDescriptor)?.visibility) { + Visibilities.PUBLIC -> return name == PsiModifier.PUBLIC + Visibilities.PRIVATE -> return name == PsiModifier.PRIVATE + Visibilities.PROTECTED -> return name == PsiModifier.PROTECTED + } + } + + return name == PsiModifier.PUBLIC + } + + return when (name) { + PsiModifier.FINAL -> !isInterface && outer !is KtConstructor<*> && isFinal(outer) + PsiModifier.ABSTRACT -> isInterface || outer.hasModifier(ABSTRACT_KEYWORD) + PsiModifier.STATIC -> forceStatic || isNamedObject() && isJvmStatic(outer) + PsiModifier.STRICTFP -> declaration is KtFunction && declaration.hasAnnotation(STRICTFP_ANNOTATION_FQ_NAME) + PsiModifier.SYNCHRONIZED -> declaration is KtFunction && declaration.hasAnnotation(SYNCHRONIZED_ANNOTATION_FQ_NAME) + else -> false + } + } + + fun KtDeclaration.isPrivate() = + hasModifier(PRIVATE_KEYWORD) || + this is KtConstructor<*> && classOrObject.hasModifier(SEALED_KEYWORD) || + this is KtFunction && typeParameters.any { it.hasModifier(REIFIED_KEYWORD) } + } + ).setConstructor(declaration is KtConstructor<*>) + } + + private fun mangleIfNeeded(declarations: List, name: String): String { + for (declaration in declarations) { + if (declaration.hasModifier(PRIVATE_KEYWORD) || + declaration.hasModifier(PROTECTED_KEYWORD) || + declaration.hasModifier(PUBLIC_KEYWORD) + ) { + return name + } + if (isInternal(declaration) && declaration.resolve()?.isPublishedApi() != true) { + return KotlinTypeMapper.InternalNameMapper.mangleInternalName(name, support.moduleName) + } + } + return name + } + + private fun KtAnnotated.hasAnnotation(name: FqName) = support.findAnnotation(this, name) != null + + private fun isInternal(f: KtDeclaration): Boolean { + if (f.hasModifier(OVERRIDE_KEYWORD)) { + val desc = f.resolve() + return desc is CallableDescriptor && + desc.visibility.effectiveVisibility(desc, false) == EffectiveVisibility.Internal + } + return f.hasModifier(INTERNAL_KEYWORD) + } + + private fun propertyAccessors(declaration: KtNamedDeclaration, mutable: Boolean, onlyJvmStatic: Boolean): List { + val propertyName = declaration.name + if (declaration.hasModifier(CONST_KEYWORD) || propertyName == null) return emptyList() + + val ktGetter = (declaration as? KtProperty)?.getter + val ktSetter = (declaration as? KtProperty)?.setter + + val isPrivate = declaration.hasModifier(PRIVATE_KEYWORD) + if (isPrivate && declaration !is KtProperty) return emptyList() + + fun needsAccessor(accessor: KtPropertyAccessor?): Boolean { + if (!onlyJvmStatic || isJvmStatic(declaration) || accessor != null && isJvmStatic(accessor)) { + if (declaration is KtProperty && declaration.hasDelegate()) { + return true + } + if (accessor?.hasModifier(PRIVATE_KEYWORD) == true) { + return false + } + if (!isPrivate || accessor?.hasBody() == true) { + return true + } + } + return false + } + + val result = arrayListOf() + + if (needsAccessor(ktGetter)) { + val getterName = mangleIfNeeded(listOfNotNull(ktGetter, declaration), JvmAbi.getterName(propertyName)) + val getterType: PsiType by lazyPub { methodReturnType(declaration) } + val getterPrototype = lightMethod(getterName, ktGetter ?: declaration, onlyJvmStatic) + .setMethodReturnType { getterType } + val getterWrapper = KtUltraLightMethod(getterPrototype, declaration, support, this) + addReceiverParameter(declaration, getterWrapper) + result.add(getterWrapper) + } + + if (mutable && needsAccessor(ktSetter)) { + val setterName = mangleIfNeeded(listOfNotNull(ktSetter, declaration), JvmAbi.setterName(propertyName)) + val setterPrototype = lightMethod(setterName, ktSetter ?: declaration, onlyJvmStatic) + .setMethodReturnType(PsiType.VOID) + val setterWrapper = KtUltraLightMethod(setterPrototype, declaration, support, this) + addReceiverParameter(declaration, setterWrapper) + val parameterOrigin = ktSetter?.parameter ?: declaration + setterPrototype.addParameter(KtUltraLightParameter(propertyName, parameterOrigin, support, setterWrapper, null)) + result.add(setterWrapper) + } + return result + } + + private fun isFinal(declaration: KtDeclaration): Boolean { + if (declaration.hasModifier(FINAL_KEYWORD)) return true + return declaration !is KtPropertyAccessor && + !declaration.hasModifier(OPEN_KEYWORD) && + !declaration.hasModifier(OVERRIDE_KEYWORD) && + !declaration.hasModifier(ABSTRACT_KEYWORD) + } + + override fun getInitializers(): Array = emptyArray() + + override fun getContainingClass(): PsiClass? = + if (tooComplex) super.getContainingClass() else classOrObject.containingClass()?.let(KtLightClassForSourceDeclaration::create) + + override fun getParent(): PsiElement? = if (tooComplex) super.getParent() else containingClass ?: containingFile + + override fun getScope(): PsiElement? = if (tooComplex) super.getScope() else parent + override fun copy(): KtLightClassImpl = KtUltraLightClass(classOrObject.copy() as KtClassOrObject, support) +} + +private class KtUltraLightField( + private val declaration: KtNamedDeclaration, + name: String, + private val containingClass: KtUltraLightClass, + private val support: UltraLightSupport, + modifiers: Set +) : LightFieldBuilder(name, PsiType.NULL, declaration), KtLightField { + private val modList = object : KtLightSimpleModifierList(this, modifiers) { + override fun hasModifierProperty(name: String): Boolean = when (name) { + PsiModifier.VOLATILE -> hasFieldAnnotation(VOLATILE_ANNOTATION_FQ_NAME) + PsiModifier.TRANSIENT -> hasFieldAnnotation(TRANSIENT_ANNOTATION_FQ_NAME) + else -> super.hasModifierProperty(name) + } + + private fun hasFieldAnnotation(fqName: FqName): Boolean { + val annotation = support.findAnnotation(declaration, fqName)?.first ?: return false + val target = annotation.useSiteTarget?.getAnnotationUseSiteTarget() ?: return true + val expectedTarget = + if (declaration is KtProperty && declaration.hasDelegate()) AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD + else AnnotationUseSiteTarget.FIELD + return target == expectedTarget + } + } + + override fun getModifierList(): PsiModifierList = modList + override fun hasModifierProperty(name: String): Boolean = + modifierList.hasModifierProperty(name) //can be removed after IDEA platform does the same + + override fun getLanguage(): Language = KotlinLanguage.INSTANCE + + private val _type: PsiType by lazyPub { + fun nonExistent() = JavaPsiFacade.getElementFactory(project).createTypeFromText("error.NonExistentClass", declaration) + when { + declaration is KtProperty && declaration.hasDelegate() -> + (declaration.resolve() as? PropertyDescriptor) + ?.let { + val context = LightClassGenerationSupport.getInstance(project).analyze(declaration) + PropertyCodegen.getDelegateTypeForProperty(declaration, it, context) + } + ?.let { it.asPsiType(declaration, support, TypeMappingMode.getOptimalModeForValueParameter(it), this) } + ?.let(TypeConversionUtil::erasure) + ?: nonExistent() + declaration is KtObjectDeclaration -> + KtLightClassForSourceDeclaration.create(declaration)?.let { JavaPsiFacade.getElementFactory(project).createType(it) } + ?: nonExistent() + else -> + declaration.getKotlinType()?.let { + val mode = when { + (declaration.resolve() as? PropertyDescriptor)?.isVar == true -> TypeMappingMode.getOptimalModeForValueParameter(it) + else -> TypeMappingMode.getOptimalModeForReturnType(it, false) + } + it.asPsiType(declaration, support, mode, this) + } ?: PsiType.NULL + } + } + + override fun getType(): PsiType = _type + + override fun getParent() = containingClass + override fun getContainingClass() = containingClass + override fun getContainingFile(): PsiFile? = containingClass.containingFile + + override fun computeConstantValue(): Any? = + if (hasModifierProperty(PsiModifier.FINAL) && + (TypeConversionUtil.isPrimitiveAndNotNull(_type) || _type.equalsToText(CommonClassNames.JAVA_LANG_STRING)) + ) + (declaration.resolve() as? VariableDescriptor)?.compileTimeInitializer?.value + else null + + override fun computeConstantValue(visitedVars: MutableSet?): Any? = computeConstantValue() + + override val kotlinOrigin = declaration + override val clsDelegate: PsiField + get() = throw IllegalStateException("Cls delegate shouldn't be loaded for ultra-light PSI!") + override val lightMemberOrigin = LightMemberOriginForDeclaration(declaration, JvmDeclarationOriginKind.OTHER) + + override fun setName(@NonNls name: String): PsiElement { + (kotlinOrigin as? KtNamedDeclaration)?.setName(name) + return this + } + + override fun setInitializer(initializer: PsiExpression?) = cannotModify() + +} + +internal class KtUltraLightMethod( + internal val delegate: LightMethodBuilder, + originalElement: KtDeclaration, + private val support: UltraLightSupport, + containingClass: KtUltraLightClass +) : KtLightMethodImpl({ delegate }, LightMemberOriginForDeclaration(originalElement, JvmDeclarationOriginKind.OTHER), containingClass) { + + override fun getReturnTypeElement(): PsiTypeElement? = null + override fun getReturnType(): PsiType? = clsDelegate.returnType + override fun getParameterList(): PsiParameterList = clsDelegate.parameterList + + // should be in super + override fun isVarArgs() = PsiImplUtil.isVarArgs(this) + + override fun buildTypeParameterList(): PsiTypeParameterList { + val origin = kotlinOrigin + return if (origin is KtFunction || origin is KtProperty) + buildTypeParameterList(origin as KtTypeParameterListOwner, this, support) + else LightTypeParameterListBuilder(manager, language) + } + + private val _throwsList: PsiReferenceList by lazyPub { + val list = LightReferenceListBuilder(manager, language, PsiReferenceList.Role.THROWS_LIST) + (kotlinOrigin?.resolve() as? FunctionDescriptor)?.let { + for (ex in FunctionCodegen.getThrownExceptions(it)) { + list.addReference(ex.fqNameSafe.asString()) + } + } + list + } + + override fun getThrowsList(): PsiReferenceList = _throwsList +} + +internal class KtUltraLightParameter( + name: String, + override val kotlinOrigin: KtDeclaration, + private val support: UltraLightSupport, + method: KtLightMethod, + private val receiver: KtTypeReference? +) : org.jetbrains.kotlin.asJava.elements.LightParameter( + name, + PsiType.NULL, + method, + method.language +), + KtLightDeclaration { + + override val clsDelegate: PsiParameter + get() = throw IllegalStateException("Cls delegate shouldn't be loaded for ultra-light PSI!") + + private val lightModifierList by lazyPub { KtLightSimpleModifierList(this, emptySet()) } + + override fun isVarArgs(): Boolean = + kotlinOrigin is KtParameter && kotlinOrigin.isVarArg && method.parameterList.parameters.last() == this + + override fun getModifierList(): PsiModifierList = lightModifierList + + override fun getNavigationElement(): PsiElement = kotlinOrigin + + private val kotlinType: KotlinType? by lazyPub { + when { + receiver != null -> (kotlinOrigin.resolve() as? CallableMemberDescriptor)?.extensionReceiverParameter?.type + else -> kotlinOrigin.getKotlinType() + } + } + private val _type: PsiType by lazyPub { + kotlinType?.let { it.asPsiType(kotlinOrigin, support, TypeMappingMode.getOptimalModeForValueParameter(it), this) } ?: PsiType.NULL + } + + override fun getType(): PsiType = _type + + override fun setName(@NonNls name: String): PsiElement { + (kotlinOrigin as? KtVariableDeclaration)?.setName(name) + return this + } + + override fun getContainingFile(): PsiFile = method.containingFile + override fun getParent(): PsiElement = method.parameterList + + override fun equals(other: Any?): Boolean = other is KtUltraLightParameter && other.kotlinOrigin == this.kotlinOrigin + override fun hashCode(): Int = kotlinOrigin.hashCode() + + internal fun annotatedOrigin(): KtAnnotated? { + if (receiver != null) return receiver + + if (kotlinOrigin is KtProperty) { + return null // we're a setter of a property with no explicit declaration, so we don't have annotation + } + return kotlinOrigin + } + + internal fun getTypeForNullability(): KotlinType? { + if (receiver != null) return kotlinType + if (kotlinOrigin is KtProperty) { + if (kotlinOrigin.setter?.hasModifier(PRIVATE_KEYWORD) == true) return null + return kotlinType + } + if (kotlinOrigin is KtParameter) { + val reference = kotlinOrigin.typeReference + if (kotlinOrigin.isVarArg && reference != null) { + LightClassGenerationSupport.getInstance(project).analyze(reference)[BindingContext.TYPE, reference]?.let { return it } + } + if (reference != null || kotlinOrigin.parent?.parent is KtPropertyAccessor) { + return kotlinType + } + } + return null + } + +} + +interface UltraLightSupport { + val moduleName: String + fun findAnnotation(owner: KtAnnotated, fqName: FqName): Pair? + fun isTooComplexForUltraLightGeneration(element: KtClassOrObject): Boolean +} \ No newline at end of file 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 new file mode 100644 index 00000000000..89530a9bf65 --- /dev/null +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightUtils.kt @@ -0,0 +1,105 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.asJava.classes + +import com.intellij.psi.* +import com.intellij.psi.impl.cache.TypeInfo +import com.intellij.psi.impl.compiled.ClsTypeElementImpl +import com.intellij.psi.impl.compiled.SignatureParsing +import com.intellij.psi.impl.compiled.StubBuildingVisitor +import com.intellij.psi.impl.light.LightReferenceListBuilder +import com.intellij.psi.impl.light.LightTypeParameterBuilder +import org.jetbrains.kotlin.asJava.LightClassGenerationSupport +import org.jetbrains.kotlin.asJava.elements.KotlinLightTypeParameterListBuilder +import org.jetbrains.kotlin.codegen.ClassBuilderMode +import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter +import org.jetbrains.kotlin.codegen.state.IncompatibleClassTracker +import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper +import org.jetbrains.kotlin.config.JvmTarget +import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor +import org.jetbrains.kotlin.descriptors.ValueDescriptor +import org.jetbrains.kotlin.load.kotlin.TypeMappingMode +import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.psi.KtFunction +import org.jetbrains.kotlin.psi.KtTypeParameterListOwner +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe +import org.jetbrains.kotlin.types.KotlinType +import java.text.StringCharacterIterator + +internal fun buildTypeParameterList( + declaration: KtTypeParameterListOwner, + owner: PsiTypeParameterListOwner, + support: UltraLightSupport +): PsiTypeParameterList { + val tpList = KotlinLightTypeParameterListBuilder(owner) + for ((i, ktParam) in declaration.typeParameters.withIndex()) { + tpList.addParameter(object : LightTypeParameterBuilder(ktParam.name.orEmpty(), owner, i) { + private val superList: LightReferenceListBuilder by lazyPub { + val boundList = LightReferenceListBuilder(manager, PsiReferenceList.Role.EXTENDS_BOUNDS_LIST) + if (ktParam.extendsBound != null || declaration.typeConstraints.isNotEmpty()) { + val boundTypes = (ktParam.resolve() as? TypeParameterDescriptor)?.upperBounds.orEmpty() + .mapNotNull { it.asPsiType(ktParam, support, TypeMappingMode.DEFAULT, this) as? PsiClassType } + val hasDefaultBound = boundTypes.size == 1 && boundTypes[0].equalsToText(CommonClassNames.JAVA_LANG_OBJECT) + if (!hasDefaultBound) { + boundTypes.forEach(boundList::addReference) + } + } + boundList + } + + override fun getExtendsList(): LightReferenceListBuilder = superList + + override fun getParent(): PsiElement = tpList + override fun getContainingFile(): PsiFile = owner.containingFile + }) + } + return tpList +} + +internal fun KtDeclaration.getKotlinType(): KotlinType? { + val descriptor = resolve() + return when (descriptor) { + is ValueDescriptor -> descriptor.type + is CallableDescriptor -> descriptor.returnType + else -> null + } +} + +internal fun KtDeclaration.resolve() = LightClassGenerationSupport.getInstance(project).resolveToDescriptor(this) + +// copy-pasted from kotlinInternalUastUtils.kt and post-processed +internal fun KotlinType.asPsiType( + declaration: KtDeclaration, + support: UltraLightSupport, + mode: TypeMappingMode, + psiContext: PsiElement = declaration +): PsiType { + val typeFqName = constructor.declarationDescriptor?.fqNameSafe?.asString() + if (typeFqName == "kotlin.Unit" && declaration is KtFunction) return PsiType.VOID + + val signatureWriter = BothSignatureWriter(BothSignatureWriter.Mode.TYPE) + typeMapper(support).mapType(this, signatureWriter, mode) + val signature = StringCharacterIterator(signatureWriter.toString()) + + val javaType = SignatureParsing.parseTypeString(signature, StubBuildingVisitor.GUESSING_MAPPER) + val typeInfo = TypeInfo.fromString(javaType, false) + val typeText = TypeInfo.createTypeText(typeInfo) ?: return PsiType.NULL + + val type = ClsTypeElementImpl(psiContext, typeText, '\u0000').type + if (type is PsiArrayType && psiContext is KtUltraLightParameter && psiContext.isVarArgs) { + return PsiEllipsisType(type.componentType, type.annotationProvider) + } + return type +} + +internal fun typeMapper(support: UltraLightSupport): KotlinTypeMapper = KotlinTypeMapper( + BindingContext.EMPTY, ClassBuilderMode.LIGHT_CLASSES, + IncompatibleClassTracker.DoNothing, support.moduleName, + JvmTarget.JVM_1_8, + true, false +) diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KotlinLightTypeParameterListBuilder.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KotlinLightTypeParameterListBuilder.kt index e6d3e39f3e4..7efadeff4ca 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KotlinLightTypeParameterListBuilder.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KotlinLightTypeParameterListBuilder.kt @@ -17,16 +17,21 @@ package org.jetbrains.kotlin.asJava.elements import com.intellij.psi.PsiElement -import com.intellij.psi.PsiManager +import com.intellij.psi.PsiFile +import com.intellij.psi.PsiTypeParameterListOwner import com.intellij.psi.ResolveState import com.intellij.psi.impl.light.LightTypeParameterListBuilder import com.intellij.psi.scope.PsiScopeProcessor import org.jetbrains.kotlin.idea.KotlinLanguage -class KotlinLightTypeParameterListBuilder(manager: PsiManager): LightTypeParameterListBuilder(manager, KotlinLanguage.INSTANCE) { +class KotlinLightTypeParameterListBuilder(private val owner: PsiTypeParameterListOwner) : + LightTypeParameterListBuilder(owner.manager, KotlinLanguage.INSTANCE) { override fun processDeclarations(processor: PsiScopeProcessor, state: ResolveState, lastParent: PsiElement?, place: PsiElement): Boolean { return typeParameters.all { processor.execute(it, state) } } + override fun getParent(): PsiElement = owner + override fun getContainingFile(): PsiFile = owner.containingFile + override fun getText(): String? = "" } diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightMethodImpl.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightMethodImpl.kt index 6b6c390356b..b8af12f5a4d 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightMethodImpl.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightMethodImpl.kt @@ -19,7 +19,9 @@ package org.jetbrains.kotlin.asJava.elements import com.intellij.psi.* import com.intellij.psi.impl.compiled.ClsTypeElementImpl import com.intellij.psi.scope.PsiScopeProcessor -import com.intellij.psi.util.* +import com.intellij.psi.util.MethodSignature +import com.intellij.psi.util.MethodSignatureBackedByPsiMethod +import com.intellij.psi.util.PsiTreeUtil import org.jetbrains.kotlin.asJava.LightClassUtil import org.jetbrains.kotlin.asJava.builder.LightMemberOrigin import org.jetbrains.kotlin.asJava.builder.LightMemberOriginForDeclaration @@ -36,7 +38,7 @@ import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.jvm.KotlinJavaPsiFacade -class KtLightMethodImpl private constructor( +open class KtLightMethodImpl protected constructor( computeRealDelegate: () -> PsiMethod, lightMemberOrigin: LightMemberOrigin?, containingClass: KtLightClass, @@ -55,25 +57,15 @@ class KtLightMethodImpl private constructor( } } - private val typeParamsList: CachedValue by lazyPub { - val cacheManager = CachedValuesManager.getManager(clsDelegate.project) - cacheManager.createCachedValue( - { - val origin = (lightMemberOrigin as? LightMemberOriginForDeclaration)?.originalElement - val list = if (origin != null) { - if (origin is KtClassOrObject) { - KotlinLightTypeParameterListBuilder(manager) - } - else { - LightClassUtil.buildLightTypeParameterList(this@KtLightMethodImpl, origin) - } - } - else { - clsDelegate.typeParameterList - } - CachedValueProvider.Result.create(list, PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT) - }, false - ) + private val typeParamsList: PsiTypeParameterList? by lazyPub { buildTypeParameterList() } + + protected open fun buildTypeParameterList(): PsiTypeParameterList? { + val origin = (lightMemberOrigin as? LightMemberOriginForDeclaration)?.originalElement + return when { + origin is KtClassOrObject -> KotlinLightTypeParameterListBuilder(this) + origin != null -> LightClassUtil.buildLightTypeParameterList(this, origin) + else -> clsDelegate.typeParameterList + } } override fun accept(visitor: PsiElementVisitor) { @@ -128,7 +120,7 @@ class KtLightMethodImpl private constructor( override fun getParameterList() = paramsList - override fun getTypeParameterList() = typeParamsList.value + override fun getTypeParameterList() = typeParamsList override fun getTypeParameters(): Array = typeParameterList?.typeParameters ?: PsiTypeParameter.EMPTY_ARRAY diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightModifierList.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightModifierList.kt index bf5a367ffda..282b7411bb2 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightModifierList.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightModifierList.kt @@ -23,6 +23,7 @@ import com.intellij.psi.PsiModifierListOwner import org.jetbrains.kotlin.asJava.LightClassGenerationSupport import org.jetbrains.kotlin.asJava.builder.LightMemberOriginForDeclaration import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration +import org.jetbrains.kotlin.asJava.classes.KtUltraLightParameter import org.jetbrains.kotlin.asJava.classes.lazyPub import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor @@ -37,7 +38,7 @@ import org.jetbrains.kotlin.resolve.source.getPsi abstract class KtLightModifierList>(protected val owner: T) : KtLightElementBase(owner), PsiModifierList, KtLightElement { override val clsDelegate by lazyPub { owner.clsDelegate.modifierList!! } - private val _annotations by lazyPub { computeAnnotations(this) } + private val _annotations by lazyPub { computeAnnotations() } override val kotlinOrigin: KtModifierList? get() = owner.kotlinOrigin?.modifierList @@ -61,9 +62,28 @@ abstract class KtLightModifierList { + val annotationsForEntries = lightAnnotationsForEntries(this) + val modifierListOwner = parent + if (modifierListOwner is KtLightClassForSourceDeclaration && modifierListOwner.isAnnotationType) { + val sourceAnnotationNames = annotationsForEntries.mapTo(mutableSetOf()) { it.qualifiedName } + val specialAnnotationsOnAnnotationClass = modifierListOwner.clsDelegate.modifierList?.annotations.orEmpty().filter { + it.qualifiedName !in sourceAnnotationNames + }.map { KtLightNonSourceAnnotation(this, it) } + return annotationsForEntries + specialAnnotationsOnAnnotationClass + } + if ((modifierListOwner is KtLightMember<*> && modifierListOwner !is KtLightFieldImpl.KtLightEnumConstant) + || modifierListOwner is LightParameter) { + return annotationsForEntries + + listOf(KtLightNullabilityAnnotation(modifierListOwner as KtLightElement<*, PsiModifierListOwner>, this)) + } + return annotationsForEntries + } + } -class KtLightSimpleModifierList( +open class KtLightSimpleModifierList( owner: KtLightElement, private val modifiers: Set ) : KtLightModifierList>(owner) { override fun hasModifierProperty(name: String) = name in modifiers @@ -71,31 +91,14 @@ class KtLightSimpleModifierList( override fun copy() = KtLightSimpleModifierList(owner, modifiers) } -private fun computeAnnotations(lightModifierList: KtLightModifierList<*>): List { - val annotationsForEntries = lightAnnotationsForEntries(lightModifierList) - val modifierListOwner = lightModifierList.parent - if (modifierListOwner is KtLightClassForSourceDeclaration && modifierListOwner.isAnnotationType) { - val sourceAnnotationNames = annotationsForEntries.mapTo(mutableSetOf()) { it.qualifiedName } - val specialAnnotationsOnAnnotationClass = modifierListOwner.clsDelegate.modifierList?.annotations.orEmpty().filter { - it.qualifiedName !in sourceAnnotationNames - }.map { KtLightNonSourceAnnotation(lightModifierList, it) } - return annotationsForEntries + specialAnnotationsOnAnnotationClass - } - if ((modifierListOwner is KtLightMember<*> && modifierListOwner !is KtLightFieldImpl.KtLightEnumConstant) - || modifierListOwner is KtLightParameter) { - return annotationsForEntries + - @Suppress("UNCHECKED_CAST") - listOf(KtLightNullabilityAnnotation(modifierListOwner as KtLightElement<*, PsiModifierListOwner>, lightModifierList)) - } - return annotationsForEntries -} - private fun lightAnnotationsForEntries(lightModifierList: KtLightModifierList<*>): List { val lightModifierListOwner = lightModifierList.parent if (!isFromSources(lightModifierList)) return emptyList() - val annotatedKtDeclaration = lightModifierListOwner.kotlinOrigin as? KtDeclaration + val annotatedKtDeclaration = + if (lightModifierListOwner is KtUltraLightParameter) lightModifierListOwner.annotatedOrigin() + else lightModifierListOwner.kotlinOrigin as? KtDeclaration if (annotatedKtDeclaration == null || !annotatedKtDeclaration.isValid || !hasAnnotationsInSource(annotatedKtDeclaration)) { return emptyList() @@ -128,11 +131,11 @@ fun isFromSources(lightElement: KtLightElement<*, *>): Boolean { return true } -private fun getAnnotationDescriptors(declaration: KtDeclaration, annotatedLightElement: KtLightElement<*, *>): List { +private fun getAnnotationDescriptors(declaration: KtAnnotated, annotatedLightElement: KtLightElement<*, *>): List { val context = LightClassGenerationSupport.getInstance(declaration.project).analyze(declaration) val descriptor = if (declaration is KtParameter && declaration.isPropertyParameter()) { - if (annotatedLightElement is KtLightParameter && annotatedLightElement.method.isConstructor) + if (annotatedLightElement is LightParameter && annotatedLightElement.method.isConstructor) context[BindingContext.VALUE_PARAMETER, declaration] else context[BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, declaration] @@ -145,7 +148,8 @@ private fun getAnnotationDescriptors(declaration: KtDeclaration, annotatedLightE descriptor is ClassDescriptor && annotatedLightElement is KtLightMethod && annotatedLightElement.isConstructor -> descriptor.unsubstitutedPrimaryConstructor descriptor !is PropertyDescriptor -> descriptor - annotatedLightElement is KtLightFieldImpl.KtLightFieldForDeclaration -> descriptor.backingField + annotatedLightElement is KtLightFieldImpl.KtLightEnumConstant -> descriptor + annotatedLightElement is KtLightField -> descriptor.backingField annotatedLightElement !is KtLightMethod -> descriptor annotatedLightElement.isGetter -> descriptor.getter annotatedLightElement.isSetter -> descriptor.setter @@ -164,7 +168,7 @@ private fun getAnnotationDescriptors(declaration: KtDeclaration, annotatedLightE return annotations } -private fun hasAnnotationsInSource(declaration: KtDeclaration): Boolean { +private fun hasAnnotationsInSource(declaration: KtAnnotated): Boolean { if (declaration.annotationEntries.isNotEmpty()) { return true } @@ -175,3 +179,4 @@ private fun hasAnnotationsInSource(declaration: KtDeclaration): Boolean { return false } + diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightParameter.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightParameter.kt index 63cd407554b..a624213a5f7 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightParameter.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightParameter.kt @@ -25,7 +25,7 @@ import org.jetbrains.kotlin.psi.psiUtil.isExtensionDeclaration class KtLightParameter( override val clsDelegate: PsiParameter, private val index: Int, - val method: KtLightMethod + method: KtLightMethod ) : LightParameter(clsDelegate.name ?: "p$index", clsDelegate.type, method, KotlinLanguage.INSTANCE), KtLightDeclaration { diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/LightParameter.java b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/LightParameter.java index a8258e3168c..fd26e46348b 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/LightParameter.java +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/LightParameter.java @@ -25,14 +25,14 @@ public class LightParameter extends LightVariableBuilder implements PsiParameter public static final LightParameter[] EMPTY_ARRAY = new LightParameter[0]; private final String myName; - private final PsiElement myDeclarationScope; + private final KtLightMethod myDeclarationScope; private final boolean myVarArgs; - public LightParameter(@NotNull String name, @NotNull PsiType type, PsiElement declarationScope, Language language) { + public LightParameter(@NotNull String name, @NotNull PsiType type, @NotNull KtLightMethod declarationScope, Language language) { this(name, type, declarationScope, language, type instanceof PsiEllipsisType); } - public LightParameter(@NotNull String name, @NotNull PsiType type, PsiElement declarationScope, Language language, boolean isVarArgs) { + public LightParameter(@NotNull String name, @NotNull PsiType type, @NotNull KtLightMethod declarationScope, Language language, boolean isVarArgs) { super(declarationScope.getManager(), name, type, language); myName = name; myDeclarationScope = declarationScope; @@ -41,7 +41,11 @@ public class LightParameter extends LightVariableBuilder implements PsiParameter @NotNull @Override - public PsiElement getDeclarationScope() { + public KtLightMethod getDeclarationScope() { + return myDeclarationScope; + } + + public KtLightMethod getMethod() { return myDeclarationScope; } diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/lightAnnotations.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/lightAnnotations.kt index 7723fbf79e8..6e7f2f5d842 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/lightAnnotations.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/lightAnnotations.kt @@ -24,6 +24,7 @@ import org.jetbrains.annotations.NotNull import org.jetbrains.annotations.Nullable import org.jetbrains.annotations.TestOnly import org.jetbrains.kotlin.asJava.LightClassGenerationSupport +import org.jetbrains.kotlin.asJava.classes.KtUltraLightParameter import org.jetbrains.kotlin.asJava.classes.cannotModify import org.jetbrains.kotlin.asJava.classes.lazyPub import org.jetbrains.kotlin.builtins.KotlinBuiltIns @@ -298,6 +299,10 @@ class KtLightNullabilityAnnotation(val member: KtLightElement<*, PsiModifierList internal fun KtTypeReference.getType(): KotlinType? = analyze()[BindingContext.TYPE, this] private fun getTargetType(annotatedElement: PsiElement): KotlinType? { + if (member is KtUltraLightParameter) { + return member.getTypeForNullability() + } + if (annotatedElement is KtTypeReference) { annotatedElement.getType()?.let { return it } } diff --git a/compiler/testData/asJava/ultraLightClasses/annotations.kt b/compiler/testData/asJava/ultraLightClasses/annotations.kt new file mode 100644 index 00000000000..99599161494 --- /dev/null +++ b/compiler/testData/asJava/ultraLightClasses/annotations.kt @@ -0,0 +1,44 @@ +import kotlin.reflect.KClass + +/** should load cls */ +annotation class Anno(val p: String = "", val x: Array = arrayOf(Anno(p="a"), Anno(p="b"))) + +/** should load cls */ +@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, + AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.EXPRESSION) +@Retention(AnnotationRetention.SOURCE) +@MustBeDocumented +@Deprecated("This anno is deprecated, use === instead", ReplaceWith("this === other")) +annotation class Fancy + +/** should load cls */ +annotation class ReplaceWith(val expression: String) + +/** should load cls */ +annotation class Deprecated( + val message: String, + val replaceWith: ReplaceWith = ReplaceWith("")) + +/** should load cls */ +annotation class Ann(val arg1: KClass<*>, val arg2: KClass) + + +@Anno class F: Runnable { + @Anno("f") fun f(@Anno p: String) {} + @Anno("p") var prop = "x" +} + + +class Foo @Anno constructor(dependency: MyDependency) { + var x: String? = null + @Anno set + + @Anno + fun String.f4() {} +} + +@Ann(String::class, Int::class) class MyClass + +class Example(@field:Ann val foo, // annotate Java field + @get:Ann val bar, // annotate Java getter + @param:Ann val quux) // annotate Java constructor parameter diff --git a/compiler/testData/asJava/ultraLightClasses/classModifiers.kt b/compiler/testData/asJava/ultraLightClasses/classModifiers.kt new file mode 100644 index 00000000000..df2452132f1 --- /dev/null +++ b/compiler/testData/asJava/ultraLightClasses/classModifiers.kt @@ -0,0 +1,16 @@ + +package pkg + +open class Open { + private class Private: Open {} + protected inner class Private2 {} + internal class StaticInternal {} +} +internal class OuterInternal {} +private class TopLevelPrivate {} + +sealed class Season { + class Nested: Season() +} + +sealed class SealedWithArgs(val a: Int) \ No newline at end of file diff --git a/compiler/testData/asJava/ultraLightClasses/constructors.kt b/compiler/testData/asJava/ultraLightClasses/constructors.kt new file mode 100644 index 00000000000..4c2c30179a8 --- /dev/null +++ b/compiler/testData/asJava/ultraLightClasses/constructors.kt @@ -0,0 +1,8 @@ + +class TestConstructor private constructor(p: Int = 1) +class A(vararg a: Int, f: () -> Unit) {} + +class B { + @Deprecated("", level = DeprecationLevel.HIDDEN) + constructor() +} \ No newline at end of file diff --git a/compiler/testData/asJava/ultraLightClasses/coroutines.kt b/compiler/testData/asJava/ultraLightClasses/coroutines.kt new file mode 100644 index 00000000000..9e888ecabb2 --- /dev/null +++ b/compiler/testData/asJava/ultraLightClasses/coroutines.kt @@ -0,0 +1,19 @@ +/** should load cls */ +class Foo { + suspend fun doSomething(foo: Foo): Bar {} +} + +/** should load cls */ +class Bar { + fun async(block: suspend () -> T) +} + +/** should load cls */ +interface Base { + suspend fun foo() +} + +/** should load cls */ +class Derived: Base { + override suspend fun foo() { ... } +} diff --git a/compiler/testData/asJava/ultraLightClasses/dataClasses.kt b/compiler/testData/asJava/ultraLightClasses/dataClasses.kt new file mode 100644 index 00000000000..365f25885c5 --- /dev/null +++ b/compiler/testData/asJava/ultraLightClasses/dataClasses.kt @@ -0,0 +1,7 @@ +/** should load cls */ +data class User(val name: String = "", val age: Int = 0) + +/** should load cls */ +data class Person(val name: String) { + var age: Int = 0 +} diff --git a/compiler/testData/asJava/ultraLightClasses/delegatingToInterfaces.kt b/compiler/testData/asJava/ultraLightClasses/delegatingToInterfaces.kt new file mode 100644 index 00000000000..d01d281d2bf --- /dev/null +++ b/compiler/testData/asJava/ultraLightClasses/delegatingToInterfaces.kt @@ -0,0 +1,15 @@ + +interface Base { + fun printMessage() + fun printMessageLine() +} + +class BaseImpl(val x: Int) : Base { + override fun printMessage() { print(x) } + override fun printMessageLine() { println(x) } +} + +/** should load cls */ +class Derived(b: Base) : Base by b { + override fun printMessage() { print("abc") } +} diff --git a/compiler/testData/asJava/ultraLightClasses/enums.kt b/compiler/testData/asJava/ultraLightClasses/enums.kt new file mode 100644 index 00000000000..e856b5721e5 --- /dev/null +++ b/compiler/testData/asJava/ultraLightClasses/enums.kt @@ -0,0 +1,43 @@ + +import java.util.function.* + +/** should load cls */ +enum class Direction { + NORTH, SOUTH, WEST, EAST +} + +/** should load cls */ +enum class Color(val rgb: Int) { + RED(0xFF0000), + GREEN(0x00FF00), + BLUE(0x0000FF) +} + +/** should load cls */ +enum class ProtocolState { + WAITING { + override fun signal() = TALKING + }, + + TALKING { + override fun signal() = WAITING + }; + + abstract fun signal(): ProtocolState +} + +/** should load cls */ +enum class IntArithmetics : BinaryOperator, IntBinaryOperator { + PLUS { + override fun apply(t: Int, u: Int): Int = t + u + }, + TIMES { + override fun apply(t: Int, u: Int): Int = t * u + }; + + override fun applyAsInt(t: Int, u: Int) = apply(t, u) +} + +class C { + val enumConst: Direction? = Direction.EAST +} \ No newline at end of file diff --git a/compiler/testData/asJava/ultraLightClasses/generics.kt b/compiler/testData/asJava/ultraLightClasses/generics.kt new file mode 100644 index 00000000000..46343457d3f --- /dev/null +++ b/compiler/testData/asJava/ultraLightClasses/generics.kt @@ -0,0 +1,27 @@ + +abstract class C(var constructorParam: List) { + fun foo(p1: V, p2: C, p4: Sequence): T {} + + inline fun > printAllValues() { + print(enumValues().joinToString { it.name }) + } + + val Q.w: Q get() = null!! + + var sListProp: List? + var sSetProp: Set? + var sMutableSetProp: MutableSet? + var sHashSetProp: HashSet? + var csListProp: List? + + abstract fun listCS(l: List): List + abstract fun listS(l: List): List + abstract fun mutables(cin: MutableCollection, sOut: MutableList>): MutableSet + abstract fun nested(l: List>): Collection> + + fun max(p0 : Collection?): T? where T : Comparable? {} + +} + +open class K> { } +class Sub: K>() diff --git a/compiler/testData/asJava/ultraLightClasses/implementingKotlinCollections.kt b/compiler/testData/asJava/ultraLightClasses/implementingKotlinCollections.kt new file mode 100644 index 00000000000..3130f492cd6 --- /dev/null +++ b/compiler/testData/asJava/ultraLightClasses/implementingKotlinCollections.kt @@ -0,0 +1,27 @@ +import java.util.* + +/** should load cls */ +class MyList : List { + override operator fun get(index: Int): String {} +} + +/** should load cls */ +interface ASet : MutableCollection {} + +/** should load cls */ +abstract class MySet : ASet { + override fun remove(elem: String): Boolean {} + +} + +/** should load cls */ +abstract class SmartSet private constructor() : AbstractSet() { + override fun iterator(): MutableIterator = unresolved + + override fun add(element: T): Boolean { + return true + } + + override fun contains(element: T): Boolean = true + +} diff --git a/compiler/testData/asJava/ultraLightClasses/importAliases.kt b/compiler/testData/asJava/ultraLightClasses/importAliases.kt new file mode 100644 index 00000000000..1716fc9a228 --- /dev/null +++ b/compiler/testData/asJava/ultraLightClasses/importAliases.kt @@ -0,0 +1,6 @@ +import kotlin.jvm.JvmStatic as JS + +/** should load cls */ +object O { + @JS fun foo() {} +} diff --git a/compiler/testData/asJava/ultraLightClasses/inferringAnonymousObjectTypes.kt b/compiler/testData/asJava/ultraLightClasses/inferringAnonymousObjectTypes.kt new file mode 100644 index 00000000000..e7f75f2caa5 --- /dev/null +++ b/compiler/testData/asJava/ultraLightClasses/inferringAnonymousObjectTypes.kt @@ -0,0 +1,41 @@ +/** should load cls */ +class Prop { + private val someProp = object { } +} + + +/** should load cls */ +class Fun { + private fun someFun() = object { } +} + +/** should load cls */ +class Array { + val a1 = arrayOf( + object { val fy = "text"} + ) +} + +/** should load cls */ +private class C(val y: Int) { + val initChild = { -> + object { + override fun toString(): String { + return "child" + y + } + } + } +} + + +class Super { + val a: Any? +} + +/** should load cls */ +class Sub { + override val a = arrayOf( + object { val fy = "text"} + ) + +} \ No newline at end of file diff --git a/compiler/testData/asJava/ultraLightClasses/inheritance.kt b/compiler/testData/asJava/ultraLightClasses/inheritance.kt new file mode 100644 index 00000000000..dba936c8021 --- /dev/null +++ b/compiler/testData/asJava/ultraLightClasses/inheritance.kt @@ -0,0 +1,31 @@ + +interface Intf { + fun v(): Int +} +interface IntfWithProp : Intf { + val x: Int +} +abstract class Base(p: Int) { + open protected fun v(): Int? { } + fun nv() { } + abstract fun abs(): Int + + internal open val x: Int get() { } + open var y = 1 + open protected var z = 1 +} +class Derived(p: Int) : Base(p), IntfWithProp { + override fun v() = unknown() + override val x = 3 + override fun abs() = 0 +} +abstract class AnotherDerived(override val x: Int, override val y: Int, override val z: Int) : Base(2) { + final override fun v() { } + abstract fun noReturn(s: String) + abstract val abstractProp: Int +} + +private class Private { + override val overridesNothing: Boolean + get() = false +} diff --git a/compiler/testData/asJava/ultraLightClasses/inlineClasses.kt b/compiler/testData/asJava/ultraLightClasses/inlineClasses.kt new file mode 100644 index 00000000000..a1444d4526f --- /dev/null +++ b/compiler/testData/asJava/ultraLightClasses/inlineClasses.kt @@ -0,0 +1,23 @@ +/** should load cls */ +inline class UInt(private val value: Int) { } + +/** should load cls */ +inline enum class Foo(val x: Int) { + A(0), B(1); + + fun example() { } +} + +/** should load cls */ +inline class InlinedDelegate(var node: T) { + operator fun setValue(thisRef: A, property: KProperty<*>, value: T) { + if (node !== value) { + thisRef.notify(node, value) + } + node = value + } + + operator fun getValue(thisRef: A, property: KProperty<*>): T { + return node + } +} diff --git a/compiler/testData/asJava/ultraLightClasses/jvmName.kt b/compiler/testData/asJava/ultraLightClasses/jvmName.kt new file mode 100644 index 00000000000..58db822993d --- /dev/null +++ b/compiler/testData/asJava/ultraLightClasses/jvmName.kt @@ -0,0 +1,11 @@ +/** should load cls */ +class C { + var rwProp: Int + @JvmName("get_rwProp") + get() = 0 + @JvmName("set_rwProp") + set(v) {} + + fun getRwProp(): Int = 123 + fun setRwProp(v: Int) {} +} diff --git a/compiler/testData/asJava/ultraLightClasses/jvmOverloads.kt b/compiler/testData/asJava/ultraLightClasses/jvmOverloads.kt new file mode 100644 index 00000000000..3d420b75e88 --- /dev/null +++ b/compiler/testData/asJava/ultraLightClasses/jvmOverloads.kt @@ -0,0 +1,6 @@ +/** should load cls */ +class C @JvmOverloads constructor( + val type: String?, + val p1: Boolean = false, + val p2: String = type +) \ No newline at end of file diff --git a/compiler/testData/asJava/ultraLightClasses/objects.kt b/compiler/testData/asJava/ultraLightClasses/objects.kt new file mode 100644 index 00000000000..0f3fdf9b840 --- /dev/null +++ b/compiler/testData/asJava/ultraLightClasses/objects.kt @@ -0,0 +1,31 @@ + +class C { + companion object { + @JvmStatic fun foo() {} + fun bar() {} + @JvmStatic var x: String = "" + + var I.c: String + @JvmStatic get() = "OK" + @JvmStatic set(t: String) {} + + var c1: String + get() = "OK" + @JvmStatic set(t: String) {} + } + companion object Factory {} +} + +class C1 { + private companion object {} +} + +interface I { + companion object { } +} + +object Obj : java.lang.Runnable { + @JvmStatic var x: String = "" + override fun run() {} + @JvmStatic fun zoo(): Int = 2 +} diff --git a/compiler/testData/asJava/ultraLightClasses/properties.kt b/compiler/testData/asJava/ultraLightClasses/properties.kt new file mode 100644 index 00000000000..ad7305f6259 --- /dev/null +++ b/compiler/testData/asJava/ultraLightClasses/properties.kt @@ -0,0 +1,104 @@ + +import kotlin.reflect.KProperty + +class Foo(a: Int, val b:Foo, var c:Boolean, private val d: List, protected val e: Long = 2) { + val f1 = 2 + + val intConst: dynamic = 30 + val arrayConst: Any = byteArrayOf(1,2) + + protected var f2 = 3 + + var name: String = "x" + + val isEmpty get() = false + var isEmptyMutable: Boolean? + var islowercase: Boolean? + var isEmptyInt: Int? + var getInt: Int? + private var noAccessors: String + + internal var stringRepresentation: String + get() = this.toString() + set(value) { + setDataFromString(value) + } + + const val SUBSYSTEM_DEPRECATED: String = "This subsystem is deprecated" + + var counter = 0 + set(value) { + if (value >= 0) field = value + } + var counter2 : Int? + get() = field + set(value) { + if (value >= 0) field = value + } + + lateinit var subject: Unresolved + internal lateinit var internalVarPrivateSet: String + private set + protected lateinit var protectedLateinitVar: String + + var delegatedProp: String by Delegate() + var delegatedProp2 by MyProperty() + private var privateDelegated: Int by Delegate() + var lazyProp: String by lazy { "abc" } + + val Int.intProp: Int + get() = 1 + + final internal var internalWithPrivateSet: Int = 1 + private set + + protected var protectedWithPrivateSet: String = "" + private set + + private var privateVarWithPrivateSet = { 0 }() + private set + + private val privateValWithGet: String? + get() = "" + + private var privateVarWithGet: Object = Object() + get + + val sum: (Int)->Int = { x: Int -> sum(x - 1) + x } + + companion object { + public val prop3: Int = { 12 }() + get() { + return field + } + public var prop7 : Int = { 20 }() + set(i: Int) { + field++ + } + private const val contextBean = Context.BEAN + + val f1 = 4 + } +} + +class MyProperty { + operator fun getValue(t: T, p: KProperty<*>): Int = 42 + operator fun setValue(t: T, p: KProperty<*>, i: Int) {} +} + +class Modifiers { + @delegate:Transient + val plainField: Int = 1 + + @delegate:Transient + val lazy by lazy { 1 } +} + +interface A { + public var int1: Int + private set + protected get + public var int2: Int + public get + internal set +} diff --git a/compiler/testData/asJava/ultraLightClasses/simpleFunctions.kt b/compiler/testData/asJava/ultraLightClasses/simpleFunctions.kt new file mode 100644 index 00000000000..959d4821e19 --- /dev/null +++ b/compiler/testData/asJava/ultraLightClasses/simpleFunctions.kt @@ -0,0 +1,13 @@ +class Foo { + open fun bar(a: Int, b:Any, c:Foo): Unit {} + internal fun bar2(a: Sequence, b: Unresolved) {} + private fun bar3(x: Foo.Inner, vararg y: Inner) = "str" + fun bar4() = 42 + + public fun nullableVararg(vararg o: Any?): Unit + + operator fun plus(increment: Int): Foo {} + fun String.onString(a: (Int) -> Any?): Foo {} + + class Inner {} +} diff --git a/compiler/testData/asJava/ultraLightClasses/throwsAnnotation.kt b/compiler/testData/asJava/ultraLightClasses/throwsAnnotation.kt new file mode 100644 index 00000000000..900ad970585 --- /dev/null +++ b/compiler/testData/asJava/ultraLightClasses/throwsAnnotation.kt @@ -0,0 +1,6 @@ + +class MyException : Exception +class C @Throws(Exception::class) constructor(a: Int = 1) { + @Throws(java.io.IOException::class, MyException::class) + fun readFile(name: String): String {} +} diff --git a/compiler/testData/asJava/ultraLightClasses/typeAliases.kt b/compiler/testData/asJava/ultraLightClasses/typeAliases.kt new file mode 100644 index 00000000000..22660b288a9 --- /dev/null +++ b/compiler/testData/asJava/ultraLightClasses/typeAliases.kt @@ -0,0 +1,6 @@ +typealias JO = JvmOverloads + +/** should load cls */ +object O { + @JO fun foo(a: Int = 1, b: String = "") {} +} diff --git a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt index 31c8858eccd..692a96bea63 100755 --- a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt +++ b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt @@ -32,6 +32,8 @@ import org.jetbrains.kotlin.android.quickfix.AbstractAndroidQuickFixMultiFileTes import org.jetbrains.kotlin.android.synthetic.test.AbstractAndroidBoxTest import org.jetbrains.kotlin.android.synthetic.test.AbstractAndroidBytecodeShapeTest import org.jetbrains.kotlin.android.synthetic.test.AbstractAndroidSyntheticPropertyDescriptorTest +import org.jetbrains.kotlin.asJava.classes.AbstractUltraLightClassLoadingTest +import org.jetbrains.kotlin.asJava.classes.AbstractUltraLightClassSanityTest import org.jetbrains.kotlin.checkers.AbstractJavaAgainstKotlinBinariesCheckerTest import org.jetbrains.kotlin.checkers.AbstractJavaAgainstKotlinSourceCheckerTest import org.jetbrains.kotlin.checkers.AbstractJsCheckerTest @@ -825,6 +827,13 @@ fun main(args: Array) { model("asJava/lightClasses", excludeDirs = listOf("delegation"), pattern = KT_OR_KTS_WITHOUT_DOTS_IN_NAME) } + testClass { + model("asJava/lightClasses", pattern = KT_OR_KTS) + } + testClass { + model("asJava/ultraLightClasses", pattern = KT_OR_KTS) + } + testClass { model("asJava/lightClasses", excludeDirs = listOf("local", "compilationErrors", "ideRegression"), pattern = KT_OR_KTS_WITHOUT_DOTS_IN_NAME) } 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 35b905fa047..7776b18024a 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 @@ -16,23 +16,171 @@ package org.jetbrains.kotlin.idea.caches.resolve +import com.intellij.openapi.diagnostic.debug +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.search.GlobalSearchScope +import com.intellij.psi.util.CachedValueProvider +import com.intellij.psi.util.CachedValuesManager +import com.intellij.psi.util.PsiModificationTracker +import com.intellij.psi.util.PsiTreeUtil +import com.intellij.util.containers.ConcurrentFactoryMap 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.LightClassDataHolder +import org.jetbrains.kotlin.asJava.classes.KtUltraLightClass +import org.jetbrains.kotlin.asJava.classes.UltraLightSupport import org.jetbrains.kotlin.asJava.classes.shouldNotBeVisibleAsLightClass import org.jetbrains.kotlin.asJava.finder.JavaElementFinder +import org.jetbrains.kotlin.descriptors.ClassifierDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.idea.caches.lightClasses.IDELightClassContexts import org.jetbrains.kotlin.idea.caches.lightClasses.LazyLightClassDataHolder +import org.jetbrains.kotlin.idea.facet.KotlinFacet import org.jetbrains.kotlin.idea.resolve.frontendService +import org.jetbrains.kotlin.idea.stubindex.KotlinTypeAliasShortNameIndex +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.hasExpectModifier +import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe +import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperClassifiers import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.lazy.NoDescriptorForDeclarationException +import java.util.concurrent.ConcurrentMap + +class IDELightClassGenerationSupport(private val project: Project) : LightClassGenerationSupport() { + override fun createUltraLightClass(element: KtClassOrObject): KtUltraLightClass? { + if (element.shouldNotBeVisibleAsLightClass() || + element is KtObjectDeclaration && element.isObjectLiteral() || + element.isLocal || + element is KtEnumEntry + ) { + return null + } + + val module = ModuleUtilCore.findModuleForPsiElement(element) ?: return null + return KtUltraLightClass(element, object : UltraLightSupport { + override fun isTooComplexForUltraLightGeneration(element: KtClassOrObject): Boolean { + val facet = KotlinFacet.get(module) + val pluginClasspath = facet?.configuration?.settings?.compilerArguments?.pluginClasspaths + if (!pluginClasspath.isNullOrEmpty()) { + LOG.debug { "Using heavy light classes for ${element.fqName?.asString()} because of compiler plugins $pluginClasspath" } + 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 moduleName: String = module.name + + override fun findAnnotation(owner: KtAnnotated, fqName: FqName): Pair? { + val candidates = owner.annotationEntries.filter { it.shortName == fqName.shortName() || hasAlias(owner, fqName.shortName()) } + for (entry in candidates) { + val descriptor = analyze(entry).get(BindingContext.ANNOTATION, entry) + if (descriptor?.fqName == fqName) { + return Pair(entry, descriptor) + } + } + return null + } + }) + } + + private fun findTooComplexDeclaration(declaration: KtDeclaration): PsiElement? { + fun KtAnnotationEntry.seemsNonTrivial(): Boolean { + val name = shortName + return name == null || hasAlias(declaration, name) || name.asString().startsWith("Jvm") && name.asString() != "JvmStatic" + } + + if (declaration.hasExpectModifier() || + declaration.hasModifier(KtTokens.ANNOTATION_KEYWORD) || + declaration.hasModifier(KtTokens.INLINE_KEYWORD) && declaration is KtClassOrObject || + declaration.hasModifier(KtTokens.DATA_KEYWORD) || + declaration.hasModifier(KtTokens.ENUM_KEYWORD) || + declaration.hasModifier(KtTokens.SUSPEND_KEYWORD)) { + return declaration + } + + declaration.annotationEntries.find(KtAnnotationEntry::seemsNonTrivial)?.let { return it } + + if (declaration is KtClassOrObject) { + declaration.superTypeListEntries.find { it is KtDelegatedSuperTypeEntry }?.let { return it } + + 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 == null && (declaration as? KtFunction)?.hasBlockBody() != true) { + findPotentiallyReturnedAnonymousObject(declaration)?.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 + + } + + private fun findPotentiallyReturnedAnonymousObject(declaration: KtDeclaration): KtObjectDeclaration? { + val spine = declaration.containingKtFile.stubbedSpine + for (i in 0 until spine.stubCount) { + if (spine.getStubType(i) == KtStubElementTypes.OBJECT_DECLARATION) { + val obj = spine.getStubPsi(i) as KtObjectDeclaration + if (obj.isObjectLiteral() && PsiTreeUtil.isContextAncestor(declaration, obj, true)) { + return obj + } + } + } + return null + } + + private fun implementsKotlinCollection(classOrObject: KtClassOrObject): Boolean { + if (classOrObject.superTypeListEntries.isEmpty()) return false + + return (resolveToDescriptor(classOrObject) as? ClassifierDescriptor)?.getAllSuperClassifiers()?.any { + it.fqNameSafe.asString().startsWith("kotlin.collections.") + } == true + } + + private fun hasAlias(element: KtElement, shortName: Name): Boolean = allAliases(element.containingKtFile)[shortName.asString()] == true + + private fun allAliases(file: KtFile): ConcurrentMap = CachedValuesManager.getCachedValue(file) { + val importAliases = file.importDirectives.mapNotNull { it.aliasName }.toSet() + val map = ConcurrentFactoryMap.createMap { s -> + s in importAliases || KotlinTypeAliasShortNameIndex.getInstance().get(s, project, file.resolveScope).isNotEmpty() + } + CachedValueProvider.Result.create>(map, PsiModificationTracker.MODIFICATION_COUNT) + } -class IDELightClassGenerationSupport(project: Project) : LightClassGenerationSupport() { private val scopeFileComparator = JavaElementFinder.byClasspathComparator(GlobalSearchScope.allScope(project)) override fun createDataHolderForClass(classOrObject: KtClassOrObject, builder: LightClassBuilder): LightClassDataHolder.ForClass { diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/perf/UltraLightChecker.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/perf/UltraLightChecker.kt new file mode 100644 index 00000000000..34709159339 --- /dev/null +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/perf/UltraLightChecker.kt @@ -0,0 +1,125 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.perf + +import com.intellij.psi.* +import org.jetbrains.annotations.TestOnly +import org.jetbrains.kotlin.asJava.LightClassGenerationSupport +import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration +import org.jetbrains.kotlin.asJava.classes.KtUltraLightClass +import org.jetbrains.kotlin.psi.KtClassOrObject +import org.jetbrains.kotlin.psi.KtFile +import org.junit.Assert + +@TestOnly +object UltraLightChecker { + fun checkClassEquivalence(file: KtFile) { + for (ktClass in allClasses(file)) { + checkClassEquivalence(ktClass) + } + } + + fun allClasses(file: KtFile): List = + SyntaxTraverser.psiTraverser(file).filter(KtClassOrObject::class.java).toList() + + fun checkClassEquivalence(ktClass: KtClassOrObject): KtUltraLightClass? { + val gold = KtLightClassForSourceDeclaration.create(ktClass) + val ultraLightClass = LightClassGenerationSupport.getInstance(ktClass.project).createUltraLightClass(ktClass) ?: return null + + if (gold != null) { + Assert.assertFalse(gold.javaClass.name.contains("Ultra")) + } + + val goldText = gold?.renderClass().orEmpty() + val ultraText = ultraLightClass.renderClass() + + if (goldText != ultraText) { + Assert.assertEquals( + "// Classic implementation:\n$goldText", + "// Ultra-light implementation:\n$ultraText" + ) + } + return ultraLightClass + } + + private fun PsiAnnotation.renderAnnotation() = + "@" + qualifiedName + "(" + parameterList.attributes.joinToString { it.name + "=" + (it.value?.text ?: "?") } + ")" + + private fun PsiModifierListOwner.renderModifiers(): String { + val buffer = StringBuilder() + for (annotation in annotations) { + buffer.append(annotation.renderAnnotation()) + buffer.append(if (this is PsiParameter) " " else "\n") + } + for (modifier in PsiModifier.MODIFIERS.filter(::hasModifierProperty)) { + buffer.append(modifier).append(" ") + } + return buffer.toString() + } + + private fun PsiType.renderType() = getCanonicalText(true) + + private fun PsiReferenceList?.renderRefList(keyword: String): String { + if (this == null || this.referencedTypes.isEmpty()) return "" + return " " + keyword + " " + referencedTypes.joinToString { it.renderType() } + } + + private fun PsiVariable.renderVar(): String { + var result = this.renderModifiers() + type.renderType() + " " + name + if (this is PsiParameter && this.isVarArgs) { + result += " /* vararg */" + } + computeConstantValue()?.let { result += " /* constant value $it */" } + return result + } + + private fun PsiTypeParameterListOwner.renderTypeParams() = + if (typeParameters.isEmpty()) "" + else "<" + typeParameters.joinToString { + val bounds = + if (it.extendsListTypes.isNotEmpty()) + " extends " + it.extendsListTypes.joinToString(" & ", transform = { it.renderType() }) + else "" + it.name!! + bounds + } + "> " + + private fun PsiMethod.renderMethod() = + renderModifiers() + + (if (isVarArgs) "/* vararg */ " else "") + + renderTypeParams() + + (returnType?.renderType() ?: "") + " " + + name + + "(" + parameterList.parameters.joinToString { it.renderModifiers() + it.type.renderType() } + ")" + + (this as? PsiAnnotationMethod)?.defaultValue?.let { " default " + it.text }.orEmpty() + + throwsList.referencedTypes.let { thrownTypes -> + if (thrownTypes.isEmpty()) "" + else " throws " + thrownTypes.joinToString { it.renderType() } + } + + ";" + + private fun PsiClass.renderClass(): String { + val classWord = when { + isAnnotationType -> "@interface" + isInterface -> "interface" + isEnum -> "enum" + else -> "class" + } + + return renderModifiers() + + classWord + " " + + name + " /* " + qualifiedName + "*/" + + renderTypeParams() + + extendsList.renderRefList("extends") + + implementsList.renderRefList("implements") + + " {\n" + + (if (isEnum) fields.filterIsInstance().joinToString(",\n") { it.name } + ";\n\n" else "") + + fields.filterNot { it is PsiEnumConstant }.map { it.renderVar().prependIndent(" ") + ";\n\n" }.sorted().joinToString("") + + methods.map { it.renderMethod().prependIndent(" ") + "\n\n" }.sorted().joinToString("") + + innerClasses.map { "class ${it.name} ...\n\n".prependIndent(" ") }.sorted().joinToString("") + + "}" + } + +} \ No newline at end of file diff --git a/idea/performanceTests/org/jetbrains/kotlin/idea/perf/WholeProjectLightClassTest.kt.183 b/idea/performanceTests/org/jetbrains/kotlin/idea/perf/WholeProjectLightClassTest.kt.183 new file mode 100644 index 00000000000..eb45723ece5 --- /dev/null +++ b/idea/performanceTests/org/jetbrains/kotlin/idea/perf/WholeProjectLightClassTest.kt.183 @@ -0,0 +1,73 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.perf + +import com.intellij.openapi.util.registry.Registry +import com.intellij.openapi.vfs.VirtualFile +import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration +import org.jetbrains.kotlin.asJava.toLightClass +import org.jetbrains.kotlin.cfg.pseudocode.containingDeclarationForPseudocode +import org.jetbrains.kotlin.idea.refactoring.toPsiFile +import org.jetbrains.kotlin.psi.KtClassOrObject +import org.jetbrains.kotlin.psi.KtVisitorVoid +import java.util.* +import kotlin.system.measureNanoTime + +class WholeProjectLightClassTest : WholeProjectPerformanceTest(), WholeProjectKotlinFileProvider { + + override fun doTest(file: VirtualFile): PerFileTestResult { + val results = mutableMapOf() + var totalNs = 0L + + val psiFile = file.toPsiFile(project) ?: run { + return WholeProjectPerformanceTest.PerFileTestResult(results, totalNs, listOf(AssertionError("PsiFile not found for $file"))) + } + + val errors = mutableListOf() + + fun buildAllLightClasses(name: String, predicate: (KtClassOrObject) -> Boolean) { + val result = measureNanoTime { + try { + // Build light class by PsiFile + psiFile.acceptRecursively(object : KtVisitorVoid() { + override fun visitClassOrObject(classOrObject: KtClassOrObject) { + if (!predicate(classOrObject)) return + val lightClass = classOrObject.toLightClass() as? KtLightClassForSourceDeclaration ?: return + Arrays.hashCode(lightClass.superTypes) + Arrays.hashCode(lightClass.fields) + Arrays.hashCode(lightClass.methods) + // Just to be sure: access types + lightClass.fields.map { it.type }.hashCode() + lightClass.methods.map { it.returnType }.hashCode() + lightClass.hashCode() + } + }) + + } catch (t: Throwable) { + t.printStackTrace() + errors += t + } + } + results[name] = result + totalNs += result + } + + buildAllLightClasses("LightClasses_Top") { + it.containingDeclarationForPseudocode == null + } + + buildAllLightClasses("LightClasses_Members") { + !it.isLocal && it.containingDeclarationForPseudocode is KtClassOrObject + } + + return PerFileTestResult(results, totalNs, errors) + } + + fun testUltraLightPerformance() { + Registry.get("kotlin.use.ultra.light.classes").setValue(true, testRootDisposable) + testWholeProjectPerformance() + } +} \ No newline at end of file diff --git a/idea/performanceTests/org/jetbrains/kotlin/idea/perf/WholeProjectUltraLightClassTest.kt b/idea/performanceTests/org/jetbrains/kotlin/idea/perf/WholeProjectUltraLightClassTest.kt new file mode 100644 index 00000000000..14249f5df98 --- /dev/null +++ b/idea/performanceTests/org/jetbrains/kotlin/idea/perf/WholeProjectUltraLightClassTest.kt @@ -0,0 +1,33 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.perf + +import com.intellij.openapi.vfs.VirtualFile +import org.jetbrains.kotlin.idea.refactoring.toPsiFile +import org.jetbrains.kotlin.psi.KtFile +import kotlin.system.measureNanoTime + +// abstract so that it doesn't run in CI until known issues (JDK absence in the test project, different module names in mangled methods) are addressed +abstract class WholeProjectUltraLightClassTest : WholeProjectPerformanceTest(), WholeProjectKotlinFileProvider { + + override fun doTest(file: VirtualFile): PerFileTestResult { + val psiFile = file.toPsiFile(project) as? KtFile ?: run { + return WholeProjectPerformanceTest.PerFileTestResult(mapOf(), 0, listOf(AssertionError("PsiFile not found for $file"))) + } + + val errors = mutableListOf() + val elapsed = measureNanoTime { + try { + UltraLightChecker.checkClassEquivalence(psiFile) + } catch (t: Throwable) { + t.printStackTrace() + errors += t + } + } + + return PerFileTestResult(mapOf("ultraLightEquivalence" to elapsed), elapsed, errors) + } +} \ No newline at end of file diff --git a/idea/src/META-INF/jvm.xml b/idea/src/META-INF/jvm.xml index f62d455e259..014105f0246 100644 --- a/idea/src/META-INF/jvm.xml +++ b/idea/src/META-INF/jvm.xml @@ -170,5 +170,10 @@ + + diff --git a/idea/tests/org/jetbrains/kotlin/asJava/classes/AbstractUltraLightClassLoadingTest.kt b/idea/tests/org/jetbrains/kotlin/asJava/classes/AbstractUltraLightClassLoadingTest.kt new file mode 100644 index 00000000000..87b29c37f80 --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/asJava/classes/AbstractUltraLightClassLoadingTest.kt @@ -0,0 +1,33 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.asJava.classes + +import com.intellij.testFramework.LightProjectDescriptor +import org.jetbrains.kotlin.idea.perf.UltraLightChecker +import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase +import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor +import org.jetbrains.kotlin.psi.KtFile +import java.io.File + +abstract class AbstractUltraLightClassLoadingTest : KotlinLightCodeInsightFixtureTestCase() { + override fun getProjectDescriptor(): LightProjectDescriptor = KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE + + fun doTest(testDataPath: String) { + val file = myFixture.addFileToProject(testDataPath, File(testDataPath).readText()) as KtFile + for (ktClass in UltraLightChecker.allClasses(file)) { + val clsLoadingExpected = ktClass.docComment?.text?.contains("should load cls") == true + val ultraLightClass = UltraLightChecker.checkClassEquivalence(ktClass) + if (ultraLightClass != null) { + assertEquals( + "Cls-loaded status differs from expected for ${ultraLightClass.qualifiedName}", + clsLoadingExpected, + ultraLightClass.isClsDelegateLoaded + ) + } + } + + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/asJava/classes/AbstractUltraLightClassSanityTest.kt b/idea/tests/org/jetbrains/kotlin/asJava/classes/AbstractUltraLightClassSanityTest.kt new file mode 100644 index 00000000000..40862f9fe82 --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/asJava/classes/AbstractUltraLightClassSanityTest.kt @@ -0,0 +1,27 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.asJava.classes + +import com.intellij.testFramework.LightProjectDescriptor +import org.jetbrains.kotlin.idea.perf.UltraLightChecker +import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase +import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor +import org.jetbrains.kotlin.psi.KtFile +import java.io.File + +abstract class AbstractUltraLightClassSanityTest : KotlinLightCodeInsightFixtureTestCase() { + override fun getProjectDescriptor(): LightProjectDescriptor = KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE + + fun doTest(testDataPath: String) { + val ioFile = File(testDataPath) + if (ioFile.name == "AllOpenAnnotatedClasses.kt") { + return //tests allopen compiler plugin that we don't have in this test + } + + val file = myFixture.addFileToProject(testDataPath, ioFile.readText()) as KtFile + UltraLightChecker.checkClassEquivalence(file) + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/asJava/classes/UltraLightClassLoadingTestGenerated.java b/idea/tests/org/jetbrains/kotlin/asJava/classes/UltraLightClassLoadingTestGenerated.java new file mode 100644 index 00000000000..fbdef2e4e3e --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/asJava/classes/UltraLightClassLoadingTestGenerated.java @@ -0,0 +1,131 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.asJava.classes; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.JUnit3RunnerWithInners; +import org.jetbrains.kotlin.test.KotlinTestUtils; +import org.jetbrains.kotlin.test.TargetBackend; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.runner.RunWith; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("compiler/testData/asJava/ultraLightClasses") +@TestDataPath("$PROJECT_ROOT") +@RunWith(JUnit3RunnerWithInners.class) +public class UltraLightClassLoadingTestGenerated extends AbstractUltraLightClassLoadingTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInUltraLightClasses() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/ultraLightClasses"), Pattern.compile("^(.+)\\.(kt|kts)$"), TargetBackend.ANY, true); + } + + @TestMetadata("annotations.kt") + public void testAnnotations() throws Exception { + runTest("compiler/testData/asJava/ultraLightClasses/annotations.kt"); + } + + @TestMetadata("classModifiers.kt") + public void testClassModifiers() throws Exception { + runTest("compiler/testData/asJava/ultraLightClasses/classModifiers.kt"); + } + + @TestMetadata("constructors.kt") + public void testConstructors() throws Exception { + runTest("compiler/testData/asJava/ultraLightClasses/constructors.kt"); + } + + @TestMetadata("coroutines.kt") + public void testCoroutines() throws Exception { + runTest("compiler/testData/asJava/ultraLightClasses/coroutines.kt"); + } + + @TestMetadata("dataClasses.kt") + public void testDataClasses() throws Exception { + runTest("compiler/testData/asJava/ultraLightClasses/dataClasses.kt"); + } + + @TestMetadata("delegatingToInterfaces.kt") + public void testDelegatingToInterfaces() throws Exception { + runTest("compiler/testData/asJava/ultraLightClasses/delegatingToInterfaces.kt"); + } + + @TestMetadata("enums.kt") + public void testEnums() throws Exception { + runTest("compiler/testData/asJava/ultraLightClasses/enums.kt"); + } + + @TestMetadata("generics.kt") + public void testGenerics() throws Exception { + runTest("compiler/testData/asJava/ultraLightClasses/generics.kt"); + } + + @TestMetadata("implementingKotlinCollections.kt") + public void testImplementingKotlinCollections() throws Exception { + runTest("compiler/testData/asJava/ultraLightClasses/implementingKotlinCollections.kt"); + } + + @TestMetadata("importAliases.kt") + public void testImportAliases() throws Exception { + runTest("compiler/testData/asJava/ultraLightClasses/importAliases.kt"); + } + + @TestMetadata("inferringAnonymousObjectTypes.kt") + public void testInferringAnonymousObjectTypes() throws Exception { + runTest("compiler/testData/asJava/ultraLightClasses/inferringAnonymousObjectTypes.kt"); + } + + @TestMetadata("inheritance.kt") + public void testInheritance() throws Exception { + runTest("compiler/testData/asJava/ultraLightClasses/inheritance.kt"); + } + + @TestMetadata("inlineClasses.kt") + public void testInlineClasses() throws Exception { + runTest("compiler/testData/asJava/ultraLightClasses/inlineClasses.kt"); + } + + @TestMetadata("jvmName.kt") + public void testJvmName() throws Exception { + runTest("compiler/testData/asJava/ultraLightClasses/jvmName.kt"); + } + + @TestMetadata("jvmOverloads.kt") + public void testJvmOverloads() throws Exception { + runTest("compiler/testData/asJava/ultraLightClasses/jvmOverloads.kt"); + } + + @TestMetadata("objects.kt") + public void testObjects() throws Exception { + runTest("compiler/testData/asJava/ultraLightClasses/objects.kt"); + } + + @TestMetadata("properties.kt") + public void testProperties() throws Exception { + runTest("compiler/testData/asJava/ultraLightClasses/properties.kt"); + } + + @TestMetadata("simpleFunctions.kt") + public void testSimpleFunctions() throws Exception { + runTest("compiler/testData/asJava/ultraLightClasses/simpleFunctions.kt"); + } + + @TestMetadata("throwsAnnotation.kt") + public void testThrowsAnnotation() throws Exception { + runTest("compiler/testData/asJava/ultraLightClasses/throwsAnnotation.kt"); + } + + @TestMetadata("typeAliases.kt") + public void testTypeAliases() throws Exception { + runTest("compiler/testData/asJava/ultraLightClasses/typeAliases.kt"); + } +} diff --git a/idea/tests/org/jetbrains/kotlin/asJava/classes/UltraLightClassSanityTestGenerated.java b/idea/tests/org/jetbrains/kotlin/asJava/classes/UltraLightClassSanityTestGenerated.java new file mode 100644 index 00000000000..3ed0f8a4569 --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/asJava/classes/UltraLightClassSanityTestGenerated.java @@ -0,0 +1,548 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.asJava.classes; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.JUnit3RunnerWithInners; +import org.jetbrains.kotlin.test.KotlinTestUtils; +import org.jetbrains.kotlin.test.TargetBackend; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.runner.RunWith; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("compiler/testData/asJava/lightClasses") +@TestDataPath("$PROJECT_ROOT") +@RunWith(JUnit3RunnerWithInners.class) +public class UltraLightClassSanityTestGenerated extends AbstractUltraLightClassSanityTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInLightClasses() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses"), Pattern.compile("^(.+)\\.(kt|kts)$"), TargetBackend.ANY, true); + } + + @TestMetadata("AnnotationClass.kt") + public void testAnnotationClass() throws Exception { + runTest("compiler/testData/asJava/lightClasses/AnnotationClass.kt"); + } + + @TestMetadata("DataClassWithCustomImplementedMembers.kt") + public void testDataClassWithCustomImplementedMembers() throws Exception { + runTest("compiler/testData/asJava/lightClasses/DataClassWithCustomImplementedMembers.kt"); + } + + @TestMetadata("DelegatedNested.kt") + public void testDelegatedNested() throws Exception { + runTest("compiler/testData/asJava/lightClasses/DelegatedNested.kt"); + } + + @TestMetadata("Delegation.kt") + public void testDelegation() throws Exception { + runTest("compiler/testData/asJava/lightClasses/Delegation.kt"); + } + + @TestMetadata("DeprecatedEnumEntry.kt") + public void testDeprecatedEnumEntry() throws Exception { + runTest("compiler/testData/asJava/lightClasses/DeprecatedEnumEntry.kt"); + } + + @TestMetadata("DeprecatedNotHiddenInClass.kt") + public void testDeprecatedNotHiddenInClass() throws Exception { + runTest("compiler/testData/asJava/lightClasses/DeprecatedNotHiddenInClass.kt"); + } + + @TestMetadata("DollarsInName.kt") + public void testDollarsInName() throws Exception { + runTest("compiler/testData/asJava/lightClasses/DollarsInName.kt"); + } + + @TestMetadata("DollarsInNameNoPackage.kt") + public void testDollarsInNameNoPackage() throws Exception { + runTest("compiler/testData/asJava/lightClasses/DollarsInNameNoPackage.kt"); + } + + @TestMetadata("ExtendingInterfaceWithDefaultImpls.kt") + public void testExtendingInterfaceWithDefaultImpls() throws Exception { + runTest("compiler/testData/asJava/lightClasses/ExtendingInterfaceWithDefaultImpls.kt"); + } + + @TestMetadata("HiddenDeprecated.kt") + public void testHiddenDeprecated() throws Exception { + runTest("compiler/testData/asJava/lightClasses/HiddenDeprecated.kt"); + } + + @TestMetadata("HiddenDeprecatedInClass.kt") + public void testHiddenDeprecatedInClass() throws Exception { + runTest("compiler/testData/asJava/lightClasses/HiddenDeprecatedInClass.kt"); + } + + @TestMetadata("InheritingInterfaceDefaultImpls.kt") + public void testInheritingInterfaceDefaultImpls() throws Exception { + runTest("compiler/testData/asJava/lightClasses/InheritingInterfaceDefaultImpls.kt"); + } + + @TestMetadata("JvmNameOnMember.kt") + public void testJvmNameOnMember() throws Exception { + runTest("compiler/testData/asJava/lightClasses/JvmNameOnMember.kt"); + } + + @TestMetadata("JvmStatic.kt") + public void testJvmStatic() throws Exception { + runTest("compiler/testData/asJava/lightClasses/JvmStatic.kt"); + } + + @TestMetadata("NestedObjects.kt") + public void testNestedObjects() throws Exception { + runTest("compiler/testData/asJava/lightClasses/NestedObjects.kt"); + } + + @TestMetadata("NonDataClassWithComponentFunctions.kt") + public void testNonDataClassWithComponentFunctions() throws Exception { + runTest("compiler/testData/asJava/lightClasses/NonDataClassWithComponentFunctions.kt"); + } + + @TestMetadata("PublishedApi.kt") + public void testPublishedApi() throws Exception { + runTest("compiler/testData/asJava/lightClasses/PublishedApi.kt"); + } + + @TestMetadata("SpecialAnnotationsOnAnnotationClass.kt") + public void testSpecialAnnotationsOnAnnotationClass() throws Exception { + runTest("compiler/testData/asJava/lightClasses/SpecialAnnotationsOnAnnotationClass.kt"); + } + + @TestMetadata("StubOrderForOverloads.kt") + public void testStubOrderForOverloads() throws Exception { + runTest("compiler/testData/asJava/lightClasses/StubOrderForOverloads.kt"); + } + + @TestMetadata("VarArgs.kt") + public void testVarArgs() throws Exception { + runTest("compiler/testData/asJava/lightClasses/VarArgs.kt"); + } + + @TestMetadata("compiler/testData/asJava/lightClasses/compilationErrors") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class CompilationErrors extends AbstractUltraLightClassSanityTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + @TestMetadata("ActualClass.kt") + public void testActualClass() throws Exception { + runTest("compiler/testData/asJava/lightClasses/compilationErrors/ActualClass.kt"); + } + + @TestMetadata("ActualTypeAlias.kt") + public void testActualTypeAlias() throws Exception { + runTest("compiler/testData/asJava/lightClasses/compilationErrors/ActualTypeAlias.kt"); + } + + @TestMetadata("ActualTypeAliasCustomJvmPackageName.kt") + public void testActualTypeAliasCustomJvmPackageName() throws Exception { + runTest("compiler/testData/asJava/lightClasses/compilationErrors/ActualTypeAliasCustomJvmPackageName.kt"); + } + + public void testAllFilesPresentInCompilationErrors() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/compilationErrors"), Pattern.compile("^(.+)\\.(kt|kts)$"), TargetBackend.ANY, true); + } + + @TestMetadata("AllInlineOnly.kt") + public void testAllInlineOnly() throws Exception { + runTest("compiler/testData/asJava/lightClasses/compilationErrors/AllInlineOnly.kt"); + } + + @TestMetadata("AnnotationModifiers.kt") + public void testAnnotationModifiers() throws Exception { + runTest("compiler/testData/asJava/lightClasses/compilationErrors/AnnotationModifiers.kt"); + } + + @TestMetadata("ExpectClass.kt") + public void testExpectClass() throws Exception { + runTest("compiler/testData/asJava/lightClasses/compilationErrors/ExpectClass.kt"); + } + + @TestMetadata("ExpectObject.kt") + public void testExpectObject() throws Exception { + runTest("compiler/testData/asJava/lightClasses/compilationErrors/ExpectObject.kt"); + } + + @TestMetadata("ExpectedNestedClass.kt") + public void testExpectedNestedClass() throws Exception { + runTest("compiler/testData/asJava/lightClasses/compilationErrors/ExpectedNestedClass.kt"); + } + + @TestMetadata("ExpectedNestedClassInObject.kt") + public void testExpectedNestedClassInObject() throws Exception { + runTest("compiler/testData/asJava/lightClasses/compilationErrors/ExpectedNestedClassInObject.kt"); + } + + @TestMetadata("JvmPackageName.kt") + public void testJvmPackageName() throws Exception { + runTest("compiler/testData/asJava/lightClasses/compilationErrors/JvmPackageName.kt"); + } + + @TestMetadata("LocalInAnnotation.kt") + public void testLocalInAnnotation() throws Exception { + runTest("compiler/testData/asJava/lightClasses/compilationErrors/LocalInAnnotation.kt"); + } + + @TestMetadata("PrivateInTrait.kt") + public void testPrivateInTrait() throws Exception { + runTest("compiler/testData/asJava/lightClasses/compilationErrors/PrivateInTrait.kt"); + } + + @TestMetadata("RepetableAnnotations.kt") + public void testRepetableAnnotations() throws Exception { + runTest("compiler/testData/asJava/lightClasses/compilationErrors/RepetableAnnotations.kt"); + } + + @TestMetadata("SameName.kt") + public void testSameName() throws Exception { + runTest("compiler/testData/asJava/lightClasses/compilationErrors/SameName.kt"); + } + + @TestMetadata("TopLevelDestructuring.kt") + public void testTopLevelDestructuring() throws Exception { + runTest("compiler/testData/asJava/lightClasses/compilationErrors/TopLevelDestructuring.kt"); + } + + @TestMetadata("TraitClassObjectField.kt") + public void testTraitClassObjectField() throws Exception { + runTest("compiler/testData/asJava/lightClasses/compilationErrors/TraitClassObjectField.kt"); + } + + @TestMetadata("WrongAnnotations.kt") + public void testWrongAnnotations() throws Exception { + runTest("compiler/testData/asJava/lightClasses/compilationErrors/WrongAnnotations.kt"); + } + } + + @TestMetadata("compiler/testData/asJava/lightClasses/delegation") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Delegation extends AbstractUltraLightClassSanityTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInDelegation() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/delegation"), Pattern.compile("^(.+)\\.(kt|kts)$"), TargetBackend.ANY, true); + } + + @TestMetadata("Function.kt") + public void testFunction() throws Exception { + runTest("compiler/testData/asJava/lightClasses/delegation/Function.kt"); + } + + @TestMetadata("Property.kt") + public void testProperty() throws Exception { + runTest("compiler/testData/asJava/lightClasses/delegation/Property.kt"); + } + + @TestMetadata("WithPlatformTypes.NoCompile.kt") + public void testWithPlatformTypes_NoCompile() throws Exception { + runTest("compiler/testData/asJava/lightClasses/delegation/WithPlatformTypes.NoCompile.kt"); + } + } + + @TestMetadata("compiler/testData/asJava/lightClasses/facades") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Facades extends AbstractUltraLightClassSanityTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInFacades() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/facades"), Pattern.compile("^(.+)\\.(kt|kts)$"), TargetBackend.ANY, true); + } + + @TestMetadata("AllPrivate.kt") + public void testAllPrivate() throws Exception { + runTest("compiler/testData/asJava/lightClasses/facades/AllPrivate.kt"); + } + + @TestMetadata("EmptyFile.NoCompile.kt") + public void testEmptyFile_NoCompile() throws Exception { + runTest("compiler/testData/asJava/lightClasses/facades/EmptyFile.NoCompile.kt"); + } + + @TestMetadata("MultiFile.kt") + public void testMultiFile() throws Exception { + runTest("compiler/testData/asJava/lightClasses/facades/MultiFile.kt"); + } + + @TestMetadata("SingleFile.kt") + public void testSingleFile() throws Exception { + runTest("compiler/testData/asJava/lightClasses/facades/SingleFile.kt"); + } + + @TestMetadata("SingleJvmClassName.kt") + public void testSingleJvmClassName() throws Exception { + runTest("compiler/testData/asJava/lightClasses/facades/SingleJvmClassName.kt"); + } + } + + @TestMetadata("compiler/testData/asJava/lightClasses/ideRegression") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class IdeRegression extends AbstractUltraLightClassSanityTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInIdeRegression() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/ideRegression"), Pattern.compile("^(.+)\\.(kt|kts)$"), TargetBackend.ANY, true); + } + + @TestMetadata("AllOpenAnnotatedClasses.kt") + public void testAllOpenAnnotatedClasses() throws Exception { + runTest("compiler/testData/asJava/lightClasses/ideRegression/AllOpenAnnotatedClasses.kt"); + } + + @TestMetadata("ImplementingCharSequenceAndNumber.kt") + public void testImplementingCharSequenceAndNumber() throws Exception { + runTest("compiler/testData/asJava/lightClasses/ideRegression/ImplementingCharSequenceAndNumber.kt"); + } + + @TestMetadata("ImplementingMap.kt") + public void testImplementingMap() throws Exception { + runTest("compiler/testData/asJava/lightClasses/ideRegression/ImplementingMap.kt"); + } + + @TestMetadata("ImplementingMutableSet.kt") + public void testImplementingMutableSet() throws Exception { + runTest("compiler/testData/asJava/lightClasses/ideRegression/ImplementingMutableSet.kt"); + } + + @TestMetadata("InheritingInterfaceDefaultImpls.kt") + public void testInheritingInterfaceDefaultImpls() throws Exception { + runTest("compiler/testData/asJava/lightClasses/ideRegression/InheritingInterfaceDefaultImpls.kt"); + } + + @TestMetadata("OverridingFinalInternal.kt") + public void testOverridingFinalInternal() throws Exception { + runTest("compiler/testData/asJava/lightClasses/ideRegression/OverridingFinalInternal.kt"); + } + + @TestMetadata("OverridingFinalInternal.extra.kt") + public void testOverridingFinalInternal_extra() throws Exception { + runTest("compiler/testData/asJava/lightClasses/ideRegression/OverridingFinalInternal.extra.kt"); + } + + @TestMetadata("OverridingInternal.kt") + public void testOverridingInternal() throws Exception { + runTest("compiler/testData/asJava/lightClasses/ideRegression/OverridingInternal.kt"); + } + + @TestMetadata("OverridingInternal.extra.kt") + public void testOverridingInternal_extra() throws Exception { + runTest("compiler/testData/asJava/lightClasses/ideRegression/OverridingInternal.extra.kt"); + } + + @TestMetadata("OverridingProtected.kt") + public void testOverridingProtected() throws Exception { + runTest("compiler/testData/asJava/lightClasses/ideRegression/OverridingProtected.kt"); + } + + @TestMetadata("OverridingProtected.extra.kt") + public void testOverridingProtected_extra() throws Exception { + runTest("compiler/testData/asJava/lightClasses/ideRegression/OverridingProtected.extra.kt"); + } + } + + @TestMetadata("compiler/testData/asJava/lightClasses/local") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Local extends AbstractUltraLightClassSanityTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInLocal() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/local"), Pattern.compile("^(.+)\\.(kt|kts)$"), TargetBackend.ANY, true); + } + + @TestMetadata("DollarsInNameLocal.kt") + public void testDollarsInNameLocal() throws Exception { + runTest("compiler/testData/asJava/lightClasses/local/DollarsInNameLocal.kt"); + } + } + + @TestMetadata("compiler/testData/asJava/lightClasses/nullabilityAnnotations") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class NullabilityAnnotations extends AbstractUltraLightClassSanityTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInNullabilityAnnotations() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/nullabilityAnnotations"), Pattern.compile("^(.+)\\.(kt|kts)$"), TargetBackend.ANY, true); + } + + @TestMetadata("Class.kt") + public void testClass() throws Exception { + runTest("compiler/testData/asJava/lightClasses/nullabilityAnnotations/Class.kt"); + } + + @TestMetadata("ClassObjectField.kt") + public void testClassObjectField() throws Exception { + runTest("compiler/testData/asJava/lightClasses/nullabilityAnnotations/ClassObjectField.kt"); + } + + @TestMetadata("ClassWithConstructor.kt") + public void testClassWithConstructor() throws Exception { + runTest("compiler/testData/asJava/lightClasses/nullabilityAnnotations/ClassWithConstructor.kt"); + } + + @TestMetadata("ClassWithConstructorAndProperties.kt") + public void testClassWithConstructorAndProperties() throws Exception { + runTest("compiler/testData/asJava/lightClasses/nullabilityAnnotations/ClassWithConstructorAndProperties.kt"); + } + + @TestMetadata("FileFacade.kt") + public void testFileFacade() throws Exception { + runTest("compiler/testData/asJava/lightClasses/nullabilityAnnotations/FileFacade.kt"); + } + + @TestMetadata("Generic.kt") + public void testGeneric() throws Exception { + runTest("compiler/testData/asJava/lightClasses/nullabilityAnnotations/Generic.kt"); + } + + @TestMetadata("IntOverridesAny.kt") + public void testIntOverridesAny() throws Exception { + runTest("compiler/testData/asJava/lightClasses/nullabilityAnnotations/IntOverridesAny.kt"); + } + + @TestMetadata("JvmOverloads.kt") + public void testJvmOverloads() throws Exception { + runTest("compiler/testData/asJava/lightClasses/nullabilityAnnotations/JvmOverloads.kt"); + } + + @TestMetadata("NullableUnitReturn.kt") + public void testNullableUnitReturn() throws Exception { + runTest("compiler/testData/asJava/lightClasses/nullabilityAnnotations/NullableUnitReturn.kt"); + } + + @TestMetadata("OverrideAnyWithUnit.kt") + public void testOverrideAnyWithUnit() throws Exception { + runTest("compiler/testData/asJava/lightClasses/nullabilityAnnotations/OverrideAnyWithUnit.kt"); + } + + @TestMetadata("PlatformTypes.kt") + public void testPlatformTypes() throws Exception { + runTest("compiler/testData/asJava/lightClasses/nullabilityAnnotations/PlatformTypes.kt"); + } + + @TestMetadata("Primitives.kt") + public void testPrimitives() throws Exception { + runTest("compiler/testData/asJava/lightClasses/nullabilityAnnotations/Primitives.kt"); + } + + @TestMetadata("PrivateInClass.kt") + public void testPrivateInClass() throws Exception { + runTest("compiler/testData/asJava/lightClasses/nullabilityAnnotations/PrivateInClass.kt"); + } + + @TestMetadata("Synthetic.kt") + public void testSynthetic() throws Exception { + runTest("compiler/testData/asJava/lightClasses/nullabilityAnnotations/Synthetic.kt"); + } + + @TestMetadata("Trait.kt") + public void testTrait() throws Exception { + runTest("compiler/testData/asJava/lightClasses/nullabilityAnnotations/Trait.kt"); + } + + @TestMetadata("UnitAsGenericArgument.kt") + public void testUnitAsGenericArgument() throws Exception { + runTest("compiler/testData/asJava/lightClasses/nullabilityAnnotations/UnitAsGenericArgument.kt"); + } + + @TestMetadata("UnitParameter.kt") + public void testUnitParameter() throws Exception { + runTest("compiler/testData/asJava/lightClasses/nullabilityAnnotations/UnitParameter.kt"); + } + + @TestMetadata("VoidReturn.kt") + public void testVoidReturn() throws Exception { + runTest("compiler/testData/asJava/lightClasses/nullabilityAnnotations/VoidReturn.kt"); + } + } + + @TestMetadata("compiler/testData/asJava/lightClasses/object") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Object extends AbstractUltraLightClassSanityTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInObject() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/object"), Pattern.compile("^(.+)\\.(kt|kts)$"), TargetBackend.ANY, true); + } + + @TestMetadata("SimpleObject.kt") + public void testSimpleObject() throws Exception { + runTest("compiler/testData/asJava/lightClasses/object/SimpleObject.kt"); + } + } + + @TestMetadata("compiler/testData/asJava/lightClasses/publicField") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class PublicField extends AbstractUltraLightClassSanityTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInPublicField() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/publicField"), Pattern.compile("^(.+)\\.(kt|kts)$"), TargetBackend.ANY, true); + } + + @TestMetadata("CompanionObject.kt") + public void testCompanionObject() throws Exception { + runTest("compiler/testData/asJava/lightClasses/publicField/CompanionObject.kt"); + } + + @TestMetadata("Simple.kt") + public void testSimple() throws Exception { + runTest("compiler/testData/asJava/lightClasses/publicField/Simple.kt"); + } + } + + @TestMetadata("compiler/testData/asJava/lightClasses/script") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Script extends AbstractUltraLightClassSanityTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInScript() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/script"), Pattern.compile("^(.+)\\.(kt|kts)$"), TargetBackend.ANY, true); + } + + @TestMetadata("HelloWorld.kts") + public void testHelloWorld() throws Exception { + runTest("compiler/testData/asJava/lightClasses/script/HelloWorld.kts"); + } + + @TestMetadata("InnerClasses.kts") + public void testInnerClasses() throws Exception { + runTest("compiler/testData/asJava/lightClasses/script/InnerClasses.kts"); + } + } +}