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
]