Added deprecated diagnostic for invoking default methods within jvm-target 1.6

This commit is contained in:
Mikhael Bogdanov
2017-01-17 14:10:04 +01:00
parent 7a27a9d51f
commit 591de36666
17 changed files with 446 additions and 14 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,9 +17,14 @@
package org.jetbrains.kotlin.resolve.jvm.checkers
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.config.JvmTarget
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils.*
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.getSuperCallExpression
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
@@ -27,19 +32,35 @@ import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
class InterfaceDefaultMethodCallChecker : CallChecker {
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
val supportDefaults = context.compilerConfiguration.get(JVMConfigurationKeys.JVM_TARGET) == JvmTarget.JVM_1_8
val descriptor = resolvedCall.resultingDescriptor as? FunctionDescriptor ?: return
if (!supportDefaults &&
isStaticDeclaration(descriptor) &&
isInterface(descriptor.containingDeclaration) &&
descriptor is JavaCallableMemberDescriptor) {
context.trace.report(ErrorsJvm.INTERFACE_STATIC_METHOD_CALL_FROM_JAVA6_TARGET.on(reportOn))
}
if (getSuperCallExpression(resolvedCall.call) == null) return
val targetDescriptor = resolvedCall.resultingDescriptor.original
val containerDescriptor = targetDescriptor.containingDeclaration
if (!isInterface(descriptor.original.containingDeclaration)) return
if (containerDescriptor is JavaClassDescriptor && DescriptorUtils.isInterface(containerDescriptor)) {
//is java interface default method called from trait
val realDescriptor = unwrapFakeOverride(descriptor)
val realDescriptorOwner = realDescriptor.containingDeclaration as? ClassDescriptor ?: return
if (isInterface(realDescriptorOwner) && realDescriptor is JavaCallableMemberDescriptor) {
val classifier = DescriptorUtils.getParentOfType(context.scope.ownerDescriptor, ClassifierDescriptor::class.java)
//is java interface default method called from trait
if (classifier != null && DescriptorUtils.isInterface(classifier)) {
context.trace.report(ErrorsJvm.INTERFACE_CANT_CALL_DEFAULT_METHOD_VIA_SUPER.on(reportOn))
}
else if (!supportDefaults) {
context.trace.report(ErrorsJvm.DEFAULT_METHOD_CALL_FROM_JAVA6_TARGET.on(reportOn))
}
}
}
}
}
@@ -112,6 +112,9 @@ public class DefaultErrorMessagesJvm implements DefaultErrorMessages.Extension {
"Method implementation inheritance is restricted for such cases. " +
"Please make explicit overrides (abstract or concrete) for the following non-abstract members of ''{1}'': {2}",
Renderers.NAME, Renderers.NAME, Renderers.TO_STRING);
MAP.put(ErrorsJvm.DEFAULT_METHOD_CALL_FROM_JAVA6_TARGET, "Super calls to Java default methods are deprecated in JVM target 1.6. Recompile with ''-jvm-target 1.8''");
MAP.put(ErrorsJvm.INTERFACE_STATIC_METHOD_CALL_FROM_JAVA6_TARGET, "Calls to static methods in Java interfaces are deprecated in JVM target 1.6. Recompile with ''-jvm-target 1.8''");
}
@NotNull
@@ -89,6 +89,9 @@ public interface ErrorsJvm {
DiagnosticFactory3<PsiElement, DeclarationDescriptor, DeclarationDescriptor, String> TARGET6_INTERFACE_INHERITANCE = DiagnosticFactory3.create(ERROR);
DiagnosticFactory0<PsiElement> DEFAULT_METHOD_CALL_FROM_JAVA6_TARGET = DiagnosticFactory0.create(WARNING);
DiagnosticFactory0<PsiElement> INTERFACE_STATIC_METHOD_CALL_FROM_JAVA6_TARGET = DiagnosticFactory0.create(WARNING);
@SuppressWarnings("UnusedDeclaration")
Object _initializer = new Object() {
{
@@ -0,0 +1,26 @@
// FILE: Simple.java
public interface Simple {
default String test() {
return "O";
}
static String testStatic() {
return "K";
}
}
// FILE: main.kt
// JVM_TARGET: 1.8
interface KSimple : Simple {}
class TestClass : KSimple {
override fun test(): String {
return super.test()
}
}
fun box(): String {
return TestClass().test() + Simple.testStatic()
}
+20 -3
View File
@@ -15,9 +15,26 @@ interface KTrait : Test {
}
class A : KTrait {
fun a() {
super.test()
interface KTrait2 : KTrait {
fun ktest2() {
super.<!INTERFACE_CANT_CALL_DEFAULT_METHOD_VIA_SUPER!>test<!>()
test()
}
}
class A : KTrait {
fun a() {
super.<!DEFAULT_METHOD_CALL_FROM_JAVA6_TARGET!>test<!>()
test()
}
}
class A2 : KTrait2 {
fun a() {
super.<!DEFAULT_METHOD_CALL_FROM_JAVA6_TARGET!>test<!>()
test()
}
@@ -10,6 +10,17 @@ public final class A : KTrait {
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class A2 : KTrait2 {
public constructor A2()
public final fun a(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun ktest(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun ktest2(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun test(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public interface KTrait : Test {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
@@ -18,6 +29,15 @@ public interface KTrait : Test {
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public interface KTrait2 : KTrait {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun ktest(): kotlin.Unit
public open fun ktest2(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun test(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public interface Test {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
@@ -0,0 +1,70 @@
// FILE: JavaInterface.java
public interface JavaInterface {
static String testStatic() {
return "OK";
}
default String test() {
return "OK";
}
default String testOverride() {
return "OK";
}
}
// FILE: 1.kt
import JavaInterface.testStatic
interface KotlinInterface : JavaInterface {
fun fooo() {
<!INTERFACE_STATIC_METHOD_CALL_FROM_JAVA6_TARGET!>testStatic<!>()
super.<!INTERFACE_CANT_CALL_DEFAULT_METHOD_VIA_SUPER!>test<!>()
}
override fun testOverride(): String {
return "OK";
}
}
interface KotlinInterfaceInderectInheritance : KotlinInterface {
fun foooo() {
<!INTERFACE_STATIC_METHOD_CALL_FROM_JAVA6_TARGET!>testStatic<!>()
super.<!INTERFACE_CANT_CALL_DEFAULT_METHOD_VIA_SUPER!>test<!>()
}
}
open class KotlinClass : JavaInterface {
fun foo(){
<!INTERFACE_STATIC_METHOD_CALL_FROM_JAVA6_TARGET!>testStatic<!>()
super.<!DEFAULT_METHOD_CALL_FROM_JAVA6_TARGET!>test<!>()
super.<!DEFAULT_METHOD_CALL_FROM_JAVA6_TARGET!>testOverride<!>()
}
}
class KotlinClassInderectInheritance : KotlinClass() {
fun foo2(){
<!INTERFACE_STATIC_METHOD_CALL_FROM_JAVA6_TARGET!>testStatic<!>()
super.test()
super.testOverride()
}
}
class KotlinClassInderectInheritance2 : KotlinInterfaceInderectInheritance {
fun foo(){
<!INTERFACE_STATIC_METHOD_CALL_FROM_JAVA6_TARGET!>testStatic<!>()
super.<!DEFAULT_METHOD_CALL_FROM_JAVA6_TARGET!>test<!>()
super.testOverride()
}
}
fun test() {
JavaInterface.<!INTERFACE_STATIC_METHOD_CALL_FROM_JAVA6_TARGET!>testStatic<!>()
KotlinClass().foo()
KotlinClassInderectInheritance2().foo()
KotlinClass().test()
KotlinClass().testOverride()
KotlinClassInderectInheritance().testOverride()
}
@@ -0,0 +1,66 @@
package
public fun test(): kotlin.Unit
public interface JavaInterface {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open fun test(): kotlin.String!
public open fun testOverride(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
// Static members
public open fun testStatic(): kotlin.String!
}
public open class KotlinClass : JavaInterface {
public constructor KotlinClass()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun foo(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun test(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun testOverride(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class KotlinClassInderectInheritance : KotlinClass {
public constructor KotlinClassInderectInheritance()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final override /*1*/ /*fake_override*/ fun foo(): kotlin.Unit
public final fun foo2(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun test(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun testOverride(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class KotlinClassInderectInheritance2 : KotlinInterfaceInderectInheritance {
public constructor KotlinClassInderectInheritance2()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun foo(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun fooo(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun foooo(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun test(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun testOverride(): kotlin.String
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public interface KotlinInterface : JavaInterface {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open fun fooo(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun test(): kotlin.String!
public open override /*1*/ fun testOverride(): kotlin.String
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public interface KotlinInterfaceInderectInheritance : KotlinInterface {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun fooo(): kotlin.Unit
public open fun foooo(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun test(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun testOverride(): kotlin.String
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,79 @@
// FILE: JavaInterfaceBase.java
public interface JavaInterfaceBase {
default String test() {
return "OK";
}
default String testOverride() {
return "OK";
}
}
// FILE: JavaInterface.java
public interface JavaInterface extends JavaInterfaceBase {
static String testStatic() {
return "OK";
}
}
// FILE: 1.kt
import JavaInterface.testStatic
interface KotlinInterface : JavaInterface {
fun fooo() {
<!INTERFACE_STATIC_METHOD_CALL_FROM_JAVA6_TARGET!>testStatic<!>()
super.<!INTERFACE_CANT_CALL_DEFAULT_METHOD_VIA_SUPER!>test<!>()
test()
testOverride()
}
override fun testOverride(): String {
return "OK";
}
}
interface KotlinInterfaceIndirectInheritance : KotlinInterface {
fun foooo() {
<!INTERFACE_STATIC_METHOD_CALL_FROM_JAVA6_TARGET!>testStatic<!>()
super.<!INTERFACE_CANT_CALL_DEFAULT_METHOD_VIA_SUPER!>test<!>()
testOverride()
super.testOverride()
}
}
open class KotlinClass : JavaInterface {
fun foo(){
<!INTERFACE_STATIC_METHOD_CALL_FROM_JAVA6_TARGET!>testStatic<!>()
super.<!DEFAULT_METHOD_CALL_FROM_JAVA6_TARGET!>test<!>()
super.<!DEFAULT_METHOD_CALL_FROM_JAVA6_TARGET!>testOverride<!>()
}
}
class KotlinClassIndirectInheritance : KotlinClass() {
fun foo2(){
<!INTERFACE_STATIC_METHOD_CALL_FROM_JAVA6_TARGET!>testStatic<!>()
super.test()
super.testOverride()
}
}
class KotlinClassIndirectInheritance2 : KotlinInterfaceIndirectInheritance {
fun foo(){
<!INTERFACE_STATIC_METHOD_CALL_FROM_JAVA6_TARGET!>testStatic<!>()
super.<!DEFAULT_METHOD_CALL_FROM_JAVA6_TARGET!>test<!>()
super.testOverride()
}
}
fun test() {
JavaInterface.<!INTERFACE_STATIC_METHOD_CALL_FROM_JAVA6_TARGET!>testStatic<!>()
KotlinClass().foo()
KotlinClassIndirectInheritance2().foo()
KotlinClass().test()
KotlinClass().testOverride()
KotlinClassIndirectInheritance().testOverride()
}
@@ -0,0 +1,74 @@
package
public fun test(): kotlin.Unit
public interface JavaInterface : JavaInterfaceBase {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun test(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun testOverride(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
// Static members
public open fun testStatic(): kotlin.String!
}
public interface JavaInterfaceBase {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open fun test(): kotlin.String!
public open fun testOverride(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public open class KotlinClass : JavaInterface {
public constructor KotlinClass()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun foo(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun test(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun testOverride(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class KotlinClassIndirectInheritance : KotlinClass {
public constructor KotlinClassIndirectInheritance()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final override /*1*/ /*fake_override*/ fun foo(): kotlin.Unit
public final fun foo2(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun test(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun testOverride(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class KotlinClassIndirectInheritance2 : KotlinInterfaceIndirectInheritance {
public constructor KotlinClassIndirectInheritance2()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun foo(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun fooo(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun foooo(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun test(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun testOverride(): kotlin.String
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public interface KotlinInterface : JavaInterface {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open fun fooo(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun test(): kotlin.String!
public open override /*1*/ fun testOverride(): kotlin.String
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public interface KotlinInterfaceIndirectInheritance : KotlinInterface {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun fooo(): kotlin.Unit
public open fun foooo(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun test(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun testOverride(): kotlin.String
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,16 @@
// FILE: JavaClass.java
public class JavaClass {
public static String testStatic() {
return "OK";
}
}
// FILE: 1.kt
import JavaClass.testStatic
fun test() {
JavaClass.testStatic()
testStatic()
}
@@ -0,0 +1,13 @@
package
public fun test(): kotlin.Unit
public open class JavaClass {
public constructor JavaClass()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
// Static members
public open fun testStatic(): kotlin.String!
}
@@ -18,7 +18,7 @@ class K : C()
fun main(args: Array<String>) {
I.a
I.foo()
I.<!INTERFACE_STATIC_METHOD_CALL_FROM_JAVA6_TARGET!>foo<!>()
C.a
C.b
@@ -1,6 +1,6 @@
abstract class A : MutableList<String> {
override fun sort(/*0*/ p0: java.util.Comparator<in String>) {
super.sort(p0)
super.<!DEFAULT_METHOD_CALL_FROM_JAVA6_TARGET!>sort<!>(p0)
}
}
@@ -1,7 +1,7 @@
import java.util.stream.*
interface A : Collection<String> {
override fun stream(): Stream<String> = Stream.of()
override fun stream(): Stream<String> = Stream.<!INTERFACE_STATIC_METHOD_CALL_FROM_JAVA6_TARGET!>of<!>()
}
fun foo(x: List<String>, y: A) {
@@ -36,12 +36,30 @@ public class DiagnosticsWithJava8TestGenerated extends AbstractDiagnosticsWithFu
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/testsWithJava8"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("defaultMethods.kt")
public void testDefaultMethods() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJava8/defaultMethods.kt");
doTest(fileName);
}
@TestMetadata("defaultMethodsIndirectInheritance.kt")
public void testDefaultMethodsIndirectInheritance() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJava8/defaultMethodsIndirectInheritance.kt");
doTest(fileName);
}
@TestMetadata("samWithConsumer.kt")
public void testSamWithConsumer() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJava8/samWithConsumer.kt");
doTest(fileName);
}
@TestMetadata("staticMethodInClass.kt")
public void testStaticMethodInClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJava8/staticMethodInClass.kt");
doTest(fileName);
}
@TestMetadata("compiler/testData/diagnostics/testsWithJava8/annotations")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -393,6 +393,12 @@ public class BlackBoxWithJava8CodegenTestGenerated extends AbstractBlackBoxCodeg
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/java8/box/jvm8/interfaceFlag/superCall.kt");
doTest(fileName);
}
@TestMetadata("superCallIndirect.kt")
public void testSuperCallIndirect() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/java8/box/jvm8/interfaceFlag/superCallIndirect.kt");
doTest(fileName);
}
}
}