[FIR] FirBasedSymbol: iterate annotations by index instead of iterator to avoid possible ConcurrentModificationException

^KT-56046
This commit is contained in:
Dmitrii Gridin
2023-01-31 14:23:57 +01:00
committed by Space Team
parent 19a61015c0
commit 38575cdbc1
2 changed files with 31 additions and 10 deletions
@@ -51,12 +51,15 @@ internal fun annotationsByClassId(
annotationContainer: FirAnnotationContainer = firSymbol.fir, annotationContainer: FirAnnotationContainer = firSymbol.fir,
): List<KtAnnotationApplicationWithArgumentsInfo> = ): List<KtAnnotationApplicationWithArgumentsInfo> =
if (firSymbol.isFromCompilerRequiredAnnotationsPhase(classId)) { if (firSymbol.isFromCompilerRequiredAnnotationsPhase(classId)) {
annotationContainer.resolvedCompilerRequiredAnnotations(firSymbol).mapIndexedNotNull { index, annotation -> buildList {
if (!useSiteTargetFilter.isAllowed(annotation.useSiteTarget) || annotation.toAnnotationClassIdSafe(useSiteSession) != classId) { // this loop by index is required to avoid possible ConcurrentModificationException
return@mapIndexedNotNull null val annotations = annotationContainer.resolvedCompilerRequiredAnnotations(firSymbol)
for (index in annotations.indices) {
val annotation = annotations[index]
if (useSiteTargetFilter.isAllowed(annotation.useSiteTarget) && annotation.toAnnotationClassIdSafe(useSiteSession) == classId) {
add(annotation.toKtAnnotationApplication(useSiteSession, index))
}
} }
annotation.toKtAnnotationApplication(useSiteSession, index)
} }
} else { } else {
annotationContainer.resolvedAnnotationsWithArguments(firSymbol).mapIndexedNotNull { index, annotation -> annotationContainer.resolvedAnnotationsWithArguments(firSymbol).mapIndexedNotNull { index, annotation ->
@@ -99,16 +102,24 @@ internal fun hasAnnotation(
useSiteTargetFilter: AnnotationUseSiteTargetFilter, useSiteTargetFilter: AnnotationUseSiteTargetFilter,
useSiteSession: FirSession, useSiteSession: FirSession,
annotationContainer: FirAnnotationContainer = firSymbol.fir, annotationContainer: FirAnnotationContainer = firSymbol.fir,
): Boolean = ): Boolean {
if (firSymbol.isFromCompilerRequiredAnnotationsPhase(classId)) { return if (firSymbol.isFromCompilerRequiredAnnotationsPhase(classId)) {
annotationContainer.resolvedCompilerRequiredAnnotations(firSymbol).any { // this loop by index is required to avoid possible ConcurrentModificationException
useSiteTargetFilter.isAllowed(it.useSiteTarget) && it.toAnnotationClassIdSafe(useSiteSession) == classId val annotations = annotationContainer.resolvedCompilerRequiredAnnotations(firSymbol)
for (index in annotations.indices) {
val annotation = annotations[index]
if (useSiteTargetFilter.isAllowed(annotation.useSiteTarget) && annotation.toAnnotationClassIdSafe(useSiteSession) == classId) {
return true
}
} }
false
} else { } else {
annotationContainer.resolvedAnnotationsWithClassIds(firSymbol).any { annotationContainer.resolvedAnnotationsWithClassIds(firSymbol).any {
useSiteTargetFilter.isAllowed(it.useSiteTarget) && it.toAnnotationClassId(useSiteSession) == classId useSiteTargetFilter.isAllowed(it.useSiteTarget) && it.toAnnotationClassId(useSiteSession) == classId
} }
} }
}
private fun FirBasedSymbol<*>.isFromCompilerRequiredAnnotationsPhase(classId: ClassId): Boolean = private fun FirBasedSymbol<*>.isFromCompilerRequiredAnnotationsPhase(classId: ClassId): Boolean =
fir.resolvePhase < FirResolvePhase.TYPES && classId in CompilerRequiredAnnotationsHelper.REQUIRED_ANNOTATIONS fir.resolvePhase < FirResolvePhase.TYPES && classId in CompilerRequiredAnnotationsHelper.REQUIRED_ANNOTATIONS
@@ -79,7 +79,17 @@ fun FirAnnotationContainer.resolvedAnnotationsWithArguments(anchorElement: FirBa
fun List<FirAnnotation>.resolvedAnnotationsWithArguments(anchorElement: FirBasedSymbol<*>): List<FirAnnotation> { fun List<FirAnnotation>.resolvedAnnotationsWithArguments(anchorElement: FirBasedSymbol<*>): List<FirAnnotation> {
if (isEmpty()) return emptyList() if (isEmpty()) return emptyList()
val phase = if (any { it is FirAnnotationCall && it.arguments.isNotEmpty() }) { // this loop by index is required to avoid possible ConcurrentModificationException
var hasAnnotationCallWithArguments = false
for (i in indices) {
val currentAnnotation = get(i)
if (currentAnnotation is FirAnnotationCall && currentAnnotation.arguments.isNotEmpty()) {
hasAnnotationCallWithArguments = true
break
}
}
val phase = if (hasAnnotationCallWithArguments) {
FirResolvePhase.ANNOTATIONS_ARGUMENTS_MAPPING FirResolvePhase.ANNOTATIONS_ARGUMENTS_MAPPING
} else { } else {
FirResolvePhase.TYPES FirResolvePhase.TYPES