Work in progress on consistent UAST structure

This commit is contained in:
Dmitry Jemerov
2017-09-13 17:21:27 +02:00
parent a5a5b37e1e
commit c98c3a7033
19 changed files with 292 additions and 150 deletions
@@ -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<KtPrimaryConstructor>() ?: 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) }
}
}
}
@@ -137,13 +137,20 @@ class KotlinUastLanguagePlugin : UastLanguagePlugin {
return with(requiredType) {
when (original) {
is KtLightMethod -> el<UMethod>(build(KotlinUMethod.Companion::create)) // .Companion is needed because of KT-13934
is KtLightClass -> el<UClass>(build(KotlinUClass.Companion::create))
is KtLightClass -> el<UDeclaration> {
(original.kotlinOrigin as? KtEnumEntry)?.let { enumEntry ->
convertEnumEntry(enumEntry, givenParent)
} ?: KotlinUClass.create(original, givenParent)
}
is KtLightFieldImpl.KtLightEnumConstant -> el<UEnumConstant>(build(::KotlinUEnumConstant))
is KtLightField -> el<UField>(build(::KotlinUField))
is KtLightParameter, is UastKotlinPsiParameter -> el<UParameter>(build(::KotlinUParameter))
is UastKotlinPsiVariable -> el<UVariable>(build(::KotlinUVariable))
is KtEnumEntry -> el<UEnumConstant> {
convertEnumEntry(original, givenParent)
}
is KtClassOrObject -> el<UClass> {
original.toLightClass()?.let { lightClass ->
KotlinUClass.create(lightClass, givenParent)
@@ -154,13 +161,18 @@ class KotlinUastLanguagePlugin : UastLanguagePlugin {
convertDeclaration(lightMethod, givenParent, requiredType)
}
is KtPropertyAccessor -> el<UMethod> {
javaPlugin.convertOpt<UMethod>(
LightClassUtil.getLightClassAccessorMethod(original), givenParent)
val lightMethod = LightClassUtil.getLightClassAccessorMethod(original) ?: return null
convertDeclaration(lightMethod, givenParent, requiredType)
}
is KtProperty -> el<UField> {
javaPlugin.convertOpt<UField>(
LightClassUtil.getLightClassBackingField(original), givenParent)
?: convertDeclaration(element.parent, givenParent, requiredType)
is KtProperty -> el<UVariable> {
if (original.isLocal) {
KotlinConverter.convertPsiElement(element, givenParent, requiredType)
}
else {
LightClassUtil.getLightClassBackingField(original)?.let {
KotlinUField(it, givenParent)
}
}
}
is KtFile -> el<UFile> { 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 <reified ActualT : UElement> Class<out UElement>?.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<UExpressionList>(build(KotlinUExpressionList.Companion::createClassBody))
is KtCatchClause -> el<UCatchClause>(build(::KotlinUCatchClause))
is KtVariableDeclaration -> el<UVariable> {
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<ULiteralExpression>(build(::KotlinStringULiteralExpression))
is KtStringTemplateEntry -> element.expression?.let { convertExpression(it, givenParent, requiredType) } ?: expr<UExpression> { UastEmptyExpression }
is KtWhenEntry -> el<USwitchClauseExpressionWithBody>(build(::KotlinUSwitchEntry))
is KtWhenCondition -> convertWhenCondition(element, givenParent)
is KtTypeReference -> el<UTypeReferenceExpression> { LazyKotlinUTypeReferenceExpression(element, givenParent) }
else -> {
if (element is LeafPsiElement && element.elementType == KtTokens.IDENTIFIER) {
@@ -349,7 +377,33 @@ internal object KotlinConverter {
else -> expr<UExpression>(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 ->
@@ -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 ||
@@ -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<UClass, PsiClass>(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<UClass>(it, this)
}.mapNotNull {
getLanguagePlugin().convertOpt<UClass>(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<UAnonymousClass, PsiAnonymousClass>(psi)
override fun getOriginalElement(): PsiElement? = super<AbstractJavaUClass>.getOriginalElement()
override fun getOriginalElement(): PsiElement? = super<AbstractKotlinUClass>.getOriginalElement()
override fun getSuperClass(): UClass? = super<AbstractJavaUClass>.getSuperClass()
override fun getFields(): Array<UField> = super<AbstractJavaUClass>.getFields()
override fun getMethods(): Array<UMethod> = super<AbstractJavaUClass>.getMethods()
override fun getInitializers(): Array<UClassInitializer> = super<AbstractJavaUClass>.getInitializers()
override fun getInnerClasses(): Array<UClass> = super<AbstractJavaUClass>.getInnerClasses()
override fun getSuperClass(): UClass? = super<AbstractKotlinUClass>.getSuperClass()
override fun getFields(): Array<UField> = super<AbstractKotlinUClass>.getFields()
override fun getMethods(): Array<UMethod> = super<AbstractKotlinUClass>.getMethods()
override fun getInitializers(): Array<UClassInitializer> = super<AbstractKotlinUClass>.getInitializers()
override fun getInnerClasses(): Array<UClass> = super<AbstractKotlinUClass>.getInnerClasses()
override fun getContainingFile(): PsiFile = unwrapFakeFileForLightClass(psi.containingFile)
@@ -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<UClass>(this, this@KotlinUFile)
private fun PsiClass.toUClass() = languagePlugin.convertOpt<UClass>(this, this@KotlinUFile)
}
@@ -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<UEnumConstant, PsiEnumConstant>(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<UClass>(psi.initializingClass, this) }
override val psi = unwrap<UEnumConstant, PsiEnumConstant>(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
@@ -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<UAnnotation> = emptyList()
override val expressions: List<UExpression> by lz {
createElvisExpressions(left, right, this, elvisExpression.parent)
@@ -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()) {
@@ -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<UDeclaration>
@@ -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
}
}
@@ -45,52 +45,52 @@ class KotlinUNamedExpression private constructor(
valueArguments: List<ValueArgument>,
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<UExpression> by lz {
valueArguments.map {
it.getArgumentExpression()?.let { argumentExpression ->
getLanguagePlugin().convert<UExpression>(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<PsiType>
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)
}
}
}
}
}
class KotlinUVarargExpression(private val valueArgs: List<ValueArgument>,
uastParent: UElement?) : KotlinAbstractUExpression(uastParent), UCallExpression {
override val kind: UastCallKind = UastCallKind.NESTED_ARRAY_INITIALIZER
override val valueArguments: List<UExpression> by lz {
valueArgs.map {
it.getArgumentExpression()?.let { argumentExpression ->
getLanguagePlugin().convert<UExpression>(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<PsiType>
get() = emptyList()
override val returnType: PsiType?
get() = null
override fun resolve() = null
override val receiver: UExpression?
get() = null
override val receiverType: PsiType?
get() = null
}
@@ -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
}
}
@@ -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() }
}
override val type: PsiType by lz {
typeSupplier?.invoke() ?: psi.toPsiType(uastParent ?: this)
}
}
@@ -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<UDeclaration>()?.psi ?: parent
val psi = containingElement.psiAnchor ?: containingElement.psi
val psiParent = psi?.getNonStrictParentOfType<KtDeclaration>() ?: parent
val initializerExpression = initializer ?: declaration.initializer
return UastKotlinPsiVariable(
manager = declaration.manager,
@@ -0,0 +1,2 @@
fun foo(a: Int = 1, foo: String? = null) {
}
@@ -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
@@ -0,0 +1,4 @@
public final class DefaultParameterValuesKt {
public static final fun foo(a: int, foo: java.lang.String) : void {
}
}
@@ -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<PsiElement, String>()
file.accept(object : UastVisitor {
private val parentStack = Stack<UElement>()
@@ -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)
}
})
}
@@ -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")