Work in progress on consistent UAST structure
This commit is contained in:
@@ -16,16 +16,31 @@
|
||||
|
||||
package org.jetbrains.uast.kotlin
|
||||
|
||||
import org.jetbrains.kotlin.psi.KtAnnotatedExpression
|
||||
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
||||
import org.jetbrains.kotlin.psi.KtValueArgument
|
||||
import org.jetbrains.uast.UAnnotation
|
||||
import org.jetbrains.uast.UElement
|
||||
import org.jetbrains.uast.UExpression
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.uast.*
|
||||
|
||||
abstract class KotlinAbstractUElement(private val givenParent: UElement?) : UElement {
|
||||
|
||||
override val uastParent: UElement? by lz { convertParent(givenParent) }
|
||||
override val uastParent: UElement? by lz {
|
||||
givenParent ?: convertParent()
|
||||
}
|
||||
|
||||
protected open fun convertParent(): UElement? {
|
||||
var parent = psi?.parent ?: psi?.containingFile
|
||||
|
||||
if (parent is KtStringTemplateExpression && parent.entries.size == 1) {
|
||||
parent = parent.parent
|
||||
}
|
||||
|
||||
val result = doConvertParent(this, parent)
|
||||
if (result == this) {
|
||||
throw IllegalStateException("Loop in parent structure when converting a $psi")
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other !is UElement) {
|
||||
@@ -38,25 +53,35 @@ abstract class KotlinAbstractUElement(private val givenParent: UElement?) : UEle
|
||||
override fun hashCode() = psi?.hashCode() ?: 0
|
||||
}
|
||||
|
||||
internal fun UElement.convertParent(givenParent: UElement?): UElement? {
|
||||
return if (givenParent != null)
|
||||
givenParent
|
||||
else {
|
||||
val parent = psi?.parent
|
||||
val result = KotlinConverter.unwrapElements(parent)?.let { parentUnwrapped ->
|
||||
if (parent is KtValueArgument && parentUnwrapped is KtAnnotationEntry) {
|
||||
val argumentName = parent.getArgumentName()?.asName?.asString() ?: ""
|
||||
(KotlinUastLanguagePlugin().convertElementWithParent(parentUnwrapped, null) as? UAnnotation)
|
||||
?.attributeValues?.find { it.name == argumentName }
|
||||
}
|
||||
else
|
||||
KotlinUastLanguagePlugin().convertElementWithParent(parentUnwrapped, null)
|
||||
}
|
||||
if (result == this) {
|
||||
throw IllegalStateException("Loop in parent structure")
|
||||
}
|
||||
result
|
||||
fun doConvertParent(element: UElement, parent: PsiElement?): UElement? {
|
||||
val parentUnwrapped = KotlinConverter.unwrapElements(parent) ?: return null
|
||||
if (parent is KtValueArgument && parentUnwrapped is KtAnnotationEntry) {
|
||||
return (KotlinUastLanguagePlugin().convertElementWithParent(parentUnwrapped, null) as? KotlinUAnnotation)
|
||||
?.findAttributeValueExpression(parent)
|
||||
}
|
||||
|
||||
if (parent is KtParameter) {
|
||||
val annotationClass = findAnnotationClassFromConstructorParameter(parent)
|
||||
if (annotationClass != null) {
|
||||
return annotationClass.methods.find { it.name == parent.name }
|
||||
}
|
||||
}
|
||||
|
||||
val result = KotlinUastLanguagePlugin().convertElementWithParent(parentUnwrapped, null)
|
||||
|
||||
if (result is UEnumConstant && element is UDeclaration) {
|
||||
return result.initializingClass
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun findAnnotationClassFromConstructorParameter(parameter: KtParameter): UClass? {
|
||||
val primaryConstructor = parameter.getStrictParentOfType<KtPrimaryConstructor>() ?: return null
|
||||
val containingClass = primaryConstructor.getContainingClassOrObject()
|
||||
if (containingClass.isAnnotation()) {
|
||||
return KotlinUastLanguagePlugin().convertElementWithParent(containingClass, null) as UClass
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
abstract class KotlinAbstractUExpression(givenParent: UElement?)
|
||||
@@ -67,4 +92,5 @@ abstract class KotlinAbstractUExpression(givenParent: UElement?)
|
||||
val annotatedExpression = psi?.parent as? KtAnnotatedExpression ?: return emptyList()
|
||||
return annotatedExpression.annotationEntries.map { KotlinUAnnotation(it, this) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -137,13 +137,20 @@ class KotlinUastLanguagePlugin : UastLanguagePlugin {
|
||||
return with(requiredType) {
|
||||
when (original) {
|
||||
is KtLightMethod -> el<UMethod>(build(KotlinUMethod.Companion::create)) // .Companion is needed because of KT-13934
|
||||
is KtLightClass -> el<UClass>(build(KotlinUClass.Companion::create))
|
||||
is KtLightClass -> el<UDeclaration> {
|
||||
(original.kotlinOrigin as? KtEnumEntry)?.let { enumEntry ->
|
||||
convertEnumEntry(enumEntry, givenParent)
|
||||
} ?: KotlinUClass.create(original, givenParent)
|
||||
}
|
||||
|
||||
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 KtEnumEntry -> el<UEnumConstant> {
|
||||
convertEnumEntry(original, givenParent)
|
||||
}
|
||||
is KtClassOrObject -> el<UClass> {
|
||||
original.toLightClass()?.let { lightClass ->
|
||||
KotlinUClass.create(lightClass, givenParent)
|
||||
@@ -154,13 +161,18 @@ class KotlinUastLanguagePlugin : UastLanguagePlugin {
|
||||
convertDeclaration(lightMethod, givenParent, requiredType)
|
||||
}
|
||||
is KtPropertyAccessor -> el<UMethod> {
|
||||
javaPlugin.convertOpt<UMethod>(
|
||||
LightClassUtil.getLightClassAccessorMethod(original), givenParent)
|
||||
val lightMethod = LightClassUtil.getLightClassAccessorMethod(original) ?: return null
|
||||
convertDeclaration(lightMethod, givenParent, requiredType)
|
||||
}
|
||||
is KtProperty -> el<UField> {
|
||||
javaPlugin.convertOpt<UField>(
|
||||
LightClassUtil.getLightClassBackingField(original), givenParent)
|
||||
?: convertDeclaration(element.parent, givenParent, requiredType)
|
||||
is KtProperty -> el<UVariable> {
|
||||
if (original.isLocal) {
|
||||
KotlinConverter.convertPsiElement(element, givenParent, requiredType)
|
||||
}
|
||||
else {
|
||||
LightClassUtil.getLightClassBackingField(original)?.let {
|
||||
KotlinUField(it, givenParent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is KtFile -> el<UFile> { KotlinUFile(original, this@KotlinUastLanguagePlugin) }
|
||||
@@ -171,6 +183,17 @@ class KotlinUastLanguagePlugin : UastLanguagePlugin {
|
||||
}
|
||||
}
|
||||
|
||||
private fun convertEnumEntry(original: KtEnumEntry, givenParent: UElement?): UElement? {
|
||||
return LightClassUtil.getLightClassBackingField(original)?.let { psiField ->
|
||||
if (psiField is KtLightFieldImpl.KtLightEnumConstant) {
|
||||
KotlinUEnumConstant(psiField, givenParent)
|
||||
}
|
||||
else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun isExpressionValueUsed(element: UExpression): Boolean {
|
||||
return when (element) {
|
||||
is KotlinUSimpleReferenceExpression.KotlinAccessorCallExpression -> element.setterValue != null
|
||||
@@ -191,14 +214,13 @@ internal inline fun <reified ActualT : UElement> Class<out UElement>?.expr(f: ()
|
||||
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 tailrec fun unwrapElements(element: PsiElement?): PsiElement? = when (element) {
|
||||
is KtValueArgumentList -> unwrapElements(element.parent)
|
||||
is KtValueArgument -> unwrapElements(element.parent)
|
||||
is KtDeclarationModifierList -> unwrapElements(element.parent)
|
||||
is KtContainerNode -> unwrapElements(element.parent)
|
||||
is KtSimpleNameStringTemplateEntry -> unwrapElements(element.parent)
|
||||
else -> element
|
||||
}
|
||||
|
||||
@@ -220,6 +242,9 @@ internal object KotlinConverter {
|
||||
}
|
||||
is KtClassBody -> el<UExpressionList>(build(KotlinUExpressionList.Companion::createClassBody))
|
||||
is KtCatchClause -> el<UCatchClause>(build(::KotlinUCatchClause))
|
||||
is KtVariableDeclaration -> el<UVariable> {
|
||||
convertVariablesDeclaration(element, givenParent).declarations.singleOrNull()
|
||||
}
|
||||
is KtExpression -> KotlinConverter.convertExpression(element, givenParent, requiredType)
|
||||
is KtLambdaArgument -> KotlinConverter.convertExpression(element.getLambdaExpression(), givenParent, requiredType)
|
||||
is KtLightAnnotationForSourceEntry.LightExpressionValue<*> -> {
|
||||
@@ -231,6 +256,9 @@ internal object KotlinConverter {
|
||||
}
|
||||
is KtLiteralStringTemplateEntry, is KtEscapeStringTemplateEntry -> el<ULiteralExpression>(build(::KotlinStringULiteralExpression))
|
||||
is KtStringTemplateEntry -> element.expression?.let { convertExpression(it, givenParent, requiredType) } ?: expr<UExpression> { UastEmptyExpression }
|
||||
is KtWhenEntry -> el<USwitchClauseExpressionWithBody>(build(::KotlinUSwitchEntry))
|
||||
is KtWhenCondition -> convertWhenCondition(element, givenParent)
|
||||
is KtTypeReference -> el<UTypeReferenceExpression> { LazyKotlinUTypeReferenceExpression(element, givenParent) }
|
||||
|
||||
else -> {
|
||||
if (element is LeafPsiElement && element.elementType == KtTokens.IDENTIFIER) {
|
||||
@@ -349,7 +377,33 @@ internal object KotlinConverter {
|
||||
else -> expr<UExpression>(build(::UnknownKotlinExpression))
|
||||
}}
|
||||
}
|
||||
|
||||
|
||||
internal fun convertWhenCondition(condition: KtWhenCondition, givenParent: UElement?): UExpression {
|
||||
return when (condition) {
|
||||
is KtWhenConditionInRange -> KotlinCustomUBinaryExpression(condition, givenParent).apply {
|
||||
leftOperand = KotlinStringUSimpleReferenceExpression("it", this)
|
||||
operator = when {
|
||||
condition.isNegated -> KotlinBinaryOperators.NOT_IN
|
||||
else -> KotlinBinaryOperators.IN
|
||||
}
|
||||
rightOperand = KotlinConverter.convertOrEmpty(condition.rangeExpression, this)
|
||||
}
|
||||
is KtWhenConditionIsPattern -> KotlinCustomUBinaryExpressionWithType(condition, givenParent).apply {
|
||||
operand = KotlinStringUSimpleReferenceExpression("it", this)
|
||||
operationKind = when {
|
||||
condition.isNegated -> KotlinBinaryExpressionWithTypeKinds.NEGATED_INSTANCE_CHECK
|
||||
else -> UastBinaryExpressionWithTypeKind.INSTANCE_CHECK
|
||||
}
|
||||
val typeRef = condition.typeReference
|
||||
typeReference = typeRef?.let {
|
||||
LazyKotlinUTypeReferenceExpression(it, this) { typeRef.toPsiType(this, boxed = true) }
|
||||
}
|
||||
}
|
||||
is KtWhenConditionWithExpression -> KotlinConverter.convertOrEmpty(condition.expression, givenParent)
|
||||
else -> UastEmptyExpression
|
||||
}
|
||||
}
|
||||
|
||||
internal fun convertOrEmpty(expression: KtExpression?, parent: UElement?): UExpression {
|
||||
return expression?.let { convertExpression(it, parent, null) } ?: UastEmptyExpression
|
||||
}
|
||||
@@ -376,7 +430,7 @@ private fun convertVariablesDeclaration(
|
||||
psi: KtVariableDeclaration,
|
||||
parent: UElement?
|
||||
): UDeclarationsExpression {
|
||||
val declarationsExpression = KotlinUDeclarationsExpression(parent)
|
||||
val declarationsExpression = KotlinUDeclarationsExpression(null, parent, psi)
|
||||
val parentPsiElement = parent?.psi
|
||||
val variable = KotlinUAnnotatedLocalVariable(
|
||||
UastKotlinPsiVariable.create(psi, parentPsiElement, declarationsExpression), declarationsExpression) { annotationParent ->
|
||||
|
||||
@@ -4,8 +4,10 @@ import com.intellij.psi.PsiClass
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
||||
import org.jetbrains.kotlin.psi.KtParameter
|
||||
import org.jetbrains.kotlin.psi.ValueArgument
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass
|
||||
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||
@@ -44,6 +46,14 @@ class KotlinUAnnotation(
|
||||
override fun findAttributeValue(name: String?): UExpression? =
|
||||
findDeclaredAttributeValue(name) ?: findAttributeDefaultValue(name ?: "value")
|
||||
|
||||
fun findAttributeValueExpression(arg: ValueArgument): UExpression? {
|
||||
val mapping = resolvedCall?.getArgumentMapping(arg)
|
||||
return (mapping as? ArgumentMatch)?.let { match ->
|
||||
val namedExpression = attributeValues.find { it.name == match.valueParameter.name.asString() }
|
||||
namedExpression?.expression as? KotlinUVarargExpression ?: namedExpression
|
||||
}
|
||||
}
|
||||
|
||||
override fun findDeclaredAttributeValue(name: String?): UExpression? {
|
||||
return attributeValues.find {
|
||||
it.name == name ||
|
||||
|
||||
@@ -28,15 +28,19 @@ import org.jetbrains.uast.java.AbstractJavaUClass
|
||||
import org.jetbrains.uast.kotlin.declarations.KotlinUMethod
|
||||
import org.jetbrains.uast.kotlin.declarations.UastLightIdentifier
|
||||
|
||||
abstract class AbstractKotlinUClass(private val givenParent: UElement?) : AbstractJavaUClass() {
|
||||
override val uastParent: UElement? by lz {
|
||||
givenParent ?: KotlinUastLanguagePlugin().convertElementWithParent(psi.parent ?: psi.containingFile, null)
|
||||
}
|
||||
}
|
||||
|
||||
open class KotlinUClass private constructor(
|
||||
psi: KtLightClass,
|
||||
private val givenParent: UElement?
|
||||
) : AbstractJavaUClass(), PsiClass by psi {
|
||||
givenParent: UElement?
|
||||
) : AbstractKotlinUClass(givenParent), PsiClass by psi {
|
||||
|
||||
val ktClass = psi.kotlinOrigin
|
||||
|
||||
override val uastParent: UElement? by lz { convertParent(givenParent) }
|
||||
|
||||
override val psi = unwrap<UClass, PsiClass>(psi)
|
||||
|
||||
override fun getOriginalElement(): PsiElement? = super.getOriginalElement()
|
||||
@@ -56,8 +60,8 @@ open class KotlinUClass private constructor(
|
||||
// filter Enum entry classes to avoid duplication with PsiEnumConstant initializer class
|
||||
return psi.innerClasses.filter {
|
||||
it.name != JvmAbi.DEFAULT_IMPLS_CLASS_NAME && !it.isEnumEntryLightClass()
|
||||
}.map {
|
||||
getLanguagePlugin().convert<UClass>(it, this)
|
||||
}.mapNotNull {
|
||||
getLanguagePlugin().convertOpt<UClass>(it, this)
|
||||
}.toTypedArray()
|
||||
}
|
||||
|
||||
@@ -112,20 +116,18 @@ open class KotlinUClass private constructor(
|
||||
|
||||
class KotlinUAnonymousClass(
|
||||
psi: PsiAnonymousClass,
|
||||
private val givenParent: UElement?
|
||||
) : AbstractJavaUClass(), UAnonymousClass, PsiAnonymousClass by psi {
|
||||
|
||||
override val uastParent: UElement? by lz { convertParent(givenParent) }
|
||||
|
||||
givenParent: UElement?
|
||||
) : AbstractKotlinUClass(givenParent), UAnonymousClass, PsiAnonymousClass by psi {
|
||||
|
||||
override val psi: PsiAnonymousClass = unwrap<UAnonymousClass, PsiAnonymousClass>(psi)
|
||||
|
||||
override fun getOriginalElement(): PsiElement? = super<AbstractJavaUClass>.getOriginalElement()
|
||||
override fun getOriginalElement(): PsiElement? = super<AbstractKotlinUClass>.getOriginalElement()
|
||||
|
||||
override fun getSuperClass(): UClass? = super<AbstractJavaUClass>.getSuperClass()
|
||||
override fun getFields(): Array<UField> = super<AbstractJavaUClass>.getFields()
|
||||
override fun getMethods(): Array<UMethod> = super<AbstractJavaUClass>.getMethods()
|
||||
override fun getInitializers(): Array<UClassInitializer> = super<AbstractJavaUClass>.getInitializers()
|
||||
override fun getInnerClasses(): Array<UClass> = super<AbstractJavaUClass>.getInnerClasses()
|
||||
override fun getSuperClass(): UClass? = super<AbstractKotlinUClass>.getSuperClass()
|
||||
override fun getFields(): Array<UField> = super<AbstractKotlinUClass>.getFields()
|
||||
override fun getMethods(): Array<UMethod> = super<AbstractKotlinUClass>.getMethods()
|
||||
override fun getInitializers(): Array<UClassInitializer> = super<AbstractKotlinUClass>.getInitializers()
|
||||
override fun getInnerClasses(): Array<UClass> = super<AbstractKotlinUClass>.getInnerClasses()
|
||||
|
||||
override fun getContainingFile(): PsiFile = unwrapFakeFileForLightClass(psi.containingFile)
|
||||
|
||||
|
||||
@@ -49,8 +49,8 @@ class KotlinUFile(override val psi: KtFile, override val languagePlugin: UastLan
|
||||
val facadeOrScriptClass = if (psi.isScript()) psi.script?.toLightClass() else psi.findFacadeClass()
|
||||
val classes = psi.declarations.mapNotNull { (it as? KtClassOrObject)?.toLightClass()?.toUClass() }
|
||||
|
||||
(facadeOrScriptClass?.let { listOf(it.toUClass()) } ?: emptyList()) + classes
|
||||
(facadeOrScriptClass?.toUClass()?.let { listOf(it) } ?: emptyList()) + classes
|
||||
}
|
||||
|
||||
private fun PsiClass.toUClass() = languagePlugin.convert<UClass>(this, this@KotlinUFile)
|
||||
private fun PsiClass.toUClass() = languagePlugin.convertOpt<UClass>(this, this@KotlinUFile)
|
||||
}
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.uast.kotlin
|
||||
|
||||
import com.intellij.psi.*
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClass
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightElement
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtParameter
|
||||
@@ -215,6 +216,13 @@ open class KotlinUEnumConstant(
|
||||
psi: PsiEnumConstant,
|
||||
givenParent: UElement?
|
||||
) : AbstractKotlinUVariable(givenParent), UEnumConstant, PsiEnumConstant by psi {
|
||||
override val initializingClass: UClass? by lz {
|
||||
(psi.initializingClass as? KtLightClass)?.let { initializingClass ->
|
||||
KotlinUClass.create(initializingClass, this)
|
||||
}
|
||||
}
|
||||
|
||||
override val psi = unwrap<UEnumConstant, PsiEnumConstant>(psi)
|
||||
|
||||
override fun getContainingFile(): PsiFile {
|
||||
return super.getContainingFile()
|
||||
@@ -224,10 +232,6 @@ open class KotlinUEnumConstant(
|
||||
return super.getNameIdentifier()
|
||||
}
|
||||
|
||||
override val initializingClass: UClass? by lz { getLanguagePlugin().convertOpt<UClass>(psi.initializingClass, this) }
|
||||
|
||||
override val psi = unwrap<UEnumConstant, PsiEnumConstant>(psi)
|
||||
|
||||
override val kind: UastCallKind
|
||||
get() = UastCallKind.CONSTRUCTOR_CALL
|
||||
|
||||
@@ -270,7 +274,10 @@ open class KotlinUEnumConstant(
|
||||
override val psi: PsiEnumConstant,
|
||||
private val givenParent: UElement?
|
||||
) : JavaAbstractUExpression(), USimpleNameReferenceExpression {
|
||||
override val uastParent: UElement? by lz { convertParent(givenParent) }
|
||||
override val uastParent: UElement? by lz {
|
||||
givenParent ?: KotlinUastLanguagePlugin().convertElementWithParent(psi.parent ?: psi.containingFile, null)
|
||||
}
|
||||
|
||||
override fun resolve() = psi.containingClass
|
||||
override val resolvedName: String?
|
||||
get() = psi.containingClass?.name
|
||||
|
||||
@@ -68,14 +68,13 @@ private fun createElvisExpressions(
|
||||
return listOf(declaration, ifExpression)
|
||||
}
|
||||
|
||||
fun createElvisExpression(elvisExpression: KtBinaryExpression, containingElement: UElement?): UExpression {
|
||||
fun createElvisExpression(elvisExpression: KtBinaryExpression, givenParent: UElement?): UExpression {
|
||||
val left = elvisExpression.left ?: return UastEmptyExpression
|
||||
val right = elvisExpression.right ?: return UastEmptyExpression
|
||||
|
||||
return object : UExpressionList, KotlinEvaluatableUElement {
|
||||
return object : KotlinAbstractUElement(givenParent), UExpressionList, KotlinEvaluatableUElement {
|
||||
override val psi: PsiElement? = elvisExpression
|
||||
override val kind = KotlinSpecialExpressionKinds.ELVIS
|
||||
override val uastParent: UElement? = containingElement
|
||||
override val annotations: List<UAnnotation> = emptyList()
|
||||
override val expressions: List<UExpression> by lz {
|
||||
createElvisExpressions(left, right, this, elvisExpression.parent)
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ class KotlinUBinaryExpressionWithType(
|
||||
override val type by lz { psi.right.toPsiType(this) }
|
||||
|
||||
override val typeReference by lz {
|
||||
psi.right?.let { LazyKotlinUTypeReferenceExpression(it, this) { it.toPsiType(this) } }
|
||||
psi.right?.let { LazyKotlinUTypeReferenceExpression(it, this) }
|
||||
}
|
||||
|
||||
override val operationKind = when (psi.operationReference.getReferencedNameElementType()) {
|
||||
|
||||
+6
-1
@@ -17,12 +17,17 @@ package org.jetbrains.uast
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.uast.kotlin.KotlinAbstractUExpression
|
||||
import org.jetbrains.uast.kotlin.doConvertParent
|
||||
|
||||
class KotlinUDeclarationsExpression(
|
||||
override val psi: PsiElement?,
|
||||
givenParent: UElement?
|
||||
givenParent: UElement?,
|
||||
val psiAnchor: PsiElement? = null
|
||||
) : KotlinAbstractUExpression(givenParent), UDeclarationsExpression {
|
||||
|
||||
override val uastParent: UElement?
|
||||
get() = if (psiAnchor != null) doConvertParent(this, psiAnchor.parent) else super.uastParent
|
||||
|
||||
constructor(uastParent: UElement?) : this(null, uastParent)
|
||||
|
||||
override lateinit var declarations: List<UDeclaration>
|
||||
|
||||
+2
-1
@@ -20,6 +20,7 @@ import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.KtNodeTypes
|
||||
import org.jetbrains.kotlin.psi.KtConstantExpression
|
||||
import org.jetbrains.kotlin.psi.KtEscapeStringTemplateEntry
|
||||
import org.jetbrains.kotlin.psi.KtStringTemplateExpression
|
||||
import org.jetbrains.uast.UElement
|
||||
import org.jetbrains.uast.ULiteralExpression
|
||||
|
||||
@@ -45,4 +46,4 @@ class KotlinStringULiteralExpression(
|
||||
get() = text
|
||||
|
||||
override fun evaluate() = value
|
||||
}
|
||||
}
|
||||
|
||||
+46
-46
@@ -45,52 +45,52 @@ class KotlinUNamedExpression private constructor(
|
||||
valueArguments: List<ValueArgument>,
|
||||
uastParent: UElement?): UNamedExpression {
|
||||
return KotlinUNamedExpression(name, uastParent) { expressionParent ->
|
||||
object : KotlinAbstractUExpression(uastParent), UCallExpression {
|
||||
override val uastParent: UElement? = expressionParent
|
||||
|
||||
override val kind: UastCallKind = UastCallKind.NESTED_ARRAY_INITIALIZER
|
||||
|
||||
override val valueArguments: List<UExpression> by lz {
|
||||
valueArguments.map {
|
||||
it.getArgumentExpression()?.let { argumentExpression ->
|
||||
getLanguagePlugin().convert<UExpression>(argumentExpression, this)
|
||||
} ?: UastEmptyExpression
|
||||
}
|
||||
}
|
||||
|
||||
override val valueArgumentCount: Int
|
||||
get() = valueArguments.size
|
||||
|
||||
override val psi: PsiElement?
|
||||
get() = null
|
||||
|
||||
override val methodIdentifier: UIdentifier?
|
||||
get() = null
|
||||
|
||||
override val classReference: UReferenceExpression?
|
||||
get() = null
|
||||
|
||||
override val methodName: String?
|
||||
get() = null
|
||||
|
||||
override val typeArgumentCount: Int
|
||||
get() = 0
|
||||
|
||||
override val typeArguments: List<PsiType>
|
||||
get() = emptyList()
|
||||
|
||||
override val returnType: PsiType?
|
||||
get() = null
|
||||
|
||||
override fun resolve() = null
|
||||
|
||||
override val receiver: UExpression?
|
||||
get() = null
|
||||
|
||||
override val receiverType: PsiType?
|
||||
get() = null
|
||||
}
|
||||
KotlinUVarargExpression(valueArguments, expressionParent)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
class KotlinUVarargExpression(private val valueArgs: List<ValueArgument>,
|
||||
uastParent: UElement?) : KotlinAbstractUExpression(uastParent), UCallExpression {
|
||||
override val kind: UastCallKind = UastCallKind.NESTED_ARRAY_INITIALIZER
|
||||
|
||||
override val valueArguments: List<UExpression> by lz {
|
||||
valueArgs.map {
|
||||
it.getArgumentExpression()?.let { argumentExpression ->
|
||||
getLanguagePlugin().convert<UExpression>(argumentExpression, this)
|
||||
} ?: UastEmptyExpression
|
||||
}
|
||||
}
|
||||
|
||||
override val valueArgumentCount: Int
|
||||
get() = valueArgs.size
|
||||
|
||||
override val psi: PsiElement?
|
||||
get() = null
|
||||
|
||||
override val methodIdentifier: UIdentifier?
|
||||
get() = null
|
||||
|
||||
override val classReference: UReferenceExpression?
|
||||
get() = null
|
||||
|
||||
override val methodName: String?
|
||||
get() = null
|
||||
|
||||
override val typeArgumentCount: Int
|
||||
get() = 0
|
||||
|
||||
override val typeArguments: List<PsiType>
|
||||
get() = emptyList()
|
||||
|
||||
override val returnType: PsiType?
|
||||
get() = null
|
||||
|
||||
override fun resolve() = null
|
||||
|
||||
override val receiver: UExpression?
|
||||
get() = null
|
||||
|
||||
override val receiverType: PsiType?
|
||||
get() = null
|
||||
}
|
||||
|
||||
+12
-25
@@ -17,7 +17,9 @@
|
||||
package org.jetbrains.uast.kotlin
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
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.kinds.KotlinSpecialExpressionKinds
|
||||
|
||||
@@ -48,32 +50,10 @@ class KotlinUSwitchExpression(
|
||||
|
||||
class KotlinUSwitchEntry(
|
||||
override val psi: KtWhenEntry,
|
||||
givenParent: UExpression
|
||||
givenParent: UElement?
|
||||
) : KotlinAbstractUExpression(givenParent), USwitchClauseExpressionWithBody {
|
||||
override val caseValues by lz {
|
||||
psi.conditions.map { when (it) {
|
||||
is KtWhenConditionInRange -> KotlinCustomUBinaryExpression(it, this).apply {
|
||||
leftOperand = KotlinStringUSimpleReferenceExpression("it", this)
|
||||
operator = when {
|
||||
it.isNegated -> KotlinBinaryOperators.NOT_IN
|
||||
else -> KotlinBinaryOperators.IN
|
||||
}
|
||||
rightOperand = KotlinConverter.convertOrEmpty(it.rangeExpression, this)
|
||||
}
|
||||
is KtWhenConditionIsPattern -> KotlinCustomUBinaryExpressionWithType(it, this).apply {
|
||||
operand = KotlinStringUSimpleReferenceExpression("it", this)
|
||||
operationKind = when {
|
||||
it.isNegated -> KotlinBinaryExpressionWithTypeKinds.NEGATED_INSTANCE_CHECK
|
||||
else -> UastBinaryExpressionWithTypeKind.INSTANCE_CHECK
|
||||
}
|
||||
val typeRef = it.typeReference
|
||||
typeReference = typeRef?.let {
|
||||
LazyKotlinUTypeReferenceExpression(it, this) { typeRef.toPsiType(this, boxed = true) }
|
||||
}
|
||||
}
|
||||
is KtWhenConditionWithExpression -> KotlinConverter.convertOrEmpty(it.expression, this)
|
||||
else -> UastEmptyExpression
|
||||
}}
|
||||
psi.conditions.map { KotlinConverter.convertWhenCondition(it, this) }
|
||||
}
|
||||
|
||||
override val body: UExpressionList by lz {
|
||||
@@ -101,4 +81,11 @@ class KotlinUSwitchEntry(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun convertParent(): UElement? {
|
||||
val result = KotlinConverter.unwrapElements(psi.parent)?.let { parentUnwrapped ->
|
||||
KotlinUastLanguagePlugin().convertElementWithParent(parentUnwrapped, null)
|
||||
}
|
||||
return (result as? KotlinUSwitchExpression)?.body ?: result
|
||||
}
|
||||
}
|
||||
+7
-4
@@ -2,6 +2,7 @@ package org.jetbrains.uast.kotlin
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiType
|
||||
import org.jetbrains.kotlin.psi.KtTypeReference
|
||||
import org.jetbrains.uast.UElement
|
||||
import org.jetbrains.uast.UTypeReferenceExpression
|
||||
|
||||
@@ -13,9 +14,11 @@ open class KotlinUTypeReferenceExpression(
|
||||
|
||||
|
||||
class LazyKotlinUTypeReferenceExpression(
|
||||
override val psi: PsiElement,
|
||||
override val psi: KtTypeReference,
|
||||
givenParent: UElement?,
|
||||
private val typeSupplier: () -> PsiType
|
||||
private val typeSupplier: (() -> PsiType)? = null
|
||||
) : KotlinAbstractUExpression(givenParent), UTypeReferenceExpression {
|
||||
override val type: PsiType by lz { typeSupplier() }
|
||||
}
|
||||
override val type: PsiType by lz {
|
||||
typeSupplier?.invoke() ?: psi.toPsiType(uastParent ?: this)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,9 +7,11 @@ import org.jetbrains.kotlin.builtins.createFunctionType
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.uast.*
|
||||
import org.jetbrains.kotlin.types.isError
|
||||
import org.jetbrains.uast.UDeclaration
|
||||
import org.jetbrains.uast.UElement
|
||||
@@ -73,10 +75,11 @@ class UastKotlinPsiVariable private constructor(
|
||||
fun create(
|
||||
declaration: KtVariableDeclaration,
|
||||
parent: PsiElement?,
|
||||
containingElement: UElement,
|
||||
containingElement: KotlinUDeclarationsExpression,
|
||||
initializer: KtExpression? = null
|
||||
): PsiLocalVariable {
|
||||
val psiParent = containingElement.getParentOfType<UDeclaration>()?.psi ?: parent
|
||||
val psi = containingElement.psiAnchor ?: containingElement.psi
|
||||
val psiParent = psi?.getNonStrictParentOfType<KtDeclaration>() ?: parent
|
||||
val initializerExpression = initializer ?: declaration.initializer
|
||||
return UastKotlinPsiVariable(
|
||||
manager = declaration.manager,
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
fun foo(a: Int = 1, foo: String? = null) {
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
UFile (package = )
|
||||
UClass (name = DefaultParameterValuesKt)
|
||||
UAnnotationMethod (name = foo)
|
||||
UParameter (name = a)
|
||||
UAnnotation (fqName = null)
|
||||
ULiteralExpression (value = 1)
|
||||
UParameter (name = foo)
|
||||
UAnnotation (fqName = org.jetbrains.annotations.Nullable)
|
||||
ULiteralExpression (value = null)
|
||||
UBlockExpression
|
||||
@@ -0,0 +1,4 @@
|
||||
public final class DefaultParameterValuesKt {
|
||||
public static final fun foo(a: int, foo: java.lang.String) : void {
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,14 @@
|
||||
package org.jetbrains.uast.test.kotlin
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiRecursiveElementVisitor
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.assertedCast
|
||||
import org.jetbrains.uast.UDeclaration
|
||||
import org.jetbrains.uast.UElement
|
||||
import org.jetbrains.uast.UFile
|
||||
import org.jetbrains.uast.kotlin.KOTLIN_CACHED_UELEMENT_KEY
|
||||
import org.jetbrains.uast.kotlin.KotlinUastLanguagePlugin
|
||||
import org.jetbrains.uast.test.common.RenderLogTestBase
|
||||
import org.jetbrains.uast.visitor.UastVisitor
|
||||
@@ -21,12 +23,7 @@ abstract class AbstractKotlinRenderLogTest : AbstractKotlinUastTest(), RenderLog
|
||||
override fun check(testName: String, file: UFile) {
|
||||
super.check(testName, file)
|
||||
|
||||
file.psi.accept(object : PsiRecursiveElementVisitor() {
|
||||
override fun visitElement(element: PsiElement) {
|
||||
KotlinUastLanguagePlugin().convertElementWithParent(element, null)
|
||||
super.visitElement(element)
|
||||
}
|
||||
})
|
||||
val parentMap = mutableMapOf<PsiElement, String>()
|
||||
|
||||
file.accept(object : UastVisitor {
|
||||
private val parentStack = Stack<UElement>()
|
||||
@@ -39,6 +36,11 @@ abstract class AbstractKotlinRenderLogTest : AbstractKotlinUastTest(), RenderLog
|
||||
else {
|
||||
Assert.assertEquals("Wrong parent of $node", parentStack.peek(), parent)
|
||||
}
|
||||
node.psi?.let {
|
||||
if (it !in parentMap) {
|
||||
parentMap[it] = parentStack.reversed().joinToString { it.asLogString() }
|
||||
}
|
||||
}
|
||||
parentStack.push(node)
|
||||
return false
|
||||
}
|
||||
@@ -48,6 +50,22 @@ abstract class AbstractKotlinRenderLogTest : AbstractKotlinUastTest(), RenderLog
|
||||
parentStack.pop()
|
||||
}
|
||||
})
|
||||
|
||||
file.psi.clearUastCaches()
|
||||
|
||||
file.psi.accept(object : PsiRecursiveElementVisitor() {
|
||||
override fun visitElement(element: PsiElement) {
|
||||
val uElement = KotlinUastLanguagePlugin().convertElementWithParent(element, null)
|
||||
val expectedParents = parentMap[element]
|
||||
if (expectedParents != null) {
|
||||
assertNotNull("Expected to be able to convert PSI element $element", uElement)
|
||||
val parents = generateSequence(uElement!!.uastParent) { it.uastParent }.joinToString { it.asLogString() }
|
||||
assertEquals("Inconsistent parents for $uElement", expectedParents, parents)
|
||||
}
|
||||
super.visitElement(element)
|
||||
}
|
||||
})
|
||||
|
||||
file.checkContainingFileForAllElements()
|
||||
}
|
||||
|
||||
@@ -68,3 +86,12 @@ abstract class AbstractKotlinRenderLogTest : AbstractKotlinUastTest(), RenderLog
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun PsiFile.clearUastCaches() {
|
||||
accept(object : PsiRecursiveElementVisitor() {
|
||||
override fun visitElement(element: PsiElement) {
|
||||
super.visitElement(element)
|
||||
element.putUserData(KOTLIN_CACHED_UELEMENT_KEY, null)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -39,6 +39,8 @@ class SimpleKotlinRenderLogTest : AbstractKotlinRenderLogTest() {
|
||||
|
||||
@Test fun testDestructuringDeclaration() = doTest("DestructuringDeclaration")
|
||||
|
||||
@Test fun testDefaultParameterValues() = doTest("DefaultParameterValues")
|
||||
|
||||
@Test fun testParameterPropertyWithAnnotation() = doTest("ParameterPropertyWithAnnotation")
|
||||
|
||||
@Test fun testParametersWithDefaultValues() = doTest("ParametersWithDefaultValues")
|
||||
|
||||
Reference in New Issue
Block a user