Skip to content

Commit 9155484

Browse files
lunakolySpace Team
authored and
Space Team
committed
[FIR] Report all diagnostics in FirNotImplementedOverrideChecker
Before this change, the checker only reported one of the unimplemented symbols. ^KT-68363
1 parent 72404cf commit 9155484

File tree

19 files changed

+240
-90
lines changed

19 files changed

+240
-90
lines changed

analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDataClassConverters.kt

+12-4
Original file line numberDiff line numberDiff line change
@@ -3173,7 +3173,9 @@ internal val KT_DIAGNOSTIC_CONVERTER = KaDiagnosticConverterBuilder.buildConvert
31733173
add(FirErrors.ABSTRACT_MEMBER_NOT_IMPLEMENTED) { firDiagnostic ->
31743174
AbstractMemberNotImplementedImpl(
31753175
firSymbolBuilder.classifierBuilder.buildClassLikeSymbol(firDiagnostic.a),
3176-
firSymbolBuilder.callableBuilder.buildCallableSymbol(firDiagnostic.b),
3176+
firDiagnostic.b.map { firCallableSymbol ->
3177+
firSymbolBuilder.callableBuilder.buildCallableSymbol(firCallableSymbol)
3178+
},
31773179
firDiagnostic as KtPsiDiagnostic,
31783180
token,
31793181
)
@@ -3191,23 +3193,29 @@ internal val KT_DIAGNOSTIC_CONVERTER = KaDiagnosticConverterBuilder.buildConvert
31913193
add(FirErrors.ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED) { firDiagnostic ->
31923194
AbstractClassMemberNotImplementedImpl(
31933195
firSymbolBuilder.classifierBuilder.buildClassLikeSymbol(firDiagnostic.a),
3194-
firSymbolBuilder.callableBuilder.buildCallableSymbol(firDiagnostic.b),
3196+
firDiagnostic.b.map { firCallableSymbol ->
3197+
firSymbolBuilder.callableBuilder.buildCallableSymbol(firCallableSymbol)
3198+
},
31953199
firDiagnostic as KtPsiDiagnostic,
31963200
token,
31973201
)
31983202
}
31993203
add(FirErrors.INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER.errorFactory) { firDiagnostic ->
32003204
InvisibleAbstractMemberFromSuperErrorImpl(
32013205
firSymbolBuilder.classifierBuilder.buildClassLikeSymbol(firDiagnostic.a),
3202-
firSymbolBuilder.callableBuilder.buildCallableSymbol(firDiagnostic.b),
3206+
firDiagnostic.b.map { firCallableSymbol ->
3207+
firSymbolBuilder.callableBuilder.buildCallableSymbol(firCallableSymbol)
3208+
},
32033209
firDiagnostic as KtPsiDiagnostic,
32043210
token,
32053211
)
32063212
}
32073213
add(FirErrors.INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER.warningFactory) { firDiagnostic ->
32083214
InvisibleAbstractMemberFromSuperWarningImpl(
32093215
firSymbolBuilder.classifierBuilder.buildClassLikeSymbol(firDiagnostic.a),
3210-
firSymbolBuilder.callableBuilder.buildCallableSymbol(firDiagnostic.b),
3216+
firDiagnostic.b.map { firCallableSymbol ->
3217+
firSymbolBuilder.callableBuilder.buildCallableSymbol(firCallableSymbol)
3218+
},
32113219
firDiagnostic as KtPsiDiagnostic,
32123220
token,
32133221
)

analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDiagnostics.kt

+4-4
Original file line numberDiff line numberDiff line change
@@ -2245,7 +2245,7 @@ sealed interface KaFirDiagnostic<PSI : PsiElement> : KaDiagnosticWithPsi<PSI> {
22452245
interface AbstractMemberNotImplemented : KaFirDiagnostic<KtClassOrObject> {
22462246
override val diagnosticClass get() = AbstractMemberNotImplemented::class
22472247
val classOrObject: KaClassLikeSymbol
2248-
val missingDeclaration: KaCallableSymbol
2248+
val missingDeclarations: List<KaCallableSymbol>
22492249
}
22502250

22512251
interface AbstractMemberNotImplementedByEnumEntry : KaFirDiagnostic<KtEnumEntry> {
@@ -2257,19 +2257,19 @@ sealed interface KaFirDiagnostic<PSI : PsiElement> : KaDiagnosticWithPsi<PSI> {
22572257
interface AbstractClassMemberNotImplemented : KaFirDiagnostic<KtClassOrObject> {
22582258
override val diagnosticClass get() = AbstractClassMemberNotImplemented::class
22592259
val classOrObject: KaClassLikeSymbol
2260-
val missingDeclaration: KaCallableSymbol
2260+
val missingDeclarations: List<KaCallableSymbol>
22612261
}
22622262

22632263
interface InvisibleAbstractMemberFromSuperError : KaFirDiagnostic<KtClassOrObject> {
22642264
override val diagnosticClass get() = InvisibleAbstractMemberFromSuperError::class
22652265
val classOrObject: KaClassLikeSymbol
2266-
val invisibleDeclaration: KaCallableSymbol
2266+
val invisibleDeclarations: List<KaCallableSymbol>
22672267
}
22682268

22692269
interface InvisibleAbstractMemberFromSuperWarning : KaFirDiagnostic<KtClassOrObject> {
22702270
override val diagnosticClass get() = InvisibleAbstractMemberFromSuperWarning::class
22712271
val classOrObject: KaClassLikeSymbol
2272-
val invisibleDeclaration: KaCallableSymbol
2272+
val invisibleDeclarations: List<KaCallableSymbol>
22732273
}
22742274

22752275
interface AmbiguousAnonymousTypeInferred : KaFirDiagnostic<KtDeclaration> {

analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDiagnosticsImpl.kt

+4-4
Original file line numberDiff line numberDiff line change
@@ -2687,7 +2687,7 @@ internal class ConflictingInheritedMembersImpl(
26872687

26882688
internal class AbstractMemberNotImplementedImpl(
26892689
override val classOrObject: KaClassLikeSymbol,
2690-
override val missingDeclaration: KaCallableSymbol,
2690+
override val missingDeclarations: List<KaCallableSymbol>,
26912691
firDiagnostic: KtPsiDiagnostic,
26922692
token: KaLifetimeToken,
26932693
) : KaAbstractFirDiagnostic<KtClassOrObject>(firDiagnostic, token), KaFirDiagnostic.AbstractMemberNotImplemented
@@ -2701,21 +2701,21 @@ internal class AbstractMemberNotImplementedByEnumEntryImpl(
27012701

27022702
internal class AbstractClassMemberNotImplementedImpl(
27032703
override val classOrObject: KaClassLikeSymbol,
2704-
override val missingDeclaration: KaCallableSymbol,
2704+
override val missingDeclarations: List<KaCallableSymbol>,
27052705
firDiagnostic: KtPsiDiagnostic,
27062706
token: KaLifetimeToken,
27072707
) : KaAbstractFirDiagnostic<KtClassOrObject>(firDiagnostic, token), KaFirDiagnostic.AbstractClassMemberNotImplemented
27082708

27092709
internal class InvisibleAbstractMemberFromSuperErrorImpl(
27102710
override val classOrObject: KaClassLikeSymbol,
2711-
override val invisibleDeclaration: KaCallableSymbol,
2711+
override val invisibleDeclarations: List<KaCallableSymbol>,
27122712
firDiagnostic: KtPsiDiagnostic,
27132713
token: KaLifetimeToken,
27142714
) : KaAbstractFirDiagnostic<KtClassOrObject>(firDiagnostic, token), KaFirDiagnostic.InvisibleAbstractMemberFromSuperError
27152715

27162716
internal class InvisibleAbstractMemberFromSuperWarningImpl(
27172717
override val classOrObject: KaClassLikeSymbol,
2718-
override val invisibleDeclaration: KaCallableSymbol,
2718+
override val invisibleDeclarations: List<KaCallableSymbol>,
27192719
firDiagnostic: KtPsiDiagnostic,
27202720
token: KaLifetimeToken,
27212721
) : KaAbstractFirDiagnostic<KtClassOrObject>(firDiagnostic, token), KaFirDiagnostic.InvisibleAbstractMemberFromSuperWarning

compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt

+3-3
Original file line numberDiff line numberDiff line change
@@ -1116,22 +1116,22 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
11161116

11171117
val ABSTRACT_MEMBER_NOT_IMPLEMENTED by error<KtClassOrObject>(PositioningStrategy.DECLARATION_NAME) {
11181118
parameter<FirClassSymbol<*>>("classOrObject")
1119-
parameter<FirCallableSymbol<*>>("missingDeclaration")
1119+
parameter<List<FirCallableSymbol<*>>>("missingDeclarations")
11201120
}
11211121
val ABSTRACT_MEMBER_NOT_IMPLEMENTED_BY_ENUM_ENTRY by error<KtEnumEntry>(PositioningStrategy.DECLARATION_NAME) {
11221122
parameter<FirEnumEntrySymbol>("enumEntry")
11231123
parameter<List<FirCallableSymbol<*>>>("missingDeclarations")
11241124
}
11251125
val ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED by error<KtClassOrObject>(PositioningStrategy.DECLARATION_NAME) {
11261126
parameter<FirClassSymbol<*>>("classOrObject")
1127-
parameter<FirCallableSymbol<*>>("missingDeclaration")
1127+
parameter<List<FirCallableSymbol<*>>>("missingDeclarations")
11281128
}
11291129
val INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER by deprecationError<KtClassOrObject>(
11301130
LanguageFeature.ProhibitInvisibleAbstractMethodsInSuperclasses,
11311131
PositioningStrategy.DECLARATION_NAME
11321132
) {
11331133
parameter<FirClassSymbol<*>>("classOrObject")
1134-
parameter<FirCallableSymbol<*>>("invisibleDeclaration")
1134+
parameter<List<FirCallableSymbol<*>>>("invisibleDeclarations")
11351135
}
11361136
val AMBIGUOUS_ANONYMOUS_TYPE_INFERRED by error<KtDeclaration>(PositioningStrategy.DECLARATION_NAME) {
11371137
parameter<Collection<ConeKotlinType>>("superTypes")

compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt

+3-3
Original file line numberDiff line numberDiff line change
@@ -578,10 +578,10 @@ object FirErrors {
578578
val PROPERTY_TYPE_MISMATCH_BY_DELEGATION: KtDiagnosticFactory2<FirCallableSymbol<*>, FirCallableSymbol<*>> = KtDiagnosticFactory2("PROPERTY_TYPE_MISMATCH_BY_DELEGATION", ERROR, SourceElementPositioningStrategies.DECLARATION_NAME, KtClassOrObject::class)
579579
val VAR_OVERRIDDEN_BY_VAL_BY_DELEGATION: KtDiagnosticFactory2<FirCallableSymbol<*>, FirCallableSymbol<*>> = KtDiagnosticFactory2("VAR_OVERRIDDEN_BY_VAL_BY_DELEGATION", ERROR, SourceElementPositioningStrategies.DECLARATION_NAME, KtClassOrObject::class)
580580
val CONFLICTING_INHERITED_MEMBERS: KtDiagnosticFactory2<FirClassSymbol<*>, List<FirCallableSymbol<*>>> = KtDiagnosticFactory2("CONFLICTING_INHERITED_MEMBERS", ERROR, SourceElementPositioningStrategies.DECLARATION_NAME, KtClassOrObject::class)
581-
val ABSTRACT_MEMBER_NOT_IMPLEMENTED: KtDiagnosticFactory2<FirClassSymbol<*>, FirCallableSymbol<*>> = KtDiagnosticFactory2("ABSTRACT_MEMBER_NOT_IMPLEMENTED", ERROR, SourceElementPositioningStrategies.DECLARATION_NAME, KtClassOrObject::class)
581+
val ABSTRACT_MEMBER_NOT_IMPLEMENTED: KtDiagnosticFactory2<FirClassSymbol<*>, List<FirCallableSymbol<*>>> = KtDiagnosticFactory2("ABSTRACT_MEMBER_NOT_IMPLEMENTED", ERROR, SourceElementPositioningStrategies.DECLARATION_NAME, KtClassOrObject::class)
582582
val ABSTRACT_MEMBER_NOT_IMPLEMENTED_BY_ENUM_ENTRY: KtDiagnosticFactory2<FirEnumEntrySymbol, List<FirCallableSymbol<*>>> = KtDiagnosticFactory2("ABSTRACT_MEMBER_NOT_IMPLEMENTED_BY_ENUM_ENTRY", ERROR, SourceElementPositioningStrategies.DECLARATION_NAME, KtEnumEntry::class)
583-
val ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED: KtDiagnosticFactory2<FirClassSymbol<*>, FirCallableSymbol<*>> = KtDiagnosticFactory2("ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED", ERROR, SourceElementPositioningStrategies.DECLARATION_NAME, KtClassOrObject::class)
584-
val INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER: KtDiagnosticFactoryForDeprecation2<FirClassSymbol<*>, FirCallableSymbol<*>> = KtDiagnosticFactoryForDeprecation2("INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER", ProhibitInvisibleAbstractMethodsInSuperclasses, SourceElementPositioningStrategies.DECLARATION_NAME, KtClassOrObject::class)
583+
val ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED: KtDiagnosticFactory2<FirClassSymbol<*>, List<FirCallableSymbol<*>>> = KtDiagnosticFactory2("ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED", ERROR, SourceElementPositioningStrategies.DECLARATION_NAME, KtClassOrObject::class)
584+
val INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER: KtDiagnosticFactoryForDeprecation2<FirClassSymbol<*>, List<FirCallableSymbol<*>>> = KtDiagnosticFactoryForDeprecation2("INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER", ProhibitInvisibleAbstractMethodsInSuperclasses, SourceElementPositioningStrategies.DECLARATION_NAME, KtClassOrObject::class)
585585
val AMBIGUOUS_ANONYMOUS_TYPE_INFERRED: KtDiagnosticFactory1<Collection<ConeKotlinType>> = KtDiagnosticFactory1("AMBIGUOUS_ANONYMOUS_TYPE_INFERRED", ERROR, SourceElementPositioningStrategies.DECLARATION_NAME, KtDeclaration::class)
586586
val MANY_IMPL_MEMBER_NOT_IMPLEMENTED: KtDiagnosticFactory2<FirClassSymbol<*>, FirCallableSymbol<*>> = KtDiagnosticFactory2("MANY_IMPL_MEMBER_NOT_IMPLEMENTED", ERROR, SourceElementPositioningStrategies.DECLARATION_NAME, KtClassOrObject::class)
587587
val MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED: KtDiagnosticFactory2<FirClassSymbol<*>, FirCallableSymbol<*>> = KtDiagnosticFactory2("MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED", ERROR, SourceElementPositioningStrategies.DECLARATION_NAME, KtClassOrObject::class)

compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirNotImplementedOverrideChecker.kt

+58-40
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VAR_IMPLEMENTED_B
2525
import org.jetbrains.kotlin.fir.containingClassLookupTag
2626
import org.jetbrains.kotlin.fir.declarations.FirClass
2727
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
28-
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
2928
import org.jetbrains.kotlin.fir.declarations.FirEnumEntry
3029
import org.jetbrains.kotlin.fir.declarations.utils.*
3130
import org.jetbrains.kotlin.fir.delegatedWrapperData
@@ -116,7 +115,7 @@ object FirNotImplementedOverrideChecker : FirClassChecker(MppCheckerKind.Platfor
116115
classScope.processPropertiesByName(name, ::collectSymbol)
117116
}
118117

119-
varsImplementedByInheritedVal.firstOrNull()?.let { symbol ->
118+
varsImplementedByInheritedVal.forEach { symbol ->
120119
val implementationVal = symbol.intersections.first { it is FirPropertySymbol && it.isVal && !it.isAbstract }
121120
val abstractVar = symbol.intersections.first { it is FirPropertySymbol && it.isVar && it.isAbstract }
122121
reporter.reportOn(
@@ -128,36 +127,54 @@ object FirNotImplementedOverrideChecker : FirClassChecker(MppCheckerKind.Platfor
128127
context,
129128
)
130129
}
131-
if (!canHaveAbstractDeclarations && notImplementedSymbols.isNotEmpty()) {
132-
val notImplemented = (notImplementedSymbols.firstOrNull { !it.isFromInterfaceOrEnum(context) } ?: notImplementedSymbols.first())
133-
.unwrapFakeOverrides()
134-
if (notImplemented.isFromInterfaceOrEnum(context)) {
135-
val containingDeclaration = context.containingDeclarations.lastOrNull()
136-
if (declaration.isInitializerOfEnumEntry(containingDeclaration)) {
137-
reporter.reportOn(
138-
source,
139-
ABSTRACT_MEMBER_NOT_IMPLEMENTED_BY_ENUM_ENTRY,
140-
containingDeclaration.symbol,
141-
notImplementedSymbols,
142-
context
143-
)
144-
} else {
145-
reporter.reportOn(source, ABSTRACT_MEMBER_NOT_IMPLEMENTED, classSymbol, notImplemented, context)
146-
}
147-
} else {
148-
reporter.reportOn(source, ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED, classSymbol, notImplemented, context)
130+
if (!canHaveAbstractDeclarations) {
131+
val (fromInterfaceOrEnum, notFromInterfaceOrEnum) = notImplementedSymbols.partition {
132+
it.unwrapFakeOverrides().isFromInterfaceOrEnum(context)
133+
}
134+
val containingDeclaration = context.containingDeclarations.lastOrNull()
135+
val (fromInitializerOfEnumEntry, notFromInitializerOfEnumEntry) = fromInterfaceOrEnum.partition {
136+
declaration.isInitializerOfEnumEntry(containingDeclaration)
137+
}
138+
139+
if (containingDeclaration is FirEnumEntry && fromInitializerOfEnumEntry.isNotEmpty()) {
140+
reporter.reportOn(
141+
source,
142+
ABSTRACT_MEMBER_NOT_IMPLEMENTED_BY_ENUM_ENTRY,
143+
containingDeclaration.symbol,
144+
fromInitializerOfEnumEntry,
145+
context,
146+
)
147+
}
148+
149+
if (notFromInitializerOfEnumEntry.isNotEmpty()) {
150+
reporter.reportOn(
151+
source,
152+
ABSTRACT_MEMBER_NOT_IMPLEMENTED,
153+
classSymbol,
154+
notFromInitializerOfEnumEntry.map { it.unwrapFakeOverrides() },
155+
context,
156+
)
157+
}
158+
159+
if (notFromInterfaceOrEnum.isNotEmpty()) {
160+
reporter.reportOn(
161+
source,
162+
ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED,
163+
classSymbol,
164+
notFromInterfaceOrEnum.map { it.unwrapFakeOverrides() },
165+
context,
166+
)
149167
}
150168
}
151169
if (!canHaveAbstractDeclarations && invisibleSymbols.isNotEmpty()) {
152-
val invisible = invisibleSymbols.first()
153-
reporter.reportOn(source, INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER, classSymbol, invisible, context)
170+
reporter.reportOn(source, INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER, classSymbol, invisibleSymbols, context)
154171
}
155172

156-
manyImplementationsDelegationSymbols.firstOrNull()?.let {
173+
manyImplementationsDelegationSymbols.forEach {
157174
reporter.reportOn(source, MANY_IMPL_MEMBER_NOT_IMPLEMENTED, classSymbol, it, context)
158175
}
159176

160-
delegationOverrideOfFinal.firstOrNull()?.let { (delegated, final) ->
177+
delegationOverrideOfFinal.forEach { (delegated, final) ->
161178
reporter.reportOn(
162179
source,
163180
OVERRIDING_FINAL_MEMBER_BY_DELEGATION,
@@ -167,7 +184,7 @@ object FirNotImplementedOverrideChecker : FirClassChecker(MppCheckerKind.Platfor
167184
)
168185
}
169186

170-
delegationOverrideOfOpen.firstOrNull()?.let { (delegated, open) ->
187+
delegationOverrideOfOpen.forEach { (delegated, open) ->
171188
reporter.reportOn(
172189
source,
173190
DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE,
@@ -177,25 +194,26 @@ object FirNotImplementedOverrideChecker : FirClassChecker(MppCheckerKind.Platfor
177194
)
178195
}
179196

180-
if (manyImplementationsDelegationSymbols.isEmpty() && notImplementedIntersectionSymbols.isNotEmpty()) {
181-
val notImplementedIntersectionSymbol = notImplementedIntersectionSymbols.first()
182-
val (abstractIntersections, implIntersections) =
183-
(notImplementedIntersectionSymbol as FirIntersectionCallableSymbol).intersections.partition {
184-
it.modality == Modality.ABSTRACT
185-
}
186-
if (implIntersections.any {
187-
it.containingClassLookupTag()?.toRegularClassSymbol(context.session)?.classKind == ClassKind.CLASS
188-
}
189-
) {
190-
reporter.reportOn(source, MANY_IMPL_MEMBER_NOT_IMPLEMENTED, classSymbol, notImplementedIntersectionSymbol, context)
191-
} else {
192-
if (canHaveAbstractDeclarations && abstractIntersections.any {
197+
if (manyImplementationsDelegationSymbols.isEmpty()) {
198+
notImplementedIntersectionSymbols.forEach { notImplementedIntersectionSymbol ->
199+
val (abstractIntersections, implIntersections) =
200+
(notImplementedIntersectionSymbol as FirIntersectionCallableSymbol).intersections.partition {
201+
it.modality == Modality.ABSTRACT
202+
}
203+
if (implIntersections.any {
193204
it.containingClassLookupTag()?.toRegularClassSymbol(context.session)?.classKind == ClassKind.CLASS
194205
}
195206
) {
196-
return
207+
reporter.reportOn(source, MANY_IMPL_MEMBER_NOT_IMPLEMENTED, classSymbol, notImplementedIntersectionSymbol, context)
208+
} else {
209+
if (canHaveAbstractDeclarations && abstractIntersections.any {
210+
it.containingClassLookupTag()?.toRegularClassSymbol(context.session)?.classKind == ClassKind.CLASS
211+
}
212+
) {
213+
return
214+
}
215+
reporter.reportOn(source, MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED, classSymbol, notImplementedIntersectionSymbol, context)
197216
}
198-
reporter.reportOn(source, MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED, classSymbol, notImplementedIntersectionSymbol, context)
199217
}
200218
}
201219
}

compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDiagnosticRenderers.kt

+14
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,20 @@ object FirDiagnosticRenderers {
8787
symbols.joinToString(separator = "\n", prefix = "\n", transform = SYMBOL::render)
8888
}
8989

90+
/**
91+
* Prepends [singular] or [plural] depending on the elements count.
92+
*/
93+
fun <Q> prefix(
94+
singular: String,
95+
plural: String,
96+
renderer: ContextIndependentParameterRenderer<Collection<Q>>,
97+
): ContextIndependentParameterRenderer<Collection<Q>> {
98+
return Renderer { elements ->
99+
val decoration = if (elements.size == 1) singular else plural
100+
decoration + renderer.render(elements)
101+
}
102+
}
103+
90104
val SYMBOLS_ON_NEWLINE_WITH_INDENT = object : ContextIndependentParameterRenderer<Collection<FirCallableSymbol<*>>> {
91105
private val mode = MultiplatformDiagnosticRenderingMode()
92106

0 commit comments

Comments
 (0)