From 5fc9ca8fc754207595d186ef311a7f0bba27ac6e Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Wed, 19 Dec 2018 15:57:03 +0300 Subject: [PATCH] New J2K: Add resolving for kotlin properties and object members calls --- .../kotlin/j2k/JavaToJKTreeBuilder.kt | 121 ++++++++++++++---- .../conversions/ImportStatementConversion.kt | 8 ++ 2 files changed, 107 insertions(+), 22 deletions(-) diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/JavaToJKTreeBuilder.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/JavaToJKTreeBuilder.kt index bd66aa15cdb..48752edeb48 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/JavaToJKTreeBuilder.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/JavaToJKTreeBuilder.kt @@ -21,10 +21,17 @@ 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 org.jetbrains.kotlin.j2k.ast.Nullability +import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade +import org.jetbrains.kotlin.asJava.elements.KtLightMethod +import org.jetbrains.kotlin.j2k.ast.* +import org.jetbrains.kotlin.j2k.ast.LiteralExpression.NullLiteral.isNullable import org.jetbrains.kotlin.j2k.tree.* import org.jetbrains.kotlin.j2k.tree.JKLiteralExpression.LiteralType.* +import org.jetbrains.kotlin.j2k.tree.Mutability 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.utils.addToStdlib.safeAs @@ -44,12 +51,14 @@ class JavaToJKTreeBuilder(var symbolProvider: JKSymbolProvider) { private fun PsiPackageStatement.toJK(): JKPackageDeclaration = JKPackageDeclarationImpl(JKNameIdentifierImpl(packageName)) - private fun PsiImportStatement.toJK() = - JKImportStatementImpl( - JKNameIdentifierImpl( - text.substringAfter("import").substringBeforeLast(";").trim() - ) - ) + private fun PsiImportStatement.toJK(): JKImportStatementImpl { + val target = resolve() + val rawName = text.substringAfter("import").substringBeforeLast(";").trim() + val name = + if (target is KtLightClassForFacade) rawName.replaceAfterLast('.', "*") + else rawName + return JKImportStatementImpl(JKNameIdentifierImpl(name)) + } private inner class ExpressionTreeMapper { @@ -165,24 +174,92 @@ class JavaToJKTreeBuilder(var symbolProvider: JKSymbolProvider) { }) } + private fun JKExpression.qualified(qualifier: JKExpression?) = + if (qualifier != null) { + JKQualifiedExpressionImpl(qualifier, JKJavaQualifierImpl.DOT, this) + } else this + + //TODO mostly copied from old j2k, refactor fun PsiMethodCallExpression.toJK(): JKExpression { - val method = methodExpression as PsiReferenceExpressionImpl - val referenceNameElement = methodExpression.referenceNameElement - val symbol = symbolProvider.provideSymbol(method) - return if (referenceNameElement is PsiKeyword) { - val callee = when (referenceNameElement.tokenType) { - SUPER_KEYWORD -> JKSuperExpressionImpl() - THIS_KEYWORD -> JKThisExpressionImpl(JKLabelEmptyImpl()) - else -> error("Unknown keyword in callee position") + val arguments = argumentList.toJK() + val typeArguments = typeArgumentList.toJK() + val qualifier = methodExpression.qualifierExpression?.toJK() + val target = methodExpression.resolve() + val symbol = symbolProvider.provideSymbol(methodExpression as PsiReferenceExpressionImpl) + + return when { + methodExpression.referenceNameElement is PsiKeyword -> { + val callee = when ((methodExpression.referenceNameElement as PsiKeyword).tokenType) { + SUPER_KEYWORD -> JKSuperExpressionImpl() + THIS_KEYWORD -> JKThisExpressionImpl(JKLabelEmptyImpl()) + else -> error("Unknown keyword in callee position") + } + JKDelegationConstructorCallImpl(symbol, callee, arguments) } - JKDelegationConstructorCallImpl(symbol, callee, argumentList.toJK()) - } else { - val call = JKJavaMethodCallExpressionImpl(symbol, argumentList.toJK(), typeArgumentList.toJK()) - if (method.findChildByRole(ChildRole.DOT) != null) { - JKQualifiedExpressionImpl((method.qualifier as PsiExpression).toJK(), JKJavaQualifierImpl.DOT, call) - } else { - call + + target is KtLightMethod -> { + val origin = target.kotlinOrigin + when (origin) { + is KtNamedFunction -> { + if (origin.isExtensionDeclaration()) { + val receiver = arguments.expressions.firstOrNull() + JKJavaMethodCallExpressionImpl( + symbolProvider.provideDirectSymbol(origin) as JKMethodSymbol, + arguments.also { it.expressions = it.expressions.drop(1) }, + typeArguments + ).qualified(receiver) + } else { + JKJavaMethodCallExpressionImpl( + symbolProvider.provideDirectSymbol(origin) as JKMethodSymbol, + arguments, + typeArguments + ).qualified(qualifier) + } + } + is KtProperty, is KtPropertyAccessor, is KtParameter -> { + val property = + if (origin is KtPropertyAccessor) origin.parent as KtProperty + else origin as KtNamedDeclaration + val parameterCount = target.parameterList.parameters.size + val propertyAccessExpression = + JKFieldAccessExpressionImpl(symbolProvider.provideDirectSymbol(property) as JKFieldSymbol) + val isExtension = property.isExtensionDeclaration() + val isTopLevel = origin.getStrictParentOfType() == null + val propertyAccess = if (isTopLevel) { + if (isExtension) JKQualifiedExpressionImpl( + arguments.expressions.first().detached(arguments), + JKJavaQualifierImpl.DOT, + propertyAccessExpression + ) + else propertyAccessExpression + } else propertyAccessExpression.qualified(qualifier) as JKAssignableExpression + + when (if (isExtension) parameterCount - 1 else parameterCount) { + 0 /* getter */ -> + propertyAccess + + 1 /* setter */ -> { + val argument = (arguments.expressions[if (isExtension) 1 else 0]).detached(arguments) + JKJavaAssignmentExpressionImpl( + propertyAccess, + argument, + JKJavaOperatorImpl.tokenToOperator[JavaTokenType.EQ]!! + ) + } + else -> TODO() + } + } + + else -> TODO() + } } + + target is PsiMethod -> + JKJavaMethodCallExpressionImpl(symbol, arguments, typeArguments) + .qualified(qualifier) + else -> + JKJavaMethodCallExpressionImpl(symbol, arguments, typeArguments) + .qualified(qualifier) } } diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/ImportStatementConversion.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/ImportStatementConversion.kt index a0af1b1f62b..91ad876dff9 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/ImportStatementConversion.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/ImportStatementConversion.kt @@ -90,6 +90,14 @@ class ImportStatementConversion : RecursiveApplicableConversionBase() { unfilteredCollectedFqNames += classType.classReference.fqName!! } + override fun visitFieldAccessExpression(fieldAccessExpression: JKFieldAccessExpression) { + unfilteredCollectedFqNames += fieldAccessExpression.identifier.fqName + } + + override fun visitMethodCallExpression(methodCallExpression: JKMethodCallExpression) { + unfilteredCollectedFqNames += methodCallExpression.identifier.fqName + } + override fun visitClassLiteralExpression(classLiteralExpression: JKClassLiteralExpression) { val type = classLiteralExpression.classType.type if (type is JKClassType) {