191: Uast: initial support for multiple required types
This commit is contained in:
@@ -76,23 +76,27 @@ class KotlinUastLanguagePlugin : UastLanguagePlugin {
|
||||
|
||||
override fun convertElement(element: PsiElement, parent: UElement?, requiredType: Class<out UElement>?): UElement? {
|
||||
if (!element.isJvmElement) return null
|
||||
return convertDeclarationOrElement(element, parent, requiredType)
|
||||
return convertDeclarationOrElement(element, parent, elementTypes(requiredType))
|
||||
}
|
||||
|
||||
override fun convertElementWithParent(element: PsiElement, requiredType: Class<out UElement>?): UElement? {
|
||||
if (!element.isJvmElement) return null
|
||||
if (element is PsiFile) return convertDeclaration(element, null, requiredType)
|
||||
if (element is KtLightClassForFacade) return convertDeclaration(element, null, requiredType)
|
||||
if (element is PsiFile) return convertDeclaration(element, null, elementTypes(requiredType))
|
||||
if (element is KtLightClassForFacade) return convertDeclaration(element, null, elementTypes(requiredType))
|
||||
|
||||
return convertDeclarationOrElement(element, null, requiredType)
|
||||
return convertDeclarationOrElement(element, null, elementTypes(requiredType))
|
||||
}
|
||||
|
||||
private fun convertDeclarationOrElement(element: PsiElement, givenParent: UElement?, requiredType: Class<out UElement>?): UElement? {
|
||||
private fun convertDeclarationOrElement(
|
||||
element: PsiElement,
|
||||
givenParent: UElement?,
|
||||
requiredType: Array<out Class<out UElement>>
|
||||
): UElement? {
|
||||
if (element is UElement) return element
|
||||
|
||||
if (element.isValid) {
|
||||
element.getUserData(KOTLIN_CACHED_UELEMENT_KEY)?.get()?.let { cachedUElement ->
|
||||
return if (requiredType == null || requiredType.isInstance(cachedUElement)) cachedUElement else null
|
||||
return if (requiredType.isAssignableFrom(cachedUElement.javaClass)) cachedUElement else null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,8 +151,9 @@ class KotlinUastLanguagePlugin : UastLanguagePlugin {
|
||||
}
|
||||
|
||||
internal fun convertDeclaration(element: PsiElement,
|
||||
givenParent: UElement?,
|
||||
requiredType: Class<out UElement>?): UElement? {
|
||||
givenParent: UElement?,
|
||||
expectedTypes: Array<out Class<out UElement>>
|
||||
): UElement? {
|
||||
fun <P : PsiElement> build(ctor: (P, UElement?) -> UElement): () -> UElement? = { ctor(element as P, givenParent) }
|
||||
|
||||
fun <P : PsiElement, K : KtElement> buildKt(ktElement: K, ctor: (P, K, UElement?) -> UElement): () -> UElement? =
|
||||
@@ -158,7 +163,7 @@ class KotlinUastLanguagePlugin : UastLanguagePlugin {
|
||||
{ ctor(element as P, ktElement, givenParent) }
|
||||
|
||||
val original = element.originalElement
|
||||
return with(requiredType) {
|
||||
return with(expectedTypes) {
|
||||
when (original) {
|
||||
is KtLightMethod -> el<UMethod>(build(KotlinUMethod.Companion::create)) // .Companion is needed because of KT-13934
|
||||
is KtLightClass -> when (original.kotlinOrigin) {
|
||||
@@ -200,21 +205,21 @@ class KotlinUastLanguagePlugin : UastLanguagePlugin {
|
||||
else {
|
||||
el<UMethod> {
|
||||
val lightMethod = LightClassUtil.getLightClassMethod(original) ?: return null
|
||||
convertDeclaration(lightMethod, givenParent, requiredType)
|
||||
convertDeclaration(lightMethod, givenParent, expectedTypes)
|
||||
}
|
||||
}
|
||||
|
||||
is KtPropertyAccessor -> el<UMethod> {
|
||||
val lightMethod = LightClassUtil.getLightClassAccessorMethod(original) ?: return null
|
||||
convertDeclaration(lightMethod, givenParent, requiredType)
|
||||
convertDeclaration(lightMethod, givenParent, expectedTypes)
|
||||
}
|
||||
|
||||
is KtProperty ->
|
||||
if (original.isLocal) {
|
||||
KotlinConverter.convertPsiElement(element, givenParent, requiredType)
|
||||
KotlinConverter.convertPsiElement(element, givenParent, expectedTypes)
|
||||
}
|
||||
else {
|
||||
convertNonLocalProperty(original, givenParent, requiredType)
|
||||
convertNonLocalProperty(original, givenParent, expectedTypes)
|
||||
}
|
||||
|
||||
is KtParameter -> el<UParameter> {
|
||||
@@ -228,10 +233,10 @@ class KotlinUastLanguagePlugin : UastLanguagePlugin {
|
||||
is FakeFileForLightClass -> el<UFile> { KotlinUFile(original.navigationElement, this@KotlinUastLanguagePlugin) }
|
||||
is KtAnnotationEntry -> el<UAnnotation>(build(::KotlinUAnnotation))
|
||||
is KtCallExpression ->
|
||||
if (requiredType != null && UAnnotation::class.java.isAssignableFrom(requiredType)) {
|
||||
if (expectedTypes.isAssignableFrom(KotlinUNestedAnnotation::class.java) && !expectedTypes.isAssignableFrom(UCallExpression::class.java)) {
|
||||
el<UAnnotation> { KotlinUNestedAnnotation.tryCreate(original, givenParent) }
|
||||
} else null
|
||||
is KtLightAnnotationForSourceEntry -> convertElement(original.kotlinOrigin, givenParent, requiredType)
|
||||
is KtLightAnnotationForSourceEntry -> convertElement(original.kotlinOrigin, givenParent, expectedTypes)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
@@ -258,19 +263,41 @@ class KotlinUastLanguagePlugin : UastLanguagePlugin {
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T : UElement> convertElement(element: PsiElement, parent: UElement?, expectedTypes: Array<out Class<out T>>): T? {
|
||||
val nonEmptyExpectedTypes = expectedTypes.nonEmptyOr(DEFAULT_TYPES_LIST)
|
||||
return (convertDeclaration(element, parent, nonEmptyExpectedTypes)
|
||||
?: KotlinConverter.convertPsiElement(element, parent, nonEmptyExpectedTypes)) as? T
|
||||
}
|
||||
|
||||
override fun <T : UElement> convertElementWithParent(element: PsiElement, requiredTypes: Array<out Class<out T>>): T? {
|
||||
return convertElement(element, null, requiredTypes)
|
||||
}
|
||||
|
||||
override fun <T : UElement> convertToAlternatives(element: PsiElement, requiredTypes: Array<out Class<out T>>) = when (element) {
|
||||
else -> sequenceOf(convertElementWithParent(element, requiredTypes.nonEmptyOr(DEFAULT_TYPES_LIST)) as? T).filterNotNull()
|
||||
}
|
||||
}
|
||||
|
||||
internal inline fun <reified ActualT : UElement> Class<out UElement>?.el(f: () -> UElement?): UElement? {
|
||||
internal inline fun <reified ActualT : UElement> Class<*>?.el(f: () -> UElement?): UElement? {
|
||||
return if (this == null || isAssignableFrom(ActualT::class.java)) f() else null
|
||||
}
|
||||
|
||||
internal inline fun <reified ActualT : UElement> Class<out UElement>?.expr(f: () -> UExpression?): UExpression? {
|
||||
return if (this == null || isAssignableFrom(ActualT::class.java)) f() else null
|
||||
internal inline fun <reified ActualT : UElement> Array<out Class<out UElement>>.el(f: () -> UElement?): UElement? {
|
||||
return if (isAssignableFrom(ActualT::class.java)) f() else null
|
||||
}
|
||||
|
||||
internal inline fun <reified ActualT : UElement> Array<out Class<out UElement>>.expr(f: () -> UExpression?): UExpression? {
|
||||
return if (isAssignableFrom(ActualT::class.java)) f() else null
|
||||
}
|
||||
|
||||
internal fun Array<out Class<out UElement>>.isAssignableFrom(cls: Class<*>) = any { it.isAssignableFrom(cls) }
|
||||
|
||||
private fun convertNonLocalProperty(property: KtProperty,
|
||||
givenParent: UElement?,
|
||||
requiredType: Class<out UElement>?): UElement? {
|
||||
requiredType: Array<out Class<out UElement>>
|
||||
): UElement? {
|
||||
val methods = LightClassUtil.getLightClassPropertyMethods(property)
|
||||
return methods.backingField?.let { backingField ->
|
||||
with(requiredType) {
|
||||
@@ -298,12 +325,13 @@ internal object KotlinConverter {
|
||||
|
||||
internal fun convertPsiElement(element: PsiElement?,
|
||||
givenParent: UElement?,
|
||||
requiredType: Class<out UElement>?): UElement? {
|
||||
expectedTypes: Array<out Class<out UElement>>
|
||||
): UElement? {
|
||||
fun <P : PsiElement> build(ctor: (P, UElement?) -> UElement): () -> UElement? {
|
||||
return { ctor(element as P, givenParent) }
|
||||
}
|
||||
|
||||
return with (requiredType) { when (element) {
|
||||
return with (expectedTypes) { when (element) {
|
||||
is KtParameterList -> el<UDeclarationsExpression> {
|
||||
val declarationsExpression = KotlinUDeclarationsExpression(givenParent)
|
||||
declarationsExpression.apply {
|
||||
@@ -328,19 +356,19 @@ internal object KotlinConverter {
|
||||
}
|
||||
}
|
||||
|
||||
is KtExpression -> KotlinConverter.convertExpression(element, givenParent, requiredType)
|
||||
is KtLambdaArgument -> element.getLambdaExpression()?.let { KotlinConverter.convertExpression(it, givenParent, requiredType) }
|
||||
is KtExpression -> KotlinConverter.convertExpression(element, givenParent, expectedTypes)
|
||||
is KtLambdaArgument -> element.getLambdaExpression()?.let { KotlinConverter.convertExpression(it, givenParent, expectedTypes) }
|
||||
is KtLightElementBase -> {
|
||||
val expression = element.kotlinOrigin
|
||||
when (expression) {
|
||||
is KtExpression -> KotlinConverter.convertExpression(expression, givenParent, requiredType)
|
||||
is KtExpression -> KotlinConverter.convertExpression(expression, givenParent, expectedTypes)
|
||||
else -> el<UExpression> { UastEmptyExpression(givenParent) }
|
||||
}
|
||||
}
|
||||
is KtLiteralStringTemplateEntry, is KtEscapeStringTemplateEntry -> el<ULiteralExpression>(build(::KotlinStringULiteralExpression))
|
||||
is KtStringTemplateEntry -> element.expression?.let { convertExpression(it, givenParent, requiredType) } ?: expr<UExpression> { UastEmptyExpression }
|
||||
is KtStringTemplateEntry -> element.expression?.let { convertExpression(it, givenParent, expectedTypes) } ?: expr<UExpression> { UastEmptyExpression }
|
||||
is KtWhenEntry -> el<USwitchClauseExpressionWithBody>(build(::KotlinUSwitchEntry))
|
||||
is KtWhenCondition -> convertWhenCondition(element, givenParent, requiredType)
|
||||
is KtWhenCondition -> convertWhenCondition(element, givenParent, expectedTypes)
|
||||
is KtTypeReference -> el<UTypeReferenceExpression> { LazyKotlinUTypeReferenceExpression(element, givenParent) }
|
||||
is KtConstructorDelegationCall ->
|
||||
el<UCallExpression> { KotlinUFunctionCallExpression(element, givenParent) }
|
||||
@@ -378,7 +406,8 @@ internal object KotlinConverter {
|
||||
|
||||
internal fun convertEntry(entry: KtStringTemplateEntry,
|
||||
givenParent: UElement?,
|
||||
requiredType: Class<out UElement>? = null): UExpression? {
|
||||
requiredType: Array<out Class<out UElement>>
|
||||
): UExpression? {
|
||||
return with(requiredType) {
|
||||
if (entry is KtStringTemplateEntryWithExpression) {
|
||||
expr<UExpression> {
|
||||
@@ -404,7 +433,8 @@ internal object KotlinConverter {
|
||||
|
||||
internal fun convertExpression(expression: KtExpression,
|
||||
givenParent: UElement?,
|
||||
requiredType: Class<out UElement>? = null): UExpression? {
|
||||
requiredType: Array<out Class<out UElement>>
|
||||
): UExpression? {
|
||||
fun <P : PsiElement> build(ctor: (P, UElement?) -> UExpression): () -> UExpression? {
|
||||
return { ctor(expression as P, givenParent) }
|
||||
}
|
||||
@@ -414,7 +444,7 @@ internal object KotlinConverter {
|
||||
|
||||
is KtStringTemplateExpression -> {
|
||||
when {
|
||||
forceUInjectionHost || (requiredType != null && UInjectionHost::class.java.isAssignableFrom(requiredType)) ->
|
||||
forceUInjectionHost || requiredType.contains(UInjectionHost::class.java) ->
|
||||
expr<UInjectionHost> { KotlinStringTemplateUPolyadicExpression(expression, givenParent) }
|
||||
expression.entries.isEmpty() -> {
|
||||
expr<ULiteralExpression> { KotlinStringULiteralExpression(expression, givenParent, "") }
|
||||
@@ -496,7 +526,8 @@ internal object KotlinConverter {
|
||||
|
||||
internal fun convertWhenCondition(condition: KtWhenCondition,
|
||||
givenParent: UElement?,
|
||||
requiredType: Class<out UElement>? = null): UExpression? {
|
||||
requiredType: Array<out Class<out UElement>>
|
||||
): UExpression? {
|
||||
return with(requiredType) {
|
||||
when (condition) {
|
||||
is KtWhenConditionInRange -> expr<UBinaryExpression> {
|
||||
@@ -532,11 +563,11 @@ internal object KotlinConverter {
|
||||
}
|
||||
|
||||
internal fun convertOrEmpty(expression: KtExpression?, parent: UElement?): UExpression {
|
||||
return expression?.let { convertExpression(it, parent, null) } ?: UastEmptyExpression
|
||||
return expression?.let { convertExpression(it, parent, DEFAULT_EXPRESSION_TYPES_LIST) } ?: UastEmptyExpression
|
||||
}
|
||||
|
||||
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, DEFAULT_EXPRESSION_TYPES_LIST) else null
|
||||
}
|
||||
|
||||
internal fun KtPsiFactory.createAnalyzableExpression(text: String, context: PsiElement): KtExpression =
|
||||
@@ -567,3 +598,10 @@ private fun convertVariablesDeclaration(
|
||||
}
|
||||
return declarationsExpression.apply { declarations = listOf(variable) }
|
||||
}
|
||||
|
||||
private fun expressionTypes(requiredType: Class<out UElement>?) = requiredType?.let { arrayOf(it) } ?: DEFAULT_EXPRESSION_TYPES_LIST
|
||||
|
||||
private fun elementTypes(requiredType: Class<out UElement>?) = requiredType?.let { arrayOf(it) } ?: DEFAULT_TYPES_LIST
|
||||
|
||||
private fun <T : UElement> Array<out Class<out T>>.nonEmptyOr(default: Array<out Class<out UElement>>) = takeIf { it.isNotEmpty() }
|
||||
?: default
|
||||
@@ -0,0 +1,121 @@
|
||||
package org.jetbrains.uast.kotlin.expressions
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiMethod
|
||||
import com.intellij.psi.PsiType
|
||||
import org.jetbrains.kotlin.psi.KtBinaryExpression
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.types.CommonSupertypes
|
||||
import org.jetbrains.uast.*
|
||||
import org.jetbrains.uast.kotlin.*
|
||||
import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier
|
||||
import org.jetbrains.uast.kotlin.kinds.KotlinSpecialExpressionKinds
|
||||
import org.jetbrains.uast.kotlin.psi.UastKotlinPsiVariable
|
||||
|
||||
|
||||
private fun createVariableReferenceExpression(variable: UVariable, containingElement: UElement?) =
|
||||
object : USimpleNameReferenceExpression, JvmDeclarationUElementPlaceholder {
|
||||
override val psi: PsiElement? = null
|
||||
override fun resolve(): PsiElement? = variable
|
||||
override val uastParent: UElement? = containingElement
|
||||
override val resolvedName: String? = variable.name
|
||||
override val annotations: List<UAnnotation> = emptyList()
|
||||
override val identifier: String = variable.name.orAnonymous()
|
||||
override val javaPsi: PsiElement? = null
|
||||
override val sourcePsi: PsiElement? = null
|
||||
}
|
||||
|
||||
private fun createNullLiteralExpression(containingElement: UElement?) =
|
||||
object : ULiteralExpression, JvmDeclarationUElementPlaceholder {
|
||||
override val psi: PsiElement? = null
|
||||
override val uastParent: UElement? = containingElement
|
||||
override val value: Any? = null
|
||||
override val annotations: List<UAnnotation> = emptyList()
|
||||
override val javaPsi: PsiElement? = null
|
||||
override val sourcePsi: PsiElement? = null
|
||||
}
|
||||
|
||||
private fun createNotEqWithNullExpression(variable: UVariable, containingElement: UElement?) =
|
||||
object : UBinaryExpression, JvmDeclarationUElementPlaceholder {
|
||||
override val psi: PsiElement? = null
|
||||
override val uastParent: UElement? = containingElement
|
||||
override val leftOperand: UExpression by lz { createVariableReferenceExpression(variable, this) }
|
||||
override val rightOperand: UExpression by lz { createNullLiteralExpression(this) }
|
||||
override val operator: UastBinaryOperator = UastBinaryOperator.NOT_EQUALS
|
||||
override val operatorIdentifier: UIdentifier? = KotlinUIdentifier(null, this)
|
||||
override fun resolveOperator(): PsiMethod? = null
|
||||
override val annotations: List<UAnnotation> = emptyList()
|
||||
override val javaPsi: PsiElement? = null
|
||||
override val sourcePsi: PsiElement? = null
|
||||
}
|
||||
|
||||
private fun createElvisExpressions(
|
||||
left: KtExpression,
|
||||
right: KtExpression,
|
||||
containingElement: UElement?,
|
||||
psiParent: PsiElement): List<UExpression> {
|
||||
|
||||
val declaration = KotlinUDeclarationsExpression(containingElement)
|
||||
val tempVariable = KotlinULocalVariable(UastKotlinPsiVariable.create(left, declaration, psiParent), left, declaration)
|
||||
declaration.declarations = listOf(tempVariable)
|
||||
|
||||
val ifExpression = object : UIfExpression, JvmDeclarationUElementPlaceholder {
|
||||
override val psi: PsiElement? = null
|
||||
override val uastParent: UElement? = containingElement
|
||||
override val javaPsi: PsiElement? = null
|
||||
override val sourcePsi: PsiElement? = null
|
||||
override val condition: UExpression by lz { createNotEqWithNullExpression(tempVariable, this) }
|
||||
override val thenExpression: UExpression? by lz { createVariableReferenceExpression(tempVariable, this) }
|
||||
override val elseExpression: UExpression? by lz { KotlinConverter.convertExpression(right, this, DEFAULT_EXPRESSION_TYPES_LIST) }
|
||||
override val isTernary: Boolean = false
|
||||
override val annotations: List<UAnnotation> = emptyList()
|
||||
override val ifIdentifier: UIdentifier = KotlinUIdentifier(null, this)
|
||||
override val elseIdentifier: UIdentifier? = KotlinUIdentifier(null, this)
|
||||
}
|
||||
|
||||
return listOf(declaration, ifExpression)
|
||||
}
|
||||
|
||||
fun createElvisExpression(elvisExpression: KtBinaryExpression, givenParent: UElement?): UExpression {
|
||||
val left = elvisExpression.left ?: return UastEmptyExpression
|
||||
val right = elvisExpression.right ?: return UastEmptyExpression
|
||||
|
||||
return KotlinUElvisExpression(elvisExpression, left, right, givenParent)
|
||||
}
|
||||
|
||||
class KotlinUElvisExpression(
|
||||
private val elvisExpression: KtBinaryExpression,
|
||||
private val left: KtExpression,
|
||||
private val right: KtExpression,
|
||||
givenParent: UElement?
|
||||
) : KotlinAbstractUElement(givenParent), UExpressionList, KotlinEvaluatableUElement {
|
||||
|
||||
override val javaPsi: PsiElement? = null
|
||||
override val sourcePsi: PsiElement? = elvisExpression
|
||||
override val psi: PsiElement? = sourcePsi
|
||||
override val kind = KotlinSpecialExpressionKinds.ELVIS
|
||||
override val annotations: List<UAnnotation> = emptyList()
|
||||
override val expressions: List<UExpression> by lz {
|
||||
createElvisExpressions(left, right, this, elvisExpression.parent)
|
||||
}
|
||||
|
||||
val lhsDeclaration get() = (expressions[0] as UDeclarationsExpression).declarations.single()
|
||||
val rhsIfExpression get() = expressions[1] as UIfExpression
|
||||
|
||||
override fun asRenderString(): String {
|
||||
return kind.name + " " +
|
||||
expressions.joinToString(separator = "\n", prefix = "{\n", postfix = "\n}") {
|
||||
it.asRenderString().withMargin
|
||||
}
|
||||
}
|
||||
|
||||
override fun getExpressionType(): PsiType? {
|
||||
val leftType = left.analyze()[BindingContext.EXPRESSION_TYPE_INFO, left]?.type ?: return null
|
||||
val rightType = right.analyze()[BindingContext.EXPRESSION_TYPE_INFO, right]?.type ?: return null
|
||||
|
||||
return CommonSupertypes
|
||||
.commonSupertype(listOf(leftType, rightType))
|
||||
.toPsiType(this, elvisExpression, boxed = false)
|
||||
}
|
||||
}
|
||||
+10
-5
@@ -18,10 +18,7 @@ package org.jetbrains.uast.kotlin
|
||||
|
||||
import com.intellij.psi.PsiLanguageInjectionHost
|
||||
import org.jetbrains.kotlin.psi.KtStringTemplateExpression
|
||||
import org.jetbrains.uast.UElement
|
||||
import org.jetbrains.uast.UExpression
|
||||
import org.jetbrains.uast.UPolyadicExpression
|
||||
import org.jetbrains.uast.UastBinaryOperator
|
||||
import org.jetbrains.uast.*
|
||||
import org.jetbrains.uast.expressions.UInjectionHost
|
||||
|
||||
class KotlinStringTemplateUPolyadicExpression(
|
||||
@@ -32,7 +29,15 @@ class KotlinStringTemplateUPolyadicExpression(
|
||||
KotlinUElementWithType,
|
||||
KotlinEvaluatableUElement,
|
||||
UInjectionHost {
|
||||
override val operands: List<UExpression> by lz { psi.entries.map { KotlinConverter.convertEntry(it, this)!! } }
|
||||
override val operands: List<UExpression> by lz {
|
||||
psi.entries.map {
|
||||
KotlinConverter.convertEntry(
|
||||
it,
|
||||
this,
|
||||
DEFAULT_EXPRESSION_TYPES_LIST
|
||||
)!!
|
||||
}
|
||||
}
|
||||
override val operator = UastBinaryOperator.PLUS
|
||||
|
||||
override val psiLanguageInjectionHost: PsiLanguageInjectionHost get() = psi
|
||||
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.uast.kotlin
|
||||
|
||||
import com.intellij.psi.PsiNamedElement
|
||||
import com.intellij.psi.ResolveResult
|
||||
import org.jetbrains.kotlin.psi.KtCallableReferenceExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext.DOUBLE_COLON_LHS
|
||||
import org.jetbrains.uast.*
|
||||
import org.jetbrains.uast.kotlin.internal.getResolveResultVariants
|
||||
|
||||
class KotlinUCallableReferenceExpression(
|
||||
override val psi: KtCallableReferenceExpression,
|
||||
givenParent: UElement?
|
||||
) : KotlinAbstractUExpression(givenParent), UCallableReferenceExpression, UMultiResolvable, KotlinUElementWithType {
|
||||
override val qualifierExpression: UExpression?
|
||||
get() {
|
||||
if (qualifierType != null) return null
|
||||
val receiverExpression = psi.receiverExpression ?: return null
|
||||
return KotlinConverter.convertExpression(receiverExpression, this, DEFAULT_EXPRESSION_TYPES_LIST)
|
||||
}
|
||||
|
||||
override val qualifierType by lz {
|
||||
val ktType = psi.analyze()[DOUBLE_COLON_LHS, psi.receiverExpression]?.type ?: return@lz null
|
||||
ktType.toPsiType(this, psi, boxed = true)
|
||||
}
|
||||
|
||||
override val callableName: String
|
||||
get() = psi.callableReference.getReferencedName()
|
||||
|
||||
override val resolvedName: String?
|
||||
get() = (resolve() as? PsiNamedElement)?.name
|
||||
|
||||
override fun resolve() = psi.callableReference.resolveCallToDeclaration(this)
|
||||
|
||||
override fun multiResolve(): Iterable<ResolveResult> = getResolveResultVariants(psi.callableReference)
|
||||
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.uast.kotlin
|
||||
|
||||
import org.jetbrains.kotlin.psi.KtClassLiteralExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext.DOUBLE_COLON_LHS
|
||||
import org.jetbrains.uast.DEFAULT_EXPRESSION_TYPES_LIST
|
||||
import org.jetbrains.uast.UClassLiteralExpression
|
||||
import org.jetbrains.uast.UElement
|
||||
import org.jetbrains.uast.UExpression
|
||||
|
||||
class KotlinUClassLiteralExpression(
|
||||
override val psi: KtClassLiteralExpression,
|
||||
givenParent: UElement?
|
||||
) : KotlinAbstractUExpression(givenParent), UClassLiteralExpression, KotlinUElementWithType {
|
||||
override val type by lz {
|
||||
val ktType = psi.analyze()[DOUBLE_COLON_LHS, psi.receiverExpression]?.type ?: return@lz null
|
||||
ktType.toPsiType(this, psi, boxed = true)
|
||||
}
|
||||
|
||||
override val expression: UExpression?
|
||||
get() {
|
||||
if (type != null) return null
|
||||
val receiverExpression = psi.receiverExpression ?: return null
|
||||
return KotlinConverter.convertExpression(receiverExpression, this, DEFAULT_EXPRESSION_TYPES_LIST)
|
||||
}
|
||||
}
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.uast.kotlin
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
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.declarations.KotlinUIdentifier
|
||||
import org.jetbrains.uast.kotlin.kinds.KotlinSpecialExpressionKinds
|
||||
|
||||
class KotlinUSwitchExpression(
|
||||
override val psi: KtWhenExpression,
|
||||
givenParent: UElement?
|
||||
) : KotlinAbstractUExpression(givenParent), USwitchExpression, KotlinUElementWithType {
|
||||
override val expression by lz { KotlinConverter.convertOrNull(psi.subjectExpression, this) }
|
||||
|
||||
override val body: UExpressionList by lz {
|
||||
object : KotlinUExpressionList(psi, KotlinSpecialExpressionKinds.WHEN, this@KotlinUSwitchExpression) {
|
||||
override fun asRenderString() = expressions.joinToString("\n") { it.asRenderString().withMargin }
|
||||
}.apply {
|
||||
expressions = this@KotlinUSwitchExpression.psi.entries.map { KotlinUSwitchEntry(it, this) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun asRenderString() = buildString {
|
||||
val expr = expression?.let { "(" + it.asRenderString() + ") " } ?: ""
|
||||
appendln("switch $expr {")
|
||||
appendln(body.asRenderString())
|
||||
appendln("}")
|
||||
}
|
||||
|
||||
override val switchIdentifier: UIdentifier
|
||||
get() = KotlinUIdentifier(null, this)
|
||||
}
|
||||
|
||||
class KotlinUSwitchEntry(
|
||||
override val psi: KtWhenEntry,
|
||||
givenParent: UElement?
|
||||
) : KotlinAbstractUExpression(givenParent), USwitchClauseExpressionWithBody {
|
||||
override val caseValues by lz {
|
||||
psi.conditions.map { KotlinConverter.convertWhenCondition(it, this, DEFAULT_EXPRESSION_TYPES_LIST) ?: UastEmptyExpression }
|
||||
}
|
||||
|
||||
override val body: UExpressionList by lz {
|
||||
object : KotlinUExpressionList(psi, KotlinSpecialExpressionKinds.WHEN_ENTRY, this@KotlinUSwitchEntry) {
|
||||
override fun asRenderString() = buildString {
|
||||
appendln("{")
|
||||
expressions.forEach { appendln(it.asRenderString().withMargin) }
|
||||
appendln("}")
|
||||
}
|
||||
}.apply {
|
||||
val exprPsi = this@KotlinUSwitchEntry.psi.expression
|
||||
val userExpressions = when (exprPsi) {
|
||||
is KtBlockExpression -> exprPsi.statements.map { KotlinConverter.convertOrEmpty(it, this) }
|
||||
else -> listOf(KotlinConverter.convertOrEmpty(exprPsi, this))
|
||||
}
|
||||
expressions = userExpressions + object : UBreakExpression, JvmDeclarationUElementPlaceholder {
|
||||
override val javaPsi: PsiElement? = null
|
||||
override val sourcePsi: PsiElement? = null
|
||||
override val psi: PsiElement?
|
||||
get() = null
|
||||
override val label: String?
|
||||
get() = null
|
||||
override val uastParent: UElement?
|
||||
get() = this@KotlinUSwitchEntry
|
||||
override val annotations: List<UAnnotation>
|
||||
get() = emptyList()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun convertParent(): UElement? {
|
||||
val result = KotlinConverter.unwrapElements(psi.parent)?.let { parentUnwrapped ->
|
||||
KotlinUastLanguagePlugin().convertElementWithParent(parentUnwrapped, null)
|
||||
}
|
||||
return (result as? KotlinUSwitchExpression)?.body ?: result
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.uast.kotlin
|
||||
|
||||
import org.jetbrains.kotlin.psi.KtTryExpression
|
||||
import org.jetbrains.uast.*
|
||||
import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier
|
||||
|
||||
class KotlinUTryExpression(
|
||||
override val psi: KtTryExpression,
|
||||
givenParent: UElement?
|
||||
) : KotlinAbstractUExpression(givenParent), UTryExpression, KotlinUElementWithType {
|
||||
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,
|
||||
DEFAULT_EXPRESSION_TYPES_LIST
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override val resourceVariables: List<UVariable>
|
||||
get() = emptyList()
|
||||
|
||||
override val hasResources: Boolean
|
||||
get() = false
|
||||
|
||||
override val tryIdentifier: UIdentifier
|
||||
get() = KotlinUIdentifier(null, this)
|
||||
|
||||
override val finallyIdentifier: UIdentifier?
|
||||
get() = null
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
UFile (package = )
|
||||
UClass (name = Foo)
|
||||
UClass (name = Bar)
|
||||
UAnnotationMethod (name = Bar)
|
||||
UAnnotationMethod (name = getAPlusB)
|
||||
UClass (name = Baz)
|
||||
UAnnotationMethod (name = doNothing)
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.uast.test.kotlin
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiElementVisitor
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.uast.*
|
||||
import org.jetbrains.uast.test.env.kotlin.assertEqualsToFile
|
||||
import java.io.File
|
||||
|
||||
class MultiplesRequiredTypesTest : AbstractKotlinUastTest() {
|
||||
|
||||
|
||||
fun testInnerClasses() = doTest("InnerClasses")
|
||||
|
||||
override fun check(testName: String, file: UFile) {
|
||||
val valuesFile = getTestFile(testName, "splog.txt")
|
||||
assertEqualsToFile("MultiplesTargetConversionResult", valuesFile, file.asMultiplesTargetConversionResult())
|
||||
}
|
||||
|
||||
private fun UFile.asMultiplesTargetConversionResult(): String {
|
||||
|
||||
val builder = StringBuilder()
|
||||
var level = 0
|
||||
(this.psi as KtFile).accept(object : PsiElementVisitor() {
|
||||
override fun visitElement(element: PsiElement) {
|
||||
val uElement =
|
||||
element.toUElementOfExpectedTypes(UFile::class.java, UClass::class.java, UField::class.java, UMethod::class.java)
|
||||
if (uElement != null) {
|
||||
builder.append(" ".repeat(level))
|
||||
builder.append(uElement.asLogString())
|
||||
builder.appendln()
|
||||
}
|
||||
if (uElement != null) level++
|
||||
element.acceptChildren(this)
|
||||
if (uElement != null) level--
|
||||
}
|
||||
})
|
||||
return builder.toString()
|
||||
}
|
||||
|
||||
private fun getTestFile(testName: String, ext: String) =
|
||||
File(File(AbstractKotlinUastTest.TEST_KOTLIN_MODEL_DIR, testName).canonicalPath + '.' + ext)
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user