New J2K: Handle correctly modifiers of class members when there is no parent class in the AST

This commit is contained in:
Ilya Kirillov
2019-04-01 14:08:34 +03:00
committed by Ilya Kirillov
parent c05a01e12b
commit 854fc6a7d7
7 changed files with 126 additions and 95 deletions
@@ -18,6 +18,8 @@ package org.jetbrains.kotlin.nj2k
import org.jetbrains.kotlin.nj2k.conversions.* import org.jetbrains.kotlin.nj2k.conversions.*
import org.jetbrains.kotlin.nj2k.tree.JKTreeElement import org.jetbrains.kotlin.nj2k.tree.JKTreeElement
import org.jetbrains.kotlin.nj2k.tree.JKTreeRoot
import org.jetbrains.kotlin.nj2k.tree.impl.JKTreeRootImpl
object ConversionsRunner { object ConversionsRunner {
@@ -73,7 +75,7 @@ object ConversionsRunner {
+EqualsOperatorConversion(context) +EqualsOperatorConversion(context)
+TypeMappingConversion(context) +TypeMappingConversion(context)
+ImplicitCastsConversion(context) +ImplicitCastsConversion(context)
+InternalDeclarationConversion() +InternalDeclarationConversion(context)
//Kotlin --> Kotlin conversions //Kotlin --> Kotlin conversions
+InnerClassConversion() +InnerClassConversion()
@@ -103,7 +103,7 @@ class JavaToJKTreeBuilder constructor(
} }
private fun PsiImportStatement.toJK(): JKImportStatementImpl { private fun PsiImportStatement.toJK(): JKImportStatement {
val target = resolve() val target = resolve()
val rawName = text.substringAfter("import").substringBeforeLast(";").trim() val rawName = text.substringAfter("import").substringBeforeLast(";").trim()
val name = val name =
@@ -517,21 +517,11 @@ class JavaToJKTreeBuilder constructor(
it.assignNonCodeElements(this) it.assignNonCodeElements(this)
} }
fun PsiClass.toJK(): JKClass { fun PsiClass.toJK(): JKClass =
val classKind: JKClass.ClassKind = when { JKClassImpl(
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(
nameIdentifier.toJK(), nameIdentifier.toJK(),
inheritanceInfo(), inheritanceInfo(),
classKind, classKind(),
typeParameterList?.toJK() ?: JKTypeParameterListImpl(), typeParameterList?.toJK() ?: JKTypeParameterListImpl(),
createClassBody(), createClassBody(),
annotationList(this), annotationList(this),
@@ -544,7 +534,7 @@ class JavaToJKTreeBuilder constructor(
}.also { }.also {
it.assignNonCodeElements(this) it.assignNonCodeElements(this)
} }
}
fun PsiClass.inheritanceInfo(): JKInheritanceInfo { fun PsiClass.inheritanceInfo(): JKInheritanceInfo {
val implTypes = val implTypes =
@@ -601,18 +591,7 @@ class JavaToJKTreeBuilder constructor(
fun PsiMember.modality() = fun PsiMember.modality() =
modifierList?.children?.mapNotNull { child -> modality({ ast, psi -> ast.assignNonCodeElements(psi) })
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)
fun PsiMember.extraModifiers() = fun PsiMember.extraModifiers() =
modifierList?.children?.mapNotNull { child -> modifierList?.children?.mapNotNull { child ->
@@ -631,56 +610,9 @@ class JavaToJKTreeBuilder constructor(
} }
}.orEmpty() }.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<PsiClass>().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 { fun PsiField.toJK(): JKJavaField {
return JKJavaFieldImpl( return JKJavaFieldImpl(
@@ -5,14 +5,35 @@
package org.jetbrains.kotlin.nj2k.conversions 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.*
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 { override fun applyToElement(element: JKTreeElement): JKTreeElement {
if (element !is JKVisibilityOwner || element !is JKModalityOwner) return recurse(element) if (element !is JKVisibilityOwner || element !is JKModalityOwner) return recurse(element)
val containingClass = element.parentOfType<JKClass>() ?: return recurse(element) val containingClass = element.parentOfType<JKClass>()
if (containingClass.visibility == Visibility.INTERNAL if (element is JKClass && element.isLocalClass()) {
element.visibility = Visibility.PUBLIC
}
val containingClassVisibility =
containingClass?.visibility
?: element.psi<PsiMember>()
?.containingClass
?.visibility(context.converter.oldConverterServices.referenceSearcher, null)
?.visibility
val containingClassKind =
containingClass?.classKind
?: element.psi<PsiMember>()
?.containingClass
?.classKind
if (containingClassVisibility == Visibility.INTERNAL
&& element.visibility == Visibility.INTERNAL && element.visibility == Visibility.INTERNAL
&& element.modality == Modality.FINAL && element.modality == Modality.FINAL
&& (element is JKMethod || element is JKField) && (element is JKMethod || element is JKField)
@@ -20,11 +41,11 @@ class InternalDeclarationConversion : RecursiveApplicableConversionBase() {
element.visibility = Visibility.PUBLIC element.visibility = Visibility.PUBLIC
} }
if (containingClass.classKind == JKClass.ClassKind.INTERFACE) { if (containingClassKind == JKClass.ClassKind.INTERFACE) {
element.visibility = Visibility.PUBLIC element.visibility = Visibility.PUBLIC
} }
if (containingClass.classKind == JKClass.ClassKind.ENUM if (containingClassKind == JKClass.ClassKind.ENUM
&& element is JKKtPrimaryConstructor && element is JKKtPrimaryConstructor
) { ) {
element.visibility = Visibility.PRIVATE element.visibility = Visibility.PRIVATE
@@ -12,15 +12,6 @@ import org.jetbrains.kotlin.nj2k.tree.*
class JavaModifiersConversion(private val context: ConversionContext) : RecursiveApplicableConversionBase() { class JavaModifiersConversion(private val context: ConversionContext) : RecursiveApplicableConversionBase() {
override fun applyToElement(element: JKTreeElement): JKTreeElement { 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) { if (element is JKModalityOwner && element is JKAnnotationListOwner) {
val overrideAnnotation = element.annotationList.annotationByFqName("java.lang.Override") val overrideAnnotation = element.annotationList.annotationByFqName("java.lang.Override")
if (overrideAnnotation != null) { if (overrideAnnotation != null) {
@@ -10,10 +10,10 @@ import org.jetbrains.kotlin.nj2k.tree.impl.JKBranchElementBase
abstract class MatchBasedConversion : SequentialBaseConversion { abstract class MatchBasedConversion : SequentialBaseConversion {
fun <R : JKTreeElement, T> applyRecursive(element: R, data: T, func: (JKTreeElement, T) -> JKTreeElement): R = fun <R : JKTreeElement, T> applyRecursive(element: R, data: T, func: (JKTreeElement, T) -> JKTreeElement): R =
org.jetbrains.kotlin.nj2k.tree.applyRecursive(element, data, ::onElementChanged, func) org.jetbrains.kotlin.nj2k.tree.applyRecursive(element, data, ::onElementChanged, func)
inline fun <R : JKTreeElement> applyRecursive(element: R, crossinline func: (JKTreeElement) -> JKTreeElement): R { fun <R : JKTreeElement> applyRecursive(element: R, func: (JKTreeElement) -> JKTreeElement): R {
return applyRecursive(element, null) { it, _ -> func(it) } return applyRecursive(element, null) { it, _ -> func(it) }
} }
+87 -1
View File
@@ -8,8 +8,15 @@ package org.jetbrains.kotlin.nj2k
import com.intellij.codeInsight.generation.GenerateEqualsHelper.getEqualsSignature import com.intellij.codeInsight.generation.GenerateEqualsHelper.getEqualsSignature
import com.intellij.psi.* import com.intellij.psi.*
import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.util.InheritanceUtil
import com.intellij.psi.util.MethodSignatureUtil 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.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 //copied from old j2k
fun canKeepEqEq(left: PsiExpression, right: PsiExpression?): Boolean { fun canKeepEqEq(left: PsiExpression, right: PsiExpression?): Boolean {
@@ -34,5 +41,84 @@ fun canKeepEqEq(left: PsiExpression, right: PsiExpression?): Boolean {
else -> return false else -> return false
} }
} }
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<PsiClass>().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
}
@@ -211,7 +211,6 @@ interface JKVisibilityOwner : JKModifiersListOwner {
enum class Visibility(override val text: String) : Modifier { enum class Visibility(override val text: String) : Modifier {
PUBLIC("public"), PUBLIC("public"),
INTERNAL("internal"), INTERNAL("internal"),
PACKAGE_PRIVATE(""),
PROTECTED("protected"), PROTECTED("protected"),
PRIVATE("private") PRIVATE("private")
} }