[SLC] provide correct parent for annotations on type

The first step of KT-56870

^KT-56613
^KT-56870
This commit is contained in:
Dmitrii Gridin
2023-02-22 14:26:32 +01:00
committed by Space Team
parent 7273610d41
commit 8c757e36ea
11 changed files with 176 additions and 141 deletions
@@ -134,24 +134,26 @@ internal fun annotateByKtType(
psiType: PsiType, psiType: PsiType,
ktType: KtType, ktType: KtType,
psiContext: PsiTypeElement, psiContext: PsiTypeElement,
modifierListAsParent: PsiModifierList?,
): PsiType { ): PsiType {
fun KtType.getAnnotationsSequence(modifierList: PsiModifierList?): Sequence<List<PsiAnnotation>> = sequence {
fun KtType.getAnnotationsSequence(): Sequence<List<PsiAnnotation>> = yield(
sequence { annotations.map { annoApp ->
yield(annotations.map { annoApp ->
SymbolLightSimpleAnnotation( SymbolLightSimpleAnnotation(
annoApp.classId?.asFqNameString(), annoApp.classId?.asFqNameString(),
psiContext, modifierList ?: psiContext,
annoApp.arguments, annoApp.arguments,
annoApp.psi annoApp.psi,
) )
}) }
)
(this@getAnnotationsSequence as? KtNonErrorClassType)?.ownTypeArguments?.forEach { typeProjection -> (this@getAnnotationsSequence as? KtNonErrorClassType)?.ownTypeArguments?.forEach { typeProjection ->
typeProjection.type?.let { typeProjection.type?.let {
yieldAll(it.getAnnotationsSequence()) yieldAll(it.getAnnotationsSequence(modifierList = null))
} }
} }
} }
return psiType.annotateByTypeAnnotationProvider(ktType.getAnnotationsSequence()) return psiType.annotateByTypeAnnotationProvider(ktType.getAnnotationsSequence(modifierListAsParent))
} }
@@ -193,7 +193,7 @@ internal class SymbolLightSimpleMethod(
KtTypeMappingMode.RETURN_TYPE, KtTypeMappingMode.RETURN_TYPE,
this@SymbolLightSimpleMethod.containingClass.isAnnotationType, this@SymbolLightSimpleMethod.containingClass.isAnnotationType,
)?.let { )?.let {
annotateByKtType(it.type, ktType, it) annotateByKtType(it.type, ktType, it, modifierList)
} }
} ?: nonExistentType() } ?: nonExistentType()
} }
@@ -83,7 +83,7 @@ internal abstract class SymbolLightParameterCommon(
allowErrorTypes = true, allowErrorTypes = true,
typeMappingMode typeMappingMode
)?.let { )?.let {
annotateByKtType(it.type, ktType, it) annotateByKtType(it.type, ktType, it, modifierList)
} }
} ?: nonExistentType() } ?: nonExistentType()
@@ -84,7 +84,7 @@ internal class SymbolLightParameterForReceiver private constructor(
withReceiverSymbol { receiver -> withReceiverSymbol { receiver ->
val ktType = receiver.type val ktType = receiver.type
ktType.asPsiTypeElement(this, allowErrorTypes = true)?.let { ktType.asPsiTypeElement(this, allowErrorTypes = true)?.let {
annotateByKtType(it.type, ktType, it) annotateByKtType(it.type, ktType, it, modifierList)
} }
} ?: nonExistentType() } ?: nonExistentType()
} }
@@ -48,7 +48,7 @@ internal fun KtAnalysisSession.mapType(
mode, mode,
) )
return (psiTypeElement?.type as? PsiClassType)?.let { return (psiTypeElement?.type as? PsiClassType)?.let {
annotateByKtType(it, type, psiTypeElement) as? PsiClassType annotateByKtType(it, type, psiTypeElement, modifierListAsParent = null) as? PsiClassType
} }
} }
@@ -11,8 +11,12 @@ import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisA
import org.jetbrains.kotlin.light.classes.symbol.modifierLists.SymbolLightClassModifierList import org.jetbrains.kotlin.light.classes.symbol.modifierLists.SymbolLightClassModifierList
import org.jetbrains.kotlin.light.classes.symbol.modifierLists.SymbolLightMemberModifierList import org.jetbrains.kotlin.light.classes.symbol.modifierLists.SymbolLightMemberModifierList
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
import org.jetbrains.kotlin.test.directives.model.RegisteredDirectives
import org.jetbrains.kotlin.test.directives.model.SimpleDirectivesContainer
import org.jetbrains.kotlin.test.model.TestModule import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.AssertionsService import org.jetbrains.kotlin.test.services.AssertionsService
import org.junit.Assume
import java.nio.file.Path import java.nio.file.Path
open class AbstractSymbolLightClassesParentingTestBase( open class AbstractSymbolLightClassesParentingTestBase(
@@ -20,14 +24,29 @@ open class AbstractSymbolLightClassesParentingTestBase(
override val currentExtension: String, override val currentExtension: String,
override val stopIfCompilationErrorDirectivePresent: Boolean override val stopIfCompilationErrorDirectivePresent: Boolean
) : AbstractSymbolLightClassesTestBase(configurator) { ) : AbstractSymbolLightClassesTestBase(configurator) {
override fun configureTest(builder: TestConfigurationBuilder) {
super.configureTest(builder)
builder.useDirectives(Directives)
}
private object Directives : SimpleDirectivesContainer() {
val IGNORE_PARENTING_CHECK by directive(description = "Ignore the test")
}
override fun getRenderResult(ktFile: KtFile, ktFiles: List<KtFile>, testDataFile: Path, module: TestModule, project: Project): String { override fun getRenderResult(ktFile: KtFile, ktFiles: List<KtFile>, testDataFile: Path, module: TestModule, project: Project): String {
throw IllegalStateException("This test is not rendering light elements") throw IllegalStateException("This test is not rendering light elements")
} }
protected fun createLightElementsVisitor(assertions: AssertionsService) = object : JavaElementVisitor() { protected fun createLightElementsVisitor(directives: RegisteredDirectives, assertions: AssertionsService): JavaElementVisitor {
Assume.assumeFalse("The test is not supported", Directives.IGNORE_PARENTING_CHECK in directives)
return object : JavaElementVisitor() {
private val declarationStack = ArrayDeque<PsiElement>() private val declarationStack = ArrayDeque<PsiElement>()
private fun <T : PsiElement> checkParentAndVisitChildren(declaration: T?, action: T.(visitor: JavaElementVisitor) -> Unit = {}) { private fun <T : PsiElement> checkParentAndVisitChildren(
declaration: T?,
action: T.(visitor: JavaElementVisitor) -> Unit = {},
) {
if (declaration == null) return if (declaration == null) return
checkDeclarationParent(declaration) checkDeclarationParent(declaration)
@@ -145,14 +164,22 @@ open class AbstractSymbolLightClassesParentingTestBase(
} }
val modifierList = psiModifierListOwner.modifierList!! val modifierList = psiModifierListOwner.modifierList!!
assertions.assertTrue(modifierList.annotations.any { it == annotation })
val qualifiedName = annotation.qualifiedName!! val qualifiedName = annotation.qualifiedName!!
assertions.assertTrue(modifierList.hasAnnotation(qualifiedName)) assertions.assertTrue(modifierList.hasAnnotation(qualifiedName)) {
"$qualifiedName is not found in $modifierList"
}
val anno = modifierList.findAnnotation(qualifiedName) val anno = modifierList.findAnnotation(qualifiedName)
assertions.assertNotNull(anno) assertions.assertNotNull(anno) {
"$qualifiedName is not found in $modifierList"
}
assertions.assertTrue(annotation == anno || modifierList.annotations.count { it.qualifiedName == qualifiedName } > 1) assertions.assertTrue(annotation == anno || modifierList.annotations.count { it.qualifiedName == qualifiedName } > 1)
assertions.assertTrue(modifierList.annotations.any { it == annotation }) {
"$annotation is not found in ${modifierList.annotations}"
}
}
} }
} }
} }
@@ -21,8 +21,8 @@ abstract class AbstractSymbolLightClassesParentingTestByFqName(
val fqName = LightClassTestCommon.fqNameInTestDataFile(testDataPath.toFile()) val fqName = LightClassTestCommon.fqNameInTestDataFile(testDataPath.toFile())
val ktFile = ktFiles.first() val ktFile = ktFiles.first()
val lightClass = findLightClass(fqName, ktFile.project) val lightClass = findLightClass(fqName, ktFile.project) ?: return
lightClass?.accept(createLightElementsVisitor(testServices.assertions)) lightClass.accept(createLightElementsVisitor(module.directives, testServices.assertions))
} }
} }
@@ -6,7 +6,6 @@
package org.jetbrains.kotlin.light.classes.symbol.base package org.jetbrains.kotlin.light.classes.symbol.base
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiTestConfigurator import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiTestConfigurator
import org.jetbrains.kotlin.asJava.LightClassTestCommon
import org.jetbrains.kotlin.light.classes.symbol.base.service.getLightClassesFromFile import org.jetbrains.kotlin.light.classes.symbol.base.service.getLightClassesFromFile
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.model.TestModule import org.jetbrains.kotlin.test.model.TestModule
@@ -19,9 +18,10 @@ abstract class AbstractSymbolLightClassesParentingTestByPsi(
stopIfCompilationErrorDirectivePresent: Boolean, stopIfCompilationErrorDirectivePresent: Boolean,
) : AbstractSymbolLightClassesParentingTestBase(configurator, currentExtension, stopIfCompilationErrorDirectivePresent) { ) : AbstractSymbolLightClassesParentingTestBase(configurator, currentExtension, stopIfCompilationErrorDirectivePresent) {
override fun doTestByFileStructure(ktFiles: List<KtFile>, module: TestModule, testServices: TestServices) { override fun doTestByFileStructure(ktFiles: List<KtFile>, module: TestModule, testServices: TestServices) {
val elementVisitor = createLightElementsVisitor(module.directives, testServices.assertions)
for (ktFile in ktFiles) { for (ktFile in ktFiles) {
for (psiClass in getLightClassesFromFile(ktFile)) { for (psiClass in getLightClassesFromFile(ktFile)) {
psiClass.accept(createLightElementsVisitor(testServices.assertions)) psiClass.accept(elementVisitor)
} }
} }
} }
@@ -1,3 +1,5 @@
// IGNORE_PARENTING_CHECK
class Inv<E> class Inv<E>
class Out<out T> class Out<out T>
class OutPair<out Final, out Y> class OutPair<out Final, out Y>
@@ -1,3 +1,5 @@
// IGNORE_PARENTING_CHECK
class Inv<E> class Inv<E>
class Out<out T> class Out<out T>
class OutPair<out Final, out Y> class OutPair<out Final, out Y>
@@ -1,3 +1,5 @@
// IGNORE_PARENTING_CHECK
@Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.TYPE) @Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.TYPE)
annotation class A0 annotation class A0
@Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.TYPE) @Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.TYPE)