[FIR] NOTHING_TO_OVERRIDE diagnostic

This commit is contained in:
Andrey Zinovyev
2021-06-21 12:56:40 +03:00
committed by teamcityserver
parent 9452b788bf
commit b44785c24e
38 changed files with 99 additions and 250 deletions
@@ -19,13 +19,13 @@ fun test(z: Int, c: Char) {}
}<!>
<!REDECLARATION!>class B : <!FINAL_SUPERTYPE, SUPERTYPE_NOT_INITIALIZED!>A<!> {
<!CONFLICTING_OVERLOADS!>override fun rest(s: String)<!> {}
<!CONFLICTING_OVERLOADS!><!NOTHING_TO_OVERRIDE!>override<!> fun rest(s: String)<!> {}
<!CONFLICTING_OVERLOADS!>fun rest(s: String)<!> {}
fun rest(l: Long) {}
override val u = 310
<!NOTHING_TO_OVERRIDE!>override<!> val u = 310
}<!>
<!REDECLARATION!>interface B<!>
@@ -17,17 +17,17 @@ class CallBasedInExpressionGenerator(
private val resolvedCall = operatorReference.<!UNRESOLVED_REFERENCE!>getResolvedCallWithAssert<!>(codegen.<!UNRESOLVED_REFERENCE!>bindingContext<!>)
private val isInverted = operatorReference.<!UNRESOLVED_REFERENCE!>getReferencedNameElementType<!>() == <!UNRESOLVED_REFERENCE!>KtTokens<!>.NOT_IN
override fun generate(argument: StackValue): BranchedValue =
<!NOTHING_TO_OVERRIDE!>override<!> fun generate(argument: StackValue): BranchedValue =
gen(argument).let { if (isInverted) <!UNRESOLVED_REFERENCE!>Invert<!>(it) else it }
private fun gen(argument: StackValue): BranchedValue =
object : BranchedValue(<!TOO_MANY_ARGUMENTS!>argument<!>, <!TOO_MANY_ARGUMENTS!>null<!>, <!TOO_MANY_ARGUMENTS!>argument.<!UNRESOLVED_REFERENCE!>type<!><!>, <!TOO_MANY_ARGUMENTS!><!UNRESOLVED_REFERENCE!>Opcodes<!>.IFEQ<!>) {
override fun putSelector(type: Type, kotlinType: KotlinType?, v: InstructionAdapter) {
<!NOTHING_TO_OVERRIDE!>override<!> fun putSelector(type: Type, kotlinType: KotlinType?, v: InstructionAdapter) {
invokeFunction(v)
<!UNRESOLVED_REFERENCE!>coerceTo<!>(type, kotlinType, v)
}
override fun condJump(jumpLabel: Label, v: InstructionAdapter, jumpIfFalse: Boolean) {
<!NOTHING_TO_OVERRIDE!>override<!> fun condJump(jumpLabel: Label, v: InstructionAdapter, jumpIfFalse: Boolean) {
invokeFunction(v)
v.<!UNRESOLVED_REFERENCE!>visitJumpInsn<!>(if (jumpIfFalse) <!UNRESOLVED_REFERENCE!>Opcodes<!>.IFEQ else <!UNRESOLVED_REFERENCE!>Opcodes<!>.IFNE, jumpLabel)
}
@@ -25,7 +25,7 @@ interface B {
interface Foo
expect abstract class AbstractClass : Foo {
abstract override fun foo()
abstract <!NOTHING_TO_OVERRIDE!>override<!> fun foo()
abstract fun bar()
@@ -9,7 +9,7 @@ open class A {
class B : A() {
override fun foo(): B = this
fun <!VIRTUAL_MEMBER_HIDDEN!>bar<!>(): B = this // Missing 'override'
override fun buz(p: B): B = this //No override as B not :> A
<!NOTHING_TO_OVERRIDE!>override<!> fun buz(p: B): B = this //No override as B not :> A
fun test() {
foo()
@@ -6,8 +6,8 @@ public interface JA<E> {
// FILE: main.kt
interface KB<F> {
override fun getFoo(): F
override fun getBar(): F
<!NOTHING_TO_OVERRIDE!>override<!> fun getFoo(): F
<!NOTHING_TO_OVERRIDE!>override<!> fun getBar(): F
}
interface D1 : JA<String>, KB<String>
@@ -250,10 +250,8 @@ object FirOverrideChecker : FirClassChecker() {
}
}
@Suppress("UNUSED_PARAMETER") // TODO: delete me after implementing body
private fun DiagnosticReporter.reportNothingToOverride(declaration: FirMemberDeclaration, context: CheckerContext) {
// TODO: not ready yet, e.g., Collections
// reportOn(declaration.source, FirErrors.NOTHING_TO_OVERRIDE, declaration, context)
reportOn(declaration.source, FirErrors.NOTHING_TO_OVERRIDE, declaration, context)
}
private fun DiagnosticReporter.reportOverridingFinalMember(
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.declarations.utils.isFinal
import org.jetbrains.kotlin.fir.dispatchReceiverTypeOrNull
import org.jetbrains.kotlin.fir.originalOrSelf
import org.jetbrains.kotlin.fir.resolve.toFirRegularClass
import org.jetbrains.kotlin.fir.scopes.getDirectOverriddenFunctions
import org.jetbrains.kotlin.fir.scopes.getDirectOverriddenProperties
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
@@ -67,7 +68,16 @@ object FirJvmOverridesBackwardCompatibilityHelper : FirOverridesBackwardCompatib
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
if (JavaToKotlinClassMap.mapKotlinToJava(containingClassName) != null) {
return true
}
if (!originalMember.isAbstract) {
val containingClass = originalMember.containingClass()?.toFirRegularClass(context.session)
if (containingClass?.isInterface == false) {
return false
}
}
val scope =
symbol.dispatchReceiverTypeOrNull()?.toRegularClass(context.session)?.unsubstitutedScope(context) ?: return false
@@ -58,9 +58,19 @@ class FirStandardOverrideChecker(private val session: FirSession) : FirAbstractO
fun isEqualTypes(candidateTypeRef: FirTypeRef, baseTypeRef: FirTypeRef, substitutor: ConeSubstitutor): Boolean {
candidateTypeRef.ensureResolvedTypeDeclaration(session, requiredPhase = FirResolvePhase.TYPES)
baseTypeRef.ensureResolvedTypeDeclaration(session, requiredPhase = FirResolvePhase.TYPES)
if (candidateTypeRef is FirErrorTypeRef && baseTypeRef is FirErrorTypeRef) {
return maybeEqualErrorTypes(candidateTypeRef, baseTypeRef)
}
return isEqualTypes(candidateTypeRef.coneType, baseTypeRef.coneType, substitutor)
}
private fun maybeEqualErrorTypes(ref1: FirErrorTypeRef, ref2: FirErrorTypeRef): Boolean {
val delegated1 = ref1.delegatedTypeRef as? FirUserTypeRef ?: return false
val delegated2 = ref2.delegatedTypeRef as? FirUserTypeRef ?: return false
if (delegated1.qualifier.size != delegated2.qualifier.size) return false
return delegated1.qualifier.zip(delegated2.qualifier).all { (l, r) -> l.name == r.name }
}
/**
* Good case complexity is O(1)
@@ -11,5 +11,5 @@ open class B1 {
}
class D1 : B1() {
override fun foo() {}
<!NOTHING_TO_OVERRIDE!>override<!> fun foo() {}
}
@@ -1,25 +0,0 @@
// KT-11306 ABSTRACT_MEMBER_NOT_IMPLEMENTED for data class should inheriting interfaces requiring equals(), hashCode(), or toString()
interface Foo {
override fun equals(other: Any?): Boolean
override fun hashCode(): Int
override fun toString(): String
}
data class FooImpl(val num: Int) : Foo
data class FooImplSome(val num: Int) : Foo {
override fun hashCode() = 42
}
data class FooImplAll(val num: Int) : Foo {
override fun equals(other: Any?) = false
override fun hashCode() = 42
override fun toString() = "OK"
}
data class WrongSignatures(val num: Int) : Foo {
override fun equals(other: WrongSignatures) = false
override fun hashCode(): <!RETURN_TYPE_MISMATCH_ON_OVERRIDE!>Boolean<!> = true
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// KT-11306 ABSTRACT_MEMBER_NOT_IMPLEMENTED for data class should inheriting interfaces requiring equals(), hashCode(), or toString()
interface Foo {
@@ -1,11 +0,0 @@
interface A {
fun visit(a:Int, b:String="") : String = b + a
}
class B : A {
override fun visit(a:Int, b:String) : String = b + a
}
class C : A {
override fun visit(a:Int) : String = "" + a
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
interface A {
fun visit(a:Int, b:String="") : String = b + a
}
@@ -3,5 +3,5 @@ interface B {
}
class C : B {
override val x = 1
<!NOTHING_TO_OVERRIDE!>override<!> val x = 1
}
@@ -5,10 +5,10 @@ interface A<T> {
fun bar(x: T!!): T!!
}
interface B<T1> : A<T1> {
override fun foo(x: T1): T1
override fun bar(x: T1!!): T1!!
}
//interface B<T1> : A<T1> {
// override fun foo(x: T1): T1
// override fun bar(x: T1!!): T1!!
//}
interface C<T2> : A<T2> {
override fun foo(x: T2!!): T2!!
@@ -17,7 +17,7 @@ interface C<T2> : A<T2> {
interface D : A<String?> {
override fun foo(x: String?): String?
override fun bar(x: String): String
<!NOTHING_TO_OVERRIDE!>override<!> fun bar(x: String): String
}
interface E : A<String> {
@@ -26,7 +26,7 @@ interface E : A<String> {
}
interface F : A<String?> {
override fun foo(x: String): String
<!NOTHING_TO_OVERRIDE!>override<!> fun foo(x: String): String
override fun bar(x: String?): String?
}
@@ -32,8 +32,8 @@ interface E : A<String> {
}
interface F : A<String?> {
override fun foo(x: String): String
override fun bar(x: String?): String?
<!NOTHING_TO_OVERRIDE!>override<!> fun foo(x: String): String
<!NOTHING_TO_OVERRIDE!>override<!> fun bar(x: String?): String?
}
interface G<T3 : Any> : A<T3> {
+1 -1
View File
@@ -11,7 +11,7 @@ abstract class A<T> {
// while for being a correct override it should be A<A<T>.B<S>>.B<A<T>.B<S>.C<U>>
// It happens because at the beginning we search implicit arguments for an outer classes through supertypes
// See TypeResolver.computeImplicitOuterClassArguments for clarifications
override fun foo(x: B<C<U>>) {
<!NOTHING_TO_OVERRIDE!>override<!> fun foo(x: B<C<U>>) {
throw UnsupportedOperationException()
}
@@ -0,0 +1,30 @@
// fir reports NOTHING_TO_OVERRIDE because it keeps only one definition of p.Base
// MODULE: m1
// FILE: x.kt
package p
public interface Base {
public fun <T> foo(t: Array<T>) {}
}
public interface A : Base
// MODULE: m2
// FILE: x.kt
package p
public interface Base {
public fun <T: Base> foo(t: Array<T>) {}
}
public interface B : Base
// MODULE: m3(m1, m2)
// FILE: x.kt
import p.*
class Foo: A, B {
override fun <T> foo(t: Array<T>) {}
<!NOTHING_TO_OVERRIDE!>override<!> fun <T: Base> foo(t: Array<T>) {}
}
@@ -1,4 +1,3 @@
// FIR_IDENTICAL
// MODULE: m1
// FILE: x.kt
package p
@@ -27,4 +26,4 @@ import p.*
class Foo: A, B {
override fun <T> foo(t: Array<T>) {}
override fun <T: Base> foo(t: Array<T>) {}
}
}
@@ -42,8 +42,8 @@ abstract class MyAbstractClass1 : MyTrait<Int>, MyAbstractClass<String>() {
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>class MyIllegalGenericClass1<!><T> : MyTrait<T>, MyAbstractClass<T>() {}
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>class MyIllegalGenericClass2<!><T, R>(r : R) : MyTrait<T>, MyAbstractClass<R>() {
override fun foo(r: R) = r
override val <<!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>T<!>> pr : R = r
<!NOTHING_TO_OVERRIDE!>override<!> fun foo(r: R) = r
<!NOTHING_TO_OVERRIDE!>override<!> val <<!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>T<!>> pr : R = r
}
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>class MyIllegalClass1<!> : MyTrait<Int>, MyAbstractClass<String>() {}
abstract class MyLegalAbstractClass1 : MyTrait<Int>, MyAbstractClass<String>() {}
@@ -38,8 +38,8 @@ class MyChildClass() : MyClass() {}
<!ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED!>class MyIllegalClass4<!>() : MyTrait, MyAbstractClass() {
fun <!VIRTUAL_MEMBER_HIDDEN!>foo<!>() {}
<!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>val <!VIRTUAL_MEMBER_HIDDEN!>pr<!> : Unit<!>
override fun other() {}
override val otherPr : Int = 1
<!NOTHING_TO_OVERRIDE!>override<!> fun other() {}
<!NOTHING_TO_OVERRIDE!>override<!> val otherPr : Int = 1
}
class MyChildClass1() : MyClass() {
@@ -1,7 +0,0 @@
interface A {
fun <T> foo() where T : Any, T : Cloneable?
}
interface B : A {
override fun <T> foo() where T : Any?, T : Cloneable
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
interface A {
fun <T> foo() where T : Any, T : Cloneable?
}
@@ -1,41 +0,0 @@
// FILE: A.java
import java.util.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class A<T> {
public void bar(@NotNull T x) {
}
}
// FILE: B1.java
public class B1 extends A<String> {
// real override
public void bar(String x) {
}
}
// FILE: B2.java
public class B2 extends A<String> {
// fake override bar
}
// FILE: k.kt
class C1 : A<String?>() {
override fun bar(x: String) {}
}
class C2 : A<String?>() {
override fun bar(x: String?) {}
}
fun test() {
B1().bar(<!NULL_FOR_NONNULL_TYPE!>null<!>)
B2().bar(<!NULL_FOR_NONNULL_TYPE!>null<!>)
C1().bar(<!NULL_FOR_NONNULL_TYPE!>null<!>)
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// FILE: A.java
import java.util.*;
@@ -1,41 +0,0 @@
// FILE: A.java
import java.util.*;
public interface A<T> {
<E extends CharSequence> E foo(T x, List<? extends T> y);
}
// FILE: B.java
import java.util.*;
public interface B extends A {
@Override
public String foo(Object x, List y);
}
// FILE: C.java
import java.util.*;
public abstract class C {
<E extends CharSequence, F extends E> E bar(F x, List<Map<E, F>> y);
}
// FILE: D.java
import java.util.*;
public class D extends C {
@Override
public String bar(CharSequence x, List y) {
return null;
}
}
// FILE: main.kt
class E : D(), B {
override fun foo(x: Any, y: List<Any?>): String = ""
override fun bar(x: CharSequence?, y: List<*>?): String = ""
}
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>class E2<!> : B {
override fun foo(x: Any, y: List<String?>): String = ""
}
class F : D()
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// FILE: A.java
import java.util.*;
public interface A<T> {
@@ -1,41 +0,0 @@
// (failed) attempt to reproduce exception in
// http://stackoverflow.com/questions/42571812/unsupportedoperationexception-while-building-a-kotlin-project-in-idea
// FILE: Fun.java
public interface Fun<T> {
public void invoke(T x);
}
// FILE: A.java
public interface A<T> {
public void foo(T x, Fun<? extends T> y);
}
// FILE: B.java
public interface B extends A {
@Override
public void foo(Object x, Fun y);
}
// FILE: C.java
public abstract class C {
public abstract <T> void bar(Fun<T> y);
public static <T> void aStaticMethod(T x, Fun<T> y) {}
public static abstract class D extends C {
@Override
public <T> void bar(Fun<T> y) {}
public static void aStaticMethod(Object x, Fun y) {}
}
}
// FILE: main.kt
class E1 : C.D(), B {
override fun foo(x: Any, y: Fun<Any?>) {}
}
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>class E2<!> : B {
override fun foo(x: Any, y: Fun<String?>) {}
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// (failed) attempt to reproduce exception in
// http://stackoverflow.com/questions/42571812/unsupportedoperationexception-while-building-a-kotlin-project-in-idea
@@ -18,21 +18,21 @@ public class RawADerived extends A {
import java.util.*;
class B1 : RawADerived() {
override fun foo(x: CharSequence, y: Map<Any?, Any?>, z: HashMap<Any, Any>): A<*> = null!!
<!NOTHING_TO_OVERRIDE!>override<!> fun foo(x: CharSequence, y: Map<Any?, Any?>, z: HashMap<Any, Any>): A<*> = null!!
override fun bar(d: Array<Array<List<*>>>) {}
<!NOTHING_TO_OVERRIDE!>override<!> fun bar(d: Array<Array<List<*>>>) {}
}
class B2 : RawADerived() {
override fun foo(x: CharSequence?, y: MutableMap<Any?, Any?>, z: HashMap<Any?, Any?>): A<String> = null!!
<!NOTHING_TO_OVERRIDE!>override<!> fun foo(x: CharSequence?, y: MutableMap<Any?, Any?>, z: HashMap<Any?, Any?>): A<String> = null!!
override fun bar(d: Array<Array<MutableList<*>>>) {}
<!NOTHING_TO_OVERRIDE!>override<!> fun bar(d: Array<Array<MutableList<*>>>) {}
}
class B3 : RawADerived() {
// Type of second parameter (y) is not equal to overridden
// RawADerived.foo.y --- (MutableMap<Any?, Any?>..Map<out Any?, out Any?>) is not a subtype of Map<Any?, Any>
override fun foo(x: CharSequence, y: Map<Any?, Any>, z: HashMap<Any, Any>): A<*> = null!!
<!NOTHING_TO_OVERRIDE!>override<!> fun foo(x: CharSequence, y: Map<Any?, Any>, z: HashMap<Any, Any>): A<*> = null!!
}
class B4 : RawADerived() {
@@ -1,43 +0,0 @@
// FILE: A.java
import org.jetbrains.annotations.*;
public interface A<T> {
void foo(@NotNull T x, @Nullable T y);
}
// FILE: B1.java
// contains fake_override fun foo(/*0*/ org.jetbrains.annotations.NotNull() x: kotlin.String, /*1*/ org.jetbrains.annotations.Nullable() y: kotlin.String?)
public interface B1 extends A<String> {}
// FILE: B2.java
import org.jetbrains.annotations.*;
public interface B2 extends A<String> {
// Ok, consistent override
// override fun foo(/*0*/ org.jetbrains.annotations.NotNull() x: kotlin.String, /*1*/ org.jetbrains.annotations.Nullable() y: kotlin.String?)
void foo(@NotNull String x, @Nullable String y);
}
// FILE: B3.java
import org.jetbrains.annotations.*;
public interface B3 extends A<String> {
// inconsistent override, both parameters are platform
// override /*1*/ fun foo(/*0*/ org.jetbrains.annotations.Nullable() x: kotlin.String!, /*1*/ org.jetbrains.annotations.NotNull() y: kotlin.String!): kotlin.Unit
void foo(@Nullable String x, @NotNull String y);
}
// FILE: main.kt
// fake_override fun foo(/*0*/ org.jetbrains.annotations.NotNull() x: kotlin.String, /*1*/ org.jetbrains.annotations.Nullable() y: kotlin.String?): kotlin.Unit
interface C1 : A<String>
// fake_override fun foo(/*0*/ org.jetbrains.annotations.NotNull() x: kotlin.String?, /*1*/ org.jetbrains.annotations.Nullable() y: kotlin.String?): kotlin.Unit
interface C2 : A<String?>
interface C3 : B1 {
// inconsistent override
override fun foo(x: String?, y: String?);
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// FILE: A.java
import org.jetbrains.annotations.*;
@@ -18,7 +18,7 @@ open class D {
}
class E : D() {
internal override fun self() = this
internal <!NOTHING_TO_OVERRIDE!>override<!> fun self() = this
fun test() {
val s : E = self()
@@ -11,7 +11,7 @@ abstract class MyIt2<out T> : Iterator<T> {
}
abstract class MyIt3<out T> : Iterator<T> {
override fun forEachRemaining(x: Consumer<in T>?) {}
<!NOTHING_TO_OVERRIDE!>override<!> fun forEachRemaining(x: Consumer<in T>?) {}
}
abstract class MyIt4 : Iterator<String?> {
@@ -23,7 +23,7 @@ abstract class MyIt5 : Iterator<String> {
}
abstract class MyIt6 : Iterator<String?> {
override fun forEachRemaining(x: Consumer<in String>) {}
<!NOTHING_TO_OVERRIDE!>override<!> fun forEachRemaining(x: Consumer<in String>) {}
}
abstract class MyIt7 : Iterator<String> {
@@ -3,7 +3,7 @@
interface A : MutableCollection<String> {
// Override of deprecated function could be marked as deprecated too
override fun nonExistingMethod(x: String) = ""
<!NOTHING_TO_OVERRIDE!>override<!> fun nonExistingMethod(x: String) = ""
}
fun foo(x: MutableCollection<Int>, y: Collection<String>, z: A) {
@@ -2,7 +2,7 @@
abstract class A : MutableList<String> {
override fun sort(/*0*/ p0: java.util.Comparator<in String>) {
super.<!UNRESOLVED_REFERENCE!>sort<!>(p0)
super.sort(p0)
}
}
+3
View File
@@ -1,4 +1,5 @@
// TARGET_BACKEND: JVM
// IGNORE_BACKEND_FIR: JVM_IR
// SKIP_KT_DUMP
// DUMP_EXTERNAL_CLASS: X
// DUMP_EXTERNAL_CLASS: AX
@@ -8,6 +9,8 @@ abstract class A {
abstract val a: A?
}
//Fir doesn't treat B.getA as an override, because it is not return-type compatible with AX.getA
// Which might be correct behaivour. So disable fir till KT-46042
class B() : AX() {
override fun getA(): X? = super.a
}
@@ -98,7 +98,8 @@ object JvmBuiltInsSignatures {
inJavaUtil(
"List",
"replaceAll(Ljava/util/function/UnaryOperator;)V"
"replaceAll(Ljava/util/function/UnaryOperator;)V",
"sort(Ljava/util/Comparator;)V"
) +
inJavaUtil(