UAST: Fix annotation arguments processing
multiple unnamed arguments represented as value named expression with array initializer call kind for array in annotation argument should be "array initializer" instead of "method call" #KT-16600 Fixed Target Versions 1.1.5
This commit is contained in:
+27
-22
@@ -1,30 +1,39 @@
|
||||
package org.jetbrains.uast.kotlin
|
||||
|
||||
import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
||||
import org.jetbrains.kotlin.psi.KtParameter
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass
|
||||
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||
import org.jetbrains.uast.*
|
||||
|
||||
class KotlinUAnnotation(
|
||||
override val psi: KtAnnotationEntry,
|
||||
override val uastParent: UElement?
|
||||
) : UAnnotation {
|
||||
private val resolvedAnnotation by lz { psi.analyze()[BindingContext.ANNOTATION, psi] }
|
||||
private val resolvedAnnotation: AnnotationDescriptor? by lz { psi.analyze()[BindingContext.ANNOTATION, psi] }
|
||||
|
||||
private val resolvedCall: ResolvedCall<*>? by lz { psi.getResolvedCall(psi.analyze()) }
|
||||
|
||||
override val qualifiedName: String?
|
||||
get() = resolvedAnnotation?.fqName?.asString()
|
||||
|
||||
override val attributeValues by lz {
|
||||
val context = getUastContext()
|
||||
psi.valueArguments.map { arg ->
|
||||
val name = arg.getArgumentName()?.asName?.asString() ?: ""
|
||||
KotlinUNamedExpression(name, this).apply {
|
||||
val value = arg.getArgumentExpression()?.let { context.convertElement(it, this) } as? UExpression
|
||||
expression = value ?: UastEmptyExpression
|
||||
override val attributeValues: List<UNamedExpression> by lz {
|
||||
resolvedCall?.valueArguments?.entries?.mapNotNull {
|
||||
val arguments = it.value.arguments
|
||||
val name = it.key.name.asString()
|
||||
when {
|
||||
arguments.size == 1 ->
|
||||
KotlinUNamedExpression.create(name, arguments.first(), this)
|
||||
arguments.size > 1 ->
|
||||
KotlinUNamedExpression.create(name, arguments, this)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
} ?: emptyList()
|
||||
}
|
||||
|
||||
override fun resolve(): PsiClass? {
|
||||
@@ -32,20 +41,16 @@ class KotlinUAnnotation(
|
||||
return descriptor.toSource()?.getMaybeLightElement(this) as? PsiClass
|
||||
}
|
||||
|
||||
//TODO
|
||||
override fun findAttributeValue(name: String?) = findDeclaredAttributeValue(name)
|
||||
override fun findAttributeValue(name: String?): UExpression? =
|
||||
findDeclaredAttributeValue(name)
|
||||
|
||||
override fun findDeclaredAttributeValue(name: String?): UExpression? {
|
||||
return attributeValues.firstOrNull { it.name == (name ?: "value") }?.expression
|
||||
return attributeValues.find {
|
||||
it.name == name ||
|
||||
(name == null && it.name == "value") ||
|
||||
(name == "value" && it.name == null)
|
||||
}?.expression
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class KotlinUNamedExpression(override val name: String, override val uastParent: UElement?) : UNamedExpression {
|
||||
override lateinit var expression: UExpression
|
||||
|
||||
override val annotations: List<UAnnotation>
|
||||
get() = emptyList()
|
||||
|
||||
override val psi: PsiElement?
|
||||
get() = null
|
||||
}
|
||||
|
||||
+14
-6
@@ -23,9 +23,9 @@ import org.jetbrains.kotlin.asJava.LightClassUtil
|
||||
import org.jetbrains.kotlin.asJava.toLightClass
|
||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtCallExpression
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtFunction
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||
import org.jetbrains.kotlin.resolve.CompileTimeConstantUtils
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.uast.*
|
||||
@@ -89,9 +89,11 @@ class KotlinUFunctionCallExpression(
|
||||
override val returnType: PsiType?
|
||||
get() = getExpressionType()
|
||||
|
||||
override val kind by lz {
|
||||
when (resolvedCall?.resultingDescriptor) {
|
||||
is ConstructorDescriptor -> UastCallKind.CONSTRUCTOR_CALL
|
||||
override val kind: UastCallKind by lz {
|
||||
val resolvedCall = resolvedCall ?: return@lz UastCallKind.METHOD_CALL
|
||||
when {
|
||||
resolvedCall.resultingDescriptor is ConstructorDescriptor -> UastCallKind.CONSTRUCTOR_CALL
|
||||
this.isAnnotationArgumentArrayInitializer() -> UastCallKind.NESTED_ARRAY_INITIALIZER
|
||||
else -> UastCallKind.METHOD_CALL
|
||||
}
|
||||
}
|
||||
@@ -118,4 +120,10 @@ class KotlinUFunctionCallExpression(
|
||||
|
||||
visitor.afterVisitCallExpression(this)
|
||||
}
|
||||
|
||||
private fun isAnnotationArgumentArrayInitializer(): Boolean {
|
||||
val resolvedCall = resolvedCall ?: return false
|
||||
// KtAnnotationEntry -> KtValueArgumentList -> KtValueArgument -> arrayOf call
|
||||
return psi.parents.elementAtOrNull(2) is KtAnnotationEntry && CompileTimeConstantUtils.isArrayFunctionCall(resolvedCall)
|
||||
}
|
||||
}
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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 com.intellij.psi.PsiType
|
||||
import org.jetbrains.kotlin.psi.ValueArgument
|
||||
import org.jetbrains.uast.*
|
||||
|
||||
class KotlinUNamedExpression private constructor(
|
||||
override val name: String?,
|
||||
override val uastParent: UElement?,
|
||||
expressionProducer: (UElement) -> UExpression
|
||||
) : UNamedExpression {
|
||||
override val expression: UExpression by lz { expressionProducer(this) }
|
||||
|
||||
override val annotations: List<UAnnotation> = emptyList()
|
||||
|
||||
override val psi: PsiElement? = null
|
||||
|
||||
companion object {
|
||||
internal fun create(name: String?, valueArgument: ValueArgument, uastParent: UElement?): UNamedExpression {
|
||||
val expression = valueArgument.getArgumentExpression()
|
||||
return KotlinUNamedExpression(name, uastParent) { expressionParent ->
|
||||
expression?.let { expressionParent.getLanguagePlugin().convert<UExpression>(it, expressionParent) } ?: UastEmptyExpression
|
||||
}
|
||||
}
|
||||
|
||||
internal fun create(
|
||||
name: String?,
|
||||
valueArguments: List<ValueArgument>,
|
||||
uastParent: UElement?): UNamedExpression {
|
||||
return KotlinUNamedExpression(name, uastParent) { expressionParent ->
|
||||
object : KotlinAbstractUExpression(), 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+14
-1
@@ -1,5 +1,18 @@
|
||||
|
||||
annotation class IntRange(val from: Long, val to: Long)
|
||||
|
||||
annotation class RequiresPermission(val anyOf: IntArray)
|
||||
|
||||
annotation class WithDefaultValue(val value: Int = 42)
|
||||
|
||||
annotation class SuppressLint(vararg val value: String)
|
||||
|
||||
@RequiresPermission(anyOf = intArrayOf(1, 2, 3))
|
||||
@IntRange(from = 10, to = 0)
|
||||
fun foo(): Int = 5
|
||||
@WithDefaultValue
|
||||
@SuppressLint("Lorem")
|
||||
fun foo(): Int = 5
|
||||
|
||||
@IntRange(0, 100)
|
||||
@SuppressLint("Lorem", "Ipsum", "Dolor")
|
||||
fun bar() = Unit
|
||||
@@ -1,12 +1,44 @@
|
||||
UFile (package = )
|
||||
UClass (name = AnnotationParametersKt)
|
||||
UAnnotationMethod (name = foo)
|
||||
UAnnotation (fqName = RequiresPermission)
|
||||
UNamedExpression (name = anyOf)
|
||||
UCallExpression (kind = UastCallKind(name='array_initializer'), argCount = 3))
|
||||
UIdentifier (Identifier (intArrayOf))
|
||||
USimpleNameReferenceExpression (identifier = intArrayOf)
|
||||
ULiteralExpression (value = 1)
|
||||
ULiteralExpression (value = 2)
|
||||
ULiteralExpression (value = 3)
|
||||
UAnnotation (fqName = IntRange)
|
||||
UNamedExpression (name = from)
|
||||
ULiteralExpression (value = 10)
|
||||
UNamedExpression (name = to)
|
||||
ULiteralExpression (value = 0)
|
||||
UAnnotation (fqName = WithDefaultValue)
|
||||
UAnnotation (fqName = SuppressLint)
|
||||
UNamedExpression (name = value)
|
||||
ULiteralExpression (value = "Lorem")
|
||||
ULiteralExpression (value = 5)
|
||||
UAnnotationMethod (name = bar)
|
||||
UAnnotation (fqName = IntRange)
|
||||
UNamedExpression (name = from)
|
||||
ULiteralExpression (value = 0)
|
||||
UNamedExpression (name = to)
|
||||
ULiteralExpression (value = 100)
|
||||
UAnnotation (fqName = SuppressLint)
|
||||
UNamedExpression (name = value)
|
||||
UCallExpression (kind = UastCallKind(name='array_initializer'), argCount = 3))
|
||||
ULiteralExpression (value = "Lorem")
|
||||
ULiteralExpression (value = "Ipsum")
|
||||
ULiteralExpression (value = "Dolor")
|
||||
USimpleNameReferenceExpression (identifier = Unit)
|
||||
UClass (name = IntRange)
|
||||
UAnnotationMethod (name = from)
|
||||
UAnnotationMethod (name = to)
|
||||
UClass (name = RequiresPermission)
|
||||
UAnnotationMethod (name = anyOf)
|
||||
UClass (name = WithDefaultValue)
|
||||
UAnnotationMethod (name = value)
|
||||
ULiteralExpression (value = 42)
|
||||
UClass (name = SuppressLint)
|
||||
UAnnotationMethod (name = value)
|
||||
|
||||
@@ -1,9 +1,27 @@
|
||||
public final class AnnotationParametersKt {
|
||||
@RequiresPermission(anyOf = intArrayOf(1, 2, 3))
|
||||
@IntRange(from = 10, to = 0)
|
||||
@WithDefaultValue
|
||||
@SuppressLint(value = "Lorem")
|
||||
public static final fun foo() : int = 5
|
||||
@IntRange(from = 0, to = 100)
|
||||
@SuppressLint(value = <noref>("Lorem", "Ipsum", "Dolor"))
|
||||
public static final fun bar() : void = Unit
|
||||
}
|
||||
|
||||
public abstract annotation IntRange {
|
||||
public abstract fun from() : long = UastEmptyExpression
|
||||
public abstract fun to() : long = UastEmptyExpression
|
||||
}
|
||||
|
||||
public abstract annotation RequiresPermission {
|
||||
public abstract fun anyOf() : int[] = UastEmptyExpression
|
||||
}
|
||||
|
||||
public abstract annotation WithDefaultValue {
|
||||
public abstract fun value() : int = UastEmptyExpression
|
||||
}
|
||||
|
||||
public abstract annotation SuppressLint {
|
||||
public abstract fun value() : java.lang.String[] = UastEmptyExpression
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user