Add missing required type checks; correctly skip elements which have no UAST equivalents when converting an element together with parent; correctly convert string template entries (they aren't expressions)

This commit is contained in:
Dmitry Jemerov
2017-02-07 18:17:52 +01:00
parent be7158eeb2
commit 0709561869
6 changed files with 53 additions and 37 deletions
@@ -70,7 +70,7 @@ class KotlinUastLanguagePlugin(override val project: Project) : UastLanguagePlug
if (element is PsiFile) return convertDeclaration(element, null, requiredType)
if (element is KtLightClassForFacade) return convertDeclaration(element, null, requiredType)
val parent = element.parent ?: return null
val parent = KotlinConverter.unwrapElements(element.parent) ?: return null
val parentUElement = convertElementWithParent(parent, null) ?: return null
return convertElement(element, parentUElement, requiredType)
}
@@ -106,7 +106,7 @@ class KotlinUastLanguagePlugin(override val project: Project) : UastLanguagePlug
return null
}
val parent = element.parent ?: return null
val parent = KotlinConverter.unwrapElements(element.parent) ?: return null
val parentUElement = convertElementWithParent(parent, null) ?: return null
val uExpression = KotlinUFunctionCallExpression(element, parentUElement, resolvedCall)
@@ -123,28 +123,34 @@ class KotlinUastLanguagePlugin(override val project: Project) : UastLanguagePlug
}
val original = element.originalElement
return when (original) {
is KtLightMethod -> KotlinUMethod.create(original, parent)
is KtLightClass -> KotlinUClass.create(original, parent)
is KtLightField, is KtLightParameter, is UastKotlinPsiParameter, is UastKotlinPsiVariable -> {
KotlinUVariable.create(original as PsiVariable, parent)
}
return with(requiredType) {
when (original) {
is KtLightMethod -> el<UMethod> { KotlinUMethod.create(original, parent) }
is KtLightClass -> el<UClass> { KotlinUClass.create(original, parent) }
is KtLightField, is KtLightParameter, is UastKotlinPsiParameter, is UastKotlinPsiVariable -> el<UVariable> {
KotlinUVariable.create(original as PsiVariable, parent)
}
is KtClassOrObject -> original.toLightClass()?.let { lightClass -> KotlinUClass.create(lightClass, parent) }
is KtFunction -> {
val lightMethod = LightClassUtil.getLightClassMethod(original) ?: return null
convertDeclaration(lightMethod, parent, requiredType)
is KtClassOrObject -> el<UClass> { original.toLightClass()?.let { lightClass -> KotlinUClass.create(lightClass, parent) } }
is KtFunction -> el<UMethod> {
val lightMethod = LightClassUtil.getLightClassMethod(original) ?: return null
convertDeclaration(lightMethod, parent, requiredType)
}
is KtPropertyAccessor -> el<UMethod> {
javaPlugin.convertOpt<UMethod>(
LightClassUtil.getLightClassAccessorMethod(original), parent)
}
is KtProperty -> el<UField> {
javaPlugin.convertOpt<UField>(
LightClassUtil.getLightClassBackingField(original), parent)
?: convertDeclaration(element.parent, parent, requiredType)
}
is KtFile -> el<UFile> { KotlinUFile(original, this@KotlinUastLanguagePlugin) }
is FakeFileForLightClass -> el<UFile> { KotlinUFile(original.navigationElement, this@KotlinUastLanguagePlugin) }
else -> null
}
is KtPropertyAccessor -> javaPlugin.convertOpt<UMethod>(
LightClassUtil.getLightClassAccessorMethod(original), parent)
is KtProperty -> javaPlugin.convertOpt<UField>(
LightClassUtil.getLightClassBackingField(original), parent)
?: convertDeclaration(element.parent, parent, requiredType)
is KtFile -> KotlinUFile(original, this)
is FakeFileForLightClass -> KotlinUFile(original.navigationElement, this)
else -> null
}
}
@@ -164,11 +170,17 @@ internal inline fun <reified T : UElement> Class<out UElement>?.el(f: () -> UEle
return if (this == null || T::class.java == this) f() else null
}
internal inline fun <reified T : UElement> Class<out UElement>?.expr(f: () -> UExpression): UExpression {
return if (this == null || T::class.java == this) f() else UastEmptyExpression
internal inline fun <reified T : UElement> Class<out UElement>?.expr(f: () -> UExpression): UExpression? {
return if (this == null || UExpression::class.java == this || T::class.java == this) f() else null
}
internal object KotlinConverter {
internal tailrec fun unwrapElements(element: PsiElement?): PsiElement? = when (element) {
is KtValueArgumentList -> unwrapElements(element.parent)
is KtValueArgument -> unwrapElements(element.parent)
else -> element
}
internal fun convertPsiElement(element: PsiElement?, parent: UElement?, requiredType: Class<out UElement>?): UElement? {
return with (requiredType) { when (element) {
is KtParameterList -> el<UDeclarationsExpression> {
@@ -178,22 +190,28 @@ internal object KotlinConverter {
}
}
}
is KtClassBody -> KotlinUExpressionList(element, KotlinSpecialExpressionKinds.CLASS_BODY, parent).apply {
expressions = emptyList()
is KtClassBody -> el<UExpressionList> {
KotlinUExpressionList(element, KotlinSpecialExpressionKinds.CLASS_BODY, parent).apply {
expressions = emptyList()
}
}
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 {
KotlinConverter.convertExpression(it, parent, requiredType)
} ?: UastEmptyExpression
} ?: el<UExpression> { UastEmptyExpression }
is KtLightAnnotation.LightExpressionValue<*> -> {
val expression = element.originalExpression
when (expression) {
is KtExpression -> KotlinConverter.convertExpression(expression, parent, requiredType)
else -> UastEmptyExpression
else -> el<UExpression> { UastEmptyExpression }
}
}
is KtLiteralStringTemplateEntry -> expr<ULiteralExpression> { KotlinStringULiteralExpression(element, parent, element.getText()) }
is KtEscapeStringTemplateEntry -> expr<ULiteralExpression> { KotlinStringULiteralExpression(element, parent, element.unescapedValue) }
is KtStringTemplateEntry -> element.expression?.let { convertExpression(it, parent, requiredType) } ?: expr<UExpression> { UastEmptyExpression }
else -> {
if (element is LeafPsiElement && element.elementType == KtTokens.IDENTIFIER) {
el<UIdentifier> { UIdentifier(element, parent) }
@@ -221,7 +239,7 @@ internal object KotlinConverter {
}
}
internal fun convertExpression(expression: KtExpression, parent: UElement?, requiredType: Class<out UElement>? = null): UExpression {
internal fun convertExpression(expression: KtExpression, parent: UElement?, requiredType: Class<out UElement>? = null): UExpression? {
return with (requiredType) { when (expression) {
is KtVariableDeclaration -> expr<UDeclarationsExpression> { convertVariablesDeclaration(expression, parent) }
@@ -249,7 +267,6 @@ internal object KotlinConverter {
is KtLabeledExpression -> expr<ULabeledExpression> { KotlinULabeledExpression(expression, parent) }
is KtClassLiteralExpression -> expr<UClassLiteralExpression> { KotlinUClassLiteralExpression(expression, parent) }
is KtObjectLiteralExpression -> expr<UObjectLiteralExpression> { KotlinUObjectLiteralExpression(expression, parent) }
is KtStringTemplateEntry -> expression.expression?.let { convertExpression(it, parent, requiredType) } ?: UastEmptyExpression
is KtDotQualifiedExpression -> expr<UQualifiedReferenceExpression> { KotlinUQualifiedReferenceExpression(expression, parent) }
is KtSafeQualifiedExpression -> expr<UQualifiedReferenceExpression> { KotlinUSafeQualifiedExpression(expression, parent) }
is KtSimpleNameExpression -> expr<USimpleNameReferenceExpression> {
@@ -304,7 +321,7 @@ internal object KotlinConverter {
}
internal fun convertOrEmpty(expression: KtExpression?, parent: UElement?): UExpression {
return if (expression != null) convertExpression(expression, parent, null) else UastEmptyExpression
return expression?.let { convertExpression(it, parent, null) } ?: UastEmptyExpression
}
internal fun convertOrNull(expression: KtExpression?, parent: UElement?): UExpression? {
@@ -26,5 +26,5 @@ class KotlinUArrayAccessExpression(
override val containingElement: UElement?
) : KotlinAbstractUExpression(), UArrayAccessExpression, PsiElementBacked, KotlinUElementWithType, KotlinEvaluatableUElement {
override val receiver by lz { KotlinConverter.convertOrEmpty(psi.arrayExpression, this) }
override val indices by lz { psi.indexExpressions.map { KotlinConverter.convertExpression(it, this) } }
override val indices by lz { psi.indexExpressions.map { KotlinConverter.convertOrEmpty(it, this) } }
}
@@ -29,7 +29,7 @@ class KotlinUBinaryExpressionWithType(
) : KotlinAbstractUExpression(), UBinaryExpressionWithType, PsiElementBacked,
KotlinUElementWithType, KotlinEvaluatableUElement {
override val operand by lz { KotlinConverter.convertExpression(psi.left, this) }
override val operand by lz { KotlinConverter.convertOrEmpty(psi.left, this) }
override val type by lz { psi.right.toPsiType(this) }
override val typeReference by lz {
@@ -86,7 +86,7 @@ class KotlinUSwitchEntry(
}.apply {
val exprPsi = this@KotlinUSwitchEntry.psi.expression
val userExpressions = when (exprPsi) {
is KtBlockExpression -> exprPsi.statements.map { KotlinConverter.convertExpression(it, this) }
is KtBlockExpression -> exprPsi.statements.map { KotlinConverter.convertOrEmpty(it, this) }
else -> listOf(KotlinConverter.convertOrEmpty(exprPsi, this))
}
containingElement
@@ -16,7 +16,6 @@
package org.jetbrains.uast.kotlin
import com.intellij.psi.PsiResourceListElement
import org.jetbrains.kotlin.psi.KtTryExpression
import org.jetbrains.uast.UElement
import org.jetbrains.uast.UIdentifier
@@ -28,7 +27,7 @@ class KotlinUTryExpression(
override val psi: KtTryExpression,
override val containingElement: UElement?
) : KotlinAbstractUExpression(), UTryExpression, PsiElementBacked, KotlinUElementWithType {
override val tryClause by lz { KotlinConverter.convertExpression(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 finallyClause by lz { psi.finallyBlock?.finalExpression?.let { KotlinConverter.convertExpression(it, this) } }
@@ -26,7 +26,7 @@ class KotlinUTypeCheckExpression(
override val psi: KtIsExpression,
override val containingElement: UElement?
) : KotlinAbstractUExpression(), UBinaryExpressionWithType, PsiElementBacked, KotlinUElementWithType, KotlinEvaluatableUElement {
override val operand by lz { KotlinConverter.convertExpression(psi.leftHandSide, this) }
override val operand by lz { KotlinConverter.convertOrEmpty(psi.leftHandSide, this) }
override val type by lz { psi.typeReference.toPsiType(this) }