Support lazy conversion of parent chain; correctly check expected class

This commit is contained in:
Dmitry Jemerov
2017-03-09 13:22:17 +01:00
parent 8c3936a0ee
commit 01a9d9a284
11 changed files with 157 additions and 103 deletions
@@ -19,7 +19,6 @@ package org.jetbrains.uast.kotlin
import com.intellij.lang.Language import com.intellij.lang.Language
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile import com.intellij.psi.PsiFile
import com.intellij.psi.PsiVariable
import com.intellij.psi.impl.source.tree.LeafPsiElement import com.intellij.psi.impl.source.tree.LeafPsiElement
import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.asJava.LightClassUtil import org.jetbrains.kotlin.asJava.LightClassUtil
@@ -39,7 +38,6 @@ import org.jetbrains.uast.*
import org.jetbrains.uast.java.JavaUastLanguagePlugin import org.jetbrains.uast.java.JavaUastLanguagePlugin
import org.jetbrains.uast.kotlin.declarations.KotlinUMethod import org.jetbrains.uast.kotlin.declarations.KotlinUMethod
import org.jetbrains.uast.kotlin.expressions.* import org.jetbrains.uast.kotlin.expressions.*
import org.jetbrains.uast.kotlin.kinds.KotlinSpecialExpressionKinds
import org.jetbrains.uast.kotlin.psi.UastKotlinPsiParameter import org.jetbrains.uast.kotlin.psi.UastKotlinPsiParameter
import org.jetbrains.uast.kotlin.psi.UastKotlinPsiVariable import org.jetbrains.uast.kotlin.psi.UastKotlinPsiVariable
@@ -62,7 +60,8 @@ class KotlinUastLanguagePlugin : UastLanguagePlugin {
override fun convertElement(element: PsiElement, parent: UElement?, requiredType: Class<out UElement>?): UElement? { override fun convertElement(element: PsiElement, parent: UElement?, requiredType: Class<out UElement>?): UElement? {
if (element !is PsiElement) return null if (element !is PsiElement) return null
return convertDeclaration(element, parent, requiredType) ?: KotlinConverter.convertPsiElement(element, parent, requiredType) return convertDeclaration(element, parent.toCallback(), requiredType)
?: KotlinConverter.convertPsiElement(element, parent.toCallback(), requiredType)
} }
override fun convertElementWithParent(element: PsiElement, requiredType: Class<out UElement>?): UElement? { override fun convertElementWithParent(element: PsiElement, requiredType: Class<out UElement>?): UElement? {
@@ -70,9 +69,12 @@ class KotlinUastLanguagePlugin : UastLanguagePlugin {
if (element is PsiFile) return convertDeclaration(element, null, requiredType) if (element is PsiFile) return convertDeclaration(element, null, requiredType)
if (element is KtLightClassForFacade) return convertDeclaration(element, null, requiredType) if (element is KtLightClassForFacade) return convertDeclaration(element, null, requiredType)
val parent = KotlinConverter.unwrapElements(element.parent) ?: return null val parentCallback = fun(): UElement? {
val parentUElement = convertElementWithParent(parent, null) ?: return null val parent = KotlinConverter.unwrapElements(element.parent) ?: return null
return convertElement(element, parentUElement, requiredType) return convertElementWithParent(parent, null)
}
return convertDeclaration(element, parentCallback, requiredType)
?: KotlinConverter.convertPsiElement(element, parentCallback, requiredType)
} }
override fun getMethodCallExpression( override fun getMethodCallExpression(
@@ -115,35 +117,53 @@ class KotlinUastLanguagePlugin : UastLanguagePlugin {
return UastLanguagePlugin.ResolvedConstructor(uExpression, method, containingClass) return UastLanguagePlugin.ResolvedConstructor(uExpression, method, containingClass)
} }
private fun convertDeclaration(element: PsiElement, parent: UElement?, requiredType: Class<out UElement>?): UElement? { private fun convertDeclaration(element: PsiElement,
parentCallback: (() -> UElement?)?,
requiredType: Class<out UElement>?): UElement? {
if (element is UElement) return element if (element is UElement) return element
if (element.isValid) element.getUserData(KOTLIN_CACHED_UELEMENT_KEY)?.let { ref -> if (element.isValid) element.getUserData(KOTLIN_CACHED_UELEMENT_KEY)?.let { ref ->
ref.get()?.let { return it } ref.get()?.let { return it }
} }
fun <P : PsiElement> build(ctor: (P, UElement?) -> UElement): () -> UElement? {
return fun(): UElement? {
val parent = if (parentCallback == null) null else (parentCallback() ?: return null)
return ctor(element as P, parent)
}
}
val original = element.originalElement val original = element.originalElement
return with(requiredType) { return with(requiredType) {
when (original) { when (original) {
is KtLightMethod -> el<UMethod> { KotlinUMethod.create(original, parent) } is KtLightMethod -> el<UMethod>(build(KotlinUMethod.Companion::create)) // .Companion is needed because of KT-13934
is KtLightClass -> el<UClass> { KotlinUClass.create(original, parent) } is KtLightClass -> el<UClass>(build(KotlinUClass.Companion::create))
is KtLightField, is KtLightParameter, is UastKotlinPsiParameter, is UastKotlinPsiVariable -> el<UVariable> {
KotlinUVariable.create(original as PsiVariable, parent)
}
is KtClassOrObject -> el<UClass> { original.toLightClass()?.let { lightClass -> KotlinUClass.create(lightClass, parent) } } 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 KtClassOrObject -> el<UClass> {
original.toLightClass()?.let { lightClass ->
val parent = if (parentCallback == null) null else (parentCallback() ?: return null)
KotlinUClass.create(lightClass, parent)
}
}
is KtFunction -> el<UMethod> { is KtFunction -> el<UMethod> {
val lightMethod = LightClassUtil.getLightClassMethod(original) ?: return null val lightMethod = LightClassUtil.getLightClassMethod(original) ?: return null
convertDeclaration(lightMethod, parent, requiredType) convertDeclaration(lightMethod, parentCallback, requiredType)
} }
is KtPropertyAccessor -> el<UMethod> { is KtPropertyAccessor -> el<UMethod> {
val parent = if (parentCallback == null) null else (parentCallback() ?: return null)
javaPlugin.convertOpt<UMethod>( javaPlugin.convertOpt<UMethod>(
LightClassUtil.getLightClassAccessorMethod(original), parent) LightClassUtil.getLightClassAccessorMethod(original), parent)
} }
is KtProperty -> el<UField> { is KtProperty -> el<UField> {
val parent = if (parentCallback == null) null else (parentCallback() ?: return null)
javaPlugin.convertOpt<UField>( javaPlugin.convertOpt<UField>(
LightClassUtil.getLightClassBackingField(original), parent) LightClassUtil.getLightClassBackingField(original), parent)
?: convertDeclaration(element.parent, parent, requiredType) ?: convertDeclaration(element.parent, parentCallback, requiredType)
} }
is KtFile -> el<UFile> { KotlinUFile(original, this@KotlinUastLanguagePlugin) } is KtFile -> el<UFile> { KotlinUFile(original, this@KotlinUastLanguagePlugin) }
@@ -166,14 +186,16 @@ class KotlinUastLanguagePlugin : UastLanguagePlugin {
} }
} }
internal inline fun <reified T : UElement> Class<out UElement>?.el(f: () -> UElement?): UElement? { internal inline fun <reified ActualT : UElement> Class<out UElement>?.el(f: () -> UElement?): UElement? {
return if (this == null || T::class.java == this) f() else null return if (this == null || isAssignableFrom(ActualT::class.java)) f() else null
} }
internal inline fun <reified T : UElement> Class<out UElement>?.expr(f: () -> UExpression): UExpression? { internal inline fun <reified ActualT : UElement> Class<out UElement>?.expr(f: () -> UExpression?): UExpression? {
return if (this == null || UExpression::class.java == this || T::class.java == this) f() else null 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 object KotlinConverter {
internal tailrec fun unwrapElements(element: PsiElement?): PsiElement? = when (element) { internal tailrec fun unwrapElements(element: PsiElement?): PsiElement? = when (element) {
is KtValueArgumentList -> unwrapElements(element.parent) is KtValueArgumentList -> unwrapElements(element.parent)
@@ -181,69 +203,77 @@ internal object KotlinConverter {
else -> element else -> element
} }
internal fun convertPsiElement(element: PsiElement?, parent: UElement?, requiredType: Class<out UElement>?): UElement? { internal fun convertPsiElement(element: PsiElement?,
parentCallback: (() -> UElement?)?,
requiredType: Class<out UElement>?): UElement? {
fun <P : PsiElement> build(ctor: (P, UElement?) -> UElement): () -> UElement? {
return fun(): UElement? {
val parent = if (parentCallback == null) null else (parentCallback() ?: return null)
return ctor(element as P, parent)
}
}
return with (requiredType) { when (element) { return with (requiredType) { when (element) {
is KtParameterList -> el<UDeclarationsExpression> { is KtParameterList -> el<UDeclarationsExpression> {
val parent = if (parentCallback == null) null else (parentCallback() ?: return null)
KotlinUDeclarationsExpression(parent).apply { KotlinUDeclarationsExpression(parent).apply {
declarations = element.parameters.mapIndexed { i, p -> declarations = element.parameters.mapIndexed { i, p ->
KotlinUVariable.create(UastKotlinPsiParameter.create(p, element, parent!!, i), this) KotlinUVariable.create(UastKotlinPsiParameter.create(p, element, parent!!, i), this)
} }
} }
} }
is KtClassBody -> el<UExpressionList> { is KtClassBody -> el<UExpressionList>(build(KotlinUExpressionList.Companion::createClassBody))
KotlinUExpressionList(element, KotlinSpecialExpressionKinds.CLASS_BODY, parent).apply { is KtCatchClause -> el<UCatchClause>(build(::KotlinUCatchClause))
expressions = emptyList() is KtExpression -> KotlinConverter.convertExpression(element, parentCallback, requiredType)
} is KtLambdaArgument -> KotlinConverter.convertExpression(element.getLambdaExpression(), parentCallback, requiredType)
}
is KtCatchClause -> el<UCatchClause> { KotlinUCatchClause(element, parent) }
is KtExpression -> KotlinConverter.convertExpression(element, parent, requiredType)
is KtLambdaArgument -> KotlinConverter.convertExpression(element.getLambdaExpression(), parent, requiredType)
is KtContainerNode -> element.getExpression()?.let { is KtContainerNode -> element.getExpression()?.let {
KotlinConverter.convertExpression(it, parent, requiredType) KotlinConverter.convertExpression(it, parentCallback, requiredType)
} ?: el<UExpression> { UastEmptyExpression } } ?: el<UExpression> { UastEmptyExpression }
is KtLightAnnotation.LightExpressionValue<*> -> { is KtLightAnnotation.LightExpressionValue<*> -> {
val expression = element.originalExpression val expression = element.originalExpression
when (expression) { when (expression) {
is KtExpression -> KotlinConverter.convertExpression(expression, parent, requiredType) is KtExpression -> KotlinConverter.convertExpression(expression, parentCallback, requiredType)
else -> el<UExpression> { UastEmptyExpression } else -> el<UExpression> { UastEmptyExpression }
} }
} }
is KtLiteralStringTemplateEntry -> expr<ULiteralExpression> { KotlinStringULiteralExpression(element, parent, element.getText()) } is KtLiteralStringTemplateEntry, is KtEscapeStringTemplateEntry -> el<ULiteralExpression>(build(::KotlinStringULiteralExpression))
is KtEscapeStringTemplateEntry -> expr<ULiteralExpression> { KotlinStringULiteralExpression(element, parent, element.unescapedValue) } is KtStringTemplateEntry -> element.expression?.let { convertExpression(it, parentCallback, requiredType) } ?: expr<UExpression> { UastEmptyExpression }
is KtStringTemplateEntry -> element.expression?.let { convertExpression(it, parent, requiredType) } ?: expr<UExpression> { UastEmptyExpression }
else -> { else -> {
if (element is LeafPsiElement && element.elementType == KtTokens.IDENTIFIER) { if (element is LeafPsiElement && element.elementType == KtTokens.IDENTIFIER) {
el<UIdentifier> { UIdentifier(element, parent) } el<UIdentifier>(build(::UIdentifier))
} else { } else {
null null
} }
} }
}} }}
} }
private fun convertVariablesDeclaration(
psi: KtVariableDeclaration,
parent: UElement?
): UDeclarationsExpression {
val parentPsiElement = parent?.psi
val variable = KotlinUVariable.create(UastKotlinPsiVariable.create(psi, parentPsiElement, parent!!), parent)
return KotlinUDeclarationsExpression(parent).apply { declarations = listOf(variable) }
}
internal fun convert(entry: KtStringTemplateEntry, parent: UElement?): UExpression = when (entry) { internal fun convert(entry: KtStringTemplateEntry, parent: UElement?): UExpression = when (entry) {
is KtStringTemplateEntryWithExpression -> convertOrEmpty(entry.expression, parent) is KtStringTemplateEntryWithExpression -> KotlinConverter.convertOrEmpty(entry.expression, parent)
is KtEscapeStringTemplateEntry -> KotlinStringULiteralExpression(entry, parent, entry.unescapedValue) is KtEscapeStringTemplateEntry -> KotlinStringULiteralExpression(entry, parent, entry.unescapedValue)
else -> { else -> {
KotlinStringULiteralExpression(entry, parent) KotlinStringULiteralExpression(entry, parent)
} }
} }
internal fun convertExpression(expression: KtExpression, parent: UElement?, requiredType: Class<out UElement>? = null): UExpression? {
internal fun convertExpression(expression: KtExpression,
parentCallback: (() -> UElement?)?,
requiredType: Class<out UElement>? = null): UExpression? {
fun <P : PsiElement> build(ctor: (P, UElement?) -> UExpression): () -> UExpression? {
return fun(): UExpression? {
val parent = if (parentCallback == null) null else (parentCallback() ?: return null)
return ctor(expression as P, parent)
}
}
return with (requiredType) { when (expression) { return with (requiredType) { when (expression) {
is KtVariableDeclaration -> expr<UDeclarationsExpression> { convertVariablesDeclaration(expression, parent) } is KtVariableDeclaration -> expr<UDeclarationsExpression>(build(::convertVariablesDeclaration))
is KtStringTemplateExpression -> expr<ULiteralExpression> { is KtStringTemplateExpression -> expr<ULiteralExpression> {
val parent = if (parentCallback == null) null else (parentCallback() ?: return null)
if (expression.entries.isEmpty()) if (expression.entries.isEmpty())
KotlinStringULiteralExpression(expression, parent, "") KotlinStringULiteralExpression(expression, parent, "")
else if (expression.entries.size == 1) else if (expression.entries.size == 1)
@@ -252,6 +282,7 @@ internal object KotlinConverter {
KotlinStringTemplateUPolyadicExpression(expression, parent) KotlinStringTemplateUPolyadicExpression(expression, parent)
} }
is KtDestructuringDeclaration -> expr<UDeclarationsExpression> { is KtDestructuringDeclaration -> expr<UDeclarationsExpression> {
val parent = if (parentCallback == null) null else (parentCallback() ?: return null)
KotlinUDeclarationsExpression(parent).apply { KotlinUDeclarationsExpression(parent).apply {
val tempAssignment = KotlinUVariable.create(UastKotlinPsiVariable.create(expression, parent!!), parent) val tempAssignment = KotlinUVariable.create(UastKotlinPsiVariable.create(expression, parent!!), parent)
val destructuringAssignments = expression.entries.mapIndexed { i, entry -> val destructuringAssignments = expression.entries.mapIndexed { i, entry ->
@@ -264,68 +295,67 @@ internal object KotlinConverter {
declarations = listOf(tempAssignment) + destructuringAssignments declarations = listOf(tempAssignment) + destructuringAssignments
} }
} }
is KtLabeledExpression -> expr<ULabeledExpression> { KotlinULabeledExpression(expression, parent) } is KtLabeledExpression -> expr<ULabeledExpression>(build(::KotlinULabeledExpression))
is KtClassLiteralExpression -> expr<UClassLiteralExpression> { KotlinUClassLiteralExpression(expression, parent) } is KtClassLiteralExpression -> expr<UClassLiteralExpression>(build(::KotlinUClassLiteralExpression))
is KtObjectLiteralExpression -> expr<UObjectLiteralExpression> { KotlinUObjectLiteralExpression(expression, parent) } is KtObjectLiteralExpression -> expr<UObjectLiteralExpression>(build(::KotlinUObjectLiteralExpression))
is KtDotQualifiedExpression -> expr<UQualifiedReferenceExpression> { KotlinUQualifiedReferenceExpression(expression, parent) } is KtDotQualifiedExpression -> expr<UQualifiedReferenceExpression>(build(::KotlinUQualifiedReferenceExpression))
is KtSafeQualifiedExpression -> expr<UQualifiedReferenceExpression> { KotlinUSafeQualifiedExpression(expression, parent) } is KtSafeQualifiedExpression -> expr<UQualifiedReferenceExpression>(build(::KotlinUSafeQualifiedExpression))
is KtSimpleNameExpression -> expr<USimpleNameReferenceExpression> { is KtSimpleNameExpression -> expr<USimpleNameReferenceExpression>(build(::KotlinUSimpleReferenceExpression))
KotlinUSimpleReferenceExpression(expression, expression.getReferencedName(), parent) is KtCallExpression -> expr<UCallExpression>(build(::KotlinUFunctionCallExpression))
}
is KtCallExpression -> expr<UCallExpression> { KotlinUFunctionCallExpression(expression, parent) }
is KtBinaryExpression -> { is KtBinaryExpression -> {
if (expression.operationToken == KtTokens.ELVIS) { if (expression.operationToken == KtTokens.ELVIS) {
expr<UExpressionList> { createElvisExpression(expression, parent) ?: UastEmptyExpression } expr<UExpressionList>(build(::createElvisExpression))
} }
else expr<UBinaryExpression> { KotlinUBinaryExpression(expression, parent) } else expr<UBinaryExpression>(build(::KotlinUBinaryExpression))
} }
is KtParenthesizedExpression -> expr<UParenthesizedExpression> { KotlinUParenthesizedExpression(expression, parent) } is KtParenthesizedExpression -> expr<UParenthesizedExpression>(build(::KotlinUParenthesizedExpression))
is KtPrefixExpression -> expr<UPrefixExpression> { KotlinUPrefixExpression(expression, parent) } is KtPrefixExpression -> expr<UPrefixExpression>(build(::KotlinUPrefixExpression))
is KtPostfixExpression -> expr<UPostfixExpression> { KotlinUPostfixExpression(expression, parent) } is KtPostfixExpression -> expr<UPostfixExpression>(build(::KotlinUPostfixExpression))
is KtThisExpression -> expr<UThisExpression> { KotlinUThisExpression(expression, parent) } is KtThisExpression -> expr<UThisExpression>(build(::KotlinUThisExpression))
is KtSuperExpression -> expr<USuperExpression> { KotlinUSuperExpression(expression, parent) } is KtSuperExpression -> expr<USuperExpression>(build(::KotlinUSuperExpression))
is KtCallableReferenceExpression -> expr<UCallableReferenceExpression> { KotlinUCallableReferenceExpression(expression, parent) } is KtCallableReferenceExpression -> expr<UCallableReferenceExpression>(build(::KotlinUCallableReferenceExpression))
is KtIsExpression -> expr<UBinaryExpressionWithType> { KotlinUTypeCheckExpression(expression, parent) } is KtIsExpression -> expr<UBinaryExpressionWithType>(build(::KotlinUTypeCheckExpression))
is KtIfExpression -> expr<UIfExpression> { KotlinUIfExpression(expression, parent) } is KtIfExpression -> expr<UIfExpression>(build(::KotlinUIfExpression))
is KtWhileExpression -> expr<UWhileExpression> { KotlinUWhileExpression(expression, parent) } is KtWhileExpression -> expr<UWhileExpression>(build(::KotlinUWhileExpression))
is KtDoWhileExpression -> expr<UDoWhileExpression> { KotlinUDoWhileExpression(expression, parent) } is KtDoWhileExpression -> expr<UDoWhileExpression>(build(::KotlinUDoWhileExpression))
is KtForExpression -> expr<UForEachExpression> { KotlinUForEachExpression(expression, parent) } is KtForExpression -> expr<UForEachExpression>(build(::KotlinUForEachExpression))
is KtWhenExpression -> expr<USwitchExpression> { KotlinUSwitchExpression(expression, parent) } is KtWhenExpression -> expr<USwitchExpression>(build(::KotlinUSwitchExpression))
is KtBreakExpression -> expr<UBreakExpression> { KotlinUBreakExpression(expression, parent) } is KtBreakExpression -> expr<UBreakExpression>(build(::KotlinUBreakExpression))
is KtContinueExpression -> expr<UContinueExpression> { KotlinUContinueExpression(expression, parent) } is KtContinueExpression -> expr<UContinueExpression>(build(::KotlinUContinueExpression))
is KtReturnExpression -> expr<UReturnExpression> { KotlinUReturnExpression(expression, parent) } is KtReturnExpression -> expr<UReturnExpression>(build(::KotlinUReturnExpression))
is KtThrowExpression -> expr<UThrowExpression> { KotlinUThrowExpression(expression, parent) } is KtThrowExpression -> expr<UThrowExpression>(build(::KotlinUThrowExpression))
is KtBlockExpression -> expr<UBlockExpression> { KotlinUBlockExpression(expression, parent) } is KtBlockExpression -> expr<UBlockExpression>(build(::KotlinUBlockExpression))
is KtConstantExpression -> expr<ULiteralExpression> { KotlinULiteralExpression(expression, parent) } is KtConstantExpression -> expr<ULiteralExpression>(build(::KotlinULiteralExpression))
is KtTryExpression -> expr<UTryExpression> { KotlinUTryExpression(expression, parent) } is KtTryExpression -> expr<UTryExpression>(build(::KotlinUTryExpression))
is KtArrayAccessExpression -> expr<UArrayAccessExpression> { KotlinUArrayAccessExpression(expression, parent) } is KtArrayAccessExpression -> expr<UArrayAccessExpression>(build(::KotlinUArrayAccessExpression))
is KtLambdaExpression -> expr<ULambdaExpression> { KotlinULambdaExpression(expression, parent) } is KtLambdaExpression -> expr<ULambdaExpression>(build(::KotlinULambdaExpression))
is KtBinaryExpressionWithTypeRHS -> expr<UBinaryExpressionWithType> { KotlinUBinaryExpressionWithType(expression, parent) } is KtBinaryExpressionWithTypeRHS -> expr<UBinaryExpressionWithType>(build(::KotlinUBinaryExpressionWithType))
is KtClassOrObject -> expr<UDeclarationsExpression> { is KtClassOrObject -> expr<UDeclarationsExpression> {
expression.toLightClass()?.let { lightClass -> expression.toLightClass()?.let { lightClass ->
val parent = if (parentCallback == null) null else (parentCallback() ?: return null)
KotlinUDeclarationsExpression(parent).apply { KotlinUDeclarationsExpression(parent).apply {
declarations = listOf(KotlinUClass.create(lightClass, this)) declarations = listOf(KotlinUClass.create(lightClass, this))
} }
} ?: UastEmptyExpression } ?: UastEmptyExpression
} }
is KtFunction -> if (expression.name.isNullOrEmpty()) { is KtFunction -> if (expression.name.isNullOrEmpty()) {
expr<ULambdaExpression> { createLocalFunctionLambdaExpression(expression, parent) } expr<ULambdaExpression>(build(::createLocalFunctionLambdaExpression))
} }
else { else {
expr<UDeclarationsExpression> { createLocalFunctionDeclaration(expression, parent) } expr<UDeclarationsExpression>(build(::createLocalFunctionDeclaration))
} }
else -> UnknownKotlinExpression(expression, parent) else -> expr<UExpression>(build(::UnknownKotlinExpression))
}} }}
} }
internal fun convertOrEmpty(expression: KtExpression?, parent: UElement?): UExpression { internal fun convertOrEmpty(expression: KtExpression?, parent: UElement?): UExpression {
return expression?.let { convertExpression(it, parent, null) } ?: UastEmptyExpression return expression?.let { convertExpression(it, parent.toCallback(), null) } ?: UastEmptyExpression
} }
internal fun convertOrNull(expression: KtExpression?, parent: UElement?): UExpression? { internal fun convertOrNull(expression: KtExpression?, parent: UElement?): UExpression? {
return if (expression != null) convertExpression(expression, parent, null) else null return if (expression != null) convertExpression(expression, parent.toCallback(), null) else null
} }
internal fun KtPsiFactory.createAnalyzableExpression(text: String, context: PsiElement): KtExpression = internal fun KtPsiFactory.createAnalyzableExpression(text: String, context: PsiElement): KtExpression =
@@ -345,4 +375,13 @@ internal object KotlinConverter {
internal fun KtContainerNode.getExpression(): KtExpression? = internal fun KtContainerNode.getExpression(): KtExpression? =
PsiTreeUtil.getChildOfType(this, KtExpression::class.java) PsiTreeUtil.getChildOfType(this, KtExpression::class.java)
} }
private fun convertVariablesDeclaration(
psi: KtVariableDeclaration,
parent: UElement?
): UDeclarationsExpression {
val parentPsiElement = parent?.psi
val variable = KotlinUVariable.create(UastKotlinPsiVariable.create(psi, parentPsiElement, parent!!), parent)
return KotlinUDeclarationsExpression(parent).apply { declarations = listOf(variable) }
}
@@ -56,7 +56,7 @@ private fun createElvisExpressions(
override val uastParent: UElement? = containingElement override val uastParent: UElement? = containingElement
override val condition: UExpression by lz { createNotEqWithNullExpression(tempVariable, this) } override val condition: UExpression by lz { createNotEqWithNullExpression(tempVariable, this) }
override val thenExpression: UExpression? by lz { createVariableReferenceExpression(tempVariable, this) } override val thenExpression: UExpression? by lz { createVariableReferenceExpression(tempVariable, this) }
override val elseExpression: UExpression? by lz { KotlinConverter.convertExpression(right, this) } override val elseExpression: UExpression? by lz { KotlinConverter.convertExpression(right, this.toCallback() ) }
override val isTernary: Boolean = false override val isTernary: Boolean = false
override val annotations: List<UAnnotation> = emptyList() override val annotations: List<UAnnotation> = emptyList()
override val ifIdentifier: UIdentifier = UIdentifier(null, this) override val ifIdentifier: UIdentifier = UIdentifier(null, this)
@@ -66,9 +66,9 @@ private fun createElvisExpressions(
return listOf(declaration, ifExpression) return listOf(declaration, ifExpression)
} }
fun createElvisExpression(elvisExpression: KtBinaryExpression, containingElement: UElement?): UExpressionList? { fun createElvisExpression(elvisExpression: KtBinaryExpression, containingElement: UElement?): UExpression {
val left = elvisExpression.left ?: return null val left = elvisExpression.left ?: return UastEmptyExpression
val right = elvisExpression.right ?: return null val right = elvisExpression.right ?: return UastEmptyExpression
return object : UExpressionList, KotlinEvaluatableUElement, KotlinUElementWithType { return object : UExpressionList, KotlinEvaluatableUElement, KotlinUElementWithType {
override val psi: PsiElement? = elvisExpression override val psi: PsiElement? = elvisExpression
@@ -31,7 +31,7 @@ class KotlinUCallableReferenceExpression(
get() { get() {
if (qualifierType != null) return null if (qualifierType != null) return null
val receiverExpression = psi.receiverExpression ?: return null val receiverExpression = psi.receiverExpression ?: return null
return KotlinConverter.convertExpression(receiverExpression, this) return KotlinConverter.convertExpression(receiverExpression, { this })
} }
override val qualifierType by lz { override val qualifierType by lz {
@@ -35,6 +35,6 @@ class KotlinUClassLiteralExpression(
get() { get() {
if (type != null) return null if (type != null) return null
val receiverExpression = psi.receiverExpression ?: return null val receiverExpression = psi.receiverExpression ?: return null
return KotlinConverter.convertExpression(receiverExpression, this) return KotlinConverter.convertExpression(receiverExpression, { this })
} }
} }
@@ -19,10 +19,11 @@ import com.intellij.psi.PsiElement
import org.jetbrains.uast.kotlin.KotlinAbstractUExpression import org.jetbrains.uast.kotlin.KotlinAbstractUExpression
class KotlinUDeclarationsExpression( class KotlinUDeclarationsExpression(
override val psi: PsiElement?,
override val uastParent: UElement? override val uastParent: UElement?
) : KotlinAbstractUExpression(), UDeclarationsExpression { ) : KotlinAbstractUExpression(), UDeclarationsExpression {
override val psi: PsiElement?
get() = null constructor(uastParent: UElement?) : this(null, uastParent)
override lateinit var declarations: List<UDeclaration> override lateinit var declarations: List<UDeclaration>
internal set internal set
@@ -24,6 +24,7 @@ import org.jetbrains.uast.UElement
import org.jetbrains.uast.UExpression import org.jetbrains.uast.UExpression
import org.jetbrains.uast.UExpressionList import org.jetbrains.uast.UExpressionList
import org.jetbrains.uast.UastSpecialExpressionKind import org.jetbrains.uast.UastSpecialExpressionKind
import org.jetbrains.uast.kotlin.kinds.KotlinSpecialExpressionKinds
open class KotlinUExpressionList( open class KotlinUExpressionList(
override val psi: PsiElement?, override val psi: PsiElement?,
@@ -38,4 +39,11 @@ open class KotlinUExpressionList(
val compileTimeConst = ktElement.analyze()[BindingContext.COMPILE_TIME_VALUE, ktElement] val compileTimeConst = ktElement.analyze()[BindingContext.COMPILE_TIME_VALUE, ktElement]
return compileTimeConst?.getValue(TypeUtils.NO_EXPECTED_TYPE) return compileTimeConst?.getValue(TypeUtils.NO_EXPECTED_TYPE)
} }
}
companion object {
fun createClassBody(psi: PsiElement?, uastParent: UElement?): KotlinUExpressionList =
KotlinUExpressionList(psi, KotlinSpecialExpressionKinds.CLASS_BODY, uastParent).apply {
expressions = emptyList()
}
}
}
@@ -35,7 +35,7 @@ import org.jetbrains.uast.visitor.UastVisitor
class KotlinUFunctionCallExpression( class KotlinUFunctionCallExpression(
override val psi: KtCallExpression, override val psi: KtCallExpression,
override val uastParent: UElement?, override val uastParent: UElement?,
private val _resolvedCall: ResolvedCall<*>? = null private val _resolvedCall: ResolvedCall<*>?
) : KotlinAbstractUExpression(), UCallExpression, KotlinUElementWithType { ) : KotlinAbstractUExpression(), UCallExpression, KotlinUElementWithType {
companion object { companion object {
fun resolveSource(descriptor: DeclarationDescriptor, source: PsiElement?): PsiMethod? { fun resolveSource(descriptor: DeclarationDescriptor, source: PsiElement?): PsiMethod? {
@@ -53,6 +53,8 @@ class KotlinUFunctionCallExpression(
} }
} }
constructor(psi: KtCallExpression, uastParent: UElement?): this(psi, uastParent, null)
private val resolvedCall by lz { private val resolvedCall by lz {
_resolvedCall ?: psi.getResolvedCall(psi.analyze()) _resolvedCall ?: psi.getResolvedCall(psi.analyze())
} }
@@ -16,10 +16,10 @@
package org.jetbrains.uast.kotlin package org.jetbrains.uast.kotlin
import com.intellij.openapi.util.text.StringUtil
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.KtNodeTypes import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.psi.KtConstantExpression import org.jetbrains.kotlin.psi.KtConstantExpression
import org.jetbrains.kotlin.psi.KtEscapeStringTemplateEntry
import org.jetbrains.uast.UElement import org.jetbrains.uast.UElement
import org.jetbrains.uast.ULiteralExpression import org.jetbrains.uast.ULiteralExpression
@@ -36,10 +36,13 @@ class KotlinULiteralExpression(
class KotlinStringULiteralExpression( class KotlinStringULiteralExpression(
override val psi: PsiElement, override val psi: PsiElement,
override val uastParent: UElement?, override val uastParent: UElement?,
val text: String? = null val text: String
) : KotlinAbstractUExpression(), ULiteralExpression, KotlinUElementWithType{ ) : KotlinAbstractUExpression(), ULiteralExpression, KotlinUElementWithType{
constructor(psi: PsiElement, uastParent: UElement?)
: this(psi, uastParent, if (psi is KtEscapeStringTemplateEntry) psi.unescapedValue else psi.text)
override val value: String override val value: String
get() = text ?: StringUtil.unescapeStringCharacters(psi.text) get() = text
override fun evaluate() = value override fun evaluate() = value
} }
@@ -35,11 +35,12 @@ import org.jetbrains.uast.visitor.UastVisitor
open class KotlinUSimpleReferenceExpression( open class KotlinUSimpleReferenceExpression(
override val psi: KtSimpleNameExpression, override val psi: KtSimpleNameExpression,
override val identifier: String,
override val uastParent: UElement? override val uastParent: UElement?
) : KotlinAbstractUExpression(), USimpleNameReferenceExpression, KotlinUElementWithType, KotlinEvaluatableUElement { ) : KotlinAbstractUExpression(), USimpleNameReferenceExpression, KotlinUElementWithType, KotlinEvaluatableUElement {
private val resolvedDeclaration by lz { psi.resolveCallToDeclaration(this) } private val resolvedDeclaration by lz { psi.resolveCallToDeclaration(this) }
override val identifier get() = psi.getReferencedName()
override fun resolve() = resolvedDeclaration override fun resolve() = resolvedDeclaration
override val resolvedName: String? override val resolvedName: String?
@@ -28,7 +28,7 @@ class KotlinUSwitchExpression(
override val expression by lz { KotlinConverter.convertOrNull(psi.subjectExpression, this) } override val expression by lz { KotlinConverter.convertOrNull(psi.subjectExpression, this) }
override val body: UExpressionList by lz { override val body: UExpressionList by lz {
object : KotlinUExpressionList(psi, KotlinSpecialExpressionKinds.WHEN, this) { object : KotlinUExpressionList(psi, KotlinSpecialExpressionKinds.WHEN, this@KotlinUSwitchExpression) {
override fun asRenderString() = expressions.joinToString("\n") { it.asRenderString().withMargin } override fun asRenderString() = expressions.joinToString("\n") { it.asRenderString().withMargin }
}.apply { }.apply {
expressions = this@KotlinUSwitchExpression.psi.entries.map { KotlinUSwitchEntry(it, this) } expressions = this@KotlinUSwitchExpression.psi.entries.map { KotlinUSwitchEntry(it, this) }
@@ -77,7 +77,7 @@ class KotlinUSwitchEntry(
} }
override val body: UExpressionList by lz { override val body: UExpressionList by lz {
object : KotlinUExpressionList(psi, KotlinSpecialExpressionKinds.WHEN_ENTRY, this) { object : KotlinUExpressionList(psi, KotlinSpecialExpressionKinds.WHEN_ENTRY, this@KotlinUSwitchEntry) {
override fun asRenderString() = buildString { override fun asRenderString() = buildString {
appendln("{") appendln("{")
expressions.forEach { appendln(it.asRenderString().withMargin) } expressions.forEach { appendln(it.asRenderString().withMargin) }
@@ -28,7 +28,7 @@ class KotlinUTryExpression(
) : KotlinAbstractUExpression(), UTryExpression, KotlinUElementWithType { ) : KotlinAbstractUExpression(), UTryExpression, KotlinUElementWithType {
override val tryClause by lz { KotlinConverter.convertOrEmpty(psi.tryBlock, this) } override val tryClause by lz { KotlinConverter.convertOrEmpty(psi.tryBlock, this) }
override val catchClauses by lz { psi.catchClauses.map { KotlinUCatchClause(it, this) } } override val catchClauses by lz { psi.catchClauses.map { KotlinUCatchClause(it, this) } }
override val finallyClause by lz { psi.finallyBlock?.finalExpression?.let { KotlinConverter.convertExpression(it, this) } } override val finallyClause by lz { psi.finallyBlock?.finalExpression?.let { KotlinConverter.convertExpression(it, { this }) } }
override val resourceVariables: List<UVariable> override val resourceVariables: List<UVariable>
get() = emptyList() get() = emptyList()