FIR/UAST: commonize literal expressions

This commit is contained in:
Jinseong Jeon
2021-05-25 14:34:37 -07:00
committed by Ilya Kirillov
parent 6b5bddeed7
commit 16b3d2110e
90 changed files with 581 additions and 406 deletions
@@ -0,0 +1,50 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.kotlin
import org.jetbrains.kotlin.psi.KtEscapeStringTemplateEntry
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtStringTemplateEntry
import org.jetbrains.kotlin.psi.KtStringTemplateEntryWithExpression
import org.jetbrains.uast.*
interface BaseKotlinConverter {
fun convertExpression(
expression: KtExpression,
givenParent: UElement?,
requiredTypes: Array<out Class<out UElement>>
): UExpression?
fun convertEntry(
entry: KtStringTemplateEntry,
givenParent: UElement?,
requiredTypes: Array<out Class<out UElement>>
): UExpression? {
return with(requiredTypes) {
if (entry is KtStringTemplateEntryWithExpression) {
expr<UExpression> {
convertOrEmpty(entry.expression, givenParent)
}
} else {
expr<ULiteralExpression> {
if (entry is KtEscapeStringTemplateEntry)
KotlinStringULiteralExpression(entry, givenParent, entry.unescapedValue)
else
KotlinStringULiteralExpression(entry, givenParent)
}
}
}
}
fun convertOrEmpty(expression: KtExpression?, parent: UElement?): UExpression {
return expression?.let { convertExpression(it, parent, DEFAULT_EXPRESSION_TYPES_LIST) } ?: UastEmptyExpression(parent)
}
fun convertOrNull(expression: KtExpression?, parent: UElement?): UExpression? {
return if (expression != null) convertExpression(expression, parent, DEFAULT_EXPRESSION_TYPES_LIST) else null
}
}
@@ -14,6 +14,8 @@ import org.jetbrains.uast.UExpression
interface BaseKotlinUastResolveProviderService {
fun isJvmElement(psiElement: PsiElement): Boolean
val baseKotlinConverter: BaseKotlinConverter
fun convertParent(uElement: UElement): UElement?
fun resolveToDeclaration(ktExpression: KtExpression): PsiElement?
@@ -0,0 +1,37 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.kotlin
import com.intellij.psi.PsiLanguageInjectionHost
import org.jetbrains.kotlin.psi.KtStringTemplateExpression
import org.jetbrains.uast.*
import org.jetbrains.uast.expressions.UInjectionHost
class KotlinStringTemplateUPolyadicExpression(
override val sourcePsi: KtStringTemplateExpression,
givenParent: UElement?
) : KotlinAbstractUExpression(givenParent),
UPolyadicExpression,
KotlinUElementWithType,
KotlinEvaluatableUElement,
UInjectionHost {
override val operands: List<UExpression> by lz {
sourcePsi.entries.map {
baseResolveProviderService.baseKotlinConverter.convertEntry(
it,
this,
DEFAULT_EXPRESSION_TYPES_LIST
)!!
}.takeIf { it.isNotEmpty() } ?: listOf(KotlinStringULiteralExpression(sourcePsi, this, ""))
}
override val operator = UastBinaryOperator.PLUS
override val psiLanguageInjectionHost: PsiLanguageInjectionHost get() = sourcePsi
override val isString: Boolean get() = true
override fun asRenderString(): String = if (operands.isEmpty()) "\"\"" else super<UPolyadicExpression>.asRenderString()
override fun asLogString(): String = if (operands.isEmpty()) "UPolyadicExpression (value = \"\")" else super.asLogString()
}
@@ -0,0 +1,32 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.kotlin
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiType
import org.jetbrains.kotlin.psi.KtEscapeStringTemplateEntry
import org.jetbrains.uast.UElement
import org.jetbrains.uast.ULiteralExpression
import org.jetbrains.uast.kotlin.internal.KotlinFakeUElement
import org.jetbrains.uast.wrapULiteral
class KotlinStringULiteralExpression(
override val sourcePsi: PsiElement,
givenParent: UElement?,
val text: String
) : KotlinAbstractUExpression(givenParent), ULiteralExpression, KotlinUElementWithType, KotlinFakeUElement {
constructor(psi: PsiElement, uastParent: UElement?)
: this(psi, uastParent, if (psi is KtEscapeStringTemplateEntry) psi.unescapedValue else psi.text)
override val value: String
get() = text
override fun evaluate() = value
override fun getExpressionType(): PsiType = PsiType.getJavaLangString(sourcePsi.manager, sourcePsi.resolveScope)
override fun unwrapToSourcePsi(): List<PsiElement> = listOfNotNull(wrapULiteral(this).sourcePsi)
}
@@ -0,0 +1,56 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.kotlin
import com.intellij.psi.PsiArrayType
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiType
import org.jetbrains.kotlin.psi.KtCollectionLiteralExpression
import org.jetbrains.uast.*
import org.jetbrains.uast.kotlin.internal.DelegatedMultiResolve
class KotlinUCollectionLiteralExpression(
override val sourcePsi: KtCollectionLiteralExpression,
givenParent: UElement?
) : KotlinAbstractUExpression(givenParent), UCallExpressionEx, DelegatedMultiResolve, KotlinUElementWithType {
override val classReference: UReferenceExpression? get() = null
override val kind: UastCallKind = UastCallKind.NESTED_ARRAY_INITIALIZER
override val methodIdentifier: UIdentifier? by lazy { UIdentifier(sourcePsi.leftBracket, this) }
override val methodName: String? get() = null
override val receiver: UExpression? get() = null
override val receiverType: PsiType? get() = null
override val returnType: PsiType? get() = getExpressionType()
override val typeArgumentCount: Int get() = typeArguments.size
override val typeArguments: List<PsiType> get() = listOfNotNull((returnType as? PsiArrayType)?.componentType)
override val valueArgumentCount: Int
get() = sourcePsi.getInnerExpressions().size
override val valueArguments by lazy {
sourcePsi.getInnerExpressions().map {
baseResolveProviderService.baseKotlinConverter.convertOrEmpty(it, this)
}
}
override fun asRenderString(): String = "collectionLiteral[" + valueArguments.joinToString { it.asRenderString() } + "]"
override fun resolve(): PsiMethod? = null
override val psi: PsiElement get() = sourcePsi
override fun getArgumentForParameter(i: Int): UExpression? = valueArguments.getOrNull(i)
}
@@ -0,0 +1,26 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.kotlin
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.psi.KtConstantExpression
import org.jetbrains.uast.UElement
import org.jetbrains.uast.ULiteralExpression
import org.jetbrains.uast.kotlin.internal.KotlinFakeUElement
import org.jetbrains.uast.wrapULiteral
class KotlinULiteralExpression(
override val sourcePsi: KtConstantExpression,
givenParent: UElement?
) : KotlinAbstractUExpression(givenParent), ULiteralExpression, KotlinUElementWithType, KotlinEvaluatableUElement, KotlinFakeUElement {
override val isNull: Boolean
get() = sourcePsi.unwrapBlockOrParenthesis().node?.elementType == KtNodeTypes.NULL
override val value by lz { evaluate() }
override fun unwrapToSourcePsi(): List<PsiElement> = listOfNotNull(wrapULiteral(this).sourcePsi)
}
@@ -0,0 +1,12 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.kotlin.internal
import com.intellij.psi.PsiElement
interface KotlinFakeUElement {
fun unwrapToSourcePsi(): List<PsiElement>
}
@@ -10,7 +10,10 @@ import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.asJava.elements.FakeFileForLightClass
import org.jetbrains.kotlin.asJava.elements.KtLightElement
import org.jetbrains.kotlin.asJava.elements.KtLightMember
import org.jetbrains.kotlin.psi.KtBlockExpression
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtPsiUtil
import org.jetbrains.uast.UDeclaration
import org.jetbrains.uast.UElement
import java.util.function.Supplier
@@ -33,3 +36,12 @@ fun getKotlinMemberOrigin(element: PsiElement?): KtDeclaration? {
(element as? KtLightElement<*, *>)?.kotlinOrigin?.let { return it as? KtDeclaration }
return null
}
fun KtExpression.unwrapBlockOrParenthesis(): KtExpression {
val innerExpression = KtPsiUtil.safeDeparenthesize(this)
if (innerExpression is KtBlockExpression) {
val statement = innerExpression.statements.singleOrNull() ?: return this
return KtPsiUtil.safeDeparenthesize(statement)
}
return innerExpression
}
@@ -5,11 +5,13 @@
package org.jetbrains.uast.kotlin
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.uast.DEFAULT_EXPRESSION_TYPES_LIST
import org.jetbrains.uast.DEFAULT_TYPES_LIST
import org.jetbrains.uast.UElement
import org.jetbrains.uast.UExpression
import org.jetbrains.uast.kotlin.internal.KotlinFakeUElement
fun expressionTypes(requiredType: Class<out UElement>?) =
requiredType?.let { arrayOf(it) } ?: DEFAULT_EXPRESSION_TYPES_LIST
@@ -47,3 +49,8 @@ val identifiersTokens = setOf(
KtTokens.THIS_KEYWORD, KtTokens.SUPER_KEYWORD,
KtTokens.GET_KEYWORD, KtTokens.SET_KEYWORD
)
fun UElement.toSourcePsiFakeAware(): List<PsiElement> {
if (this is KotlinFakeUElement) return this.unwrapToSourcePsi()
return listOfNotNull(this.sourcePsi)
}