Uast 1.0.9

This commit is contained in:
Vyacheslav Gerasimov
2017-02-02 19:31:43 +03:00
parent 5888c75d41
commit 10517c16ee
43 changed files with 479 additions and 368 deletions
@@ -18,17 +18,13 @@ package org.jetbrains.uast.kotlin
import com.intellij.lang.Language
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiVariable
import com.intellij.psi.*
import com.intellij.psi.impl.source.tree.LeafPsiElement
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.asJava.LightClassUtil
import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.elements.FakeFileForLightClass
import org.jetbrains.kotlin.asJava.elements.KtLightField
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.asJava.elements.KtLightParameter
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
import org.jetbrains.kotlin.asJava.elements.*
import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
@@ -41,8 +37,7 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.uast.*
import org.jetbrains.uast.java.JavaUastLanguagePlugin
import org.jetbrains.uast.kotlin.declarations.KotlinUMethod
import org.jetbrains.uast.kotlin.expressions.KotlinUBreakExpression
import org.jetbrains.uast.kotlin.expressions.KotlinUContinueExpression
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.UastKotlinPsiVariable
@@ -73,6 +68,7 @@ class KotlinUastLanguagePlugin(override val project: Project) : UastLanguagePlug
override fun convertElementWithParent(element: PsiElement, requiredType: Class<out UElement>?): UElement? {
if (element !is PsiElement) return null
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 parentUElement = convertElementWithParent(parent, null) ?: return null
@@ -191,6 +187,13 @@ internal object KotlinConverter {
is KtContainerNode -> element.getExpression()?.let {
KotlinConverter.convertExpression(it, parent, requiredType)
} ?: UastEmptyExpression
is KtLightAnnotation.LightExpressionValue<*> -> {
val expression = element.originalExpression
when (expression) {
is KtExpression -> KotlinConverter.convertExpression(expression, parent, requiredType)
else -> UastEmptyExpression
}
}
else -> {
if (element is LeafPsiElement && element.elementType == KtTokens.IDENTIFIER) {
el<UIdentifier> { UIdentifier(element, parent) }
@@ -209,20 +212,6 @@ internal object KotlinConverter {
val variable = KotlinUVariable.create(UastKotlinPsiVariable.create(psi, parentPsiElement, parent!!), parent)
return KotlinUDeclarationsExpression(parent).apply { declarations = listOf(variable) }
}
private fun convertStringTemplateExpression(
expression: KtStringTemplateExpression,
parent: UElement?,
i: Int
): UExpression {
return if (i == 1) KotlinStringTemplateUBinaryExpression(expression, parent).apply {
leftOperand = convert(expression.entries[0], this)
rightOperand = convert(expression.entries[1], this)
} else KotlinStringTemplateUBinaryExpression(expression, parent).apply {
leftOperand = convertStringTemplateExpression(expression, parent, i - 1)
rightOperand = convert(expression.entries[i], this)
}
}
internal fun convert(entry: KtStringTemplateEntry, parent: UElement?): UExpression = when (entry) {
is KtStringTemplateEntryWithExpression -> convertOrEmpty(entry.expression, parent)
@@ -242,7 +231,7 @@ internal object KotlinConverter {
else if (expression.entries.size == 1)
convert(expression.entries[0], parent)
else
convertStringTemplateExpression(expression, parent, expression.entries.size - 1)
KotlinStringTemplateUPolyadicExpression(expression, parent)
}
is KtDestructuringDeclaration -> expr<UDeclarationsExpression> {
KotlinUDeclarationsExpression(parent).apply {
@@ -267,7 +256,12 @@ internal object KotlinConverter {
KotlinUSimpleReferenceExpression(expression, expression.getReferencedName(), parent)
}
is KtCallExpression -> expr<UCallExpression> { KotlinUFunctionCallExpression(expression, parent) }
is KtBinaryExpression -> expr<UBinaryExpression> { KotlinUBinaryExpression(expression, parent) }
is KtBinaryExpression -> {
if (expression.operationToken == KtTokens.ELVIS) {
expr<UExpressionList> { createElvisExpression(expression, parent) ?: UastEmptyExpression }
}
else expr<UBinaryExpression> { KotlinUBinaryExpression(expression, parent) }
}
is KtParenthesizedExpression -> expr<UParenthesizedExpression> { KotlinUParenthesizedExpression(expression, parent) }
is KtPrefixExpression -> expr<UPrefixExpression> { KotlinUPrefixExpression(expression, parent) }
is KtPostfixExpression -> expr<UPostfixExpression> { KotlinUPostfixExpression(expression, parent) }
@@ -290,6 +284,20 @@ internal object KotlinConverter {
is KtArrayAccessExpression -> expr<UArrayAccessExpression> { KotlinUArrayAccessExpression(expression, parent) }
is KtLambdaExpression -> expr<ULambdaExpression> { KotlinULambdaExpression(expression, parent) }
is KtBinaryExpressionWithTypeRHS -> expr<UBinaryExpressionWithType> { KotlinUBinaryExpressionWithType(expression, parent) }
is KtClassOrObject -> expr<UDeclarationsExpression> {
expression.toLightClass()?.let { lightClass ->
KotlinUDeclarationsExpression(parent).apply {
declarations = listOf(KotlinUClass.create(lightClass, this))
}
} ?: UastEmptyExpression
}
is KtFunction -> if (expression.name.isNullOrEmpty()) {
expr<ULambdaExpression> { createLocalFunctionLambdaExpression(expression, parent) }
}
else {
expr<UDeclarationsExpression> { createLocalFunctionDeclaration(expression, parent) }
}
else -> UnknownKotlinExpression(expression, parent)
}}
@@ -19,9 +19,12 @@ package org.jetbrains.uast.kotlin
import com.intellij.psi.PsiAnonymousClass
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMethod
import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.asJava.toLightMethods
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.psi.KtEnumEntry
import org.jetbrains.kotlin.psi.KtObjectDeclaration
import org.jetbrains.uast.*
import org.jetbrains.uast.java.AbstractJavaUClass
@@ -31,7 +34,9 @@ class KotlinUClass private constructor(
psi: KtLightClass,
override val containingElement: UElement?
) : AbstractJavaUClass(), PsiClass by psi {
val ktClass = psi.kotlinOrigin
override val psi = unwrap<UClass, PsiClass>(psi)
override fun getOriginalElement(): PsiElement? {
@@ -40,15 +45,25 @@ class KotlinUClass private constructor(
override val uastAnchor: UElement
get() = UIdentifier(psi.nameIdentifier, this)
override val uastNestedClasses: List<UClass> by lz {
// filter DefaultImpls to avoid processing same methods from original interface multiple times
// filter Enum entry classes to avoid duplication with PsiEnumConstant initializer class
psi.innerClasses.filter {
it.name != JvmAbi.DEFAULT_IMPLS_CLASS_NAME && !it.isEnumEntryLightClass()
}.map {
getLanguagePlugin().convert<UClass>(it, this)
}
}
override val uastMethods: List<UMethod> by lz {
val primaryConstructor = ktClass?.getPrimaryConstructor()?.toLightMethods()?.firstOrNull()
val initBlocks = ktClass?.getAnonymousInitializers() ?: emptyList()
psi.methods.map {
if (it is KtLightMethod && it.isConstructor && initBlocks.isNotEmpty()
&& (primaryConstructor == null || it == primaryConstructor)) {
object : KotlinUMethod(it, this@KotlinUClass) {
fun createUMethod(psiMethod: PsiMethod): UMethod {
return if (psiMethod is KtLightMethod && psiMethod.isConstructor && initBlocks.isNotEmpty()
&& (primaryConstructor == null || psiMethod == primaryConstructor)) {
object : KotlinUMethod(psiMethod, this@KotlinUClass) {
override val uastBody by lz {
val initializers = ktClass?.getAnonymousInitializers() ?: return@lz UastEmptyExpression
val containingMethod = this
@@ -68,13 +83,21 @@ class KotlinUClass private constructor(
}
}
}
} else {
getLanguagePlugin().convert<UMethod>(psiMethod, this)
}
else {
getLanguagePlugin().convert<UMethod>(it, this)
}
}
}
fun isDelegatedMethod(psiMethod: PsiMethod) = psiMethod is KtLightMethod && psiMethod.isDelegated
psi.methods.asSequence()
.filterNot(::isDelegatedMethod)
.map(::createUMethod)
.toList()
}
private fun PsiClass.isEnumEntryLightClass() = (this as? KtLightClass)?.kotlinOrigin is KtEnumEntry
companion object {
fun create(psi: KtLightClass, containingElement: UElement?): UClass {
return if (psi is PsiAnonymousClass)
@@ -89,6 +112,7 @@ class KotlinUAnonymousClass(
psi: PsiAnonymousClass,
override val containingElement: UElement?
) : AbstractJavaUClass(), UAnonymousClass, PsiAnonymousClass by psi {
override val psi: PsiAnonymousClass = unwrap<UAnonymousClass, PsiAnonymousClass>(psi)
override fun getOriginalElement(): PsiElement? {
@@ -16,8 +16,12 @@
package org.jetbrains.uast.kotlin
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiComment
import com.intellij.psi.PsiRecursiveElementWalkingVisitor
import org.jetbrains.kotlin.asJava.findFacadeClass
import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.uast.*
import java.util.*
@@ -40,5 +44,16 @@ class KotlinUFile(override val psi: KtFile, override val languagePlugin: UastLan
}
override val imports by lz { psi.importDirectives.map { KotlinUImportStatement(it, this) } }
override val classes by lz { psi.classes.map { languagePlugin.convert<UClass>(it, this) } }
override val classes by lz {
fun PsiClass.toUClass() = languagePlugin.convert<UClass>(this, this@KotlinUFile)
val classes = psi.findFacadeClass()?.let { mutableListOf(it.toUClass()) } ?: mutableListOf()
for (declaration in psi.declarations) {
(declaration as? KtClassOrObject)?.toLightClass()?.let { classes += it.toUClass() }
}
return@lz classes
}
}
@@ -20,13 +20,12 @@ import com.intellij.psi.PsiCodeBlock
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiNameIdentifierOwner
import org.jetbrains.kotlin.asJava.elements.KtLightElement
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.asJava.elements.KtLightMethodImpl
import org.jetbrains.kotlin.asJava.elements.*
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtCallableDeclaration
import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.uast.*
import org.jetbrains.uast.java.JavaUAnnotation
import org.jetbrains.uast.java.annotations
@@ -54,7 +53,16 @@ open class KotlinUMethod(
override val uastBody by lz {
val bodyExpression = (kotlinOrigin as? KtFunction)?.bodyExpression ?: return@lz null
val bodyExpression = when (kotlinOrigin) {
is KtFunction -> kotlinOrigin.bodyExpression
is KtProperty -> when {
psi.isGetter -> kotlinOrigin.getter?.bodyExpression
psi.isSetter -> kotlinOrigin.setter?.bodyExpression
else -> null
}
else -> null
} ?: return@lz null
getLanguagePlugin().convertElement(bodyExpression, this) as? UExpression
}
@@ -65,6 +73,10 @@ open class KotlinUMethod(
override fun getOriginalElement(): PsiElement? = super.getOriginalElement()
override fun equals(other: Any?) = other is KotlinUMethod && psi == other.psi
override fun hashCode() = psi.hashCode()
companion object {
fun create(psi: KtLightMethod, containingElement: UElement?) = when (psi) {
is KtLightMethodImpl.KtLightAnnotationMethod -> KotlinUAnnotationMethod(psi, containingElement)
@@ -21,8 +21,6 @@ import org.jetbrains.kotlin.asJava.elements.KtLightElement
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.psi.KtVariableDeclaration
import org.jetbrains.uast.*
import org.jetbrains.uast.expressions.UReferenceExpression
import org.jetbrains.uast.expressions.UTypeReferenceExpression
import org.jetbrains.uast.java.AbstractJavaUVariable
import org.jetbrains.uast.java.JavaAbstractUExpression
import org.jetbrains.uast.java.JavaUAnnotation
@@ -58,6 +56,9 @@ class KotlinUVariable(
) : AbstractKotlinUVariable(), UVariable, PsiVariable by psi {
override val psi = unwrap<UVariable, PsiVariable>(psi)
override val annotations by lz { psi.annotations.map { JavaUAnnotation(it, this) } }
override val typeReference by lz { getLanguagePlugin().convertOpt<UTypeReferenceExpression>(psi.typeElement, this) }
override fun getInitializer(): PsiExpression? {
return super<AbstractKotlinUVariable>.getInitializer()
}
@@ -66,9 +67,6 @@ class KotlinUVariable(
return super<AbstractKotlinUVariable>.getOriginalElement()
}
override val annotations by lz { psi.annotations.map { JavaUAnnotation(it, this) } }
override val typeReference by lz { getLanguagePlugin().convertOpt<UTypeReferenceExpression>(psi.typeElement, this) }
companion object {
fun create(psi: PsiVariable, containingElement: UElement?): UVariable {
return when (psi) {
@@ -86,6 +84,7 @@ open class KotlinUParameter(
psi: PsiParameter,
override val containingElement: UElement?
) : AbstractKotlinUVariable(), UParameter, PsiParameter by psi {
override val psi = unwrap<UParameter, PsiParameter>(psi)
override fun getInitializer(): PsiExpression? {
@@ -95,13 +94,13 @@ open class KotlinUParameter(
override fun getOriginalElement(): PsiElement? {
return super<AbstractKotlinUVariable>.getOriginalElement()
}
}
open class KotlinUField(
psi: PsiField,
override val containingElement: UElement?
) : AbstractKotlinUVariable(), UField, PsiField by psi {
override val psi = unwrap<UField, PsiField>(psi)
override fun getInitializer(): PsiExpression? {
@@ -111,13 +110,13 @@ open class KotlinUField(
override fun getOriginalElement(): PsiElement? {
return super<AbstractKotlinUVariable>.getOriginalElement()
}
}
open class KotlinULocalVariable(
psi: PsiLocalVariable,
override val containingElement: UElement?
) : AbstractKotlinUVariable(), ULocalVariable, PsiLocalVariable by psi {
override val psi = unwrap<ULocalVariable, PsiLocalVariable>(psi)
override fun getInitializer(): PsiExpression? {
@@ -134,6 +133,8 @@ open class KotlinUEnumConstant(
psi: PsiEnumConstant,
override val containingElement: UElement?
) : AbstractKotlinUVariable(), UEnumConstant, PsiEnumConstant by psi {
override val initializingClass: UClass? by lz { getLanguagePlugin().convertOpt<UClass>(psi.initializingClass, this) }
override val psi = unwrap<UEnumConstant, PsiEnumConstant>(psi)
override fun getInitializer(): PsiExpression? {
@@ -0,0 +1,58 @@
package org.jetbrains.uast.kotlin.evaluation
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.uast.UastBinaryOperator
import org.jetbrains.uast.UastPostfixOperator
import org.jetbrains.uast.evaluation.UEvaluationInfo
import org.jetbrains.uast.evaluation.UEvaluationState
import org.jetbrains.uast.evaluation.UEvaluatorExtension
import org.jetbrains.uast.kotlin.KotlinBinaryOperators
import org.jetbrains.uast.kotlin.KotlinPostfixOperators
import org.jetbrains.uast.values.*
class KotlinEvaluatorExtension : UEvaluatorExtension {
private data class Range(val from: UValue, val to: UValue) {
override fun toString() = "$from..$to"
}
private class UClosedRangeConstant(override val value: Range) : UAbstractConstant() {
constructor(from: UValue, to: UValue): this(Range(from, to))
}
override val language: KotlinLanguage = KotlinLanguage.INSTANCE
override fun evaluatePostfix(
operator: UastPostfixOperator,
operandValue: UValue,
state: UEvaluationState
): UEvaluationInfo {
return when (operator) {
KotlinPostfixOperators.EXCLEXCL -> when (operandValue.toConstant()) {
UNullConstant -> UValue.UNREACHABLE
is UConstant -> operandValue
else -> UUndeterminedValue
} to state
else -> return super.evaluatePostfix(operator, operandValue, state)
}
}
private fun UValue.contains(value: UValue): UValue {
val range = (this as? UClosedRangeConstant)?.value ?: return UUndeterminedValue
return (value greaterOrEquals range.from) and (value lessOrEquals range.to)
}
override fun evaluateBinary(
operator: UastBinaryOperator,
leftValue: UValue,
rightValue: UValue,
state: UEvaluationState
): UEvaluationInfo {
return when (operator) {
KotlinBinaryOperators.IN -> rightValue.contains(leftValue)
KotlinBinaryOperators.NOT_IN -> !rightValue.contains(leftValue)
KotlinBinaryOperators.RANGE_TO -> UClosedRangeConstant(leftValue, rightValue)
else -> UUndeterminedValue
} to state
}
}
@@ -0,0 +1,82 @@
package org.jetbrains.uast.kotlin.expressions
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMethod
import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.uast.*
import org.jetbrains.uast.kotlin.*
import org.jetbrains.uast.kotlin.kinds.KotlinSpecialExpressionKinds
import org.jetbrains.uast.kotlin.psi.UastKotlinPsiVariable
private fun createVariableReferenceExpression(variable: UVariable, containingElement: UElement?) =
object : USimpleNameReferenceExpression {
override fun resolve(): PsiElement? = variable
override val containingElement: UElement? = containingElement
override val resolvedName: String? = variable.name
override val annotations: List<UAnnotation> = emptyList()
override val identifier: String = variable.name.orAnonymous()
}
private fun createNullLiteralExpression(containingElement: UElement?) =
object : ULiteralExpression {
override val containingElement: UElement? = containingElement
override val value: Any? = null
override val annotations: List<UAnnotation> = emptyList()
}
private fun createNotEqWithNullExpression(variable: UVariable, containingElement: UElement?) =
object : UBinaryExpression {
override val containingElement: 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? = UIdentifier(null, this)
override fun resolveOperator(): PsiMethod? = null
override val annotations: List<UAnnotation> = emptyList()
}
private fun createElvisExpressions(
left: KtExpression,
right: KtExpression,
containingElement: UElement?,
psiParent: PsiElement): List<UExpression> {
val declaration = KotlinUDeclarationsExpression(containingElement)
val tempVariable = KotlinUVariable.create(UastKotlinPsiVariable.create(left, declaration, psiParent),
declaration)
declaration.declarations = listOf(tempVariable)
val ifExpression = object : UIfExpression {
override val containingElement: UElement? = containingElement
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) }
override val isTernary: Boolean = false
override val annotations: List<UAnnotation> = emptyList()
override val ifIdentifier: UIdentifier = UIdentifier(null, this)
override val elseIdentifier: UIdentifier? = UIdentifier(null, this)
}
return listOf(declaration, ifExpression)
}
fun createElvisExpression(elvisExpression: KtBinaryExpression, containingElement: UElement?): UExpressionList? {
val left = elvisExpression.left ?: return null
val right = elvisExpression.right ?: return null
return object : UExpressionList, KotlinEvaluatableUElement, KotlinUElementWithType {
override val psi: PsiElement? = elvisExpression
override val kind = KotlinSpecialExpressionKinds.ELVIS
override val containingElement: UElement? = containingElement
override val annotations: List<UAnnotation> = emptyList()
override val expressions: List<UExpression> by lz {
createElvisExpressions(left, right, this, elvisExpression.parent)
}
override fun asRenderString(): String = kind.name + " " +
expressions.joinToString(separator = "\n", prefix = "{\n", postfix = "\n}") {
it.asRenderString().withMargin
}
}
}
@@ -0,0 +1,33 @@
/*
* 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.KtStringTemplateExpression
import org.jetbrains.uast.*
import org.jetbrains.uast.psi.PsiElementBacked
class KotlinStringTemplateUPolyadicExpression(
override val psi: KtStringTemplateExpression,
override val containingElement: UElement?
) : KotlinAbstractUExpression(),
UPolyadicExpression,
PsiElementBacked,
KotlinUElementWithType,
KotlinEvaluatableUElement {
override val operands: List<UExpression> by lz { psi.entries.map { KotlinConverter.convert(it, this) } }
override val operator = UastBinaryOperator.PLUS
}
@@ -20,11 +20,7 @@ import com.intellij.psi.PsiElement
import com.intellij.psi.PsiType
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtBinaryExpressionWithTypeRHS
import org.jetbrains.uast.UBinaryExpressionWithType
import org.jetbrains.uast.UElement
import org.jetbrains.uast.UExpression
import org.jetbrains.uast.UastBinaryExpressionWithTypeKind
import org.jetbrains.uast.expressions.UTypeReferenceExpression
import org.jetbrains.uast.*
import org.jetbrains.uast.psi.PsiElementBacked
class KotlinUBinaryExpressionWithType(
@@ -37,7 +33,7 @@ class KotlinUBinaryExpressionWithType(
override val type by lz { psi.right.toPsiType(this) }
override val typeReference by lz {
psi.right?.let { KotlinUTypeReferenceExpression(it.toPsiType(this), it, this) }
psi.right?.let { LazyKotlinUTypeReferenceExpression(it, this) { it.toPsiType(this) } }
}
override val operationKind = when (psi.operationReference.getReferencedNameElementType()) {
@@ -57,9 +53,8 @@ class KotlinCustomUBinaryExpressionWithType(
lateinit override var operationKind: UastBinaryExpressionWithTypeKind
internal set
lateinit override var type: PsiType
internal set
override val type: PsiType by lz { typeReference?.type ?: UastErrorType }
override var typeReference: UTypeReferenceExpression? = null
internal set
}
@@ -16,6 +16,7 @@
package org.jetbrains.uast.kotlin
import com.intellij.psi.PsiNamedElement
import org.jetbrains.kotlin.psi.KtCallableReferenceExpression
import org.jetbrains.kotlin.resolve.BindingContext.DOUBLE_COLON_LHS
import org.jetbrains.uast.UCallableReferenceExpression
@@ -41,4 +42,9 @@ class KotlinUCallableReferenceExpression(
override val callableName: String
get() = psi.callableReference.getReferencedName()
override val resolvedName: String?
get() = (resolve() as? PsiNamedElement)?.name
override fun resolve() = psi.callableReference.resolveCallToDeclaration(this)
}
@@ -20,7 +20,7 @@ import org.jetbrains.kotlin.psi.KtCatchClause
import org.jetbrains.uast.UCatchClause
import org.jetbrains.uast.UElement
import org.jetbrains.uast.UParameter
import org.jetbrains.uast.expressions.UTypeReferenceExpression
import org.jetbrains.uast.UTypeReferenceExpression
import org.jetbrains.uast.kotlin.psi.UastKotlinPsiParameter
import org.jetbrains.uast.psi.PsiElementBacked
@@ -37,8 +37,7 @@ class KotlinUCatchClause(
override val typeReferences by lz {
val parameter = psi.catchParameter ?: return@lz emptyList<UTypeReferenceExpression>()
val typeReference = parameter.typeReference
val type = typeReference.toPsiType(this, boxed = true)
listOf(KotlinUTypeReferenceExpression(type, typeReference, this))
val typeReference = parameter.typeReference ?: return@lz emptyList<UTypeReferenceExpression>()
listOf(LazyKotlinUTypeReferenceExpression(typeReference, this) { typeReference.toPsiType(this, boxed = true) } )
}
}
@@ -22,7 +22,6 @@ import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.psi.KtObjectLiteralExpression
import org.jetbrains.kotlin.psi.KtSuperTypeCallEntry
import org.jetbrains.uast.*
import org.jetbrains.uast.expressions.UReferenceExpression
import org.jetbrains.uast.psi.PsiElementBacked
class KotlinUObjectLiteralExpression(
@@ -31,7 +31,6 @@ import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
import org.jetbrains.kotlin.utils.addToStdlib.constant
import org.jetbrains.uast.*
import org.jetbrains.uast.expressions.UReferenceExpression
import org.jetbrains.uast.psi.PsiElementBacked
import org.jetbrains.uast.visitor.UastVisitor
@@ -67,9 +67,9 @@ class KotlinUSwitchEntry(
else -> UastBinaryExpressionWithTypeKind.INSTANCE_CHECK
}
val typeRef = it.typeReference
val type = typeRef.toPsiType(this, boxed = true)
this.type = type
typeReference = typeRef?.let { KotlinUTypeReferenceExpression(type, it, this) }
typeReference = typeRef?.let {
LazyKotlinUTypeReferenceExpression(it, this) { typeRef.toPsiType(this, boxed = true) }
}
}
is KtWhenConditionWithExpression -> KotlinConverter.convertOrEmpty(it.expression, this)
else -> UastEmptyExpression
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.psi.KtTryExpression
import org.jetbrains.uast.UElement
import org.jetbrains.uast.UIdentifier
import org.jetbrains.uast.UTryExpression
import org.jetbrains.uast.UVariable
import org.jetbrains.uast.psi.PsiElementBacked
class KotlinUTryExpression(
@@ -31,10 +32,10 @@ class KotlinUTryExpression(
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 resources: List<PsiResourceListElement>?
get() = null
override val resourceVariables: List<UVariable>
get() = emptyList()
override val isResources: Boolean
override val hasResources: Boolean
get() = false
override val tryIdentifier: UIdentifier
@@ -19,6 +19,7 @@ package org.jetbrains.uast.kotlin
import org.jetbrains.kotlin.psi.KtIsExpression
import org.jetbrains.uast.UBinaryExpressionWithType
import org.jetbrains.uast.UElement
import org.jetbrains.uast.UastBinaryExpressionWithTypeKind
import org.jetbrains.uast.psi.PsiElementBacked
class KotlinUTypeCheckExpression(
@@ -29,9 +30,13 @@ class KotlinUTypeCheckExpression(
override val type by lz { psi.typeReference.toPsiType(this) }
override val typeReference by lz {
psi.typeReference?.let { KotlinUTypeReferenceExpression(it.toPsiType(this), it, this) }
override val typeReference = psi.typeReference?.let {
LazyKotlinUTypeReferenceExpression(it, this) { it.toPsiType(this) }
}
override val operationKind = KotlinBinaryExpressionWithTypeKinds.NEGATED_INSTANCE_CHECK
override val operationKind =
if(psi.isNegated)
KotlinBinaryExpressionWithTypeKinds.NEGATED_INSTANCE_CHECK
else
UastBinaryExpressionWithTypeKind.INSTANCE_CHECK
}
@@ -3,11 +3,20 @@ package org.jetbrains.uast.kotlin
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiType
import org.jetbrains.uast.UElement
import org.jetbrains.uast.expressions.UTypeReferenceExpression
import org.jetbrains.uast.UTypeReferenceExpression
import org.jetbrains.uast.psi.PsiElementBacked
open class KotlinUTypeReferenceExpression(
override val type: PsiType,
override val psi: PsiElement?,
override val containingElement: UElement?
) : KotlinAbstractUExpression(), UTypeReferenceExpression, PsiElementBacked, KotlinUElementWithType
) : KotlinAbstractUExpression(), UTypeReferenceExpression, PsiElementBacked, KotlinUElementWithType
class LazyKotlinUTypeReferenceExpression(
override val psi: PsiElement,
override val containingElement: UElement?,
private val typeSupplier: () -> PsiType
) : KotlinAbstractUExpression(), UTypeReferenceExpression, PsiElementBacked {
override val type: PsiType by lz { typeSupplier() }
}
@@ -0,0 +1,61 @@
package org.jetbrains.uast.kotlin.expressions
import com.intellij.psi.PsiVariable
import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.uast.*
import org.jetbrains.uast.kotlin.*
import org.jetbrains.uast.kotlin.psi.UastKotlinPsiParameter
import org.jetbrains.uast.kotlin.psi.UastKotlinPsiVariable
import org.jetbrains.uast.psi.PsiElementBacked
private class KotlinLocalFunctionUVariable(
val function: KtFunction,
override val psi: PsiVariable,
override val containingElement: UElement?
) : UVariable, PsiVariable by psi {
override val uastInitializer: UExpression? by lz {
createLocalFunctionLambdaExpression(function, this)
}
override val typeReference: UTypeReferenceExpression? = null
override val uastAnchor: UElement? = null
override val annotations: List<UAnnotation> = emptyList()
override fun equals(other: Any?) = other is KotlinLocalFunctionUVariable && psi == other.psi
override fun hashCode() = psi.hashCode()
}
private class KotlinLocalFunctionULambdaExpression(
override val psi: KtFunction,
override val containingElement: UElement?
): KotlinAbstractUExpression(), ULambdaExpression, PsiElementBacked {
override val body by lz { KotlinConverter.convertOrEmpty(psi.bodyExpression, this) }
override val valueParameters by lz {
psi.valueParameters.mapIndexed { i, p ->
KotlinUParameter(UastKotlinPsiParameter.create(p, psi, this, i), this)
}
}
override fun asRenderString(): String {
val renderedValueParameters = valueParameters.joinToString(prefix = "(", postfix = ")",
transform = KotlinUParameter::asRenderString)
val expressions = (body as? UBlockExpression)?.expressions?.joinToString("\n") {
it.asRenderString().withMargin
} ?: body.asRenderString()
return "fun $renderedValueParameters {\n${expressions.withMargin}\n}"
}
}
fun createLocalFunctionDeclaration(function: KtFunction, parent: UElement?): UDeclarationsExpression {
return KotlinUDeclarationsExpression(parent).apply {
val functionVariable = UastKotlinPsiVariable.create(function.name.orAnonymous(), function, this)
declarations = listOf(KotlinLocalFunctionUVariable(function, functionVariable, this))
}
}
fun createLocalFunctionLambdaExpression(function: KtFunction, parent: UElement?): ULambdaExpression =
KotlinLocalFunctionULambdaExpression(function, parent)
@@ -20,8 +20,8 @@ import org.jetbrains.uast.UastBinaryExpressionWithTypeKind
object KotlinBinaryExpressionWithTypeKinds {
@JvmField
val NEGATED_INSTANCE_CHECK = UastBinaryExpressionWithTypeKind("!is")
val NEGATED_INSTANCE_CHECK = UastBinaryExpressionWithTypeKind.InstanceCheck("!is")
@JvmField
val SAFE_TYPE_CAST = UastBinaryExpressionWithTypeKind("!is")
val SAFE_TYPE_CAST = UastBinaryExpressionWithTypeKind.TypeCast("as?")
}
@@ -27,4 +27,7 @@ object KotlinSpecialExpressionKinds {
@JvmField
val CLASS_BODY = UastSpecialExpressionKind("class_body")
@JvmField
val ELVIS = UastSpecialExpressionKind("elvis")
}
@@ -4,10 +4,8 @@ import com.intellij.lang.Language
import com.intellij.psi.*
import org.jetbrains.kotlin.asJava.elements.LightVariableBuilder
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.psi.KtDestructuringDeclaration
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtVariableDeclaration
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.uast.UDeclaration
import org.jetbrains.uast.UElement
@@ -68,7 +66,7 @@ class UastKotlinPsiVariable(
val psiParent = containingElement.getParentOfType<UDeclaration>()?.psi ?: declaration.parent
return UastKotlinPsiVariable(
declaration.manager,
"var" + Integer.toHexString(declaration.hashCode()),
"var" + Integer.toHexString(declaration.getHashCode()),
UastErrorType, //TODO,
KotlinLanguage.INSTANCE,
declaration.initializer,
@@ -76,6 +74,32 @@ class UastKotlinPsiVariable(
containingElement,
declaration)
}
fun create(initializer: KtExpression, containingElement: UElement, parent: PsiElement): PsiVariable {
val psiParent = containingElement.getParentOfType<UDeclaration>()?.psi ?: parent
return UastKotlinPsiVariable(
initializer.manager,
"var" + Integer.toHexString(initializer.getHashCode()),
UastErrorType, //TODO,
KotlinLanguage.INSTANCE,
initializer,
psiParent,
containingElement,
initializer)
}
fun create(name: String, localFunction: KtFunction, containingElement: UElement): PsiVariable {
val psiParent = containingElement.getParentOfType<UDeclaration>()?.psi ?: localFunction.parent
return UastKotlinPsiVariable(
localFunction.manager,
name,
UastErrorType, // TODO,
KotlinLanguage.INSTANCE,
localFunction,
psiParent,
containingElement,
localFunction)
}
}
}
@@ -84,4 +108,12 @@ private class KotlinUastPsiExpression(val ktExpression: KtExpression, val parent
val ktType = ktExpression.analyze()[BindingContext.EXPRESSION_TYPE_INFO, ktExpression]?.type ?: return null
return ktType.toPsiType(parent, ktExpression, boxed = false)
}
}
private fun PsiElement.getHashCode(): Int {
var result = 42
result = 41 * result + containingFile.name.hashCode()
result = 41 * result + startOffset
result = 41 * result + text.hashCode()
return result
}