From 79a603768a1399ba673296b551688f9f89f0572b Mon Sep 17 00:00:00 2001 From: Igor Yakovlev Date: Mon, 8 Jul 2019 21:27:18 +0300 Subject: [PATCH] UltraLight implementation for local and anonymous declarations --- .../kotlin/codegen/state/KotlinTypeMapper.kt | 7 +- .../KtLightClassForAnonymousDeclaration.kt | 71 ++++------ .../KtLightClassForLocalDeclaration.kt | 129 +++++++++--------- .../ultraLightClassForAnonymousDeclaration.kt | 67 +++++++++ .../ultraLightClassForLocalDeclaration.kt | 24 ++++ .../classes/ultraLightMembersCreator.kt | 3 +- .../kotlin/asJava/classes/ultraLightUtils.kt | 22 ++- .../local/DollarsInNameLocal.java | 15 -- .../ultraLightClasses/dollarsInNameLocal.java | 37 +++++ .../dollarsInNameLocal.kt} | 2 +- .../inferringAnonymousObjectTypes.java | 93 +++++++++++++ .../ultraLightClasses/localClassDerived.java | 19 +++ .../ultraLightClasses/localClassDerived.kt | 7 + .../load/kotlin/typeSignatureMapping.kt | 4 + .../resolve/IDELightClassGenerationSupport.kt | 21 ++- .../UltraLightClassLoadingTestGenerated.java | 10 ++ .../UltraLightClassSanityTestGenerated.java | 18 --- .../resolve/IdeLightClassTestGenerated.java | 18 --- 18 files changed, 389 insertions(+), 178 deletions(-) create mode 100644 compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightClassForAnonymousDeclaration.kt create mode 100644 compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightClassForLocalDeclaration.kt delete mode 100644 compiler/testData/asJava/lightClasses/local/DollarsInNameLocal.java create mode 100644 compiler/testData/asJava/ultraLightClasses/dollarsInNameLocal.java rename compiler/testData/asJava/{lightClasses/local/DollarsInNameLocal.kt => ultraLightClasses/dollarsInNameLocal.kt} (99%) create mode 100644 compiler/testData/asJava/ultraLightClasses/localClassDerived.java create mode 100644 compiler/testData/asJava/ultraLightClasses/localClassDerived.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.kt index a66d5e5f2cb..ada3bd6bb78 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.kt @@ -87,7 +87,8 @@ class KotlinTypeMapper @JvmOverloads constructor( private val incompatibleClassTracker: IncompatibleClassTracker = IncompatibleClassTracker.DoNothing, val jvmTarget: JvmTarget = JvmTarget.DEFAULT, private val isIrBackend: Boolean = false, - private val typePreprocessor: ((KotlinType) -> KotlinType?)? = null + private val typePreprocessor: ((KotlinType) -> KotlinType?)? = null, + private val namePreprocessor: ((ClassDescriptor) -> String?)? = null ) { private val isReleaseCoroutines = languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines) @@ -104,6 +105,10 @@ class KotlinTypeMapper @JvmOverloads constructor( return getPredefinedTypeForClass(classDescriptor)?.internalName } + override fun getPredefinedFullInternalNameForClass(classDescriptor: ClassDescriptor): String? { + return namePreprocessor?.invoke(classDescriptor) + } + override fun processErrorType(kotlinType: KotlinType, descriptor: ClassDescriptor) { if (classBuilderMode.generateBodies) { throw IllegalStateException(generateErrorMessageForErrorType(kotlinType, descriptor)) diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForAnonymousDeclaration.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForAnonymousDeclaration.kt index 6dea7347a66..3ce55aa15c5 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForAnonymousDeclaration.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForAnonymousDeclaration.kt @@ -1,31 +1,20 @@ /* - * Copyright 2010-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package org.jetbrains.kotlin.asJava.classes -import com.intellij.openapi.diagnostic.Logger import com.intellij.psi.* import com.intellij.psi.impl.InheritanceImplUtil import com.intellij.psi.search.GlobalSearchScope import com.intellij.reference.SoftReference +import org.jetbrains.kotlin.asJava.elements.KtLightIdentifier import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.resolve.DescriptorUtils internal open class KtLightClassForAnonymousDeclaration(classOrObject: KtClassOrObject) : - KtLightClassForLocalDeclaration(classOrObject), PsiAnonymousClass { + KtLightClassForLocalDeclaration(classOrObject), PsiAnonymousClass { private var cachedBaseType: SoftReference? = null @@ -33,33 +22,13 @@ internal open class KtLightClassForAnonymousDeclaration(classOrObject: KtClassOr return JavaPsiFacade.getElementFactory(classOrObject.project).createReferenceElementByType(baseClassType) } - private val firstSupertypeFQName: String - get() { - val descriptor = getDescriptor() ?: return CommonClassNames.JAVA_LANG_OBJECT - - val superTypes = descriptor.typeConstructor.supertypes - - if (superTypes.isEmpty()) return CommonClassNames.JAVA_LANG_OBJECT - - val superType = superTypes.iterator().next() - val superClassDescriptor = superType.constructor.declarationDescriptor - - if (superClassDescriptor == null) { - LOG.error("No declaration descriptor for supertype " + superType + " of " + getDescriptor()) - - // return java.lang.Object for recovery - return CommonClassNames.JAVA_LANG_OBJECT - } - - return DescriptorUtils.getFqName(superClassDescriptor).asString() - } - - @Synchronized override fun getBaseClassType(): PsiClassType { + @Synchronized + override fun getBaseClassType(): PsiClassType { var type: PsiClassType? = null if (cachedBaseType != null) type = cachedBaseType!!.get() if (type != null && type.isValid) return type - val firstSupertypeFQName = firstSupertypeFQName + val firstSupertypeFQName = getFirstSupertypeFQNameForAnonymousDeclaration() for (superType in superTypes) { val superClass = superType.resolve() if (superClass != null && firstSupertypeFQName == superClass.qualifiedName) { @@ -106,20 +75,36 @@ internal open class KtLightClassForAnonymousDeclaration(classOrObject: KtClassOr return InheritanceImplUtil.isInheritor(this, baseClass, checkDeep) } - override fun getNameIdentifier() = null + override fun getNameIdentifier(): KtLightIdentifier? = null override fun getModifierList(): PsiModifierList? = null override fun hasModifierProperty(name: String): Boolean = name == PsiModifier.FINAL - override fun getExtendsList() = null - override fun getImplementsList() = null + override fun getExtendsList(): PsiReferenceList? = null + override fun getImplementsList(): PsiReferenceList? = null override fun getContainingClass(): PsiClass? = null override fun isInterface() = false override fun isAnnotationType() = false - override fun getTypeParameterList() = null + override fun getTypeParameterList(): PsiTypeParameterList? = null override fun isEnum() = false override fun copy(): PsiElement = KtLightClassForAnonymousDeclaration(classOrObject) companion object { - private val LOG = Logger.getInstance(KtLightClassForAnonymousDeclaration::class.java) + fun KtLightClassForSourceDeclaration.getFirstSupertypeFQNameForAnonymousDeclaration(): String { + val descriptor = getDescriptor() ?: return CommonClassNames.JAVA_LANG_OBJECT + + val superTypes = descriptor.typeConstructor.supertypes + + if (superTypes.isEmpty()) return CommonClassNames.JAVA_LANG_OBJECT + + val superType = superTypes.iterator().next() + val superClassDescriptor = superType.constructor.declarationDescriptor + + if (superClassDescriptor === null) { + // return java.lang.Object for recovery + return CommonClassNames.JAVA_LANG_OBJECT + } + + return DescriptorUtils.getFqName(superClassDescriptor).asString() + } } } diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForLocalDeclaration.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForLocalDeclaration.kt index 77b238bd9f1..79bc7334724 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForLocalDeclaration.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForLocalDeclaration.kt @@ -1,17 +1,6 @@ /* - * Copyright 2010-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package org.jetbrains.kotlin.asJava.classes @@ -22,14 +11,16 @@ import com.intellij.psi.PsiMethod import com.intellij.psi.impl.light.LightClass import com.intellij.psi.impl.light.LightMethod import org.jetbrains.kotlin.analyzer.KotlinModificationTrackerService +import com.intellij.psi.util.PsiTreeUtil import org.jetbrains.kotlin.asJava.LightClassUtil import org.jetbrains.kotlin.asJava.toLightClass import org.jetbrains.kotlin.idea.KotlinLanguage +import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType open class KtLightClassForLocalDeclaration( - classOrObject: KtClassOrObject + classOrObject: KtClassOrObject ) : KtLightClassForSourceDeclaration(classOrObject) { override val myInnersCache: KotlinClassInnerStuffCache = KotlinClassInnerStuffCache( @@ -45,80 +36,82 @@ open class KtLightClassForLocalDeclaration( ) override fun copy(): PsiElement = KtLightClassForLocalDeclaration(classOrObject.copy() as KtClassOrObject) + override fun getQualifiedName(): String? = null override fun getParent() = _parent - private val _parent: PsiElement? by lazyPub(this::computeParent) + private val _parent: PsiElement? by lazyPub { getParentForLocalDeclaration(classOrObject) } - private fun computeParent(): PsiElement? { - fun getParentByPsiMethod(method: PsiMethod?, name: String?, forceMethodWrapping: Boolean): PsiElement? { - if (method == null || name == null) return null + companion object { + fun getParentForLocalDeclaration(classOrObject: KtClassOrObject): PsiElement? { - var containingClass: PsiClass? = method.containingClass ?: return null + fun getParentByPsiMethod(method: PsiMethod?, name: String?, forceMethodWrapping: Boolean): PsiElement? { + if (method == null || name == null) return null - val currentFileName = classOrObject.containingFile.name + var containingClass: PsiClass? = method.containingClass ?: return null - var createWrapper = forceMethodWrapping - // Use PsiClass wrapper instead of package light class to avoid names like "FooPackage" in Type Hierarchy and related views - if (containingClass is KtLightClassForFacade) { - containingClass = object : LightClass(containingClass as KtLightClassForFacade, KotlinLanguage.INSTANCE) { - override fun getName(): String? { - return currentFileName + val currentFileName = classOrObject.containingFile.name + + var createWrapper = forceMethodWrapping + // Use PsiClass wrapper instead of package light class to avoid names like "FooPackage" in Type Hierarchy and related views + if (containingClass is KtLightClassForFacade) { + containingClass = object : LightClass(containingClass as KtLightClassForFacade, KotlinLanguage.INSTANCE) { + override fun getName(): String? = currentFileName + } + createWrapper = true + } + + if (createWrapper) { + return object : LightMethod(classOrObject.manager, method, containingClass!!, KotlinLanguage.INSTANCE) { + override fun getParent(): PsiElement = getContainingClass() + override fun getName(): String = name } } - createWrapper = true + + return method } - if (createWrapper) { - return object : LightMethod(myManager, method, containingClass!!, KotlinLanguage.INSTANCE) { - override fun getParent(): PsiElement { - return getContainingClass() - } - - override fun getName(): String { - return name - } - } - } - - return method - } - - var declaration: PsiElement? = KtPsiUtil.getTopmostParentOfTypes( + var declaration: PsiElement? = KtPsiUtil.getTopmostParentOfTypes( classOrObject, KtNamedFunction::class.java, KtConstructor::class.java, KtProperty::class.java, KtAnonymousInitializer::class.java, - KtParameter::class.java) + KtParameter::class.java + ) - if (declaration is KtParameter) { - declaration = declaration.getStrictParentOfType() - } - - if (declaration is KtFunction) { - return getParentByPsiMethod(LightClassUtil.getLightClassMethod(declaration), declaration.name, false) - } - - // Represent the property as a fake method with the same name - if (declaration is KtProperty) { - return getParentByPsiMethod(LightClassUtil.getLightClassPropertyMethods(declaration).getter, declaration.name, true) - } - - if (declaration is KtAnonymousInitializer) { - val parent = declaration.parent - val grandparent = parent.parent - - if (parent is KtClassBody && grandparent is KtClassOrObject) { - return grandparent.toLightClass() + if (declaration is KtParameter) { + declaration = declaration.getStrictParentOfType() } - } - if (declaration is KtClass) { - return declaration.toLightClass() + if (declaration is KtFunction) { + return getParentByPsiMethod( + LightClassUtil.getLightClassMethod(declaration), + declaration.name, + forceMethodWrapping = false + ) + } + + // Represent the property as a fake method with the same name + if (declaration is KtProperty) { + return getParentByPsiMethod( + LightClassUtil.getLightClassPropertyMethods(declaration).getter, + declaration.name, + forceMethodWrapping = true + ) + } + + if (declaration is KtAnonymousInitializer) { + val parent = declaration.parent + val grandparent = parent.parent + + if (parent is KtClassBody && grandparent is KtClassOrObject) { + return grandparent.toLightClass() + } + } + + return if (declaration is KtClass) declaration.toLightClass() else null } - return null } - } \ No newline at end of file diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightClassForAnonymousDeclaration.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightClassForAnonymousDeclaration.kt new file mode 100644 index 00000000000..acf00090515 --- /dev/null +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightClassForAnonymousDeclaration.kt @@ -0,0 +1,67 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.asJava.classes + +import com.intellij.psi.* +import com.intellij.psi.impl.InheritanceImplUtil +import org.jetbrains.kotlin.asJava.classes.KtLightClassForAnonymousDeclaration.Companion.getFirstSupertypeFQNameForAnonymousDeclaration +import org.jetbrains.kotlin.asJava.elements.KtLightIdentifier +import org.jetbrains.kotlin.psi.KtClassOrObject + +open class KtUltraLightClassForAnonymousDeclaration(classOrObject: KtClassOrObject, support: KtUltraLightSupport) : + KtUltraLightClassForLocalDeclaration(classOrObject, support), PsiAnonymousClass { + + override fun getBaseClassReference() = + JavaPsiFacade.getElementFactory(classOrObject.project).createReferenceElementByType(baseClassType) + + private val _baseClassType by lazyPub { + + val firstSupertypeFQName = getFirstSupertypeFQNameForAnonymousDeclaration() + + if (firstSupertypeFQName == CommonClassNames.JAVA_LANG_OBJECT) { + return@lazyPub PsiType.getJavaLangObject(kotlinOrigin.manager, resolveScope) + } + + extendsListTypes.find { it.resolve()?.qualifiedName == firstSupertypeFQName }?.let { return@lazyPub it } + implementsListTypes.find { it.resolve()?.qualifiedName == firstSupertypeFQName }?.let { return@lazyPub it } + + PsiType.getJavaLangObject(kotlinOrigin.manager, resolveScope) + } + + override fun getBaseClassType(): PsiClassType = _baseClassType + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || this::class.java != other::class.java) return false + + val aClass = other as KtUltraLightClassForAnonymousDeclaration + + return classOrObject == aClass.classOrObject + } + + override fun isInheritor(baseClass: PsiClass, checkDeep: Boolean): Boolean { + if (baseClass is KtLightClassForSourceDeclaration) { + return super.isInheritor(baseClass, checkDeep) + } + + return InheritanceImplUtil.isInheritor(this, baseClass, checkDeep) + } + + override fun hashCode(): Int = classOrObject.hashCode() + override fun getArgumentList(): PsiExpressionList? = null + override fun isInQualifiedNew(): Boolean = false + override fun getName(): String? = null + override fun getNameIdentifier(): KtLightIdentifier? = null + override fun getModifierList(): PsiModifierList? = null + override fun hasModifierProperty(name: String): Boolean = name == PsiModifier.FINAL + override fun getContainingClass(): PsiClass? = null + override fun isInterface() = false + override fun isAnnotationType() = false + override fun getTypeParameterList(): PsiTypeParameterList? = null + override fun isEnum() = false + + override fun copy() = KtUltraLightClassForAnonymousDeclaration(classOrObject, support) +} \ No newline at end of file diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightClassForLocalDeclaration.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightClassForLocalDeclaration.kt new file mode 100644 index 00000000000..0e32ff33853 --- /dev/null +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightClassForLocalDeclaration.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.asJava.classes + +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.asJava.classes.KtLightClassForLocalDeclaration.Companion.getParentForLocalDeclaration +import org.jetbrains.kotlin.psi.KtClassOrObject + +open class KtUltraLightClassForLocalDeclaration( + classOrObject: KtClassOrObject, + support: KtUltraLightSupport +) : KtUltraLightClass(classOrObject, support) { + + private val _parent: PsiElement? by lazyPub { getParentForLocalDeclaration(classOrObject) } + + override fun copy() = KtUltraLightClassForLocalDeclaration(classOrObject.copy() as KtClassOrObject, support) + + override fun getQualifiedName(): String? = null + + override fun getParent() = _parent +} \ No newline at end of file diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMembersCreator.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMembersCreator.kt index d674ef85f28..6d3dcd363e3 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMembersCreator.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMembersCreator.kt @@ -157,8 +157,7 @@ internal class UltraLightMembersCreator( ): KtLightMethod { val isConstructor = ktFunction is KtConstructor<*> val name = - if (isConstructor) - containingClass.name + if (isConstructor) containingClass.name else computeMethodName(ktFunction, ktFunction.name ?: SpecialNames.NO_NAME_PROVIDED.asString(), MethodType.REGULAR) val method = lightMethod(name.orEmpty(), ktFunction, forceStatic, forcePrivate) diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightUtils.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightUtils.kt index 777990e8a44..d7f24432b36 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightUtils.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightUtils.kt @@ -12,9 +12,7 @@ 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.LightMethodBuilder -import com.intellij.psi.impl.light.LightModifierList -import com.intellij.psi.impl.light.LightParameterListBuilder +import com.intellij.psi.impl.light.* import com.intellij.util.BitUtil.isSet import com.intellij.util.containers.ContainerUtil import org.jetbrains.kotlin.asJava.LightClassGenerationSupport @@ -29,9 +27,10 @@ import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.load.kotlin.TypeMappingMode +import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.DescriptorUtils @@ -40,6 +39,7 @@ import org.jetbrains.kotlin.resolve.annotations.argumentValue import org.jetbrains.kotlin.resolve.constants.EnumValue import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind +import org.jetbrains.kotlin.resolve.source.KotlinSourceElement import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeProjectionImpl import org.jetbrains.kotlin.types.replace @@ -177,6 +177,15 @@ fun createTypeFromCanonicalText( return type } +fun tryGetPredefinedName(klass: ClassDescriptor): String? { + + val sourceClass = (klass.source as? KotlinSourceElement)?.psi as? KtClassOrObject + + return if (sourceClass?.isLocal == true) + (sourceClass.nameAsName ?: SpecialNames.NO_NAME_PROVIDED).asString() + else null +} + // Returns null when type is unchanged fun KotlinType.cleanFromAnonymousTypes(): KotlinType? { val returnTypeClass = constructor.declarationDescriptor as? ClassDescriptor ?: return null @@ -309,7 +318,8 @@ internal fun KtModifierListOwner.isHiddenByDeprecation(support: KtUltraLightSupp return (deprecated?.argumentValue("level") as? EnumValue)?.enumEntryName?.asString() == "HIDDEN" } -internal fun KtAnnotated.isJvmStatic(support: KtUltraLightSupport): Boolean = support.findAnnotation(this, JVM_STATIC_ANNOTATION_FQ_NAME) !== null +internal fun KtAnnotated.isJvmStatic(support: KtUltraLightSupport): Boolean = + support.findAnnotation(this, JVM_STATIC_ANNOTATION_FQ_NAME) !== null internal fun KtDeclaration.simpleVisibility(): String = when { hasModifier(KtTokens.PRIVATE_KEYWORD) -> PsiModifier.PRIVATE @@ -351,4 +361,4 @@ private fun toQualifiedName(userType: KtUserType): FqName? { } return FqName.fromSegments(ContainerUtil.reverse(reversedNames)) -} +} \ No newline at end of file diff --git a/compiler/testData/asJava/lightClasses/local/DollarsInNameLocal.java b/compiler/testData/asJava/lightClasses/local/DollarsInNameLocal.java deleted file mode 100644 index ba8bd9cbb1d..00000000000 --- a/compiler/testData/asJava/lightClasses/local/DollarsInNameLocal.java +++ /dev/null @@ -1,15 +0,0 @@ -static final class Foo$bar$A$B { - public Foo$bar$A$B() { /* compiled code */ } - - final class C$D { - public C$D() { /* compiled code */ } - } - - final class $$$$$$$ { - public $$$$$$$() { /* compiled code */ } - - final class G$G$ { - public G$G$() { /* compiled code */ } - } - } -} diff --git a/compiler/testData/asJava/ultraLightClasses/dollarsInNameLocal.java b/compiler/testData/asJava/ultraLightClasses/dollarsInNameLocal.java new file mode 100644 index 00000000000..fcae6bbea96 --- /dev/null +++ b/compiler/testData/asJava/ultraLightClasses/dollarsInNameLocal.java @@ -0,0 +1,37 @@ +public final class Foo /* c.b.a.Foo*/ { + @null() + public Foo(); + + public final void bar(); + +} + +public static final class A$B /* null*/ { + @null() + public A$B(); + + class $$$$$$$ ... + + class C$D ... + + } + +public final class C$D /* null*/ { + @null() + public C$D(); + +} + +public final class $$$$$$$ /* null*/ { + @null() + public $$$$$$$(); + + class G$G$ ... + + } + +public final class G$G$ /* null*/ { + @null() + public G$G$(); + +} \ No newline at end of file diff --git a/compiler/testData/asJava/lightClasses/local/DollarsInNameLocal.kt b/compiler/testData/asJava/ultraLightClasses/dollarsInNameLocal.kt similarity index 99% rename from compiler/testData/asJava/lightClasses/local/DollarsInNameLocal.kt rename to compiler/testData/asJava/ultraLightClasses/dollarsInNameLocal.kt index 119659bf9d3..bfeded47066 100644 --- a/compiler/testData/asJava/lightClasses/local/DollarsInNameLocal.kt +++ b/compiler/testData/asJava/ultraLightClasses/dollarsInNameLocal.kt @@ -11,4 +11,4 @@ class Foo { } } } -} +} \ No newline at end of file diff --git a/compiler/testData/asJava/ultraLightClasses/inferringAnonymousObjectTypes.java b/compiler/testData/asJava/ultraLightClasses/inferringAnonymousObjectTypes.java index 9f8ce27644f..fbdfdb5553e 100644 --- a/compiler/testData/asJava/ultraLightClasses/inferringAnonymousObjectTypes.java +++ b/compiler/testData/asJava/ultraLightClasses/inferringAnonymousObjectTypes.java @@ -6,6 +6,14 @@ public final class Prop /* Prop*/ { } +final class null /* null*/ { + @null() + public static final java.lang.Object INSTANCE; + + private (); + +} + public final class Fun /* Fun*/ { @null() public Fun(); @@ -14,6 +22,14 @@ public final class Fun /* Fun*/ { } +final class null /* null*/ { + @null() + public static final java.lang.Object INSTANCE; + + private (); + +} + public final class ArrayOfAnonymous /* ArrayOfAnonymous*/ { private final java.lang.Object[] a1; @@ -25,6 +41,19 @@ public final class ArrayOfAnonymous /* ArrayOfAnonymous*/ { } +final class null /* null*/ { + @null() + public static final java.lang.Object INSTANCE; + + private static final java.lang.String fy /* constant value text */; + + @org.jetbrains.annotations.NotNull() + public final java.lang.String getFy(); + + private (); + +} + final class C /* C*/ { private final int y; @@ -40,6 +69,17 @@ final class C /* C*/ { } +final class null /* null*/ { + @null() + public static final java.lang.Object INSTANCE; + + @org.jetbrains.annotations.NotNull() + public java.lang.String toString(); + + private (); + +} + public abstract class Super /* Super*/ { @null() public Super(); @@ -60,6 +100,19 @@ public final class Sub /* Sub*/ extends Super { } +final class null /* null*/ { + @null() + public static final java.lang.Object INSTANCE; + + private static final java.lang.String fy /* constant value text */; + + @org.jetbrains.annotations.NotNull() + public final java.lang.String getFy(); + + private (); + +} + public final class ValidPublicSupertype /* ValidPublicSupertype*/ { private final java.lang.Runnable x; @@ -74,6 +127,26 @@ public final class ValidPublicSupertype /* ValidPublicSupertype*/ { } +final class null /* null*/ implements java.lang.Runnable { + @null() + public static final java.lang.Runnable INSTANCE; + + private (); + + public void run(); + +} + +final class null /* null*/ implements java.lang.Runnable { + @null() + public static final java.lang.Runnable INSTANCE; + + private (); + + public void run(); + +} + public abstract interface I /* I*/ { } @@ -90,3 +163,23 @@ public final class InvalidPublicSupertype /* InvalidPublicSupertype*/ { public final java.lang.Runnable getX(); } + +final class null /* null*/ implements I, java.lang.Runnable { + @null() + public static final java.lang.Runnable INSTANCE; + + private (); + + public void run(); + +} + +final class null /* null*/ implements I, java.lang.Runnable { + @null() + public static final java.lang.Runnable INSTANCE; + + private (); + + public void run(); + +} \ No newline at end of file diff --git a/compiler/testData/asJava/ultraLightClasses/localClassDerived.java b/compiler/testData/asJava/ultraLightClasses/localClassDerived.java new file mode 100644 index 00000000000..2eb721d9c28 --- /dev/null +++ b/compiler/testData/asJava/ultraLightClasses/localClassDerived.java @@ -0,0 +1,19 @@ +public final class Boo /* Boo*/ { + @null() + public Boo(); + + public final void fooBar(); + +} + +public static final class LocalClassBase /* null*/ { + @null() + public LocalClassBase(); + +} + +public static final class LocalClassDerived /* null*/ extends LocalClassBase { + @null() + public LocalClassDerived(); + +} \ No newline at end of file diff --git a/compiler/testData/asJava/ultraLightClasses/localClassDerived.kt b/compiler/testData/asJava/ultraLightClasses/localClassDerived.kt new file mode 100644 index 00000000000..ff57137e3bf --- /dev/null +++ b/compiler/testData/asJava/ultraLightClasses/localClassDerived.kt @@ -0,0 +1,7 @@ +class Boo { + fun fooBar() { + class LocalClassBase + + class LocalClassDerived : LocalClassBase + } +} \ No newline at end of file diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/typeSignatureMapping.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/typeSignatureMapping.kt index f185043a72b..72fc71dc832 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/typeSignatureMapping.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/typeSignatureMapping.kt @@ -38,6 +38,7 @@ interface TypeMappingConfiguration { fun commonSupertype(types: Collection<@JvmSuppressWildcards KotlinType>): KotlinType fun getPredefinedTypeForClass(classDescriptor: ClassDescriptor): T? fun getPredefinedInternalNameForClass(classDescriptor: ClassDescriptor): String? + fun getPredefinedFullInternalNameForClass(classDescriptor: ClassDescriptor): String? = null fun processErrorType(kotlinType: KotlinType, descriptor: ClassDescriptor) // returns null when type doesn't need to be preprocessed fun preprocessType(kotlinType: KotlinType): KotlinType? = null @@ -243,6 +244,9 @@ fun computeInternalName( typeMappingConfiguration: TypeMappingConfiguration<*> = TypeMappingConfigurationImpl, isIrBackend: Boolean ): String { + + typeMappingConfiguration.getPredefinedFullInternalNameForClass(klass)?.let { return it } + val container = if (isIrBackend) getContainer(klass.containingDeclaration) else klass.containingDeclaration val name = SpecialNames.safeIdentifier(klass.name).identifier 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 1ef089ceb89..6dbbd511189 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 @@ -143,7 +143,8 @@ class IDELightClassGenerationSupport(private val project: Project) : LightClassG BindingContext.EMPTY, ClassBuilderMode.LIGHT_CLASSES, moduleName, KotlinTypeMapper.LANGUAGE_VERSION_SETTINGS_DEFAULT, // TODO use proper LanguageVersionSettings jvmTarget = JvmTarget.JVM_1_8, - typePreprocessor = KotlinType::cleanFromAnonymousTypes + typePreprocessor = KotlinType::cleanFromAnonymousTypes, + namePreprocessor = ::tryGetPredefinedName ) } @@ -198,8 +199,6 @@ class IDELightClassGenerationSupport(private val project: Project) : LightClassG override fun createUltraLightClass(element: KtClassOrObject): KtUltraLightClass? { if (element.shouldNotBeVisibleAsLightClass() || - element is KtObjectDeclaration && element.isObjectLiteral() || - element.isLocal || element is KtEnumEntry || element.containingKtFile.isScript() ) { @@ -208,9 +207,19 @@ class IDELightClassGenerationSupport(private val project: Project) : LightClassG val module = ModuleUtilCore.findModuleForPsiElement(element) ?: return null - return KtUltraLightSupportImpl(element, module).let { - if (element.hasModifier(KtTokens.INLINE_KEYWORD)) KtUltraLightInlineClass(element, it) - else KtUltraLightClass(element, it) + return KtUltraLightSupportImpl(element, module).let { support -> + when { + element is KtObjectDeclaration && element.isObjectLiteral() -> + KtUltraLightClassForAnonymousDeclaration(element, support) + + element.isLocal -> + KtUltraLightClassForLocalDeclaration(element, support) + + (element.hasModifier(KtTokens.INLINE_KEYWORD)) -> + KtUltraLightInlineClass(element, support) + + else -> KtUltraLightClass(element, support) + } } } diff --git a/idea/tests/org/jetbrains/kotlin/asJava/classes/UltraLightClassLoadingTestGenerated.java b/idea/tests/org/jetbrains/kotlin/asJava/classes/UltraLightClassLoadingTestGenerated.java index f2cb1c03da4..9ecf19f8d88 100644 --- a/idea/tests/org/jetbrains/kotlin/asJava/classes/UltraLightClassLoadingTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/asJava/classes/UltraLightClassLoadingTestGenerated.java @@ -64,6 +64,11 @@ public class UltraLightClassLoadingTestGenerated extends AbstractUltraLightClass runTest("compiler/testData/asJava/ultraLightClasses/delegatingToInterfaces.kt"); } + @TestMetadata("dollarsInNameLocal.kt") + public void testDollarsInNameLocal() throws Exception { + runTest("compiler/testData/asJava/ultraLightClasses/dollarsInNameLocal.kt"); + } + @TestMetadata("enums.kt") public void testEnums() throws Exception { runTest("compiler/testData/asJava/ultraLightClasses/enums.kt"); @@ -139,6 +144,11 @@ public class UltraLightClassLoadingTestGenerated extends AbstractUltraLightClass runTest("compiler/testData/asJava/ultraLightClasses/lateinitProperty.kt"); } + @TestMetadata("localClassDerived.kt") + public void testLocalClassDerived() throws Exception { + runTest("compiler/testData/asJava/ultraLightClasses/localClassDerived.kt"); + } + @TestMetadata("objects.kt") public void testObjects() throws Exception { runTest("compiler/testData/asJava/ultraLightClasses/objects.kt"); diff --git a/idea/tests/org/jetbrains/kotlin/asJava/classes/UltraLightClassSanityTestGenerated.java b/idea/tests/org/jetbrains/kotlin/asJava/classes/UltraLightClassSanityTestGenerated.java index 8d3012de835..c32a7f2c5cd 100644 --- a/idea/tests/org/jetbrains/kotlin/asJava/classes/UltraLightClassSanityTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/asJava/classes/UltraLightClassSanityTestGenerated.java @@ -391,24 +391,6 @@ public class UltraLightClassSanityTestGenerated extends AbstractUltraLightClassS } } - @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) diff --git a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeLightClassTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeLightClassTestGenerated.java index 8eda58d79e6..715246325ea 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeLightClassTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeLightClassTestGenerated.java @@ -343,24 +343,6 @@ public class IdeLightClassTestGenerated extends AbstractIdeLightClassTest { } } - @TestMetadata("compiler/testData/asJava/lightClasses/local") - @TestDataPath("$PROJECT_ROOT") - @RunWith(JUnit3RunnerWithInners.class) - public static class Local extends AbstractIdeLightClassTest { - 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)