FIR checker: report VIRTUAL_MEMBER_HIDDEN
This commit is contained in:
committed by
Mikhail Glukhikh
parent
d3dfb33f89
commit
32f55a2269
@@ -8,7 +8,7 @@ open class A {
|
|||||||
|
|
||||||
class B : A() {
|
class B : A() {
|
||||||
override fun foo(): B = this
|
override fun foo(): B = this
|
||||||
fun bar(): B = this // Ambiguity, no override here (really it's just "missing override" and no ambiguity)
|
fun <!VIRTUAL_MEMBER_HIDDEN!>bar<!>(): B = this // Missing 'override'
|
||||||
override fun buz(p: B): B = this //No override as B not :> A
|
override fun buz(p: B): B = this //No override as B not :> A
|
||||||
|
|
||||||
fun test() {
|
fun test() {
|
||||||
|
|||||||
+1
-1
@@ -44,7 +44,7 @@ public <!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>class LightClassWrapper<!> : Light(),
|
|||||||
}
|
}
|
||||||
|
|
||||||
public abstract class Light : Field, TypeParametersOwner {
|
public abstract class Light : Field, TypeParametersOwner {
|
||||||
fun getTypeParameters() = listOf()
|
fun <!VIRTUAL_MEMBER_HIDDEN!>getTypeParameters<!>() = listOf()
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface Field : Named
|
public interface Field : Named
|
||||||
|
|||||||
+1
-1
@@ -14,7 +14,7 @@ public class A {
|
|||||||
|
|
||||||
class B : A() {
|
class B : A() {
|
||||||
override fun foo(): B = this
|
override fun foo(): B = this
|
||||||
fun bar(): B = this // Here we should have "missing override" but no ambiguity
|
fun <!VIRTUAL_MEMBER_HIDDEN!>bar<!>(): B = this // Here we should have "missing override" but no ambiguity
|
||||||
|
|
||||||
fun test() {
|
fun test() {
|
||||||
foo()
|
foo()
|
||||||
|
|||||||
+4
@@ -563,6 +563,10 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
|||||||
}
|
}
|
||||||
val NON_FINAL_MEMBER_IN_FINAL_CLASS by warning<KtNamedDeclaration>(PositioningStrategy.OPEN_MODIFIER)
|
val NON_FINAL_MEMBER_IN_FINAL_CLASS by warning<KtNamedDeclaration>(PositioningStrategy.OPEN_MODIFIER)
|
||||||
val NON_FINAL_MEMBER_IN_OBJECT by warning<KtNamedDeclaration>(PositioningStrategy.OPEN_MODIFIER)
|
val NON_FINAL_MEMBER_IN_OBJECT by warning<KtNamedDeclaration>(PositioningStrategy.OPEN_MODIFIER)
|
||||||
|
val VIRTUAL_MEMBER_HIDDEN by error<KtNamedDeclaration>(PositioningStrategy.DECLARATION_NAME) {
|
||||||
|
parameter<FirMemberDeclaration>("declared")
|
||||||
|
parameter<FirRegularClass>("overriddenContainer")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val REDECLARATIONS by object : DiagnosticGroup("Redeclarations") {
|
val REDECLARATIONS by object : DiagnosticGroup("Redeclarations") {
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.fir.declarations.FirClass
|
|||||||
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirEnumEntry
|
import org.jetbrains.kotlin.fir.declarations.FirEnumEntry
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
|
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
|
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||||
@@ -336,6 +337,7 @@ object FirErrors {
|
|||||||
val VAR_OVERRIDDEN_BY_VAL by error2<KtNamedDeclaration, FirMemberDeclaration, FirMemberDeclaration>(SourceElementPositioningStrategies.VAL_OR_VAR_NODE)
|
val VAR_OVERRIDDEN_BY_VAL by error2<KtNamedDeclaration, FirMemberDeclaration, FirMemberDeclaration>(SourceElementPositioningStrategies.VAL_OR_VAR_NODE)
|
||||||
val NON_FINAL_MEMBER_IN_FINAL_CLASS by warning0<KtNamedDeclaration>(SourceElementPositioningStrategies.OPEN_MODIFIER)
|
val NON_FINAL_MEMBER_IN_FINAL_CLASS by warning0<KtNamedDeclaration>(SourceElementPositioningStrategies.OPEN_MODIFIER)
|
||||||
val NON_FINAL_MEMBER_IN_OBJECT by warning0<KtNamedDeclaration>(SourceElementPositioningStrategies.OPEN_MODIFIER)
|
val NON_FINAL_MEMBER_IN_OBJECT by warning0<KtNamedDeclaration>(SourceElementPositioningStrategies.OPEN_MODIFIER)
|
||||||
|
val VIRTUAL_MEMBER_HIDDEN by error2<KtNamedDeclaration, FirMemberDeclaration, FirRegularClass>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||||
|
|
||||||
// Redeclarations
|
// Redeclarations
|
||||||
val MANY_COMPANION_OBJECTS by error0<KtObjectDeclaration>(SourceElementPositioningStrategies.COMPANION_OBJECT)
|
val MANY_COMPANION_OBJECTS by error0<KtObjectDeclaration>(SourceElementPositioningStrategies.COMPANION_OBJECT)
|
||||||
|
|||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.fir.analysis
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
|
import org.jetbrains.kotlin.fir.FirSessionComponent
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||||
|
|
||||||
|
interface FirOverridesBackwardCompatibilityHelper : FirSessionComponent {
|
||||||
|
fun overrideCanBeOmitted(overriddenMemberSymbols: List<FirCallableSymbol<*>>, context: CheckerContext): Boolean
|
||||||
|
|
||||||
|
class Default : FirOverridesBackwardCompatibilityHelper {
|
||||||
|
override fun overrideCanBeOmitted(overriddenMemberSymbols: List<FirCallableSymbol<*>>, context: CheckerContext): Boolean = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val FirSession.overridesBackwardCompatibilityHelper: FirOverridesBackwardCompatibilityHelper by FirSession.sessionComponentAccessor()
|
||||||
@@ -49,7 +49,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
|||||||
|
|
||||||
private val INLINE_ONLY_ANNOTATION_CLASS_ID = ClassId.topLevel(FqName("kotlin.internal.InlineOnly"))
|
private val INLINE_ONLY_ANNOTATION_CLASS_ID = ClassId.topLevel(FqName("kotlin.internal.InlineOnly"))
|
||||||
|
|
||||||
internal fun FirClass<*>.unsubstitutedScope(context: CheckerContext) =
|
fun FirClass<*>.unsubstitutedScope(context: CheckerContext) =
|
||||||
this.unsubstitutedScope(context.sessionHolder.session, context.sessionHolder.scopeSession, withForcedTypeCalculator = false)
|
this.unsubstitutedScope(context.sessionHolder.session, context.sessionHolder.scopeSession, withForcedTypeCalculator = false)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+23
-4
@@ -7,21 +7,22 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||||
|
import org.jetbrains.kotlin.fir.*
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope
|
import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||||
import org.jetbrains.kotlin.fir.containingClass
|
import org.jetbrains.kotlin.fir.analysis.overridesBackwardCompatibilityHelper
|
||||||
import org.jetbrains.kotlin.fir.declarations.*
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
|
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.toFirRegularClass
|
||||||
import org.jetbrains.kotlin.fir.scopes.FirTypeScope
|
import org.jetbrains.kotlin.fir.scopes.FirTypeScope
|
||||||
import org.jetbrains.kotlin.fir.scopes.getDirectOverriddenFunctions
|
import org.jetbrains.kotlin.fir.scopes.getDirectOverriddenFunctions
|
||||||
import org.jetbrains.kotlin.fir.scopes.getDirectOverriddenProperties
|
import org.jetbrains.kotlin.fir.scopes.getDirectOverriddenProperties
|
||||||
import org.jetbrains.kotlin.fir.scopes.impl.toConeType
|
import org.jetbrains.kotlin.fir.scopes.impl.toConeType
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
||||||
import org.jetbrains.kotlin.fir.typeContext
|
|
||||||
import org.jetbrains.kotlin.fir.types.ConeKotlinErrorType
|
import org.jetbrains.kotlin.fir.types.ConeKotlinErrorType
|
||||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||||
import org.jetbrains.kotlin.fir.types.coneType
|
import org.jetbrains.kotlin.fir.types.coneType
|
||||||
@@ -172,12 +173,30 @@ object FirOverrideChecker : FirClassChecker() {
|
|||||||
firTypeScope: FirTypeScope,
|
firTypeScope: FirTypeScope,
|
||||||
context: CheckerContext,
|
context: CheckerContext,
|
||||||
) {
|
) {
|
||||||
|
val overriddenMemberSymbols = firTypeScope.retrieveDirectOverriddenOf(member)
|
||||||
|
|
||||||
if (!member.isOverride) {
|
if (!member.isOverride) {
|
||||||
|
if (overriddenMemberSymbols.isEmpty() ||
|
||||||
|
context.session.overridesBackwardCompatibilityHelper.overrideCanBeOmitted(overriddenMemberSymbols, context)
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val kind = member.source?.kind
|
||||||
|
// Only report if the current member has real source or it's a member property declared inside the primary constructor.
|
||||||
|
if (kind !is FirRealSourceElementKind && kind !is FirFakeSourceElementKind.PropertyFromParameter) return
|
||||||
|
|
||||||
|
val overridden = overriddenMemberSymbols.first().originalOrSelf()
|
||||||
|
val containingClass = overridden.containingClass()?.toFirRegularClass(context.session) ?: return
|
||||||
|
reporter.reportOn(
|
||||||
|
member.source,
|
||||||
|
FirErrors.VIRTUAL_MEMBER_HIDDEN,
|
||||||
|
member,
|
||||||
|
containingClass,
|
||||||
|
context
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val overriddenMemberSymbols = firTypeScope.retrieveDirectOverriddenOf(member)
|
|
||||||
|
|
||||||
if (overriddenMemberSymbols.isEmpty()) {
|
if (overriddenMemberSymbols.isEmpty()) {
|
||||||
reporter.reportNothingToOverride(member, context)
|
reporter.reportNothingToOverride(member, context)
|
||||||
return
|
return
|
||||||
|
|||||||
+6
@@ -353,6 +353,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VARIANCE_ON_TYPE_
|
|||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VAR_ANNOTATION_PARAMETER
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VAR_ANNOTATION_PARAMETER
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VAR_OVERRIDDEN_BY_VAL
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VAR_OVERRIDDEN_BY_VAL
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VAR_TYPE_MISMATCH_ON_OVERRIDE
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VAR_TYPE_MISMATCH_ON_OVERRIDE
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VIRTUAL_MEMBER_HIDDEN
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_ANNOTATION_TARGET
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_ANNOTATION_TARGET
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_GETTER_RETURN_TYPE
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_GETTER_RETURN_TYPE
|
||||||
@@ -818,6 +819,11 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
|
|||||||
)
|
)
|
||||||
map.put(NON_FINAL_MEMBER_IN_FINAL_CLASS, "'open' has no effect in a final class")
|
map.put(NON_FINAL_MEMBER_IN_FINAL_CLASS, "'open' has no effect in a final class")
|
||||||
map.put(NON_FINAL_MEMBER_IN_OBJECT, "'open' has no effect in an object")
|
map.put(NON_FINAL_MEMBER_IN_OBJECT, "'open' has no effect in an object")
|
||||||
|
map.put(
|
||||||
|
VIRTUAL_MEMBER_HIDDEN, "''{0}'' hides member of supertype ''{1}'' and needs ''override'' modifier", DECLARATION_NAME,
|
||||||
|
DECLARATION_NAME
|
||||||
|
)
|
||||||
|
|
||||||
map.put(
|
map.put(
|
||||||
GENERIC_THROWABLE_SUBCLASS,
|
GENERIC_THROWABLE_SUBCLASS,
|
||||||
"Subclass of 'Throwable' may not have type parameters"
|
"Subclass of 'Throwable' may not have type parameters"
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import com.intellij.psi.PsiFile
|
|||||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||||
import org.jetbrains.kotlin.fir.*
|
import org.jetbrains.kotlin.fir.*
|
||||||
import org.jetbrains.kotlin.fir.analysis.CheckersComponent
|
import org.jetbrains.kotlin.fir.analysis.CheckersComponent
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.FirOverridesBackwardCompatibilityHelper
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirNameConflictsTracker
|
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirNameConflictsTracker
|
||||||
import org.jetbrains.kotlin.fir.caches.FirCachesFactory
|
import org.jetbrains.kotlin.fir.caches.FirCachesFactory
|
||||||
import org.jetbrains.kotlin.fir.caches.FirThreadUnsafeCachesFactory
|
import org.jetbrains.kotlin.fir.caches.FirThreadUnsafeCachesFactory
|
||||||
@@ -92,6 +93,7 @@ fun FirSession.registerJavaSpecificResolveComponents() {
|
|||||||
register(FirPlatformClassMapper::class, FirJavaClassMapper(this))
|
register(FirPlatformClassMapper::class, FirJavaClassMapper(this))
|
||||||
register(FirSyntheticNamesProvider::class, FirJavaSyntheticNamesProvider)
|
register(FirSyntheticNamesProvider::class, FirJavaSyntheticNamesProvider)
|
||||||
register(FirJsr305StateContainer::class, FirJsr305StateContainer.Default)
|
register(FirJsr305StateContainer::class, FirJsr305StateContainer.Default)
|
||||||
|
register(FirOverridesBackwardCompatibilityHelper::class, FirJvmOverridesBackwardCompatibilityHelper)
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(SessionConfiguration::class)
|
@OptIn(SessionConfiguration::class)
|
||||||
|
|||||||
+78
@@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.fir.session
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.FirOverridesBackwardCompatibilityHelper
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClass
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope
|
||||||
|
import org.jetbrains.kotlin.fir.containingClass
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.fir.dispatchReceiverTypeOrNull
|
||||||
|
import org.jetbrains.kotlin.fir.originalOrSelf
|
||||||
|
import org.jetbrains.kotlin.fir.scopes.getDirectOverriddenFunctions
|
||||||
|
import org.jetbrains.kotlin.fir.scopes.getDirectOverriddenProperties
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||||
|
import org.jetbrains.kotlin.fir.types.classId
|
||||||
|
import org.jetbrains.kotlin.fir.types.coneTypeSafe
|
||||||
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper that determines if `override` keyword can be omitted for certain overrides. In general it can be omitted if
|
||||||
|
*
|
||||||
|
* 1. the super member is annotated with `@kotlin.internal.PlatformDependent`, OR
|
||||||
|
* 2. the super member is declared in a Java class that has special Kotlin class mapping. For example, overriding members of
|
||||||
|
* `kotlin.Throwable` does not require `override` keyword.
|
||||||
|
*
|
||||||
|
* Note that, in case of multi-override, if any super member requires `override`, then the `override` keyword cannot be omitted.
|
||||||
|
*/
|
||||||
|
object FirJvmOverridesBackwardCompatibilityHelper : FirOverridesBackwardCompatibilityHelper {
|
||||||
|
private val javaOrigin = setOf(FirDeclarationOrigin.Java, FirDeclarationOrigin.Enhancement)
|
||||||
|
private val platformDependentAnnotation = ClassId.fromString("kotlin/internal/PlatformDependent")
|
||||||
|
|
||||||
|
override fun overrideCanBeOmitted(
|
||||||
|
overriddenMemberSymbols: List<FirCallableSymbol<*>>,
|
||||||
|
context: CheckerContext
|
||||||
|
): Boolean {
|
||||||
|
// Members could share the same common interface up in the hierarchy. Hence we track the visited members to avoid redundant work.
|
||||||
|
val visitedSymbols = hashSetOf<FirCallableSymbol<*>>()
|
||||||
|
return overriddenMemberSymbols.all { isPlatformSpecificSymbolThatCanBeImplicitlyOverridden(it, visitedSymbols, context) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isPlatformSpecificSymbolThatCanBeImplicitlyOverridden(
|
||||||
|
symbol: FirCallableSymbol<*>,
|
||||||
|
visitedSymbols: MutableSet<FirCallableSymbol<*>>,
|
||||||
|
context: CheckerContext
|
||||||
|
): Boolean {
|
||||||
|
val fir = symbol.fir as? FirCallableMemberDeclaration<*> ?: return false
|
||||||
|
if (fir.isFinal) return false
|
||||||
|
|
||||||
|
if (symbol in visitedSymbols) return true
|
||||||
|
visitedSymbols += symbol
|
||||||
|
|
||||||
|
val originalMember = fir.originalOrSelf()
|
||||||
|
if (originalMember.annotations.any { it.annotationTypeRef.coneTypeSafe<ConeClassLikeType>()?.classId == platformDependentAnnotation }) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (originalMember.origin !in javaOrigin) return false
|
||||||
|
val containingClassName = originalMember.containingClass()?.classId?.asSingleFqName()?.toUnsafe() ?: return false
|
||||||
|
// If the super class is mapped to a Kotlin built-in class, then we don't require `override` keyword.
|
||||||
|
if (JavaToKotlinClassMap.mapKotlinToJava(containingClassName) != null) return true
|
||||||
|
|
||||||
|
val scope =
|
||||||
|
symbol.dispatchReceiverTypeOrNull()?.toRegularClass(context.session)?.unsubstitutedScope(context) ?: return false
|
||||||
|
val overriddenSymbols = when (originalMember) {
|
||||||
|
is FirSimpleFunction -> scope.getDirectOverriddenFunctions(originalMember.symbol)
|
||||||
|
is FirProperty -> scope.getDirectOverriddenProperties(originalMember.symbol)
|
||||||
|
else -> return false
|
||||||
|
}
|
||||||
|
if (overriddenSymbols.isEmpty()) return false
|
||||||
|
return overriddenSymbols.all { isPlatformSpecificSymbolThatCanBeImplicitlyOverridden(it, visitedSymbols, context) }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -71,6 +71,16 @@ inline fun <reified D : FirCallableDeclaration<*>> D.originalIfFakeOverride(): D
|
|||||||
inline fun <reified S : FirCallableSymbol<*>> S.originalIfFakeOverride(): S? =
|
inline fun <reified S : FirCallableSymbol<*>> S.originalIfFakeOverride(): S? =
|
||||||
fir.originalIfFakeOverride()?.symbol as S?
|
fir.originalIfFakeOverride()?.symbol as S?
|
||||||
|
|
||||||
|
inline fun <reified D : FirCallableDeclaration<*>> D.originalOrSelf(): D {
|
||||||
|
var result = this
|
||||||
|
while (result.isSubstitutionOrIntersectionOverride) {
|
||||||
|
result = result.originalIfFakeOverride() ?: break
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified S : FirCallableSymbol<*>> S.originalOrSelf(): S = fir.originalOrSelf().symbol as S
|
||||||
|
|
||||||
inline fun <reified D : FirCallableDeclaration<*>> D.unwrapFakeOverrides(): D {
|
inline fun <reified D : FirCallableDeclaration<*>> D.unwrapFakeOverrides(): D {
|
||||||
var current = this
|
var current = this
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
interface IA {
|
|
||||||
fun toString(): String = "IB"
|
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
interface IA {
|
interface IA {
|
||||||
fun <!VIRTUAL_MEMBER_HIDDEN!>toString<!>(): String = "IB"
|
fun <!VIRTUAL_MEMBER_HIDDEN!>toString<!>(): String = "IB"
|
||||||
|
|
||||||
|
|||||||
Vendored
-15
@@ -1,15 +0,0 @@
|
|||||||
interface X {
|
|
||||||
fun foo(a : Int = 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Y {
|
|
||||||
fun foo(a : Int = 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
class Z : X, Y {
|
|
||||||
fun foo(a : Int) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
object ZO : X, Y {
|
|
||||||
fun foo(a : Int) {}
|
|
||||||
}
|
|
||||||
Vendored
+1
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
interface X {
|
interface X {
|
||||||
fun foo(a : Int = 1)
|
fun foo(a : Int = 1)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,8 +36,8 @@ class MyChildClass() : MyClass() {}
|
|||||||
}
|
}
|
||||||
|
|
||||||
<!ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED!>class MyIllegalClass4<!>() : MyTrait, MyAbstractClass() {
|
<!ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED!>class MyIllegalClass4<!>() : MyTrait, MyAbstractClass() {
|
||||||
fun foo() {}
|
fun <!VIRTUAL_MEMBER_HIDDEN!>foo<!>() {}
|
||||||
<!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>val pr : Unit<!>
|
<!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>val <!VIRTUAL_MEMBER_HIDDEN!>pr<!> : Unit<!>
|
||||||
override fun other() {}
|
override fun other() {}
|
||||||
override val otherPr : Int = 1
|
override val otherPr : Int = 1
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -25,7 +25,7 @@ fun test() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class E: A() {
|
class E: A() {
|
||||||
fun foo() = A()
|
fun <!VIRTUAL_MEMBER_HIDDEN!>foo<!>() = A()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val a: A = foo() // todo: discuss
|
val a: A = foo() // todo: discuss
|
||||||
|
|||||||
-18
@@ -1,18 +0,0 @@
|
|||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER -PLATFORM_CLASS_MAPPED_TO_KOTLIN
|
|
||||||
|
|
||||||
abstract class Test1 : Map<String, String> {
|
|
||||||
fun containsKey(key: String): Boolean = TODO()
|
|
||||||
|
|
||||||
fun getOrDefault(key: String, defaultValue: String): String = TODO()
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class Test2 : MutableMap<String, String> {
|
|
||||||
fun replace(key: String, value: String): String? = TODO()
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class Test3 : java.util.AbstractMap<String, String>() {
|
|
||||||
fun containsKey(key: String): Boolean = TODO()
|
|
||||||
|
|
||||||
fun replace(key: String, value: String): String? = TODO()
|
|
||||||
}
|
|
||||||
|
|
||||||
+1
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER -PLATFORM_CLASS_MAPPED_TO_KOTLIN
|
// !DIAGNOSTICS: -UNUSED_PARAMETER -PLATFORM_CLASS_MAPPED_TO_KOTLIN
|
||||||
|
|
||||||
abstract class Test1 : Map<String, String> {
|
abstract class Test1 : Map<String, String> {
|
||||||
|
|||||||
Vendored
-32
@@ -1,32 +0,0 @@
|
|||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER -PLATFORM_CLASS_MAPPED_TO_KOTLIN
|
|
||||||
|
|
||||||
|
|
||||||
// Default methods from Java interfaces are NOT overridden by delegation.
|
|
||||||
// So, in the example below 'TestNoDelegationToDefaultMethods#replace' implicitly overrides a method from 'java.util.Map' (which is ok),
|
|
||||||
// but not a method from 'WithDelegation' (would be an error).
|
|
||||||
open class WithDelegation(val m: Map<String, String>) : Map<String, String> by m
|
|
||||||
|
|
||||||
class TestNoDelegationToDefaultMethods(m: Map<String, String>): WithDelegation(m) {
|
|
||||||
fun containsKey(key: String): Boolean = TODO()
|
|
||||||
|
|
||||||
fun getOrDefault(key: String, defaultValue: String): String = TODO()
|
|
||||||
|
|
||||||
fun replace(key: String, value: String): String? = TODO()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
interface IBaseWithKotlinDeclaration : Map<String, String> {
|
|
||||||
fun replace(key: String, value: String): String?
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class WithDelegation2(val m: Map<String, String>) : Map<String, String> by m, IBaseWithKotlinDeclaration
|
|
||||||
|
|
||||||
abstract class TestNoDelegationToDefaultMethods2(m: Map<String, String>): WithDelegation2(m) {
|
|
||||||
fun containsKey(key: String): Boolean = TODO()
|
|
||||||
|
|
||||||
fun getOrDefault(key: String, defaultValue: String): String = TODO()
|
|
||||||
|
|
||||||
// VIRTUAL_MEMBER_HIDDEN: hides member declaration inherited from a Kotlin interface
|
|
||||||
fun replace(key: String, value: String): String? = TODO()
|
|
||||||
}
|
|
||||||
+1
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER -PLATFORM_CLASS_MAPPED_TO_KOTLIN
|
// !DIAGNOSTICS: -UNUSED_PARAMETER -PLATFORM_CLASS_MAPPED_TO_KOTLIN
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
-15
@@ -1,15 +0,0 @@
|
|||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER -PLATFORM_CLASS_MAPPED_TO_KOTLIN
|
|
||||||
|
|
||||||
interface IBaseWithKotlinDeclaration : Map<String, String> {
|
|
||||||
fun replace(key: String, value: String): String?
|
|
||||||
}
|
|
||||||
|
|
||||||
interface TestDerivedInterfaceHidingWithKotlinDeclaration : IBaseWithKotlinDeclaration {
|
|
||||||
// VIRTUAL_MEMBER_HIDDEN: hides member declaration inherited from a Kotlin interface
|
|
||||||
fun replace(key: String, value: String): String?
|
|
||||||
}
|
|
||||||
|
|
||||||
interface TestDerivedInterfaceDefaultWithKotlinDeclaration : IBaseWithKotlinDeclaration {
|
|
||||||
// VIRTUAL_MEMBER_HIDDEN: hides member declaration inherited from a Kotlin interface
|
|
||||||
fun replace(key: String, value: String): String? = TODO()
|
|
||||||
}
|
|
||||||
+1
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER -PLATFORM_CLASS_MAPPED_TO_KOTLIN
|
// !DIAGNOSTICS: -UNUSED_PARAMETER -PLATFORM_CLASS_MAPPED_TO_KOTLIN
|
||||||
|
|
||||||
interface IBaseWithKotlinDeclaration : Map<String, String> {
|
interface IBaseWithKotlinDeclaration : Map<String, String> {
|
||||||
|
|||||||
+2
-2
@@ -14,11 +14,11 @@ class A : java.util.ArrayList<String>() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class A1 : java.util.ArrayList<String>() {
|
class A1 : java.util.ArrayList<String>() {
|
||||||
// `stream` is defined in ArrayList, so it was possible to declare it in 1.0 without an 'override' keyword
|
// `stream` is defined in Collection, so it was possible to declare it in 1.0 without an 'override' keyword
|
||||||
fun stream(): java.util.stream.Stream<String> = super.stream()
|
fun stream(): java.util.stream.Stream<String> = super.stream()
|
||||||
|
|
||||||
// `sort` is defined in ArrayList, so it was impossible to declare it in 1.0 without an 'override' keyword
|
// `sort` is defined in ArrayList, so it was impossible to declare it in 1.0 without an 'override' keyword
|
||||||
fun sort(c: Comparator<in String>?) {
|
fun <!VIRTUAL_MEMBER_HIDDEN!>sort<!>(c: Comparator<in String>?) {
|
||||||
super.sort(c)
|
super.sort(c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -14,7 +14,7 @@ class A : java.util.ArrayList<String>() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class A1 : java.util.ArrayList<String>() {
|
class A1 : java.util.ArrayList<String>() {
|
||||||
// `stream` is defined in ArrayList, so it was possible to declare it in 1.0 without an 'override' keyword
|
// `stream` is defined in Collection, so it was possible to declare it in 1.0 without an 'override' keyword
|
||||||
fun stream(): java.util.stream.Stream<String> = super.<!UNRESOLVED_REFERENCE!>stream<!>()
|
fun stream(): java.util.stream.Stream<String> = super.<!UNRESOLVED_REFERENCE!>stream<!>()
|
||||||
|
|
||||||
// `sort` is defined in ArrayList, so it was impossible to declare it in 1.0 without an 'override' keyword
|
// `sort` is defined in ArrayList, so it was impossible to declare it in 1.0 without an 'override' keyword
|
||||||
|
|||||||
+8
@@ -144,6 +144,14 @@ private object FirToKtConversionCreator {
|
|||||||
"firSymbolBuilder.classifierBuilder.buildClassLikeSymbol({0})",
|
"firSymbolBuilder.classifierBuilder.buildClassLikeSymbol({0})",
|
||||||
KtClassLikeSymbol::class.createType()
|
KtClassLikeSymbol::class.createType()
|
||||||
),
|
),
|
||||||
|
FirRegularClass::class to HLFunctionCallConversion(
|
||||||
|
"firSymbolBuilder.classifierBuilder.buildClassLikeSymbol({0}) as KtNamedClassOrObjectSymbol",
|
||||||
|
KtNamedClassOrObjectSymbol::class.createType(),
|
||||||
|
importsToAdd = listOf(
|
||||||
|
"org.jetbrains.kotlin.fir.declarations.FirRegularClass",
|
||||||
|
"org.jetbrains.kotlin.idea.frontend.api.symbols.KtNamedClassOrObjectSymbol"
|
||||||
|
)
|
||||||
|
),
|
||||||
FirExpression::class to HLFunctionCallConversion(
|
FirExpression::class to HLFunctionCallConversion(
|
||||||
"{0}.source!!.psi as KtExpression",
|
"{0}.source!!.psi as KtExpression",
|
||||||
KtExpression::class.createType(),
|
KtExpression::class.createType(),
|
||||||
|
|||||||
+9
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
|||||||
import org.jetbrains.kotlin.fir.declarations.FirTypeParameter
|
import org.jetbrains.kotlin.fir.declarations.FirTypeParameter
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirVariable
|
import org.jetbrains.kotlin.fir.declarations.FirVariable
|
||||||
import org.jetbrains.kotlin.fir.psi
|
import org.jetbrains.kotlin.fir.psi
|
||||||
|
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtNamedClassOrObjectSymbol
|
||||||
import org.jetbrains.kotlin.psi.KtAnnotation
|
import org.jetbrains.kotlin.psi.KtAnnotation
|
||||||
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
||||||
import org.jetbrains.kotlin.psi.KtArrayAccessExpression
|
import org.jetbrains.kotlin.psi.KtArrayAccessExpression
|
||||||
@@ -1589,6 +1590,14 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
|||||||
token,
|
token,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
add(FirErrors.VIRTUAL_MEMBER_HIDDEN) { firDiagnostic ->
|
||||||
|
VirtualMemberHiddenImpl(
|
||||||
|
firSymbolBuilder.buildSymbol(firDiagnostic.a as FirDeclaration),
|
||||||
|
firSymbolBuilder.classifierBuilder.buildClassLikeSymbol(firDiagnostic.b) as KtNamedClassOrObjectSymbol,
|
||||||
|
firDiagnostic as FirPsiDiagnostic<*>,
|
||||||
|
token,
|
||||||
|
)
|
||||||
|
}
|
||||||
add(FirErrors.MANY_COMPANION_OBJECTS) { firDiagnostic ->
|
add(FirErrors.MANY_COMPANION_OBJECTS) { firDiagnostic ->
|
||||||
ManyCompanionObjectsImpl(
|
ManyCompanionObjectsImpl(
|
||||||
firDiagnostic as FirPsiDiagnostic<*>,
|
firDiagnostic as FirPsiDiagnostic<*>,
|
||||||
|
|||||||
+7
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.idea.frontend.api.diagnostics.KtDiagnosticWithPsi
|
|||||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtCallableSymbol
|
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtCallableSymbol
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassLikeSymbol
|
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassLikeSymbol
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtFunctionLikeSymbol
|
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtFunctionLikeSymbol
|
||||||
|
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtNamedClassOrObjectSymbol
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtSymbol
|
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtSymbol
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtTypeParameterSymbol
|
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtTypeParameterSymbol
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtVariableLikeSymbol
|
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtVariableLikeSymbol
|
||||||
@@ -1129,6 +1130,12 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
|
|||||||
override val diagnosticClass get() = NonFinalMemberInObject::class
|
override val diagnosticClass get() = NonFinalMemberInObject::class
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract class VirtualMemberHidden : KtFirDiagnostic<KtNamedDeclaration>() {
|
||||||
|
override val diagnosticClass get() = VirtualMemberHidden::class
|
||||||
|
abstract val declared: KtSymbol
|
||||||
|
abstract val overriddenContainer: KtNamedClassOrObjectSymbol
|
||||||
|
}
|
||||||
|
|
||||||
abstract class ManyCompanionObjects : KtFirDiagnostic<KtObjectDeclaration>() {
|
abstract class ManyCompanionObjects : KtFirDiagnostic<KtObjectDeclaration>() {
|
||||||
override val diagnosticClass get() = ManyCompanionObjects::class
|
override val diagnosticClass get() = ManyCompanionObjects::class
|
||||||
}
|
}
|
||||||
|
|||||||
+10
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.idea.frontend.api.fir.utils.weakRef
|
|||||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtCallableSymbol
|
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtCallableSymbol
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassLikeSymbol
|
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassLikeSymbol
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtFunctionLikeSymbol
|
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtFunctionLikeSymbol
|
||||||
|
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtNamedClassOrObjectSymbol
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtSymbol
|
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtSymbol
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtTypeParameterSymbol
|
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtTypeParameterSymbol
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtVariableLikeSymbol
|
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtVariableLikeSymbol
|
||||||
@@ -1814,6 +1815,15 @@ internal class NonFinalMemberInObjectImpl(
|
|||||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class VirtualMemberHiddenImpl(
|
||||||
|
override val declared: KtSymbol,
|
||||||
|
override val overriddenContainer: KtNamedClassOrObjectSymbol,
|
||||||
|
firDiagnostic: FirPsiDiagnostic<*>,
|
||||||
|
override val token: ValidityToken,
|
||||||
|
) : KtFirDiagnostic.VirtualMemberHidden(), KtAbstractFirDiagnostic<KtNamedDeclaration> {
|
||||||
|
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||||
|
}
|
||||||
|
|
||||||
internal class ManyCompanionObjectsImpl(
|
internal class ManyCompanionObjectsImpl(
|
||||||
firDiagnostic: FirPsiDiagnostic<*>,
|
firDiagnostic: FirPsiDiagnostic<*>,
|
||||||
override val token: ValidityToken,
|
override val token: ValidityToken,
|
||||||
|
|||||||
Reference in New Issue
Block a user