AA FIR: handle (aliased)? annotation w/ vararg parameter
This commit is contained in:
committed by
Nikolay Krasko
parent
032153c673
commit
56a5d883c0
+12
@@ -56,6 +56,12 @@ public class Fe10IdeNormalAnalysisSourceModuleAnalysisApiAnnotationsOnDeclaratio
|
||||
@TestMetadata("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class Direct {
|
||||
@Test
|
||||
@TestMetadata("aliasedThrowsOnFunction.kt")
|
||||
public void testAliasedThrowsOnFunction() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct/aliasedThrowsOnFunction.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllFilesPresentInDirect() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct"), Pattern.compile("^(.+)\\.kt$"), null, true);
|
||||
@@ -84,6 +90,12 @@ public class Fe10IdeNormalAnalysisSourceModuleAnalysisApiAnnotationsOnDeclaratio
|
||||
public void testOnTypeAlias() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct/onTypeAlias.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("varargParameter.kt")
|
||||
public void testVarargParameter() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct/varargParameter.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
+47
-13
@@ -5,46 +5,80 @@
|
||||
|
||||
package org.jetbrains.kotlin.analysis.api.fir.annotations
|
||||
|
||||
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
||||
import org.jetbrains.kotlin.fakeElement
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
|
||||
import org.jetbrains.kotlin.fir.declarations.primaryConstructorIfAny
|
||||
import org.jetbrains.kotlin.fir.declarations.resolved
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.expressions.builder.buildVarargArgumentsExpression
|
||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||
import org.jetbrains.kotlin.fir.types.classId
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
internal fun mapAnnotationParameters(annotation: FirAnnotation, session: FirSession): Map<Name, FirExpression> {
|
||||
if (annotation.resolved) return annotation.argumentMapping.mapping.mapKeys { (name, _) -> name }
|
||||
if (annotation !is FirAnnotationCall) return emptyMap()
|
||||
val annotationCone = annotation.annotationTypeRef.coneType as? ConeClassLikeType ?: return emptyMap()
|
||||
val annotationCone = (annotation.annotationTypeRef.coneType as? ConeClassLikeType)?.fullyExpandedType(session)
|
||||
?: return emptyMap()
|
||||
|
||||
val annotationPrimaryCtor = (annotationCone.lookupTag.toSymbol(session)?.fir as? FirRegularClass)?.primaryConstructorIfAny(session)?.fir
|
||||
val annotationCtorParameterNames = annotationPrimaryCtor?.valueParameters?.map { it.name }
|
||||
val valueParameters = annotationPrimaryCtor?.valueParameters
|
||||
val (varargValueParameters, nonVarargValueParameters) = valueParameters?.partition { it.isVararg }
|
||||
?: (emptyList<FirValueParameter>() to emptyList())
|
||||
val annotationCtorParameterNames = nonVarargValueParameters.map { it.name }
|
||||
|
||||
val resultMap = mutableMapOf<Name, FirExpression>()
|
||||
|
||||
val namesSequence = annotationCtorParameterNames?.asSequence()?.iterator()
|
||||
val namesSequence = annotationCtorParameterNames.asSequence().iterator()
|
||||
|
||||
for (argument in annotation.argumentList.arguments.filterIsInstance<FirNamedArgumentExpression>()) {
|
||||
resultMap[argument.name] = argument.expression
|
||||
}
|
||||
|
||||
if (namesSequence != null) {
|
||||
for (argument in annotation.argumentList.arguments) {
|
||||
val argumentSequence = annotation.argumentList.arguments.asSequence().iterator()
|
||||
|
||||
while (namesSequence.hasNext()) {
|
||||
val name = namesSequence.next()
|
||||
if (name in resultMap) continue
|
||||
while (argumentSequence.hasNext()) {
|
||||
val argument = argumentSequence.next()
|
||||
if (argument is FirNamedArgumentExpression) continue
|
||||
|
||||
while (namesSequence.hasNext()) {
|
||||
val name = namesSequence.next()
|
||||
if (!resultMap.contains(name)) {
|
||||
resultMap[name] = argument
|
||||
break
|
||||
resultMap[name] = argument
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (varargValueParameters.isNotEmpty() && argumentSequence.hasNext()) {
|
||||
val varargValueParameter = varargValueParameters.single()
|
||||
val arguments = buildList {
|
||||
while (argumentSequence.hasNext()) {
|
||||
val argument = argumentSequence.next()
|
||||
if (argument is FirNamedArgumentExpression) continue
|
||||
add(argument)
|
||||
}
|
||||
}
|
||||
if (arguments.isNotEmpty()) {
|
||||
val exp = buildVarargArgumentsExpression {
|
||||
this.arguments.addAll(arguments)
|
||||
val firstArgument = arguments.first()
|
||||
firstArgument.source?.let { source = it.fakeElement(KtFakeSourceElementKind.VarargArgument) }
|
||||
(varargValueParameter.returnTypeRef as? FirResolvedTypeRef)?.coneType?.varargElementType()?.let {
|
||||
varargElementType = buildResolvedTypeRef {
|
||||
source = varargValueParameter.returnTypeRef.source
|
||||
type = it
|
||||
}
|
||||
} ?: firstArgument.typeRef.let {
|
||||
varargElementType = it
|
||||
}
|
||||
}
|
||||
resultMap[varargValueParameter.name] = exp
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+12
@@ -56,6 +56,12 @@ public class FirIdeDependentAnalysisSourceModuleAnalysisApiAnnotationsOnDeclarat
|
||||
@TestMetadata("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class Direct {
|
||||
@Test
|
||||
@TestMetadata("aliasedThrowsOnFunction.kt")
|
||||
public void testAliasedThrowsOnFunction() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct/aliasedThrowsOnFunction.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllFilesPresentInDirect() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct"), Pattern.compile("^(.+)\\.kt$"), null, true);
|
||||
@@ -84,6 +90,12 @@ public class FirIdeDependentAnalysisSourceModuleAnalysisApiAnnotationsOnDeclarat
|
||||
public void testOnTypeAlias() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct/onTypeAlias.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("varargParameter.kt")
|
||||
public void testVarargParameter() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct/varargParameter.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
+12
@@ -56,6 +56,12 @@ public class FirIdeNormalAnalysisSourceModuleAnalysisApiAnnotationsOnDeclaration
|
||||
@TestMetadata("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class Direct {
|
||||
@Test
|
||||
@TestMetadata("aliasedThrowsOnFunction.kt")
|
||||
public void testAliasedThrowsOnFunction() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct/aliasedThrowsOnFunction.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllFilesPresentInDirect() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct"), Pattern.compile("^(.+)\\.kt$"), null, true);
|
||||
@@ -84,6 +90,12 @@ public class FirIdeNormalAnalysisSourceModuleAnalysisApiAnnotationsOnDeclaration
|
||||
public void testOnTypeAlias() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct/onTypeAlias.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("varargParameter.kt")
|
||||
public void testVarargParameter() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct/varargParameter.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
+12
@@ -56,6 +56,12 @@ public class FirStandaloneNormalAnalysisSourceModuleAnalysisApiAnnotationsOnDecl
|
||||
@TestMetadata("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class Direct {
|
||||
@Test
|
||||
@TestMetadata("aliasedThrowsOnFunction.kt")
|
||||
public void testAliasedThrowsOnFunction() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct/aliasedThrowsOnFunction.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllFilesPresentInDirect() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct"), Pattern.compile("^(.+)\\.kt$"), null, true);
|
||||
@@ -84,6 +90,12 @@ public class FirStandaloneNormalAnalysisSourceModuleAnalysisApiAnnotationsOnDecl
|
||||
public void testOnTypeAlias() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct/onTypeAlias.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("varargParameter.kt")
|
||||
public void testVarargParameter() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/annotations/annotationsOnDeclaration/direct/varargParameter.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// WITH_STDLIB
|
||||
import java.io.IOException
|
||||
|
||||
typealias Throws = kotlin.jvm.Throws
|
||||
|
||||
class MyException : Exception()
|
||||
|
||||
class Foo {
|
||||
@Throws(IOException::class, MyException::class)
|
||||
fun ba<caret>r(): Boolean {
|
||||
return false
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
KtDeclaration: KtNamedFunction bar
|
||||
annotations: [
|
||||
kotlin/jvm/Throws(exceptionClasses = [java.io.IOException::class, MyException::class])
|
||||
psi: KtAnnotationEntry
|
||||
]
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
annotation class A(val a: Int, vararg val cs: KClass<*>)
|
||||
|
||||
@A(a = 1, Int::class, String::class)
|
||||
fun fo<caret>o(): Int = 42
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
KtDeclaration: KtNamedFunction foo
|
||||
annotations: [
|
||||
A(a = 1, cs = [kotlin.Int::class, kotlin.String::class])
|
||||
psi: KtAnnotationEntry
|
||||
]
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
@kotlin.annotation.MustBeDocumented()
|
||||
@kotlin.annotation.Repeatable()
|
||||
@kotlin.annotation.Retention(value = kotlin.annotation.AnnotationRetention.SOURCE)
|
||||
@kotlin.annotation.Target(allowedTargets = kotlin.annotation.AnnotationTarget.TYPE_PARAMETER)
|
||||
@kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.TYPE_PARAMETER, kotlin.annotation.AnnotationTarget.TYPE})
|
||||
public abstract @interface Anno /* Anno*/ {
|
||||
public abstract int i();// i()
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ public abstract @interface Anno3 /* Anno3*/ {
|
||||
}
|
||||
|
||||
@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
|
||||
@kotlin.annotation.Target(allowedTargets = kotlin.annotation.AnnotationTarget.CLASS)
|
||||
@kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.EXPRESSION})
|
||||
public abstract @interface Anno4 /* Anno4*/ {
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ public abstract @interface Anno /* Anno*/ {
|
||||
@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
|
||||
@kotlin.annotation.MustBeDocumented()
|
||||
@kotlin.annotation.Retention(value = kotlin.annotation.AnnotationRetention.SOURCE)
|
||||
@kotlin.annotation.Target(allowedTargets = kotlin.annotation.AnnotationTarget.CLASS)
|
||||
@kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.EXPRESSION})
|
||||
public abstract @interface Fancy /* Fancy*/ {
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -21,14 +21,14 @@ public abstract @interface Ann /* Ann*/ {
|
||||
}
|
||||
|
||||
public abstract interface Base /* Base*/ {
|
||||
@Ann(x = 1L, y = "134", z = java.lang.String.class, e = ?, depr = kotlin.DeprecationLevel.WARNING, t = ?)
|
||||
public abstract void foo(@Ann(x = 2L, y = "324", z = Ann.class, e = ?, depr = kotlin.DeprecationLevel.WARNING, t = ?) @org.jetbrains.annotations.NotNull() java.lang.String);// foo(java.lang.String)
|
||||
@Ann(x = 1L, y = "134", z = java.lang.String.class, e = ?, depr = kotlin.DeprecationLevel.WARNING, t = {})
|
||||
public abstract void foo(@Ann(x = 2L, y = "324", z = Ann.class, e = ?, depr = kotlin.DeprecationLevel.WARNING, t = {}) @org.jetbrains.annotations.NotNull() java.lang.String);// foo(java.lang.String)
|
||||
|
||||
}
|
||||
|
||||
public final class Derived /* Derived*/ implements Base {
|
||||
@Ann(x = 1L, y = "134", z = java.lang.String.class, e = ?, depr = kotlin.DeprecationLevel.WARNING, t = ?)
|
||||
public void foo(@Ann(x = 2L, y = "324", z = Ann.class, e = ?, depr = kotlin.DeprecationLevel.WARNING, t = ?) @org.jetbrains.annotations.NotNull() java.lang.String);// foo(java.lang.String)
|
||||
@Ann(x = 1L, y = "134", z = java.lang.String.class, e = ?, depr = kotlin.DeprecationLevel.WARNING, t = {})
|
||||
public void foo(@Ann(x = 2L, y = "324", z = Ann.class, e = ?, depr = kotlin.DeprecationLevel.WARNING, t = {}) @org.jetbrains.annotations.NotNull() java.lang.String);// foo(java.lang.String)
|
||||
|
||||
public Derived(@org.jetbrains.annotations.NotNull() Base);// .ctor(Base)
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
public final class A /* A*/ {
|
||||
@kotlin.Suppress(names = "INVISIBLE_REFERENCE")
|
||||
@kotlin.Suppress(names = {"INVISIBLE_REFERENCE", "INVISIBLE_MEMBER"})
|
||||
@kotlin.internal.InlineOnly()
|
||||
private final void foo();// foo()
|
||||
|
||||
|
||||
@@ -4,14 +4,14 @@ public final class MyException /* MyException*/ extends java.lang.Exception {
|
||||
}
|
||||
|
||||
public final class C /* C*/ {
|
||||
@kotlin.jvm.Throws()
|
||||
@kotlin.jvm.Throws(exceptionClasses = {java.io.IOException.class, MyException.class})
|
||||
@org.jetbrains.annotations.NotNull()
|
||||
public final java.lang.String readFile(@org.jetbrains.annotations.NotNull() java.lang.String);// readFile(java.lang.String)
|
||||
|
||||
@kotlin.jvm.Throws()
|
||||
@kotlin.jvm.Throws(exceptionClasses = {java.lang.Exception.class})
|
||||
public C(int);// .ctor(int)
|
||||
|
||||
@kotlin.jvm.Throws()
|
||||
@kotlin.jvm.Throws(exceptionClasses = {java.lang.Throwable.class})
|
||||
public final void baz();// baz()
|
||||
|
||||
public C();// .ctor()
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
|
||||
@kotlin.annotation.Target(allowedTargets = kotlin.annotation.AnnotationTarget.VALUE_PARAMETER)
|
||||
@kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.TYPE})
|
||||
public abstract @interface A0 /* A0*/ {
|
||||
}
|
||||
|
||||
@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
|
||||
@kotlin.annotation.Target(allowedTargets = kotlin.annotation.AnnotationTarget.VALUE_PARAMETER)
|
||||
@kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.TYPE})
|
||||
public abstract @interface A1 /* A1*/ {
|
||||
}
|
||||
|
||||
@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
|
||||
@kotlin.annotation.Target(allowedTargets = kotlin.annotation.AnnotationTarget.VALUE_PARAMETER)
|
||||
@kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.TYPE})
|
||||
public abstract @interface A2 /* A2*/ {
|
||||
}
|
||||
|
||||
@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
|
||||
@kotlin.annotation.Target(allowedTargets = kotlin.annotation.AnnotationTarget.VALUE_PARAMETER)
|
||||
@kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.TYPE})
|
||||
public abstract @interface A3 /* A3*/ {
|
||||
}
|
||||
|
||||
@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
|
||||
@kotlin.annotation.Target(allowedTargets = kotlin.annotation.AnnotationTarget.VALUE_PARAMETER)
|
||||
@kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.TYPE})
|
||||
public abstract @interface A4 /* A4*/ {
|
||||
}
|
||||
|
||||
@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
|
||||
@kotlin.annotation.Target(allowedTargets = kotlin.annotation.AnnotationTarget.VALUE_PARAMETER)
|
||||
@kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.TYPE})
|
||||
public abstract @interface A5 /* A5*/ {
|
||||
}
|
||||
|
||||
@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
|
||||
@kotlin.annotation.Target(allowedTargets = kotlin.annotation.AnnotationTarget.VALUE_PARAMETER)
|
||||
@kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.TYPE})
|
||||
public abstract @interface A6 /* A6*/ {
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
public final class ThrowsAnnotationKt /* ThrowsAnnotationKt*/ {
|
||||
@kotlin.jvm.Throws()
|
||||
@kotlin.jvm.Throws(exceptionClasses = {java.io.IOException.class, MyException.class})
|
||||
@org.jetbrains.annotations.NotNull()
|
||||
public static final java.lang.String readFile(@org.jetbrains.annotations.NotNull() java.lang.String);// readFile(java.lang.String)
|
||||
|
||||
@kotlin.jvm.Throws()
|
||||
@kotlin.jvm.Throws(exceptionClasses = {java.lang.Throwable.class})
|
||||
public static final void baz();// baz()
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user