181: Uast: more implementations of UCallExpressionEx

This commit is contained in:
Nicolay Mitropolsky
2018-04-11 19:15:52 +03:00
committed by xiexed
parent bd50ad87ba
commit 83573ed517
8 changed files with 217 additions and 18 deletions
@@ -380,7 +380,7 @@ class KotlinUEnumConstant(
psi: PsiEnumConstant,
override val sourcePsi: KtElement?,
givenParent: UElement?
) : AbstractKotlinUVariable(givenParent), UEnumConstant, PsiEnumConstant by psi {
) : AbstractKotlinUVariable(givenParent), UEnumConstant, UCallExpressionEx, PsiEnumConstant by psi {
override val initializingClass: UClass? by lz {
(psi.initializingClass as? KtLightClass)?.let { initializingClass ->
@@ -458,4 +458,7 @@ class KotlinUEnumConstant(
override val identifier: String
get() = psi.containingClass?.name ?: "<error>"
}
override fun getArgumentForParameter(i: Int): UExpression? = valueArguments.getOrNull(i)
}
@@ -0,0 +1,56 @@
/*
* Copyright 2000-2018 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.kotlin.expressions
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.KotlinAbstractUExpression
import org.jetbrains.uast.kotlin.KotlinConverter
import org.jetbrains.uast.kotlin.KotlinUElementWithType
class KotlinUCollectionLiteralExpression(
override val sourcePsi: KtCollectionLiteralExpression,
givenParent: UElement?
) : KotlinAbstractUExpression(givenParent), UCallExpressionEx, 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 { KotlinConverter.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)
}
@@ -21,6 +21,7 @@ import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiType
import org.jetbrains.kotlin.asJava.LightClassUtil
import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.psi.*
@@ -97,24 +98,9 @@ class KotlinUFunctionCallExpression(
val resolvedCall = resolvedCall ?: return null
val actualParamIndex = if (resolvedCall.extensionReceiver == null) i else i - 1
if (actualParamIndex == -1) return receiver
val (parameter, resolvedArgument) = resolvedCall.valueArguments.entries.find { it.key.index == actualParamIndex } ?: return null
val arguments = resolvedArgument.arguments
if (arguments.isEmpty()) return null
if (arguments.size == 1) {
val argument = arguments.single()
val expression = argument.getArgumentExpression()
if (parameter.varargElementType != null && argument.getSpreadElement() == null) {
return createVarargsHolder(arguments, this)
}
return KotlinConverter.convertOrEmpty(expression, this)
}
return createVarargsHolder(arguments, this)
return getArgumentExpressionByIndex(actualParamIndex, resolvedCall, this)
}
private fun createVarargsHolder(arguments: List<ValueArgument>, parent: UElement?): KotlinUExpressionList =
KotlinUExpressionList(null, UastSpecialExpressionKind.VARARGS, parent).apply {
expressions = arguments.map { KotlinConverter.convertOrEmpty(it.getArgumentExpression(), parent) }
}
override val typeArgumentCount: Int
get() = psi.typeArguments.size
@@ -171,3 +157,27 @@ class KotlinUFunctionCallExpression(
}
}
internal fun getArgumentExpressionByIndex(
actualParamIndex: Int,
resolvedCall: ResolvedCall<out CallableDescriptor>,
parent: UElement
): UExpression? {
val (parameter, resolvedArgument) = resolvedCall.valueArguments.entries.find { it.key.index == actualParamIndex } ?: return null
val arguments = resolvedArgument.arguments
if (arguments.isEmpty()) return null
if (arguments.size == 1) {
val argument = arguments.single()
val expression = argument.getArgumentExpression()
if (parameter.varargElementType != null && argument.getSpreadElement() == null) {
return createVarargsHolder(arguments, parent)
}
return KotlinConverter.convertOrEmpty(expression, parent)
}
return createVarargsHolder(arguments, parent)
}
private fun createVarargsHolder(arguments: List<ValueArgument>, parent: UElement?): KotlinUExpressionList =
KotlinUExpressionList(null, UastSpecialExpressionKind.VARARGS, parent).apply {
expressions = arguments.map { KotlinConverter.convertOrEmpty(it.getArgumentExpression(), parent) }
}
@@ -0,0 +1,102 @@
/*
* 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.openapi.diagnostic.Attachment
import com.intellij.openapi.diagnostic.Logger
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiType
import com.intellij.psi.impl.light.LightPsiClassBuilder
import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.psi.KtObjectLiteralExpression
import org.jetbrains.kotlin.psi.KtSuperTypeCallEntry
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.uast.*
class KotlinUObjectLiteralExpression(
override val psi: KtObjectLiteralExpression,
givenParent: UElement?
) : KotlinAbstractUExpression(givenParent), UObjectLiteralExpression, UCallExpressionEx, KotlinUElementWithType {
override val declaration: UClass by lz {
val lightClass: KtLightClass? = psi.objectDeclaration.toLightClass()
if (lightClass != null) {
getLanguagePlugin().convert<UClass>(lightClass, this)
}
else {
logger.error(
"Failed to create light class for object declaration",
Attachment(psi.containingFile.virtualFile?.path ?: "<no path>", psi.containingFile.text))
getLanguagePlugin().convert(LightPsiClassBuilder(psi, "<unnamed>"), this)
}
}
override fun getExpressionType() = psi.objectDeclaration.toPsiType()
private val superClassConstructorCall by lz {
psi.objectDeclaration.superTypeListEntries.firstOrNull { it is KtSuperTypeCallEntry } as? KtSuperTypeCallEntry
}
override val classReference: UReferenceExpression? by lz { superClassConstructorCall?.let { ObjectLiteralClassReference(it, this) } }
override val valueArgumentCount: Int
get() = superClassConstructorCall?.valueArguments?.size ?: 0
override val valueArguments by lz {
val psi = superClassConstructorCall ?: return@lz emptyList<UExpression>()
psi.valueArguments.map { KotlinConverter.convertOrEmpty(it.getArgumentExpression(), this) }
}
override val typeArgumentCount: Int
get() = superClassConstructorCall?.typeArguments?.size ?: 0
override val typeArguments by lz {
val psi = superClassConstructorCall ?: return@lz emptyList<PsiType>()
psi.typeArguments.map { it.typeReference.toPsiType(this, boxed = true) }
}
override fun resolve() = superClassConstructorCall?.resolveCallToDeclaration(this) as? PsiMethod
override fun getArgumentForParameter(i: Int): UExpression? =
superClassConstructorCall?.let { it.getResolvedCall(it.analyze()) }?.let { getArgumentExpressionByIndex(i, it, this) }
private class ObjectLiteralClassReference(
override val psi: KtSuperTypeCallEntry,
givenParent: UElement?
) : KotlinAbstractUElement(givenParent), USimpleNameReferenceExpression {
override val javaPsi = null
override val sourcePsi = psi
override fun resolve() = (psi.resolveCallToDeclaration(this) as? PsiMethod)?.containingClass
override val annotations: List<UAnnotation>
get() = emptyList()
override val resolvedName: String?
get() = identifier
override val identifier: String
get() = psi.name ?: "<error>"
}
companion object {
val logger by lz { Logger.getInstance(KotlinUObjectLiteralExpression::class.java) }
}
}
@@ -25,4 +25,11 @@ class A {
fun String.with2Receivers(a: Int, b: Float) {}
}
open class Parent(a: String, b: Int)
fun objectLiteral() {
object : Parent(b = 1, a = "foo")
}
@@ -138,6 +138,13 @@ UFile (package = )
USimpleNameReferenceExpression (identifier = with2Receivers)
ULiteralExpression (value = 8)
ULiteralExpression (value = 7.0)
UAnnotationMethod (name = objectLiteral)
UBlockExpression
UObjectLiteralExpression
ULiteralExpression (value = 1)
ULiteralExpression (value = "foo")
UClass (name = null)
UAnnotationMethod (name = ParametersDisorderKt$objectLiteral$1)
UClass (name = A)
UAnnotationMethod (name = with2Receivers)
UParameter (name = $receiver)
@@ -148,3 +155,9 @@ UFile (package = )
UAnnotation (fqName = org.jetbrains.annotations.NotNull)
UBlockExpression
UAnnotationMethod (name = A)
UClass (name = Parent)
UAnnotationMethod (name = Parent)
UParameter (name = a)
UAnnotation (fqName = org.jetbrains.annotations.NotNull)
UParameter (name = b)
UAnnotation (fqName = org.jetbrains.annotations.NotNull)
@@ -19,6 +19,10 @@ public final class ParametersDisorderKt {
"def".with2Receivers(8, 7.0)
})
}
public static final fun objectLiteral() : void {
anonymous object : Parent(b = 1, a = "foo")
}
}
public final class A {
@@ -26,3 +30,7 @@ public final class A {
}
public fun A() = UastEmptyExpression
}
public class Parent {
public fun Parent(@org.jetbrains.annotations.NotNull a: java.lang.String, @org.jetbrains.annotations.NotNull b: int) = UastEmptyExpression
}
@@ -6,7 +6,6 @@ import com.intellij.testFramework.UsefulTestCase
import org.jetbrains.kotlin.asJava.toLightAnnotation
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
import org.jetbrains.kotlin.psi.psiUtil.getValueParameterList
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase
import org.jetbrains.kotlin.utils.addToStdlib.cast
import org.jetbrains.uast.*
@@ -338,6 +337,7 @@ class KotlinUastApiTest : AbstractKotlinUastTest() {
)
assertArguments(listOf("\"%i %i %i\"", "\"\".chunked(2).toTypedArray()"), "format(\"%i %i %i\", *\"\".chunked(2).toTypedArray())")
assertArguments(listOf("\"def\"", "8", "7.0"), "with2Receivers(8, 7.0F)")
assertArguments(listOf("\"foo\"", "1"), "object : Parent(b = 1, a = \"foo\")\n")
}
}