From b3a534431db33ff8268ee6072a44acaaa881cd2e Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Thu, 11 Jan 2018 20:11:41 +0300 Subject: [PATCH] 172: Revert "Uast: handling `@receiver` annotations" This reverts commit 2f3b1485a30442db016e7f529d273483315067cf. --- .../kotlin/declarations/KotlinUMethod.kt.172 | 117 +++++ .../declarations/KotlinUVariable.kt.172 | 423 ++++++++++++++++++ .../uast-kotlin/testData/ReceiverFun.kt.172 | 0 .../testData/ReceiverFun.log.txt.172 | 0 .../testData/ReceiverFun.render.txt.172 | 0 5 files changed, 540 insertions(+) create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUMethod.kt.172 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUVariable.kt.172 create mode 100644 plugins/uast-kotlin/testData/ReceiverFun.kt.172 create mode 100644 plugins/uast-kotlin/testData/ReceiverFun.log.txt.172 create mode 100644 plugins/uast-kotlin/testData/ReceiverFun.render.txt.172 diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUMethod.kt.172 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUMethod.kt.172 new file mode 100644 index 00000000000..d820c8046f1 --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUMethod.kt.172 @@ -0,0 +1,117 @@ +/* + * 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.declarations + +import com.intellij.psi.PsiCodeBlock +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import com.intellij.psi.PsiMethod +import org.jetbrains.kotlin.asJava.elements.KtLightElement +import org.jetbrains.kotlin.asJava.elements.KtLightMethod +import org.jetbrains.kotlin.asJava.elements.isGetter +import org.jetbrains.kotlin.asJava.elements.isSetter +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject +import org.jetbrains.uast.* +import org.jetbrains.uast.java.internal.JavaUElementWithComments +import org.jetbrains.uast.kotlin.* + +open class KotlinUMethod( + psi: KtLightMethod, + givenParent: UElement? +) : KotlinAbstractUElement(givenParent), UAnnotationMethod, JavaUElementWithComments, PsiMethod by psi { + override val psi: KtLightMethod = unwrap(psi) + + override val javaPsi = psi + + override val sourcePsi = psi.kotlinOrigin + + override fun getSourceElement() = sourcePsi ?: this + + override val uastDefaultValue by lz { + val annotationParameter = psi.kotlinOrigin as? KtParameter ?: return@lz null + val defaultValue = annotationParameter.defaultValue ?: return@lz null + getLanguagePlugin().convertElement(defaultValue, this) as? UExpression + } + + private val kotlinOrigin = (psi.originalElement as KtLightElement<*, *>).kotlinOrigin + + override fun getContainingFile(): PsiFile? = unwrapFakeFileForLightClass(psi.containingFile) + + override fun getNameIdentifier() = UastLightIdentifier(psi, kotlinOrigin as KtNamedDeclaration?) + + override val annotations by lz { + psi.annotations + .mapNotNull { (it as? KtLightElement<*, *>)?.kotlinOrigin as? KtAnnotationEntry } + .map { KotlinUAnnotation(it, this) } + } + + override val uastParameters by lz { + psi.parameterList.parameters.map { KotlinUParameter(it, (it as? KtLightElement<*, *>)?.kotlinOrigin, this) } + } + + override val uastAnchor: UElement + get() = UIdentifier(nameIdentifier, this) + + + override val uastBody by lz { + val bodyExpression = when (kotlinOrigin) { + is KtFunction -> kotlinOrigin.bodyExpression + is KtProperty -> when { + psi.isGetter -> kotlinOrigin.getter?.bodyExpression + psi.isSetter -> kotlinOrigin.setter?.bodyExpression + else -> null + } + else -> null + } ?: return@lz null + + when (bodyExpression) { + !is KtBlockExpression -> { + KotlinUBlockExpression.KotlinLazyUBlockExpression(this, { block -> + val implicitReturn = KotlinUImplicitReturnExpression(block) + val uBody = getLanguagePlugin().convertElement(bodyExpression, implicitReturn) as? UExpression + ?: return@KotlinLazyUBlockExpression emptyList() + listOf(implicitReturn.apply { returnExpression = uBody }) + }) + + } + else -> getLanguagePlugin().convertElement(bodyExpression, this) as? UExpression + } + } + + override val isOverride: Boolean + get() = (kotlinOrigin as? KtCallableDeclaration)?.hasModifier(KtTokens.OVERRIDE_KEYWORD) ?: false + + override fun getBody(): PsiCodeBlock? = super.getBody() + + override fun getOriginalElement(): PsiElement? = super.getOriginalElement() + + override fun equals(other: Any?) = other is KotlinUMethod && psi == other.psi + + companion object { + fun create(psi: KtLightMethod, containingElement: UElement?) = + if (psi.kotlinOrigin is KtConstructor<*>) { + KotlinConstructorUMethod( + psi.kotlinOrigin?.containingClassOrObject, + psi, containingElement + ) + } + else + KotlinUMethod(psi, containingElement) + } +} \ No newline at end of file diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUVariable.kt.172 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUVariable.kt.172 new file mode 100644 index 00000000000..e993b8c2625 --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUVariable.kt.172 @@ -0,0 +1,423 @@ +/* + * 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.* +import com.intellij.psi.search.GlobalSearchScope +import org.jetbrains.annotations.NotNull +import org.jetbrains.annotations.Nullable +import org.jetbrains.kotlin.asJava.classes.KtLightClass +import org.jetbrains.kotlin.asJava.elements.KtLightElement +import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.getParentOfType +import org.jetbrains.kotlin.resolve.calls.callUtil.getType +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.typeUtil.TypeNullability +import org.jetbrains.kotlin.types.typeUtil.nullability +import org.jetbrains.kotlin.utils.SmartList +import org.jetbrains.uast.* +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.kotlin.declarations.UastLightIdentifier +import org.jetbrains.uast.kotlin.internal.KotlinUElementWithComments +import org.jetbrains.uast.kotlin.psi.UastKotlinPsiParameter +import org.jetbrains.uast.kotlin.psi.UastKotlinPsiVariable +import org.jetbrains.uast.visitor.UastVisitor + +abstract class AbstractKotlinUVariable(givenParent: UElement?) + : KotlinAbstractUElement(givenParent), PsiVariable, UVariable, KotlinUElementWithComments { + + override val uastInitializer: UExpression? + get() { + val psi = psi + val initializerExpression = when (psi) { + is UastKotlinPsiVariable -> psi.ktInitializer + is UastKotlinPsiParameter -> psi.ktDefaultValue + is KtLightElement<*, *> -> { + val origin = psi.kotlinOrigin + when (origin) { + is KtVariableDeclaration -> origin.initializer + is KtParameter -> origin.defaultValue + else -> null + } + } + else -> null + } ?: return null + return getLanguagePlugin().convertElement(initializerExpression, this) as? UExpression ?: UastEmptyExpression + } + + val delegateExpression: UExpression? by lz { + val psi = psi + val expression = when (psi) { + is KtLightElement<*, *> -> (psi.kotlinOrigin as? KtProperty)?.delegateExpression + is UastKotlinPsiVariable -> (psi.ktElement as? KtProperty)?.delegateExpression + else -> null + } + + expression?.let { getLanguagePlugin().convertElement(it, this) as? UExpression } + } + + override fun getNameIdentifier(): PsiIdentifier { + val kotlinOrigin = (psi as? KtLightElement<*, *>)?.kotlinOrigin + return UastLightIdentifier(psi, kotlinOrigin as KtNamedDeclaration?) + } + + override fun getContainingFile(): PsiFile = unwrapFakeFileForLightClass(psi.containingFile) + + override val annotations by lz { + val sourcePsi = sourcePsi ?: return@lz psi.annotations.map { WrappedUAnnotation(it, this) } + val annotations = SmartList(KotlinNullabilityUAnnotation(sourcePsi, this)) + if (sourcePsi is KtModifierListOwner) { + sourcePsi.annotationEntries. + filter { acceptsAnnotationTarget(it.useSiteTarget?.getAnnotationUseSiteTarget()) }. + mapTo(annotations) { KotlinUAnnotation(it, this) } + } + annotations + } + + + abstract protected fun acceptsAnnotationTarget(target: AnnotationUseSiteTarget?): Boolean + + override val typeReference by lz { getLanguagePlugin().convertOpt(psi.typeElement, this) } + + override val uastAnchor: UElement? + get() = UIdentifier(nameIdentifier, this) + + override fun equals(other: Any?) = other is AbstractKotlinUVariable && psi == other.psi + + class WrappedUAnnotation(psiAnnotation: PsiAnnotation, override val uastParent: UElement) : UAnnotation, JvmDeclarationUElement { + + override val javaPsi: PsiAnnotation = psiAnnotation + override val psi: PsiAnnotation = javaPsi + override val sourcePsi: PsiElement? = null + + override val attributeValues: List by lz { + psi.parameterList.attributes.map { WrappedUNamedExpression(it, this) } + } + + class WrappedUNamedExpression(pair: PsiNameValuePair, override val uastParent: UElement?) : UNamedExpression, JvmDeclarationUElement { + override val name: String? = pair.name + override val psi = pair + override val javaPsi: PsiElement? = psi + override val sourcePsi: PsiElement? = null + override val annotations: List = emptyList() + override val expression: UExpression by lz { toUExpression(psi.value) } + } + + override val qualifiedName: String? = psi.qualifiedName + override fun findAttributeValue(name: String?): UExpression? = psi.findAttributeValue(name)?.let { toUExpression(it) } + override fun findDeclaredAttributeValue(name: String?): UExpression? = psi.findDeclaredAttributeValue(name)?.let { toUExpression(it) } + override fun resolve(): PsiClass? = psi.nameReferenceElement?.resolve() as? PsiClass + } + +} + +private fun toUExpression(psi: PsiElement?): UExpression = psi.toUElementOfType() ?: UastEmptyExpression + +class KotlinUVariable( + psi: PsiVariable, + override val sourcePsi: KtElement, + givenParent: UElement? +) : AbstractKotlinUVariable(givenParent), UVariable, PsiVariable by psi { + + override val javaPsi = unwrap(psi) + + override val psi = javaPsi + + override val typeReference by lz { getLanguagePlugin().convertOpt(psi.typeElement, this) } + + override fun acceptsAnnotationTarget(target: AnnotationUseSiteTarget?): Boolean = true + + override fun getInitializer(): PsiExpression? { + return super.getInitializer() + } + + override fun getOriginalElement(): PsiElement? { + return super.getOriginalElement() + } + + override fun getNameIdentifier(): PsiIdentifier { + return super.getNameIdentifier() + } + + override fun getContainingFile(): PsiFile { + return super.getContainingFile() + } + +} + +open class KotlinUParameter( + psi: PsiParameter, + final override val sourcePsi: KtElement?, + givenParent: UElement? +) : AbstractKotlinUVariable(givenParent), UParameter, PsiParameter by psi { + + final override val javaPsi = unwrap(psi) + + override val psi = javaPsi + + private val isLightConstructorParam by lz { psi.getParentOfType(true)?.isConstructor } + + private val isKtConstructorParam by lz { sourcePsi?.getParentOfType(true)?.let { it is KtConstructor<*> } } + + override fun acceptsAnnotationTarget(target: AnnotationUseSiteTarget?): Boolean { + if (sourcePsi !is KtParameter) return false + if (isKtConstructorParam == isLightConstructorParam && target == null) return true + when (target) { + AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER -> return isLightConstructorParam == true + AnnotationUseSiteTarget.SETTER_PARAMETER -> return isLightConstructorParam != true + else -> return false + } + } + + override fun getInitializer(): PsiExpression? { + return super.getInitializer() + } + + override fun getOriginalElement(): PsiElement? { + return super.getOriginalElement() + } + + override fun getNameIdentifier(): PsiIdentifier { + return super.getNameIdentifier() + } + + override fun getContainingFile(): PsiFile { + return super.getContainingFile() + } +} + +class KotlinNullabilityUAnnotation(val annotatedElement: PsiElement, override val uastParent: UElement) : UAnnotation, JvmDeclarationUElement { + + private fun getTargetType(annotatedElement: PsiElement): KotlinType? { + if (annotatedElement is KtCallableDeclaration) { + annotatedElement.typeReference?.getType()?.let { return it } + } + if (annotatedElement is KtProperty) { + annotatedElement.initializer?.let { it.getType(it.analyze()) }?.let { return it } + annotatedElement.delegateExpression?.let { it.getType(it.analyze())?.arguments?.firstOrNull()?.type }?.let { return it } + } + annotatedElement.getParentOfType(false)?.let { + it.typeReference?.getType() ?: it.initializer?.let { it.getType(it.analyze()) } + }?.let { return it } + return null + } + + val nullability by lz { getTargetType(annotatedElement)?.nullability() } + + override val attributeValues: List + get() = emptyList() + override val psi: PsiElement? + get() = null + override val javaPsi: PsiAnnotation? + get() = null + override val sourcePsi: PsiElement? + get() = null + override val qualifiedName: String? + get() = when (nullability) { + TypeNullability.NOT_NULL -> NotNull::class.qualifiedName + TypeNullability.NULLABLE -> Nullable::class.qualifiedName + TypeNullability.FLEXIBLE -> null + null -> null + } + + override fun findAttributeValue(name: String?): UExpression? = null + + override fun findDeclaredAttributeValue(name: String?): UExpression? = null + + override fun resolve(): PsiClass? = qualifiedName?.let { + val project = annotatedElement.project + JavaPsiFacade.getInstance(project).findClass(it, GlobalSearchScope.allScope(project)) + } + +} + +open class KotlinUField( + psi: PsiField, + override val sourcePsi: KtElement?, + givenParent: UElement? +) : AbstractKotlinUVariable(givenParent), UField, PsiField by psi { + override fun getSourceElement() = sourcePsi ?: this + + override val javaPsi = unwrap(psi) + + override val psi = javaPsi + + override fun acceptsAnnotationTarget(target: AnnotationUseSiteTarget?): Boolean = + target == AnnotationUseSiteTarget.FIELD || + target == AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD || + (sourcePsi is KtProperty) && (target == null || target == AnnotationUseSiteTarget.PROPERTY) + + override fun getInitializer(): PsiExpression? { + return super.getInitializer() + } + + override fun getOriginalElement(): PsiElement? { + return super.getOriginalElement() + } + + override fun getNameIdentifier(): PsiIdentifier { + return super.getNameIdentifier() + } + + override fun getContainingFile(): PsiFile { + return super.getContainingFile() + } + + override fun isPhysical(): Boolean { + return true + } + + override fun accept(visitor: UastVisitor) { + if (visitor.visitField(this)) return + annotations.acceptList(visitor) + uastInitializer?.accept(visitor) + delegateExpression?.accept(visitor) + visitor.afterVisitField(this) + } +} + +open class KotlinULocalVariable( + psi: PsiLocalVariable, + override val sourcePsi: KtElement, + givenParent: UElement? +) : AbstractKotlinUVariable(givenParent), ULocalVariable, PsiLocalVariable by psi { + + override val javaPsi = unwrap(psi) + + override fun acceptsAnnotationTarget(target: AnnotationUseSiteTarget?): Boolean = true + + override val psi = javaPsi + + override fun getInitializer(): PsiExpression? { + return super.getInitializer() + } + + override fun getOriginalElement(): PsiElement? { + return super.getOriginalElement() + } + + override fun getNameIdentifier(): PsiIdentifier { + return super.getNameIdentifier() + } + + override fun getContainingFile(): PsiFile { + return super.getContainingFile() + } + + override fun accept(visitor: UastVisitor) { + if (visitor.visitLocalVariable(this)) return + annotations.acceptList(visitor) + uastInitializer?.accept(visitor) + delegateExpression?.accept(visitor) + visitor.afterVisitLocalVariable(this) + } +} + +open class KotlinUAnnotatedLocalVariable( + psi: PsiLocalVariable, + sourcePsi: KtElement, + uastParent: UElement?, + computeAnnotations: (parent: UElement) -> List +) : KotlinULocalVariable(psi, sourcePsi, uastParent) { + + override val annotations: List by lz { computeAnnotations(this) } +} + +class KotlinUEnumConstant( + psi: PsiEnumConstant, + override val sourcePsi: KtElement?, + givenParent: UElement? +) : AbstractKotlinUVariable(givenParent), UEnumConstant, PsiEnumConstant by psi { + + override val initializingClass: UClass? by lz { + (psi.initializingClass as? KtLightClass)?.let { initializingClass -> + KotlinUClass.create(initializingClass, this) + } + } + + override fun getInitializer(): PsiExpression? = super.getInitializer() + + override fun getOriginalElement(): PsiElement? = super.getOriginalElement() + + override val javaPsi = unwrap(psi) + + override val psi = javaPsi + + override fun acceptsAnnotationTarget(target: AnnotationUseSiteTarget?): Boolean = true + + override fun getContainingFile(): PsiFile { + return super.getContainingFile() + } + + override fun getNameIdentifier(): PsiIdentifier { + return super.getNameIdentifier() + } + + override val kind: UastCallKind + get() = UastCallKind.CONSTRUCTOR_CALL + + override val receiver: UExpression? + get() = null + + override val receiverType: PsiType? + get() = null + + override val methodIdentifier: UIdentifier? + get() = null + + override val classReference: UReferenceExpression? + get() = KotlinEnumConstantClassReference(psi, sourcePsi, this) + + override val typeArgumentCount: Int + get() = 0 + + override val typeArguments: List + get() = emptyList() + + override val valueArgumentCount: Int + get() = psi.argumentList?.expressions?.size ?: 0 + + override val valueArguments by lz { + psi.argumentList?.expressions?.map { + getLanguagePlugin().convertElement(it, this) as? UExpression ?: UastEmptyExpression + } ?: emptyList() + } + + override val returnType: PsiType? + get() = psi.type + + override fun resolve() = psi.resolveMethod() + + override val methodName: String? + get() = null + + private class KotlinEnumConstantClassReference( + override val psi: PsiEnumConstant, + override val sourcePsi: KtElement?, + givenParent: UElement? + ) : KotlinAbstractUExpression(givenParent), USimpleNameReferenceExpression { + override val javaPsi: PsiElement? + get() = psi + + override fun resolve() = psi.containingClass + override val resolvedName: String? + get() = psi.containingClass?.name + override val identifier: String + get() = psi.containingClass?.name ?: "" + } +} \ No newline at end of file diff --git a/plugins/uast-kotlin/testData/ReceiverFun.kt.172 b/plugins/uast-kotlin/testData/ReceiverFun.kt.172 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/testData/ReceiverFun.log.txt.172 b/plugins/uast-kotlin/testData/ReceiverFun.log.txt.172 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/testData/ReceiverFun.render.txt.172 b/plugins/uast-kotlin/testData/ReceiverFun.render.txt.172 new file mode 100644 index 00000000000..e69de29bb2d