From 6881559ec3745e39a596881f689f346f09b765c0 Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Thu, 11 Jan 2018 20:11:39 +0300 Subject: [PATCH] 172: Revert "Uast: `KotlinAccessorCallExpression` made implement `JvmDeclarationUElement`" This reverts commit f75a5d8372ab3041d8a1a8073beaa96a79a50b03. --- .../KotlinUSimpleReferenceExpression.kt.172 | 217 ++++++++++++++++++ 1 file changed, 217 insertions(+) create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSimpleReferenceExpression.kt.172 diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSimpleReferenceExpression.kt.172 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSimpleReferenceExpression.kt.172 new file mode 100644 index 00000000000..5756815f8b2 --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSimpleReferenceExpression.kt.172 @@ -0,0 +1,217 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.uast.kotlin + +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiMethod +import com.intellij.psi.PsiNamedElement +import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.descriptors.ConstructorDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.getAssignmentByLHS +import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis +import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall +import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor +import org.jetbrains.kotlin.utils.addToStdlib.constant +import org.jetbrains.uast.* +import org.jetbrains.uast.visitor.UastVisitor + +open class KotlinUSimpleReferenceExpression( + override val psi: KtSimpleNameExpression, + givenParent: UElement? +) : KotlinAbstractUExpression(givenParent), USimpleNameReferenceExpression, KotlinUElementWithType, KotlinEvaluatableUElement { + private val resolvedDeclaration by lz { psi.resolveCallToDeclaration(this) } + + override val identifier get() = psi.getReferencedName() + + override fun resolve() = resolvedDeclaration + + override val resolvedName: String? + get() = (resolvedDeclaration as? PsiNamedElement)?.name + + override fun accept(visitor: UastVisitor) { + visitor.visitSimpleNameReferenceExpression(this) + + if (psi.parent.destructuringDeclarationInitializer != true) { + visitAccessorCalls(visitor) + } + + visitor.afterVisitSimpleNameReferenceExpression(this) + } + + private fun visitAccessorCalls(visitor: UastVisitor) { + // Visit Kotlin get-set synthetic Java property calls as function calls + val bindingContext = psi.analyze() + val access = psi.readWriteAccess() + val resolvedCall = psi.getResolvedCall(bindingContext) + val resultingDescriptor = resolvedCall?.resultingDescriptor as? SyntheticJavaPropertyDescriptor + if (resultingDescriptor != null) { + val setterValue = if (access.isWrite) { + findAssignment(psi, psi.parent)?.right ?: run { + visitor.afterVisitSimpleNameReferenceExpression(this) + return + } + } else { + null + } + + if (resolvedCall != null) { + if (access.isRead) { + val getDescriptor = resultingDescriptor.getMethod + KotlinAccessorCallExpression(psi, this, resolvedCall, getDescriptor, null).accept(visitor) + } + + if (access.isWrite && setterValue != null) { + val setDescriptor = resultingDescriptor.setMethod + if (setDescriptor != null) { + KotlinAccessorCallExpression(psi, this, resolvedCall, setDescriptor, setterValue).accept(visitor) + } + } + } + } + } + + private tailrec fun findAssignment(prev: PsiElement?, element: PsiElement?): KtBinaryExpression? = when (element) { + is KtBinaryExpression -> if (element.left == prev && element.operationToken == KtTokens.EQ) element else null + is KtQualifiedExpression -> findAssignment(element, element.parent) + is KtSimpleNameExpression -> findAssignment(element, element.parent) + else -> null + } + + class KotlinAccessorCallExpression( + override val psi: KtElement, + override val uastParent: KotlinUSimpleReferenceExpression, + private val resolvedCall: ResolvedCall<*>, + private val accessorDescriptor: DeclarationDescriptor, + val setterValue: KtExpression? + ) : UCallExpression { + override val methodName: String? + get() = accessorDescriptor.name.asString() + + override val receiver: UExpression? + get() { + val containingElement = uastParent.uastParent + return if (containingElement is UQualifiedReferenceExpression && containingElement.selector == this) + containingElement.receiver + else + null + } + + override val annotations: List + get() = emptyList() + + override val receiverType by lz { + val type = (resolvedCall.dispatchReceiver ?: resolvedCall.extensionReceiver)?.type ?: return@lz null + type.toPsiType(this, psi, boxed = true) + } + + override val methodIdentifier: UIdentifier? + get() = UIdentifier(uastParent.psi, this) + + override val classReference: UReferenceExpression? + get() = null + + override val valueArgumentCount: Int + get() = if (setterValue != null) 1 else 0 + + override val valueArguments by lz { + if (setterValue != null) + listOf(KotlinConverter.convertOrEmpty(setterValue, this)) + else + emptyList() + } + + override val typeArgumentCount: Int + get() = resolvedCall.typeArguments.size + + override val typeArguments by lz { + resolvedCall.typeArguments.values.map { it.toPsiType(this, psi, true) } + } + + override val returnType by lz { + (accessorDescriptor as? CallableDescriptor)?.returnType?.toPsiType(this, psi, boxed = false) + } + + override val kind: UastCallKind + get() = UastCallKind.METHOD_CALL + + override fun resolve(): PsiMethod? { + val source = accessorDescriptor.toSource() + return KotlinUFunctionCallExpression.resolveSource(accessorDescriptor, source) + } + } + + enum class ReferenceAccess(val isRead: Boolean, val isWrite: Boolean) { + READ(true, false), WRITE(false, true), READ_WRITE(true, true) + } + + private fun KtExpression.readWriteAccess(): ReferenceAccess { + var expression = getQualifiedExpressionForSelectorOrThis() + loop@ while (true) { + val parent = expression.parent + when (parent) { + is KtParenthesizedExpression, is KtAnnotatedExpression, is KtLabeledExpression -> expression = parent as KtExpression + else -> break@loop + } + } + + val assignment = expression.getAssignmentByLHS() + if (assignment != null) { + return when (assignment.operationToken) { + KtTokens.EQ -> ReferenceAccess.WRITE + else -> ReferenceAccess.READ_WRITE + } + } + + return if ((expression.parent as? KtUnaryExpression)?.operationToken + in constant { setOf(KtTokens.PLUSPLUS, KtTokens.MINUSMINUS) }) + ReferenceAccess.READ_WRITE + else + ReferenceAccess.READ + } +} + +class KotlinClassViaConstructorUSimpleReferenceExpression( + override val psi: KtCallElement, + override val identifier: String, + givenParent: UElement? +) : KotlinAbstractUExpression(givenParent), USimpleNameReferenceExpression, KotlinUElementWithType { + override val resolvedName: String? + get() = (psi.getResolvedCall(psi.analyze())?.resultingDescriptor as? ConstructorDescriptor) + ?.containingDeclaration?.name?.asString() + + override fun resolve(): PsiElement? { + val resolvedCall = psi.getResolvedCall(psi.analyze()) + val resultingDescriptor = resolvedCall?.resultingDescriptor as? ConstructorDescriptor ?: return null + val clazz = resultingDescriptor.containingDeclaration + return clazz.toSource()?.getMaybeLightElement(this) + } +} + +class KotlinStringUSimpleReferenceExpression( + override val identifier: String, + givenParent: UElement? +) : KotlinAbstractUExpression(givenParent), USimpleNameReferenceExpression { + override val psi: PsiElement? + get() = null + override fun resolve() = null + override val resolvedName: String? + get() = identifier +} \ No newline at end of file