[FIR] Implement CONFLICTING_INHERITED_MEMBERS diagnostic

This commit is contained in:
Andrey Zinovyev
2021-06-11 17:58:30 +03:00
committed by teamcityserver
parent 78519f851e
commit 3f7d050f8f
11 changed files with 72 additions and 4 deletions
@@ -617,6 +617,10 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
parameter<FirCallableDeclaration<*>>("baseDeclaration")
}
val CONFLICTING_INHERITED_MEMBERS by error<KtClassOrObject>(PositioningStrategy.DECLARATION_NAME) {
parameter<List<FirCallableDeclaration<*>>>("conflictingDeclarations")
}
val ABSTRACT_MEMBER_NOT_IMPLEMENTED by error<KtClassOrObject>(PositioningStrategy.DECLARATION_NAME) {
parameter<FirClass>("classOrObject")
parameter<FirCallableDeclaration>("missingDeclaration")
@@ -353,6 +353,7 @@ object FirErrors {
val RETURN_TYPE_MISMATCH_BY_DELEGATION by error2<KtClassOrObject, FirCallableDeclaration<*>, FirCallableDeclaration<*>>(SourceElementPositioningStrategies.DECLARATION_NAME)
val PROPERTY_TYPE_MISMATCH_BY_DELEGATION by error2<KtClassOrObject, FirCallableDeclaration<*>, FirCallableDeclaration<*>>(SourceElementPositioningStrategies.DECLARATION_NAME)
val VAR_OVERRIDDEN_BY_VAL_BY_DELEGATION by error2<KtClassOrObject, FirCallableDeclaration<*>, FirCallableDeclaration<*>>(SourceElementPositioningStrategies.DECLARATION_NAME)
val CONFLICTING_INHERITED_MEMBERS by error1<KtClassOrObject, List<FirCallableDeclaration<*>>>(SourceElementPositioningStrategies.DECLARATION_NAME)
val ABSTRACT_MEMBER_NOT_IMPLEMENTED by error2<KtClassOrObject, FirClass, FirCallableDeclaration>(SourceElementPositioningStrategies.DECLARATION_NAME)
val ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED by error2<KtClassOrObject, FirClass, FirCallableDeclaration>(SourceElementPositioningStrategies.DECLARATION_NAME)
val INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER by error2<KtClassOrObject, FirClass, FirCallableDeclaration>(SourceElementPositioningStrategies.DECLARATION_NAME)
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.impl.deduplicating
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.scopes.FirTypeScope
import org.jetbrains.kotlin.fir.scopes.impl.delegatedWrapperData
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.typeContext
@@ -21,6 +22,7 @@ import org.jetbrains.kotlin.fir.types.ConeKotlinErrorType
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.ConeTypeCheckerContext
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.AbstractTypeChecker
object FirImplementationMismatchChecker : FirClassChecker() {
@@ -46,6 +48,7 @@ object FirImplementationMismatchChecker : FirClassChecker() {
checkInheritanceClash(declaration, context, dedupReporter, typeCheckerContext, it)
checkValOverrideVar(declaration, context, dedupReporter, it)
}
checkConflictingMembers(declaration, context, dedupReporter, classScope, name)
}
}
@@ -154,4 +157,34 @@ object FirImplementationMismatchChecker : FirClassChecker() {
reporter.reportOn(containingClass.source, FirErrors.VAR_OVERRIDDEN_BY_VAL_BY_DELEGATION, delegatedVal.fir, baseVar.fir, context)
}
}
private fun checkConflictingMembers(
containingClass: FirClass<*>,
context: CheckerContext,
reporter: DiagnosticReporter,
scope: FirTypeScope,
name: Name
) {
val allFunctions = mutableListOf<FirSimpleFunction>()
scope.processFunctionsByName(name) { sym ->
val declaredInThisClass = sym.callableId.classId == containingClass.classId
when {
sym is FirIntersectionOverrideFunctionSymbol && declaredInThisClass ->
sym.intersections.mapNotNullTo(allFunctions) { (it as? FirNamedFunctionSymbol)?.fir }
!declaredInThisClass -> allFunctions.add(sym.fir)
}
}
val sameArgumentGroups = allFunctions.groupBy { function ->
function.valueParameters.map { it.returnTypeRef.coneType }
}.values
val clash = sameArgumentGroups.mapNotNull { fs ->
fs.zipWithNext().find { (m1, m2) ->
m1.isSuspend != m2.isSuspend || m1.typeParameters.size != m2.typeParameters.size
}
}.firstOrNull() ?: return
reporter.reportOn(containingClass.source, FirErrors.CONFLICTING_INHERITED_MEMBERS, clash.toList(), context)
}
}
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.analysis.diagnostics
import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages
import org.jetbrains.kotlin.diagnostics.rendering.LanguageFeatureMessageRenderer
import org.jetbrains.kotlin.diagnostics.rendering.Renderers.RENDER_POSITION_VARIANCE
import org.jetbrains.kotlin.diagnostics.rendering.Renderers.commaSeparated
import org.jetbrains.kotlin.diagnostics.rendering.Renderers.STRING
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.AMBIGUOUS_CALLS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.DECLARATION_NAME
@@ -76,6 +77,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.COMPONENT_FUNCTIO
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.COMPONENT_FUNCTION_RETURN_TYPE_MISMATCH
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONDITION_TYPE_MISMATCH
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONFLICTING_IMPORT
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONFLICTING_INHERITED_MEMBERS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONFLICTING_OVERLOADS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONFLICTING_PROJECTION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION
@@ -983,6 +985,12 @@ class FirDefaultErrorMessages {
NAME
)
map.put(
CONFLICTING_INHERITED_MEMBERS,
"{0} inherits conflicting members: {1}",
commaSeparated(NAME)
)
// Redeclarations
map.put(MANY_COMPANION_OBJECTS, "Only one companion object is allowed per class")
map.put(CONFLICTING_OVERLOADS, "Conflicting overloads: {0}", SYMBOLS) // *
@@ -15,7 +15,7 @@ interface B {
fun <T> a(@An arg: @An Int)
}
interface C : A, B
<!CONFLICTING_INHERITED_MEMBERS!>interface C<!> : A, B
@An
abstract class D {
@@ -8,6 +8,6 @@ interface B {
fun bar()
}
interface C1 : A, B {
<!CONFLICTING_INHERITED_MEMBERS!>interface C1<!> : A, B {
override fun bar()
}
@@ -1,6 +1,6 @@
interface AsyncVal { suspend fun getVal(): Int = 1}
interface SyncVal { fun getVal(): Int = 1 }
<!MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED!>class MixSuspend<!> : AsyncVal, SyncVal {
<!CONFLICTING_INHERITED_MEMBERS, MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED!>class MixSuspend<!> : AsyncVal, SyncVal {
}
@@ -20624,7 +20624,7 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
@Test
@TestMetadata("kt13355viaJava.kt")
public void testKt13355viaJava1111() throws Exception {
public void testKt13355viaJava() throws Exception {
runTest("compiler/testData/diagnostics/tests/override/clashesOnInheritance/kt13355viaJava.kt");
}
@@ -1700,6 +1700,15 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirErrors.CONFLICTING_INHERITED_MEMBERS) { firDiagnostic ->
ConflictingInheritedMembersImpl(
firDiagnostic.a.map { firCallableDeclaration ->
firSymbolBuilder.callableBuilder.buildCallableSymbol(firCallableDeclaration as FirCallableDeclaration)
},
firDiagnostic as FirPsiDiagnostic<*>,
token,
)
}
add(FirErrors.ABSTRACT_MEMBER_NOT_IMPLEMENTED) { firDiagnostic ->
AbstractMemberNotImplementedImpl(
firSymbolBuilder.classifierBuilder.buildClassLikeSymbol(firDiagnostic.a),
@@ -1207,6 +1207,11 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
abstract val baseDeclaration: KtCallableSymbol
}
abstract class ConflictingInheritedMembers : KtFirDiagnostic<KtClassOrObject>() {
override val diagnosticClass get() = ConflictingInheritedMembers::class
abstract val conflictingDeclarations: List<KtCallableSymbol>
}
abstract class AbstractMemberNotImplemented : KtFirDiagnostic<KtClassOrObject>() {
override val diagnosticClass get() = AbstractMemberNotImplemented::class
abstract val classOrObject: KtClassLikeSymbol
@@ -1937,6 +1937,14 @@ internal class VarOverriddenByValByDelegationImpl(
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
}
internal class ConflictingInheritedMembersImpl(
override val conflictingDeclarations: List<KtCallableSymbol>,
firDiagnostic: FirPsiDiagnostic<*>,
override val token: ValidityToken,
) : KtFirDiagnostic.ConflictingInheritedMembers(), KtAbstractFirDiagnostic<KtClassOrObject> {
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
}
internal class AbstractMemberNotImplementedImpl(
override val classOrObject: KtClassLikeSymbol,
override val missingDeclaration: KtCallableSymbol,