diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/ConversionsRunner.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/ConversionsRunner.kt index d381fcb255e..29f46663651 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/ConversionsRunner.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/ConversionsRunner.kt @@ -18,6 +18,8 @@ package org.jetbrains.kotlin.nj2k import org.jetbrains.kotlin.nj2k.conversions.* import org.jetbrains.kotlin.nj2k.tree.JKTreeElement +import org.jetbrains.kotlin.nj2k.tree.JKTreeRoot +import org.jetbrains.kotlin.nj2k.tree.impl.JKTreeRootImpl object ConversionsRunner { @@ -73,7 +75,7 @@ object ConversionsRunner { +EqualsOperatorConversion(context) +TypeMappingConversion(context) +ImplicitCastsConversion(context) - +InternalDeclarationConversion() + +InternalDeclarationConversion(context) //Kotlin --> Kotlin conversions +InnerClassConversion() diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/JavaToJKTreeBuilder.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/JavaToJKTreeBuilder.kt index 5c756b6e9b5..e82b0f12a35 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/JavaToJKTreeBuilder.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/JavaToJKTreeBuilder.kt @@ -103,7 +103,7 @@ class JavaToJKTreeBuilder constructor( } - private fun PsiImportStatement.toJK(): JKImportStatementImpl { + private fun PsiImportStatement.toJK(): JKImportStatement { val target = resolve() val rawName = text.substringAfter("import").substringBeforeLast(";").trim() val name = @@ -517,21 +517,11 @@ class JavaToJKTreeBuilder constructor( it.assignNonCodeElements(this) } - fun PsiClass.toJK(): JKClass { - val classKind: JKClass.ClassKind = when { - isAnnotationType -> JKClass.ClassKind.ANNOTATION - isEnum -> JKClass.ClassKind.ENUM - isInterface -> JKClass.ClassKind.INTERFACE - else -> JKClass.ClassKind.CLASS - } - - fun PsiReferenceList.mapTypes() = - this.referencedTypes.map { JKTypeElementImpl(it.toJK(symbolProvider, Nullability.Default)) } - - return JKClassImpl( + fun PsiClass.toJK(): JKClass = + JKClassImpl( nameIdentifier.toJK(), inheritanceInfo(), - classKind, + classKind(), typeParameterList?.toJK() ?: JKTypeParameterListImpl(), createClassBody(), annotationList(this), @@ -544,7 +534,7 @@ class JavaToJKTreeBuilder constructor( }.also { it.assignNonCodeElements(this) } - } + fun PsiClass.inheritanceInfo(): JKInheritanceInfo { val implTypes = @@ -601,18 +591,7 @@ class JavaToJKTreeBuilder constructor( fun PsiMember.modality() = - modifierList?.children?.mapNotNull { child -> - if (child !is PsiKeyword) return@mapNotNull null - when (child.text) { - PsiModifier.FINAL -> Modality.FINAL - PsiModifier.ABSTRACT -> Modality.ABSTRACT - - else -> null - }?.let { - JKModalityModifierElementImpl(it).withAssignedNonCodeElements(child) - } - }?.firstOrNull() ?: JKModalityModifierElementImpl(Modality.OPEN) - + modality({ ast, psi -> ast.assignNonCodeElements(psi) }) fun PsiMember.extraModifiers() = modifierList?.children?.mapNotNull { child -> @@ -631,56 +610,9 @@ class JavaToJKTreeBuilder constructor( } }.orEmpty() - fun PsiMember.visibility() = - modifierList?.children?.mapNotNull { child -> - if (child !is PsiKeyword) return@mapNotNull null - when (child.text) { - PsiModifier.PACKAGE_LOCAL -> Visibility.PACKAGE_PRIVATE - PsiModifier.PRIVATE -> Visibility.PRIVATE - PsiModifier.PROTECTED -> handleProtectedVisibility() - PsiModifier.PUBLIC -> Visibility.PUBLIC - - else -> null - }?.let { - JKVisibilityModifierElementImpl(it).withAssignedNonCodeElements(child) - } - }?.firstOrNull() ?: JKVisibilityModifierElementImpl(Visibility.PACKAGE_PRIVATE) - - - private fun PsiMember.handleProtectedVisibility(): Visibility { - val originalClass = containingClass ?: return Visibility.PROTECTED - // Search for usages only in Java because java-protected member cannot be used in Kotlin from same package - val usages = referenceSearcher.findUsagesForExternalCodeProcessing(this, true, false) - - return if (usages.any { !allowProtected(it.element, this, originalClass) }) - Visibility.PUBLIC - else Visibility.PROTECTED - } - - private fun allowProtected(element: PsiElement, member: PsiMember, originalClass: PsiClass): Boolean { - if (element.parent is PsiNewExpression && member is PsiMethod && member.isConstructor) { - // calls to for protected constructors are allowed only within same class or as super calls - return element.parentsWithSelf.contains(originalClass) - } - - return element.parentsWithSelf.filterIsInstance().any { accessContainingClass -> - if (!InheritanceUtil.isInheritorOrSelf(accessContainingClass, originalClass, true)) return@any false - - if (element !is PsiReferenceExpression) return@any true - - val qualifierExpression = element.qualifierExpression ?: return@any true - - // super.foo is allowed if 'foo' is protected - if (qualifierExpression is PsiSuperExpression) return@any true - - val receiverType = qualifierExpression.type ?: return@any true - val resolvedClass = PsiUtil.resolveGenericsClassInType(receiverType).element ?: return@any true - - // receiver type should be subtype of containing class - InheritanceUtil.isInheritorOrSelf(resolvedClass, accessContainingClass, true) - } - } + private fun PsiMember.visibility(): JKVisibilityModifierElement = + visibility(referenceSearcher) { ast, psi -> ast.assignNonCodeElements(psi) } fun PsiField.toJK(): JKJavaField { return JKJavaFieldImpl( diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/InternalDeclarationConversion.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/InternalDeclarationConversion.kt index 10cd048806d..3bbdc31b0ae 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/InternalDeclarationConversion.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/InternalDeclarationConversion.kt @@ -5,14 +5,35 @@ package org.jetbrains.kotlin.nj2k.conversions +import com.intellij.psi.PsiMember +import org.jetbrains.kotlin.nj2k.ConversionContext import org.jetbrains.kotlin.nj2k.tree.* +import org.jetbrains.kotlin.nj2k.tree.impl.psi +import org.jetbrains.kotlin.nj2k.visibility -class InternalDeclarationConversion : RecursiveApplicableConversionBase() { +class InternalDeclarationConversion(private val context: ConversionContext) : RecursiveApplicableConversionBase() { override fun applyToElement(element: JKTreeElement): JKTreeElement { if (element !is JKVisibilityOwner || element !is JKModalityOwner) return recurse(element) - val containingClass = element.parentOfType() ?: return recurse(element) + val containingClass = element.parentOfType() - if (containingClass.visibility == Visibility.INTERNAL + if (element is JKClass && element.isLocalClass()) { + element.visibility = Visibility.PUBLIC + } + + val containingClassVisibility = + containingClass?.visibility + ?: element.psi() + ?.containingClass + ?.visibility(context.converter.oldConverterServices.referenceSearcher, null) + ?.visibility + + val containingClassKind = + containingClass?.classKind + ?: element.psi() + ?.containingClass + ?.classKind + + if (containingClassVisibility == Visibility.INTERNAL && element.visibility == Visibility.INTERNAL && element.modality == Modality.FINAL && (element is JKMethod || element is JKField) @@ -20,11 +41,11 @@ class InternalDeclarationConversion : RecursiveApplicableConversionBase() { element.visibility = Visibility.PUBLIC } - if (containingClass.classKind == JKClass.ClassKind.INTERFACE) { + if (containingClassKind == JKClass.ClassKind.INTERFACE) { element.visibility = Visibility.PUBLIC } - if (containingClass.classKind == JKClass.ClassKind.ENUM + if (containingClassKind == JKClass.ClassKind.ENUM && element is JKKtPrimaryConstructor ) { element.visibility = Visibility.PRIVATE diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/JavaModifiersConversion.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/JavaModifiersConversion.kt index 8795630e17a..99bee91f83f 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/JavaModifiersConversion.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/JavaModifiersConversion.kt @@ -12,15 +12,6 @@ import org.jetbrains.kotlin.nj2k.tree.* class JavaModifiersConversion(private val context: ConversionContext) : RecursiveApplicableConversionBase() { override fun applyToElement(element: JKTreeElement): JKTreeElement { - if (element is JKVisibilityOwner) { - if (element.visibility == Visibility.PACKAGE_PRIVATE) { - if (element is JKClass && element.isLocalClass()) { - element.visibility = Visibility.PUBLIC - } else { - element.visibility = Visibility.INTERNAL - } - } - } if (element is JKModalityOwner && element is JKAnnotationListOwner) { val overrideAnnotation = element.annotationList.annotationByFqName("java.lang.Override") if (overrideAnnotation != null) { diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/MatchBasedConversion.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/MatchBasedConversion.kt index bd8aebb3b7a..8ca16b1fcb3 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/MatchBasedConversion.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/MatchBasedConversion.kt @@ -10,10 +10,10 @@ import org.jetbrains.kotlin.nj2k.tree.impl.JKBranchElementBase abstract class MatchBasedConversion : SequentialBaseConversion { - fun applyRecursive(element: R, data: T, func: (JKTreeElement, T) -> JKTreeElement): R = + fun applyRecursive(element: R, data: T, func: (JKTreeElement, T) -> JKTreeElement): R = org.jetbrains.kotlin.nj2k.tree.applyRecursive(element, data, ::onElementChanged, func) - inline fun applyRecursive(element: R, crossinline func: (JKTreeElement) -> JKTreeElement): R { + fun applyRecursive(element: R, func: (JKTreeElement) -> JKTreeElement): R { return applyRecursive(element, null) { it, _ -> func(it) } } diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/psiUtils.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/psiUtils.kt index e1a176eac45..3b79974c94e 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/psiUtils.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/psiUtils.kt @@ -8,8 +8,15 @@ package org.jetbrains.kotlin.nj2k import com.intellij.codeInsight.generation.GenerateEqualsHelper.getEqualsSignature import com.intellij.psi.* import com.intellij.psi.search.GlobalSearchScope +import com.intellij.psi.util.InheritanceUtil import com.intellij.psi.util.MethodSignatureUtil +import com.intellij.psi.util.PsiUtil +import org.jetbrains.kotlin.j2k.ReferenceSearcher import org.jetbrains.kotlin.j2k.isNullLiteral +import org.jetbrains.kotlin.nj2k.tree.* +import org.jetbrains.kotlin.nj2k.tree.impl.JKModalityModifierElementImpl +import org.jetbrains.kotlin.nj2k.tree.impl.JKVisibilityModifierElementImpl +import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf //copied from old j2k fun canKeepEqEq(left: PsiExpression, right: PsiExpression?): Boolean { @@ -34,5 +41,84 @@ fun canKeepEqEq(left: PsiExpression, right: PsiExpression?): Boolean { else -> return false } +} -} \ No newline at end of file + +internal fun PsiMember.visibility( + referenceSearcher: ReferenceSearcher, + assignNonCodeElements: ((JKNonCodeElementsListOwner, PsiElement) -> Unit)? +): JKVisibilityModifierElement = + modifierList?.children?.mapNotNull { child -> + if (child !is PsiKeyword) return@mapNotNull null + when (child.text) { + PsiModifier.PACKAGE_LOCAL -> Visibility.INTERNAL + PsiModifier.PRIVATE -> Visibility.PRIVATE + PsiModifier.PROTECTED -> handleProtectedVisibility(referenceSearcher) + PsiModifier.PUBLIC -> Visibility.PUBLIC + + else -> null + }?.let { + JKVisibilityModifierElementImpl(it) + }?.also { modifier -> + assignNonCodeElements?.also { it(modifier, child) } + } + }?.firstOrNull() ?: JKVisibilityModifierElementImpl(Visibility.INTERNAL) + + +fun PsiMember.modality(assignNonCodeElements: ((JKNonCodeElementsListOwner, PsiElement) -> Unit)?) = + modifierList?.children?.mapNotNull { child -> + if (child !is PsiKeyword) return@mapNotNull null + when (child.text) { + PsiModifier.FINAL -> Modality.FINAL + PsiModifier.ABSTRACT -> Modality.ABSTRACT + + else -> null + }?.let { + JKModalityModifierElementImpl(it) + }?.also { modifier -> + assignNonCodeElements?.let { it(modifier, child) } + } + }?.firstOrNull() ?: JKModalityModifierElementImpl(Modality.OPEN) + + +private fun PsiMember.handleProtectedVisibility(referenceSearcher: ReferenceSearcher): Visibility { + val originalClass = containingClass ?: return Visibility.PROTECTED + // Search for usages only in Java because java-protected member cannot be used in Kotlin from same package + val usages = referenceSearcher.findUsagesForExternalCodeProcessing(this, true, false) + + return if (usages.any { !allowProtected(it.element, this, originalClass) }) + Visibility.PUBLIC + else Visibility.PROTECTED +} + +private fun allowProtected(element: PsiElement, member: PsiMember, originalClass: PsiClass): Boolean { + if (element.parent is PsiNewExpression && member is PsiMethod && member.isConstructor) { + // calls to for protected constructors are allowed only within same class or as super calls + return element.parentsWithSelf.contains(originalClass) + } + + return element.parentsWithSelf.filterIsInstance().any { accessContainingClass -> + if (!InheritanceUtil.isInheritorOrSelf(accessContainingClass, originalClass, true)) return@any false + + if (element !is PsiReferenceExpression) return@any true + + val qualifierExpression = element.qualifierExpression ?: return@any true + + // super.foo is allowed if 'foo' is protected + if (qualifierExpression is PsiSuperExpression) return@any true + + val receiverType = qualifierExpression.type ?: return@any true + val resolvedClass = PsiUtil.resolveGenericsClassInType(receiverType).element ?: return@any true + + // receiver type should be subtype of containing class + InheritanceUtil.isInheritorOrSelf(resolvedClass, accessContainingClass, true) + } +} + +fun PsiClass.classKind(): JKClass.ClassKind = + when { + isAnnotationType -> JKClass.ClassKind.ANNOTATION + isEnum -> JKClass.ClassKind.ENUM + isInterface -> JKClass.ClassKind.INTERFACE + else -> JKClass.ClassKind.CLASS + } \ No newline at end of file diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/tree/jk.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/tree/jk.kt index cf78d8b1853..58e1b888661 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/tree/jk.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/tree/jk.kt @@ -211,7 +211,6 @@ interface JKVisibilityOwner : JKModifiersListOwner { enum class Visibility(override val text: String) : Modifier { PUBLIC("public"), INTERNAL("internal"), - PACKAGE_PRIVATE(""), PROTECTED("protected"), PRIVATE("private") }