Uast: property resolve arrayOf in nested annotations (KT-29434)
This commit is contained in:
committed by
xiexed
parent
4ffeff5e6c
commit
a3ea7bcd3b
+7
-2
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
|||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.parents
|
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||||
import org.jetbrains.kotlin.resolve.CompileTimeConstantUtils
|
import org.jetbrains.kotlin.resolve.CompileTimeConstantUtils
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||||
@@ -204,8 +205,12 @@ class KotlinUFunctionCallExpression(
|
|||||||
|
|
||||||
private fun isAnnotationArgumentArrayInitializer(): Boolean {
|
private fun isAnnotationArgumentArrayInitializer(): Boolean {
|
||||||
val resolvedCall = resolvedCall ?: return false
|
val resolvedCall = resolvedCall ?: return false
|
||||||
// KtAnnotationEntry -> KtValueArgumentList -> KtValueArgument -> arrayOf call
|
// KtAnnotationEntry (or KtCallExpression when annotation is nested) -> KtValueArgumentList -> KtValueArgument -> arrayOf call
|
||||||
return psi.parents.elementAtOrNull(2) is KtAnnotationEntry && CompileTimeConstantUtils.isArrayFunctionCall(resolvedCall)
|
return when (val elementAt2 = psi.parents.elementAtOrNull(2)) {
|
||||||
|
is KtAnnotationEntry -> true
|
||||||
|
is KtCallExpression -> elementAt2.getParentOfType<KtAnnotationEntry>(true, KtDeclaration::class.java) != null
|
||||||
|
else -> false
|
||||||
|
} && CompileTimeConstantUtils.isArrayFunctionCall(resolvedCall)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun convertParent(): UElement? = super.convertParent().let { result ->
|
override fun convertParent(): UElement? = super.convertParent().let { result ->
|
||||||
|
|||||||
+7
-2
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
|||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.parents
|
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||||
import org.jetbrains.kotlin.resolve.CompileTimeConstantUtils
|
import org.jetbrains.kotlin.resolve.CompileTimeConstantUtils
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||||
@@ -148,8 +149,12 @@ class KotlinUFunctionCallExpression(
|
|||||||
|
|
||||||
private fun isAnnotationArgumentArrayInitializer(): Boolean {
|
private fun isAnnotationArgumentArrayInitializer(): Boolean {
|
||||||
val resolvedCall = resolvedCall ?: return false
|
val resolvedCall = resolvedCall ?: return false
|
||||||
// KtAnnotationEntry -> KtValueArgumentList -> KtValueArgument -> arrayOf call
|
// KtAnnotationEntry (or KtCallExpression when annotation is nested) -> KtValueArgumentList -> KtValueArgument -> arrayOf call
|
||||||
return psi.parents.elementAtOrNull(2) is KtAnnotationEntry && CompileTimeConstantUtils.isArrayFunctionCall(resolvedCall)
|
return when (val elementAt2 = psi.parents.elementAtOrNull(2)) {
|
||||||
|
is KtAnnotationEntry -> true
|
||||||
|
is KtCallExpression -> elementAt2.getParentOfType<KtAnnotationEntry>(true, KtDeclaration::class.java) != null
|
||||||
|
else -> false
|
||||||
|
} && CompileTimeConstantUtils.isArrayFunctionCall(resolvedCall)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun convertParent(): UElement? = super.convertParent().let { result ->
|
override fun convertParent(): UElement? = super.convertParent().let { result ->
|
||||||
|
|||||||
+7
-4
@@ -1,4 +1,4 @@
|
|||||||
annotation class Annotation
|
annotation class Annotation(vararg val strings: String)
|
||||||
|
|
||||||
@Annotation
|
@Annotation
|
||||||
class A
|
class A
|
||||||
@@ -8,10 +8,13 @@ annotation class AnnotationInner(val value: Annotation)
|
|||||||
@AnnotationArray(Annotation())
|
@AnnotationArray(Annotation())
|
||||||
class B1
|
class B1
|
||||||
|
|
||||||
@AnnotationArray(value = Annotation())
|
@AnnotationArray(value = Annotation("sv1", "sv2"))
|
||||||
class B2
|
class B2
|
||||||
|
|
||||||
annotation class AnnotationArray(vararg val value: Annotation)
|
annotation class AnnotationArray(vararg val value: Annotation)
|
||||||
|
|
||||||
@AnnotationArray(Annotation())
|
@AnnotationArray(Annotation(strings = arrayOf("sar1", "sar2")))
|
||||||
class C
|
class C
|
||||||
|
|
||||||
|
@AnnotationArray(Annotation(strings = ["[sar]1", "[sar]2"]))
|
||||||
|
class C2
|
||||||
+21
-2
@@ -1,5 +1,6 @@
|
|||||||
UFile (package = )
|
UFile (package = )
|
||||||
UClass (name = Annotation)
|
UClass (name = Annotation)
|
||||||
|
UAnnotationMethod (name = strings)
|
||||||
UClass (name = A)
|
UClass (name = A)
|
||||||
UAnnotation (fqName = Annotation)
|
UAnnotation (fqName = Annotation)
|
||||||
UAnnotationMethod (name = A)
|
UAnnotationMethod (name = A)
|
||||||
@@ -15,16 +16,34 @@ UFile (package = )
|
|||||||
UClass (name = B2)
|
UClass (name = B2)
|
||||||
UAnnotation (fqName = AnnotationArray)
|
UAnnotation (fqName = AnnotationArray)
|
||||||
UNamedExpression (name = value)
|
UNamedExpression (name = value)
|
||||||
UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0))
|
UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 2))
|
||||||
UIdentifier (Identifier (Annotation))
|
UIdentifier (Identifier (Annotation))
|
||||||
USimpleNameReferenceExpression (identifier = <init>)
|
USimpleNameReferenceExpression (identifier = <init>)
|
||||||
|
ULiteralExpression (value = "sv1")
|
||||||
|
ULiteralExpression (value = "sv2")
|
||||||
UAnnotationMethod (name = B2)
|
UAnnotationMethod (name = B2)
|
||||||
UClass (name = AnnotationArray)
|
UClass (name = AnnotationArray)
|
||||||
UAnnotationMethod (name = value)
|
UAnnotationMethod (name = value)
|
||||||
UClass (name = C)
|
UClass (name = C)
|
||||||
UAnnotation (fqName = AnnotationArray)
|
UAnnotation (fqName = AnnotationArray)
|
||||||
UNamedExpression (name = value)
|
UNamedExpression (name = value)
|
||||||
UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0))
|
UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 1))
|
||||||
UIdentifier (Identifier (Annotation))
|
UIdentifier (Identifier (Annotation))
|
||||||
USimpleNameReferenceExpression (identifier = <init>)
|
USimpleNameReferenceExpression (identifier = <init>)
|
||||||
|
UCallExpression (kind = UastCallKind(name='array_initializer'), argCount = 2))
|
||||||
|
UIdentifier (Identifier (arrayOf))
|
||||||
|
USimpleNameReferenceExpression (identifier = arrayOf)
|
||||||
|
ULiteralExpression (value = "sar1")
|
||||||
|
ULiteralExpression (value = "sar2")
|
||||||
UAnnotationMethod (name = C)
|
UAnnotationMethod (name = C)
|
||||||
|
UClass (name = C2)
|
||||||
|
UAnnotation (fqName = AnnotationArray)
|
||||||
|
UNamedExpression (name = value)
|
||||||
|
UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 1))
|
||||||
|
UIdentifier (Identifier (Annotation))
|
||||||
|
USimpleNameReferenceExpression (identifier = <init>)
|
||||||
|
UCallExpression (kind = UastCallKind(name='array_initializer'), argCount = 2))
|
||||||
|
UIdentifier (Identifier ([))
|
||||||
|
ULiteralExpression (value = "[sar]1")
|
||||||
|
ULiteralExpression (value = "[sar]2")
|
||||||
|
UAnnotationMethod (name = C2)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
public abstract annotation Annotation {
|
public abstract annotation Annotation {
|
||||||
|
public abstract fun strings() : java.lang.String[] = UastEmptyExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class A {
|
public final class A {
|
||||||
@@ -24,3 +25,7 @@ public abstract annotation AnnotationArray {
|
|||||||
public final class C {
|
public final class C {
|
||||||
public fun C() = UastEmptyExpression
|
public fun C() = UastEmptyExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final class C2 {
|
||||||
|
public fun C2() = UastEmptyExpression
|
||||||
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import org.jetbrains.uast.test.env.kotlin.findElementByTextFromPsi
|
|||||||
import org.jetbrains.uast.visitor.AbstractUastVisitor
|
import org.jetbrains.uast.visitor.AbstractUastVisitor
|
||||||
import org.junit.Assert
|
import org.junit.Assert
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
import kotlin.test.fail as kfail
|
||||||
|
|
||||||
|
|
||||||
class KotlinUastApiTest : AbstractKotlinUastTest() {
|
class KotlinUastApiTest : AbstractKotlinUastTest() {
|
||||||
@@ -297,8 +298,8 @@ class KotlinUastApiTest : AbstractKotlinUastTest() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testNestedAnnotation() = doTest("AnnotationComplex") { _, file ->
|
fun testNestedAnnotation() = doTest("AnnotationComplex") { _, file ->
|
||||||
file.findElementByTextFromPsi<UElement>("@AnnotationArray(value = Annotation())")
|
file.findElementByTextFromPsi<UElement>("@AnnotationArray(value = Annotation(\"sv1\", \"sv2\"))")
|
||||||
.findElementByTextFromPsi<UElement>("Annotation()")
|
.findElementByTextFromPsi<UElement>("Annotation(\"sv1\", \"sv2\")")
|
||||||
.sourcePsiElement
|
.sourcePsiElement
|
||||||
.let { referenceExpression ->
|
.let { referenceExpression ->
|
||||||
val convertedUAnnotation = referenceExpression
|
val convertedUAnnotation = referenceExpression
|
||||||
@@ -315,6 +316,44 @@ class KotlinUastApiTest : AbstractKotlinUastTest() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testNestedAnnotationParameters() = doTest("AnnotationComplex") { _, file ->
|
||||||
|
|
||||||
|
fun UFile.annotationAndParam(refText: String, check: (PsiAnnotation, String?) -> Unit) {
|
||||||
|
findElementByTextFromPsi<UElement>(refText)
|
||||||
|
.let { expression ->
|
||||||
|
val (annotation: PsiAnnotation, paramname: String?) =
|
||||||
|
getContainingAnnotationEntry(expression) ?: kfail("annotation not found for '$refText' ($expression)")
|
||||||
|
check(annotation, paramname)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
file.annotationAndParam("sv1") { annotation, paramname ->
|
||||||
|
assertEquals("Annotation", annotation.qualifiedName)
|
||||||
|
assertEquals(null, paramname)
|
||||||
|
}
|
||||||
|
file.annotationAndParam("sv2") { annotation, paramname ->
|
||||||
|
assertEquals("Annotation", annotation.qualifiedName)
|
||||||
|
assertEquals(null, paramname)
|
||||||
|
}
|
||||||
|
file.annotationAndParam("sar1") { annotation, paramname ->
|
||||||
|
assertEquals("Annotation", annotation.qualifiedName)
|
||||||
|
assertEquals("strings", paramname)
|
||||||
|
}
|
||||||
|
file.annotationAndParam("sar2") { annotation, paramname ->
|
||||||
|
assertEquals("Annotation", annotation.qualifiedName)
|
||||||
|
assertEquals("strings", paramname)
|
||||||
|
}
|
||||||
|
file.annotationAndParam("[sar]1") { annotation, paramname ->
|
||||||
|
assertEquals("Annotation", annotation.qualifiedName)
|
||||||
|
assertEquals("strings", paramname)
|
||||||
|
}
|
||||||
|
file.annotationAndParam("[sar]2") { annotation, paramname ->
|
||||||
|
assertEquals("Annotation", annotation.qualifiedName)
|
||||||
|
assertEquals("strings", paramname)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testParametersDisorder() = doTest("ParametersDisorder") { _, file ->
|
fun testParametersDisorder() = doTest("ParametersDisorder") { _, file ->
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import org.jetbrains.uast.test.env.kotlin.findElementByTextFromPsi
|
|||||||
import org.jetbrains.uast.visitor.AbstractUastVisitor
|
import org.jetbrains.uast.visitor.AbstractUastVisitor
|
||||||
import org.junit.Assert
|
import org.junit.Assert
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
import kotlin.test.fail as kfail
|
||||||
|
|
||||||
|
|
||||||
class KotlinUastApiTest : AbstractKotlinUastTest() {
|
class KotlinUastApiTest : AbstractKotlinUastTest() {
|
||||||
@@ -297,8 +298,8 @@ class KotlinUastApiTest : AbstractKotlinUastTest() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testNestedAnnotation() = doTest("AnnotationComplex") { _, file ->
|
fun testNestedAnnotation() = doTest("AnnotationComplex") { _, file ->
|
||||||
file.findElementByTextFromPsi<UElement>("@AnnotationArray(value = Annotation())")
|
file.findElementByTextFromPsi<UElement>("@AnnotationArray(value = Annotation(\"sv1\", \"sv2\"))")
|
||||||
.findElementByTextFromPsi<UElement>("Annotation()")
|
.findElementByTextFromPsi<UElement>("Annotation(\"sv1\", \"sv2\")")
|
||||||
.sourcePsiElement
|
.sourcePsiElement
|
||||||
.let { referenceExpression ->
|
.let { referenceExpression ->
|
||||||
val convertedUAnnotation = referenceExpression
|
val convertedUAnnotation = referenceExpression
|
||||||
@@ -315,6 +316,44 @@ class KotlinUastApiTest : AbstractKotlinUastTest() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testNestedAnnotationParameters() = doTest("AnnotationComplex") { _, file ->
|
||||||
|
|
||||||
|
fun UFile.annotationAndParam(refText: String, check: (PsiAnnotation, String?) -> Unit) {
|
||||||
|
findElementByTextFromPsi<UElement>(refText)
|
||||||
|
.let { expression ->
|
||||||
|
val (annotation: PsiAnnotation, paramname: String?) =
|
||||||
|
getContainingAnnotationEntry(expression) ?: kfail("annotation not found for '$refText' ($expression)")
|
||||||
|
check(annotation, paramname)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
file.annotationAndParam("sv1") { annotation, paramname ->
|
||||||
|
assertEquals("Annotation", annotation.qualifiedName)
|
||||||
|
assertEquals(null, paramname)
|
||||||
|
}
|
||||||
|
file.annotationAndParam("sv2") { annotation, paramname ->
|
||||||
|
assertEquals("Annotation", annotation.qualifiedName)
|
||||||
|
assertEquals(null, paramname)
|
||||||
|
}
|
||||||
|
file.annotationAndParam("sar1") { annotation, paramname ->
|
||||||
|
assertEquals("Annotation", annotation.qualifiedName)
|
||||||
|
assertEquals("strings", paramname)
|
||||||
|
}
|
||||||
|
file.annotationAndParam("sar2") { annotation, paramname ->
|
||||||
|
assertEquals("Annotation", annotation.qualifiedName)
|
||||||
|
assertEquals("strings", paramname)
|
||||||
|
}
|
||||||
|
file.annotationAndParam("[sar]1") { annotation, paramname ->
|
||||||
|
assertEquals("Annotation", annotation.qualifiedName)
|
||||||
|
assertEquals("strings", paramname)
|
||||||
|
}
|
||||||
|
file.annotationAndParam("[sar]2") { annotation, paramname ->
|
||||||
|
assertEquals("Annotation", annotation.qualifiedName)
|
||||||
|
assertEquals("strings", paramname)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testParametersDisorder() = doTest("ParametersDisorder") { _, file ->
|
fun testParametersDisorder() = doTest("ParametersDisorder") { _, file ->
|
||||||
|
|||||||
Reference in New Issue
Block a user