New J2K: Use protected visibility resolution from old j2k

This commit is contained in:
Ilya Kirillov
2019-01-12 01:15:27 +03:00
committed by Ilya Kirillov
parent 4c880499fb
commit d56a52fce6
2 changed files with 46 additions and 3 deletions
@@ -21,6 +21,8 @@ import com.intellij.psi.JavaTokenType.SUPER_KEYWORD
import com.intellij.psi.JavaTokenType.THIS_KEYWORD
import com.intellij.psi.impl.source.tree.ChildRole
import com.intellij.psi.impl.source.tree.java.*
import com.intellij.psi.util.InheritanceUtil
import com.intellij.psi.util.PsiUtil
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.j2k.ast.Nullability
@@ -30,13 +32,19 @@ import org.jetbrains.kotlin.j2k.tree.impl.*
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.isExtensionDeclaration
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class JavaToJKTreeBuilder(var symbolProvider: JKSymbolProvider) {
class JavaToJKTreeBuilder(
var symbolProvider: JKSymbolProvider,
private val converterServices: NewJavaToKotlinServices
) {
private val expressionTreeMapper = ExpressionTreeMapper()
val referenceSearcher: ReferenceSearcher = converterServices.oldServices.referenceSearcher
private val declarationMapper = DeclarationMapper(expressionTreeMapper)
private fun PsiJavaFile.toJK(): JKFile =
@@ -433,11 +441,46 @@ class JavaToJKTreeBuilder(var symbolProvider: JKSymbolProvider) {
modifierList == null -> Visibility.PACKAGE_PRIVATE
hasModifierProperty(PsiModifier.PACKAGE_LOCAL) -> Visibility.PACKAGE_PRIVATE
hasModifierProperty(PsiModifier.PRIVATE) -> Visibility.PRIVATE
hasModifierProperty(PsiModifier.PROTECTED) -> Visibility.PROTECTED
hasModifierProperty(PsiModifier.PROTECTED) -> handleProtectedVisibility()
hasModifierProperty(PsiModifier.PUBLIC) -> Visibility.PUBLIC
else -> 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)
}
}
fun PsiMember.modifiers() =
if (modifierList == null) emptyList()
else
@@ -42,7 +42,7 @@ class NewJavaToKotlinConverter(
fun filesToKotlin(files: List<PsiJavaFile>, progressIndicator: ProgressIndicator = EmptyProgressIndicator()): List<String> {
val symbolProvider = JKSymbolProvider()
symbolProvider.preBuildTree(files)
val treeBuilder = JavaToJKTreeBuilder(symbolProvider)
val treeBuilder = JavaToJKTreeBuilder(symbolProvider, converterServices)
val fileTrees = files.mapNotNull(treeBuilder::buildTree)
println(fileTrees.prettyPrintTrees())