diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinAbstractUElement.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinAbstractUElement.kt index ceddd6d8645..f6745ddf06b 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinAbstractUElement.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinAbstractUElement.kt @@ -16,16 +16,31 @@ package org.jetbrains.uast.kotlin -import org.jetbrains.kotlin.psi.KtAnnotatedExpression -import org.jetbrains.kotlin.psi.KtAnnotationEntry -import org.jetbrains.kotlin.psi.KtValueArgument -import org.jetbrains.uast.UAnnotation -import org.jetbrains.uast.UElement -import org.jetbrains.uast.UExpression +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType +import org.jetbrains.uast.* abstract class KotlinAbstractUElement(private val givenParent: UElement?) : UElement { - override val uastParent: UElement? by lz { convertParent(givenParent) } + override val uastParent: UElement? by lz { + givenParent ?: convertParent() + } + + protected open fun convertParent(): UElement? { + var parent = psi?.parent ?: psi?.containingFile + + if (parent is KtStringTemplateExpression && parent.entries.size == 1) { + parent = parent.parent + } + + val result = doConvertParent(this, parent) + if (result == this) { + throw IllegalStateException("Loop in parent structure when converting a $psi") + } + + return result + } override fun equals(other: Any?): Boolean { if (other !is UElement) { @@ -38,25 +53,35 @@ abstract class KotlinAbstractUElement(private val givenParent: UElement?) : UEle override fun hashCode() = psi?.hashCode() ?: 0 } -internal fun UElement.convertParent(givenParent: UElement?): UElement? { - return if (givenParent != null) - givenParent - else { - val parent = psi?.parent - val result = KotlinConverter.unwrapElements(parent)?.let { parentUnwrapped -> - if (parent is KtValueArgument && parentUnwrapped is KtAnnotationEntry) { - val argumentName = parent.getArgumentName()?.asName?.asString() ?: "" - (KotlinUastLanguagePlugin().convertElementWithParent(parentUnwrapped, null) as? UAnnotation) - ?.attributeValues?.find { it.name == argumentName } - } - else - KotlinUastLanguagePlugin().convertElementWithParent(parentUnwrapped, null) - } - if (result == this) { - throw IllegalStateException("Loop in parent structure") - } - result +fun doConvertParent(element: UElement, parent: PsiElement?): UElement? { + val parentUnwrapped = KotlinConverter.unwrapElements(parent) ?: return null + if (parent is KtValueArgument && parentUnwrapped is KtAnnotationEntry) { + return (KotlinUastLanguagePlugin().convertElementWithParent(parentUnwrapped, null) as? KotlinUAnnotation) + ?.findAttributeValueExpression(parent) } + + if (parent is KtParameter) { + val annotationClass = findAnnotationClassFromConstructorParameter(parent) + if (annotationClass != null) { + return annotationClass.methods.find { it.name == parent.name } + } + } + + val result = KotlinUastLanguagePlugin().convertElementWithParent(parentUnwrapped, null) + + if (result is UEnumConstant && element is UDeclaration) { + return result.initializingClass + } + return result +} + +private fun findAnnotationClassFromConstructorParameter(parameter: KtParameter): UClass? { + val primaryConstructor = parameter.getStrictParentOfType() ?: return null + val containingClass = primaryConstructor.getContainingClassOrObject() + if (containingClass.isAnnotation()) { + return KotlinUastLanguagePlugin().convertElementWithParent(containingClass, null) as UClass + } + return null } abstract class KotlinAbstractUExpression(givenParent: UElement?) @@ -67,4 +92,5 @@ abstract class KotlinAbstractUExpression(givenParent: UElement?) val annotatedExpression = psi?.parent as? KtAnnotatedExpression ?: return emptyList() return annotatedExpression.annotationEntries.map { KotlinUAnnotation(it, this) } } -} \ No newline at end of file +} + diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt index 7f601ac0b99..883b45c8d2b 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt @@ -137,13 +137,20 @@ class KotlinUastLanguagePlugin : UastLanguagePlugin { return with(requiredType) { when (original) { is KtLightMethod -> el(build(KotlinUMethod.Companion::create)) // .Companion is needed because of KT-13934 - is KtLightClass -> el(build(KotlinUClass.Companion::create)) + is KtLightClass -> el { + (original.kotlinOrigin as? KtEnumEntry)?.let { enumEntry -> + convertEnumEntry(enumEntry, givenParent) + } ?: KotlinUClass.create(original, givenParent) + } is KtLightFieldImpl.KtLightEnumConstant -> el(build(::KotlinUEnumConstant)) is KtLightField -> el(build(::KotlinUField)) is KtLightParameter, is UastKotlinPsiParameter -> el(build(::KotlinUParameter)) is UastKotlinPsiVariable -> el(build(::KotlinUVariable)) + is KtEnumEntry -> el { + convertEnumEntry(original, givenParent) + } is KtClassOrObject -> el { original.toLightClass()?.let { lightClass -> KotlinUClass.create(lightClass, givenParent) @@ -154,13 +161,18 @@ class KotlinUastLanguagePlugin : UastLanguagePlugin { convertDeclaration(lightMethod, givenParent, requiredType) } is KtPropertyAccessor -> el { - javaPlugin.convertOpt( - LightClassUtil.getLightClassAccessorMethod(original), givenParent) + val lightMethod = LightClassUtil.getLightClassAccessorMethod(original) ?: return null + convertDeclaration(lightMethod, givenParent, requiredType) } - is KtProperty -> el { - javaPlugin.convertOpt( - LightClassUtil.getLightClassBackingField(original), givenParent) - ?: convertDeclaration(element.parent, givenParent, requiredType) + is KtProperty -> el { + if (original.isLocal) { + KotlinConverter.convertPsiElement(element, givenParent, requiredType) + } + else { + LightClassUtil.getLightClassBackingField(original)?.let { + KotlinUField(it, givenParent) + } + } } is KtFile -> el { KotlinUFile(original, this@KotlinUastLanguagePlugin) } @@ -171,6 +183,17 @@ class KotlinUastLanguagePlugin : UastLanguagePlugin { } } + private fun convertEnumEntry(original: KtEnumEntry, givenParent: UElement?): UElement? { + return LightClassUtil.getLightClassBackingField(original)?.let { psiField -> + if (psiField is KtLightFieldImpl.KtLightEnumConstant) { + KotlinUEnumConstant(psiField, givenParent) + } + else { + null + } + } + } + override fun isExpressionValueUsed(element: UExpression): Boolean { return when (element) { is KotlinUSimpleReferenceExpression.KotlinAccessorCallExpression -> element.setterValue != null @@ -191,14 +214,13 @@ internal inline fun Class?.expr(f: () return if (this == null || isAssignableFrom(ActualT::class.java)) f() else null } -internal fun UElement?.toCallback() = if (this != null) fun(): UElement? { return this } else null - internal object KotlinConverter { internal tailrec fun unwrapElements(element: PsiElement?): PsiElement? = when (element) { is KtValueArgumentList -> unwrapElements(element.parent) is KtValueArgument -> unwrapElements(element.parent) is KtDeclarationModifierList -> unwrapElements(element.parent) is KtContainerNode -> unwrapElements(element.parent) + is KtSimpleNameStringTemplateEntry -> unwrapElements(element.parent) else -> element } @@ -220,6 +242,9 @@ internal object KotlinConverter { } is KtClassBody -> el(build(KotlinUExpressionList.Companion::createClassBody)) is KtCatchClause -> el(build(::KotlinUCatchClause)) + is KtVariableDeclaration -> el { + convertVariablesDeclaration(element, givenParent).declarations.singleOrNull() + } is KtExpression -> KotlinConverter.convertExpression(element, givenParent, requiredType) is KtLambdaArgument -> KotlinConverter.convertExpression(element.getLambdaExpression(), givenParent, requiredType) is KtLightAnnotationForSourceEntry.LightExpressionValue<*> -> { @@ -231,6 +256,9 @@ internal object KotlinConverter { } is KtLiteralStringTemplateEntry, is KtEscapeStringTemplateEntry -> el(build(::KotlinStringULiteralExpression)) is KtStringTemplateEntry -> element.expression?.let { convertExpression(it, givenParent, requiredType) } ?: expr { UastEmptyExpression } + is KtWhenEntry -> el(build(::KotlinUSwitchEntry)) + is KtWhenCondition -> convertWhenCondition(element, givenParent) + is KtTypeReference -> el { LazyKotlinUTypeReferenceExpression(element, givenParent) } else -> { if (element is LeafPsiElement && element.elementType == KtTokens.IDENTIFIER) { @@ -349,7 +377,33 @@ internal object KotlinConverter { else -> expr(build(::UnknownKotlinExpression)) }} } - + + internal fun convertWhenCondition(condition: KtWhenCondition, givenParent: UElement?): UExpression { + return when (condition) { + is KtWhenConditionInRange -> KotlinCustomUBinaryExpression(condition, givenParent).apply { + leftOperand = KotlinStringUSimpleReferenceExpression("it", this) + operator = when { + condition.isNegated -> KotlinBinaryOperators.NOT_IN + else -> KotlinBinaryOperators.IN + } + rightOperand = KotlinConverter.convertOrEmpty(condition.rangeExpression, this) + } + is KtWhenConditionIsPattern -> KotlinCustomUBinaryExpressionWithType(condition, givenParent).apply { + operand = KotlinStringUSimpleReferenceExpression("it", this) + operationKind = when { + condition.isNegated -> KotlinBinaryExpressionWithTypeKinds.NEGATED_INSTANCE_CHECK + else -> UastBinaryExpressionWithTypeKind.INSTANCE_CHECK + } + val typeRef = condition.typeReference + typeReference = typeRef?.let { + LazyKotlinUTypeReferenceExpression(it, this) { typeRef.toPsiType(this, boxed = true) } + } + } + is KtWhenConditionWithExpression -> KotlinConverter.convertOrEmpty(condition.expression, givenParent) + else -> UastEmptyExpression + } + } + internal fun convertOrEmpty(expression: KtExpression?, parent: UElement?): UExpression { return expression?.let { convertExpression(it, parent, null) } ?: UastEmptyExpression } @@ -376,7 +430,7 @@ private fun convertVariablesDeclaration( psi: KtVariableDeclaration, parent: UElement? ): UDeclarationsExpression { - val declarationsExpression = KotlinUDeclarationsExpression(parent) + val declarationsExpression = KotlinUDeclarationsExpression(null, parent, psi) val parentPsiElement = parent?.psi val variable = KotlinUAnnotatedLocalVariable( UastKotlinPsiVariable.create(psi, parentPsiElement, declarationsExpression), declarationsExpression) { annotationParent -> diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUAnnotation.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUAnnotation.kt index 48a648826ee..8e467ef6dea 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUAnnotation.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUAnnotation.kt @@ -4,8 +4,10 @@ import com.intellij.psi.PsiClass import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.psi.KtAnnotationEntry import org.jetbrains.kotlin.psi.KtParameter +import org.jetbrains.kotlin.psi.ValueArgument import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall +import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass import org.jetbrains.kotlin.resolve.source.getPsi @@ -44,6 +46,14 @@ class KotlinUAnnotation( override fun findAttributeValue(name: String?): UExpression? = findDeclaredAttributeValue(name) ?: findAttributeDefaultValue(name ?: "value") + fun findAttributeValueExpression(arg: ValueArgument): UExpression? { + val mapping = resolvedCall?.getArgumentMapping(arg) + return (mapping as? ArgumentMatch)?.let { match -> + val namedExpression = attributeValues.find { it.name == match.valueParameter.name.asString() } + namedExpression?.expression as? KotlinUVarargExpression ?: namedExpression + } + } + override fun findDeclaredAttributeValue(name: String?): UExpression? { return attributeValues.find { it.name == name || diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUClass.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUClass.kt index f0ec2045d8d..7eecbbfd959 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUClass.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUClass.kt @@ -28,15 +28,19 @@ import org.jetbrains.uast.java.AbstractJavaUClass import org.jetbrains.uast.kotlin.declarations.KotlinUMethod import org.jetbrains.uast.kotlin.declarations.UastLightIdentifier +abstract class AbstractKotlinUClass(private val givenParent: UElement?) : AbstractJavaUClass() { + override val uastParent: UElement? by lz { + givenParent ?: KotlinUastLanguagePlugin().convertElementWithParent(psi.parent ?: psi.containingFile, null) + } +} + open class KotlinUClass private constructor( psi: KtLightClass, - private val givenParent: UElement? -) : AbstractJavaUClass(), PsiClass by psi { + givenParent: UElement? +) : AbstractKotlinUClass(givenParent), PsiClass by psi { val ktClass = psi.kotlinOrigin - override val uastParent: UElement? by lz { convertParent(givenParent) } - override val psi = unwrap(psi) override fun getOriginalElement(): PsiElement? = super.getOriginalElement() @@ -56,8 +60,8 @@ open class KotlinUClass private constructor( // filter Enum entry classes to avoid duplication with PsiEnumConstant initializer class return psi.innerClasses.filter { it.name != JvmAbi.DEFAULT_IMPLS_CLASS_NAME && !it.isEnumEntryLightClass() - }.map { - getLanguagePlugin().convert(it, this) + }.mapNotNull { + getLanguagePlugin().convertOpt(it, this) }.toTypedArray() } @@ -112,20 +116,18 @@ open class KotlinUClass private constructor( class KotlinUAnonymousClass( psi: PsiAnonymousClass, - private val givenParent: UElement? -) : AbstractJavaUClass(), UAnonymousClass, PsiAnonymousClass by psi { - - override val uastParent: UElement? by lz { convertParent(givenParent) } - + givenParent: UElement? +) : AbstractKotlinUClass(givenParent), UAnonymousClass, PsiAnonymousClass by psi { + override val psi: PsiAnonymousClass = unwrap(psi) - override fun getOriginalElement(): PsiElement? = super.getOriginalElement() + override fun getOriginalElement(): PsiElement? = super.getOriginalElement() - override fun getSuperClass(): UClass? = super.getSuperClass() - override fun getFields(): Array = super.getFields() - override fun getMethods(): Array = super.getMethods() - override fun getInitializers(): Array = super.getInitializers() - override fun getInnerClasses(): Array = super.getInnerClasses() + override fun getSuperClass(): UClass? = super.getSuperClass() + override fun getFields(): Array = super.getFields() + override fun getMethods(): Array = super.getMethods() + override fun getInitializers(): Array = super.getInitializers() + override fun getInnerClasses(): Array = super.getInnerClasses() override fun getContainingFile(): PsiFile = unwrapFakeFileForLightClass(psi.containingFile) diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUFile.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUFile.kt index 751ae25f973..33dde2e91d4 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUFile.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUFile.kt @@ -49,8 +49,8 @@ class KotlinUFile(override val psi: KtFile, override val languagePlugin: UastLan val facadeOrScriptClass = if (psi.isScript()) psi.script?.toLightClass() else psi.findFacadeClass() val classes = psi.declarations.mapNotNull { (it as? KtClassOrObject)?.toLightClass()?.toUClass() } - (facadeOrScriptClass?.let { listOf(it.toUClass()) } ?: emptyList()) + classes + (facadeOrScriptClass?.toUClass()?.let { listOf(it) } ?: emptyList()) + classes } - private fun PsiClass.toUClass() = languagePlugin.convert(this, this@KotlinUFile) + private fun PsiClass.toUClass() = languagePlugin.convertOpt(this, this@KotlinUFile) } \ No newline at end of file diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUVariable.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUVariable.kt index d2a743d001a..6fb2f3f8428 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUVariable.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUVariable.kt @@ -17,6 +17,7 @@ package org.jetbrains.uast.kotlin import com.intellij.psi.* +import org.jetbrains.kotlin.asJava.classes.KtLightClass import org.jetbrains.kotlin.asJava.elements.KtLightElement import org.jetbrains.kotlin.psi.KtNamedDeclaration import org.jetbrains.kotlin.psi.KtParameter @@ -215,6 +216,13 @@ open class KotlinUEnumConstant( psi: PsiEnumConstant, 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 val psi = unwrap(psi) override fun getContainingFile(): PsiFile { return super.getContainingFile() @@ -224,10 +232,6 @@ open class KotlinUEnumConstant( return super.getNameIdentifier() } - override val initializingClass: UClass? by lz { getLanguagePlugin().convertOpt(psi.initializingClass, this) } - - override val psi = unwrap(psi) - override val kind: UastCallKind get() = UastCallKind.CONSTRUCTOR_CALL @@ -270,7 +274,10 @@ open class KotlinUEnumConstant( override val psi: PsiEnumConstant, private val givenParent: UElement? ) : JavaAbstractUExpression(), USimpleNameReferenceExpression { - override val uastParent: UElement? by lz { convertParent(givenParent) } + override val uastParent: UElement? by lz { + givenParent ?: KotlinUastLanguagePlugin().convertElementWithParent(psi.parent ?: psi.containingFile, null) + } + override fun resolve() = psi.containingClass override val resolvedName: String? get() = psi.containingClass?.name diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/ElvisExpression.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/ElvisExpression.kt index 1740b243e5c..b3ca2b62f3a 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/ElvisExpression.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/ElvisExpression.kt @@ -68,14 +68,13 @@ private fun createElvisExpressions( return listOf(declaration, ifExpression) } -fun createElvisExpression(elvisExpression: KtBinaryExpression, containingElement: UElement?): UExpression { +fun createElvisExpression(elvisExpression: KtBinaryExpression, givenParent: UElement?): UExpression { val left = elvisExpression.left ?: return UastEmptyExpression val right = elvisExpression.right ?: return UastEmptyExpression - return object : UExpressionList, KotlinEvaluatableUElement { + return object : KotlinAbstractUElement(givenParent), UExpressionList, KotlinEvaluatableUElement { override val psi: PsiElement? = elvisExpression override val kind = KotlinSpecialExpressionKinds.ELVIS - override val uastParent: UElement? = containingElement override val annotations: List = emptyList() override val expressions: List by lz { createElvisExpressions(left, right, this, elvisExpression.parent) diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUBinaryExpressionWithType.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUBinaryExpressionWithType.kt index 1b75bac2977..85c8f522f5d 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUBinaryExpressionWithType.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUBinaryExpressionWithType.kt @@ -32,7 +32,7 @@ class KotlinUBinaryExpressionWithType( override val type by lz { psi.right.toPsiType(this) } override val typeReference by lz { - psi.right?.let { LazyKotlinUTypeReferenceExpression(it, this) { it.toPsiType(this) } } + psi.right?.let { LazyKotlinUTypeReferenceExpression(it, this) } } override val operationKind = when (psi.operationReference.getReferencedNameElementType()) { diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUDeclarationsExpression.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUDeclarationsExpression.kt index e89286d6eed..6696d9c68e8 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUDeclarationsExpression.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUDeclarationsExpression.kt @@ -17,12 +17,17 @@ package org.jetbrains.uast import com.intellij.psi.PsiElement import org.jetbrains.uast.kotlin.KotlinAbstractUExpression +import org.jetbrains.uast.kotlin.doConvertParent class KotlinUDeclarationsExpression( override val psi: PsiElement?, - givenParent: UElement? + givenParent: UElement?, + val psiAnchor: PsiElement? = null ) : KotlinAbstractUExpression(givenParent), UDeclarationsExpression { + override val uastParent: UElement? + get() = if (psiAnchor != null) doConvertParent(this, psiAnchor.parent) else super.uastParent + constructor(uastParent: UElement?) : this(null, uastParent) override lateinit var declarations: List diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinULiteralExpression.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinULiteralExpression.kt index 757d45d1d8a..8f20e86285c 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinULiteralExpression.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinULiteralExpression.kt @@ -20,6 +20,7 @@ import com.intellij.psi.PsiElement import org.jetbrains.kotlin.KtNodeTypes import org.jetbrains.kotlin.psi.KtConstantExpression import org.jetbrains.kotlin.psi.KtEscapeStringTemplateEntry +import org.jetbrains.kotlin.psi.KtStringTemplateExpression import org.jetbrains.uast.UElement import org.jetbrains.uast.ULiteralExpression @@ -45,4 +46,4 @@ class KotlinStringULiteralExpression( get() = text override fun evaluate() = value -} \ No newline at end of file +} diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUNamedExpression.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUNamedExpression.kt index ba6fd45d566..15ca3c913df 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUNamedExpression.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUNamedExpression.kt @@ -45,52 +45,52 @@ class KotlinUNamedExpression private constructor( valueArguments: List, uastParent: UElement?): UNamedExpression { return KotlinUNamedExpression(name, uastParent) { expressionParent -> - object : KotlinAbstractUExpression(uastParent), UCallExpression { - override val uastParent: UElement? = expressionParent - - override val kind: UastCallKind = UastCallKind.NESTED_ARRAY_INITIALIZER - - override val valueArguments: List by lz { - valueArguments.map { - it.getArgumentExpression()?.let { argumentExpression -> - getLanguagePlugin().convert(argumentExpression, this) - } ?: UastEmptyExpression - } - } - - override val valueArgumentCount: Int - get() = valueArguments.size - - override val psi: PsiElement? - get() = null - - override val methodIdentifier: UIdentifier? - get() = null - - override val classReference: UReferenceExpression? - get() = null - - override val methodName: String? - get() = null - - override val typeArgumentCount: Int - get() = 0 - - override val typeArguments: List - get() = emptyList() - - override val returnType: PsiType? - get() = null - - override fun resolve() = null - - override val receiver: UExpression? - get() = null - - override val receiverType: PsiType? - get() = null - } + KotlinUVarargExpression(valueArguments, expressionParent) } } } -} \ No newline at end of file +} +class KotlinUVarargExpression(private val valueArgs: List, + uastParent: UElement?) : KotlinAbstractUExpression(uastParent), UCallExpression { + override val kind: UastCallKind = UastCallKind.NESTED_ARRAY_INITIALIZER + + override val valueArguments: List by lz { + valueArgs.map { + it.getArgumentExpression()?.let { argumentExpression -> + getLanguagePlugin().convert(argumentExpression, this) + } ?: UastEmptyExpression + } + } + + override val valueArgumentCount: Int + get() = valueArgs.size + + override val psi: PsiElement? + get() = null + + override val methodIdentifier: UIdentifier? + get() = null + + override val classReference: UReferenceExpression? + get() = null + + override val methodName: String? + get() = null + + override val typeArgumentCount: Int + get() = 0 + + override val typeArguments: List + get() = emptyList() + + override val returnType: PsiType? + get() = null + + override fun resolve() = null + + override val receiver: UExpression? + get() = null + + override val receiverType: PsiType? + get() = null +} diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSwitchExpression.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSwitchExpression.kt index 7be77f7bdfa..2cdda7b1f34 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSwitchExpression.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSwitchExpression.kt @@ -17,7 +17,9 @@ package org.jetbrains.uast.kotlin import com.intellij.psi.PsiElement -import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.KtBlockExpression +import org.jetbrains.kotlin.psi.KtWhenEntry +import org.jetbrains.kotlin.psi.KtWhenExpression import org.jetbrains.uast.* import org.jetbrains.uast.kotlin.kinds.KotlinSpecialExpressionKinds @@ -48,32 +50,10 @@ class KotlinUSwitchExpression( class KotlinUSwitchEntry( override val psi: KtWhenEntry, - givenParent: UExpression + givenParent: UElement? ) : KotlinAbstractUExpression(givenParent), USwitchClauseExpressionWithBody { override val caseValues by lz { - psi.conditions.map { when (it) { - is KtWhenConditionInRange -> KotlinCustomUBinaryExpression(it, this).apply { - leftOperand = KotlinStringUSimpleReferenceExpression("it", this) - operator = when { - it.isNegated -> KotlinBinaryOperators.NOT_IN - else -> KotlinBinaryOperators.IN - } - rightOperand = KotlinConverter.convertOrEmpty(it.rangeExpression, this) - } - is KtWhenConditionIsPattern -> KotlinCustomUBinaryExpressionWithType(it, this).apply { - operand = KotlinStringUSimpleReferenceExpression("it", this) - operationKind = when { - it.isNegated -> KotlinBinaryExpressionWithTypeKinds.NEGATED_INSTANCE_CHECK - else -> UastBinaryExpressionWithTypeKind.INSTANCE_CHECK - } - val typeRef = it.typeReference - typeReference = typeRef?.let { - LazyKotlinUTypeReferenceExpression(it, this) { typeRef.toPsiType(this, boxed = true) } - } - } - is KtWhenConditionWithExpression -> KotlinConverter.convertOrEmpty(it.expression, this) - else -> UastEmptyExpression - }} + psi.conditions.map { KotlinConverter.convertWhenCondition(it, this) } } override val body: UExpressionList by lz { @@ -101,4 +81,11 @@ class KotlinUSwitchEntry( } } } + + override fun convertParent(): UElement? { + val result = KotlinConverter.unwrapElements(psi.parent)?.let { parentUnwrapped -> + KotlinUastLanguagePlugin().convertElementWithParent(parentUnwrapped, null) + } + return (result as? KotlinUSwitchExpression)?.body ?: result + } } \ No newline at end of file diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUTypeReferenceExpression.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUTypeReferenceExpression.kt index c3930ece19e..0916778b714 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUTypeReferenceExpression.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUTypeReferenceExpression.kt @@ -2,6 +2,7 @@ package org.jetbrains.uast.kotlin import com.intellij.psi.PsiElement import com.intellij.psi.PsiType +import org.jetbrains.kotlin.psi.KtTypeReference import org.jetbrains.uast.UElement import org.jetbrains.uast.UTypeReferenceExpression @@ -13,9 +14,11 @@ open class KotlinUTypeReferenceExpression( class LazyKotlinUTypeReferenceExpression( - override val psi: PsiElement, + override val psi: KtTypeReference, givenParent: UElement?, - private val typeSupplier: () -> PsiType + private val typeSupplier: (() -> PsiType)? = null ) : KotlinAbstractUExpression(givenParent), UTypeReferenceExpression { - override val type: PsiType by lz { typeSupplier() } -} \ No newline at end of file + override val type: PsiType by lz { + typeSupplier?.invoke() ?: psi.toPsiType(uastParent ?: this) + } +} diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/psi/UastKotlinPsiVariable.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/psi/UastKotlinPsiVariable.kt index 0f54d3da37c..f40611d0d88 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/psi/UastKotlinPsiVariable.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/psi/UastKotlinPsiVariable.kt @@ -7,9 +7,11 @@ import org.jetbrains.kotlin.builtins.createFunctionType import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.idea.KotlinLanguage import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns +import org.jetbrains.uast.* import org.jetbrains.kotlin.types.isError import org.jetbrains.uast.UDeclaration import org.jetbrains.uast.UElement @@ -73,10 +75,11 @@ class UastKotlinPsiVariable private constructor( fun create( declaration: KtVariableDeclaration, parent: PsiElement?, - containingElement: UElement, + containingElement: KotlinUDeclarationsExpression, initializer: KtExpression? = null ): PsiLocalVariable { - val psiParent = containingElement.getParentOfType()?.psi ?: parent + val psi = containingElement.psiAnchor ?: containingElement.psi + val psiParent = psi?.getNonStrictParentOfType() ?: parent val initializerExpression = initializer ?: declaration.initializer return UastKotlinPsiVariable( manager = declaration.manager, diff --git a/plugins/uast-kotlin/testData/DefaultParameterValues.kt b/plugins/uast-kotlin/testData/DefaultParameterValues.kt new file mode 100644 index 00000000000..cf492da2b18 --- /dev/null +++ b/plugins/uast-kotlin/testData/DefaultParameterValues.kt @@ -0,0 +1,2 @@ +fun foo(a: Int = 1, foo: String? = null) { +} \ No newline at end of file diff --git a/plugins/uast-kotlin/testData/DefaultParameterValues.log.txt b/plugins/uast-kotlin/testData/DefaultParameterValues.log.txt new file mode 100644 index 00000000000..d2f13973781 --- /dev/null +++ b/plugins/uast-kotlin/testData/DefaultParameterValues.log.txt @@ -0,0 +1,10 @@ +UFile (package = ) + UClass (name = DefaultParameterValuesKt) + UAnnotationMethod (name = foo) + UParameter (name = a) + UAnnotation (fqName = null) + ULiteralExpression (value = 1) + UParameter (name = foo) + UAnnotation (fqName = org.jetbrains.annotations.Nullable) + ULiteralExpression (value = null) + UBlockExpression diff --git a/plugins/uast-kotlin/testData/DefaultParameterValues.render.txt b/plugins/uast-kotlin/testData/DefaultParameterValues.render.txt new file mode 100644 index 00000000000..0d903ca6199 --- /dev/null +++ b/plugins/uast-kotlin/testData/DefaultParameterValues.render.txt @@ -0,0 +1,4 @@ +public final class DefaultParameterValuesKt { + public static final fun foo(a: int, foo: java.lang.String) : void { + } +} diff --git a/plugins/uast-kotlin/tests/AbstractKotlinRenderLogTest.kt b/plugins/uast-kotlin/tests/AbstractKotlinRenderLogTest.kt index cb34f9977ad..13a43294cec 100644 --- a/plugins/uast-kotlin/tests/AbstractKotlinRenderLogTest.kt +++ b/plugins/uast-kotlin/tests/AbstractKotlinRenderLogTest.kt @@ -1,12 +1,14 @@ package org.jetbrains.uast.test.kotlin import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile import com.intellij.psi.PsiRecursiveElementVisitor import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.utils.addToStdlib.assertedCast import org.jetbrains.uast.UDeclaration import org.jetbrains.uast.UElement import org.jetbrains.uast.UFile +import org.jetbrains.uast.kotlin.KOTLIN_CACHED_UELEMENT_KEY import org.jetbrains.uast.kotlin.KotlinUastLanguagePlugin import org.jetbrains.uast.test.common.RenderLogTestBase import org.jetbrains.uast.visitor.UastVisitor @@ -21,12 +23,7 @@ abstract class AbstractKotlinRenderLogTest : AbstractKotlinUastTest(), RenderLog override fun check(testName: String, file: UFile) { super.check(testName, file) - file.psi.accept(object : PsiRecursiveElementVisitor() { - override fun visitElement(element: PsiElement) { - KotlinUastLanguagePlugin().convertElementWithParent(element, null) - super.visitElement(element) - } - }) + val parentMap = mutableMapOf() file.accept(object : UastVisitor { private val parentStack = Stack() @@ -39,6 +36,11 @@ abstract class AbstractKotlinRenderLogTest : AbstractKotlinUastTest(), RenderLog else { Assert.assertEquals("Wrong parent of $node", parentStack.peek(), parent) } + node.psi?.let { + if (it !in parentMap) { + parentMap[it] = parentStack.reversed().joinToString { it.asLogString() } + } + } parentStack.push(node) return false } @@ -48,6 +50,22 @@ abstract class AbstractKotlinRenderLogTest : AbstractKotlinUastTest(), RenderLog parentStack.pop() } }) + + file.psi.clearUastCaches() + + file.psi.accept(object : PsiRecursiveElementVisitor() { + override fun visitElement(element: PsiElement) { + val uElement = KotlinUastLanguagePlugin().convertElementWithParent(element, null) + val expectedParents = parentMap[element] + if (expectedParents != null) { + assertNotNull("Expected to be able to convert PSI element $element", uElement) + val parents = generateSequence(uElement!!.uastParent) { it.uastParent }.joinToString { it.asLogString() } + assertEquals("Inconsistent parents for $uElement", expectedParents, parents) + } + super.visitElement(element) + } + }) + file.checkContainingFileForAllElements() } @@ -68,3 +86,12 @@ abstract class AbstractKotlinRenderLogTest : AbstractKotlinUastTest(), RenderLog }) } } + +private fun PsiFile.clearUastCaches() { + accept(object : PsiRecursiveElementVisitor() { + override fun visitElement(element: PsiElement) { + super.visitElement(element) + element.putUserData(KOTLIN_CACHED_UELEMENT_KEY, null) + } + }) +} diff --git a/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt b/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt index 762e2fa9d60..24fbb9be153 100644 --- a/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt +++ b/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt @@ -39,6 +39,8 @@ class SimpleKotlinRenderLogTest : AbstractKotlinRenderLogTest() { @Test fun testDestructuringDeclaration() = doTest("DestructuringDeclaration") + @Test fun testDefaultParameterValues() = doTest("DefaultParameterValues") + @Test fun testParameterPropertyWithAnnotation() = doTest("ParameterPropertyWithAnnotation") @Test fun testParametersWithDefaultValues() = doTest("ParametersWithDefaultValues")