diff --git a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/FirLightIdentifier.kt b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/FirLightIdentifier.kt index fff4204745b..aee3a56ac4f 100644 --- a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/FirLightIdentifier.kt +++ b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/FirLightIdentifier.kt @@ -19,16 +19,16 @@ import org.jetbrains.kotlin.psi.KtPropertyAccessor import org.jetbrains.kotlin.psi.KtSecondaryConstructor import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject -open class FirLightIdentifier( +internal class FirLightIdentifier( private val lightOwner: PsiElement, - private val firSymbol: KtSymbol + private val firSymbol: KtSymbol? ) : LightIdentifier( lightOwner.manager, (firSymbol as? KtNamedSymbol)?.name?.identifierOrNullIfSpecial ), PsiCompiledElement, PsiElementWithOrigin { override val origin: PsiElement? - get() = when (val ktDeclaration = firSymbol.psi) { + get() = when (val ktDeclaration = firSymbol?.psi) { is KtSecondaryConstructor -> ktDeclaration.getConstructorKeyword() is KtPrimaryConstructor -> ktDeclaration.getConstructorKeyword() ?: ktDeclaration.valueParameterList @@ -44,4 +44,4 @@ open class FirLightIdentifier( override fun getContainingFile(): PsiFile = lightOwner.containingFile override fun getTextRange(): TextRange = origin?.textRange ?: TextRange.EMPTY_RANGE override fun getTextOffset(): Int = origin?.textOffset ?: -1 -} \ No newline at end of file +} diff --git a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/firLightClassUtils.kt b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/firLightClassUtils.kt index 78d9eea3169..4de74dbcd36 100644 --- a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/firLightClassUtils.kt +++ b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/firLightClassUtils.kt @@ -6,19 +6,11 @@ package org.jetbrains.kotlin.light.classes.symbol.classes import com.intellij.psi.PsiManager +import com.intellij.psi.PsiModifier import com.intellij.psi.PsiReferenceList import com.intellij.psi.util.CachedValueProvider import com.intellij.psi.util.CachedValuesManager import org.jetbrains.kotlin.analysis.providers.createProjectWideOutOfBlockModificationTracker -import org.jetbrains.kotlin.asJava.builder.LightMemberOriginForDeclaration -import org.jetbrains.kotlin.asJava.classes.KotlinSuperTypeListBuilder -import org.jetbrains.kotlin.asJava.classes.KtLightClass -import org.jetbrains.kotlin.asJava.classes.METHOD_INDEX_BASE -import org.jetbrains.kotlin.asJava.classes.shouldNotBeVisibleAsLightClass -import org.jetbrains.kotlin.asJava.elements.KtLightField -import org.jetbrains.kotlin.asJava.elements.KtLightMethod -import org.jetbrains.kotlin.descriptors.Modality -import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget import org.jetbrains.kotlin.analysis.api.symbols.* import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithMembers import org.jetbrains.kotlin.analysis.api.symbols.markers.isPrivateOrPrivateToThis @@ -26,10 +18,16 @@ import org.jetbrains.kotlin.analysis.api.tokens.HackToForceAllowRunningAnalyzeOn import org.jetbrains.kotlin.analysis.api.tokens.hackyAllowRunningOnEdt import org.jetbrains.kotlin.analysis.api.types.KtNonErrorClassType import org.jetbrains.kotlin.analysis.api.types.KtType +import org.jetbrains.kotlin.asJava.builder.LightMemberOriginForDeclaration +import org.jetbrains.kotlin.asJava.classes.* +import org.jetbrains.kotlin.asJava.elements.KtLightField +import org.jetbrains.kotlin.asJava.elements.KtLightMethod +import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.lexer.KtTokens.* import org.jetbrains.kotlin.light.classes.symbol.* import org.jetbrains.kotlin.load.java.JvmAbi -import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.StandardClassIds import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.containingClass @@ -114,17 +112,68 @@ internal fun FirLightClassBase.createConstructors( declarations: Sequence, result: MutableList ) { - for (declaration in declarations) { - if (declaration.isHiddenOrSynthetic(project)) continue + val constructors = declarations.toList() + if (constructors.isEmpty()) { + result.add(defaultConstructor()) + return + } + for (constructor in constructors) { + if (constructor.isHiddenOrSynthetic(project)) continue result.add( FirLightConstructorForSymbol( - constructorSymbol = declaration, + constructorSymbol = constructor, lightMemberOrigin = null, containingClass = this@createConstructors, methodIndex = METHOD_INDEX_BASE ) ) } + val primaryConstructor = constructors.singleOrNull { it.isPrimary } + if (primaryConstructor != null && shouldGenerateNoArgOverload(primaryConstructor, constructors)) { + result.add( + noArgConstructor(primaryConstructor.visibility.externalDisplayName, METHOD_INDEX_FOR_NO_ARG_OVERLOAD_CTOR) + ) + } +} + +private fun FirLightClassBase.shouldGenerateNoArgOverload( + primaryConstructor: KtConstructorSymbol, + constructors: Iterable, +): Boolean { + val classOrObject = kotlinOrigin ?: return false + return !primaryConstructor.visibility.isPrivateOrPrivateToThis() && + !classOrObject.hasModifier(INNER_KEYWORD) && !isEnum && + !classOrObject.hasModifier(SEALED_KEYWORD) && + primaryConstructor.valueParameters.isNotEmpty() && + primaryConstructor.valueParameters.all { it.hasDefaultValue } && + constructors.none { it.valueParameters.isEmpty() } && + !primaryConstructor.hasJvmOverloadsAnnotation() +} + +private fun FirLightClassBase.defaultConstructor(): KtLightMethod { + val classOrObject = kotlinOrigin + val visibility = when { + classOrObject is KtObjectDeclaration || classOrObject?.hasModifier(SEALED_KEYWORD) == true || isEnum -> PsiModifier.PRIVATE + classOrObject is KtEnumEntry -> PsiModifier.PACKAGE_LOCAL + else -> PsiModifier.PUBLIC + } + return noArgConstructor(visibility, METHOD_INDEX_FOR_DEFAULT_CTOR) +} + +private fun FirLightClassBase.noArgConstructor( + visibility: String, + methodIndex: Int, +): KtLightMethod { + return FirLightNoArgConstructor( + LightMemberOriginForDeclaration( + originalElement = kotlinOrigin!!, + originKind = JvmDeclarationOriginKind.OTHER, + auxiliaryOriginalElement = kotlinOrigin as? KtDeclaration + ), + this, + visibility, + methodIndex + ) } internal fun FirLightClassBase.createMethods( diff --git a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/methods/FirLightNoArgConstructor.kt b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/methods/FirLightNoArgConstructor.kt new file mode 100644 index 00000000000..a730b906825 --- /dev/null +++ b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/methods/FirLightNoArgConstructor.kt @@ -0,0 +1,63 @@ +/* + * Copyright 2010-2021 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.light.classes.symbol + +import com.intellij.psi.* +import org.jetbrains.kotlin.asJava.builder.LightMemberOrigin +import org.jetbrains.kotlin.asJava.classes.lazyPub + +internal class FirLightNoArgConstructor( + lightMemberOrigin: LightMemberOrigin?, + containingClass: FirLightClassBase, + visibility: String, + methodIndex: Int, +): FirLightMethod(lightMemberOrigin, containingClass, methodIndex) { + private val _name: String? = containingClass.name + + override fun getName(): String = _name ?: "" + + override fun isConstructor(): Boolean = true + + override fun hasTypeParameters(): Boolean = false + override fun getTypeParameterList(): PsiTypeParameterList? = null + override fun getTypeParameters(): Array = PsiTypeParameter.EMPTY_ARRAY + + private val _identifier: PsiIdentifier by lazyPub { + FirLightIdentifier(this, firSymbol = null) + } + + override fun getNameIdentifier(): PsiIdentifier = _identifier + + override fun isDeprecated(): Boolean = false + + private val _modifiers: Set by lazyPub { + setOf(visibility) + } + + private val _modifierList: PsiModifierList by lazyPub { + FirLightMemberModifierList(this, _modifiers, emptyList()) + } + + override fun getModifierList(): PsiModifierList = _modifierList + + private val _parameterList: PsiParameterList by lazyPub { + FirLightParameterList(this, callableSymbol = null) {} + } + + override fun getParameterList(): PsiParameterList = _parameterList + + override fun getReturnType(): PsiType? = null + + override fun equals(other: Any?): Boolean = + this === other || + (other is FirLightNoArgConstructor && + kotlinOrigin == other.kotlinOrigin && + containingClass == other.containingClass) + + override fun hashCode(): Int = containingClass.hashCode() + + override fun isValid(): Boolean = super.isValid() && containingClass.isValid +} diff --git a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/parameters/FirLightParameterList.kt b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/parameters/FirLightParameterList.kt index edcea61bf24..c48b3b105af 100644 --- a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/parameters/FirLightParameterList.kt +++ b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/parameters/FirLightParameterList.kt @@ -17,7 +17,7 @@ import org.jetbrains.kotlin.psi.KtParameterList internal class FirLightParameterList( private val parent: FirLightMethod, - private val callableSymbol: KtCallableSymbol, + private val callableSymbol: KtCallableSymbol?, parameterPopulator: (LightParameterListBuilder) -> Unit, ) : KtLightElement, // With this, a parent chain is properly built: from FirLightParameter through FirLightParameterList to FirLightMethod @@ -31,8 +31,10 @@ internal class FirLightParameterList( override val clsDelegate: PsiParameterList by lazyPub { val builder = LightParameterListBuilder(manager, language) - FirLightParameterForReceiver.tryGet(callableSymbol, parent)?.let { - builder.addParameter(it) + callableSymbol?.let { + FirLightParameterForReceiver.tryGet(it, parent)?.let { receiver -> + builder.addParameter(receiver) + } } parameterPopulator.invoke(builder) diff --git a/compiler/testData/asJava/ultraLightClasses/dataClasses.kt b/compiler/testData/asJava/ultraLightClasses/dataClasses.kt index ea9648d622a..ebd0f909157 100644 --- a/compiler/testData/asJava/ultraLightClasses/dataClasses.kt +++ b/compiler/testData/asJava/ultraLightClasses/dataClasses.kt @@ -3,3 +3,5 @@ data class User(val name: String = "", val age: Int = 0) data class Person(val name: String) { var age: Int = 0 } + +// FIR_COMPARISON