AA FIR: handle (aliased)? annotation w/ vararg parameter

This commit is contained in:
Jinseong Jeon
2022-08-03 15:01:55 -07:00
committed by Nikolay Krasko
parent 032153c673
commit 56a5d883c0
16 changed files with 142 additions and 33 deletions
@@ -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
@@ -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
}
}
@@ -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
@@ -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
@@ -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
@@ -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
}
}
@@ -0,0 +1,5 @@
KtDeclaration: KtNamedFunction bar
annotations: [
kotlin/jvm/Throws(exceptionClasses = [java.io.IOException::class, MyException::class])
psi: KtAnnotationEntry
]
@@ -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
@@ -0,0 +1,5 @@
KtDeclaration: KtNamedFunction foo
annotations: [
A(a = 1, cs = [kotlin.Int::class, kotlin.String::class])
psi: KtAnnotationEntry
]
@@ -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*/ {
}
@@ -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()
}