JS: report errors on different external items:

* data classes
* val/var parameters of primary constructors
* enum entry with body
* anonymous `init {}` block in classes
This commit is contained in:
Alexey Andreev
2016-12-20 17:50:44 +03:00
parent 03682ee849
commit 79ba6a57d6
28 changed files with 179 additions and 28 deletions
@@ -0,0 +1,5 @@
external class A {
<!EXTERNAL_ANONYMOUS_INITIALIZER!>init {
noImpl
}<!>
}
@@ -0,0 +1,8 @@
package
public external final class A {
public constructor A()
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
}
@@ -0,0 +1,7 @@
external enum class E {
X,
Y <!EXTERNAL_ENUM_ENTRY_WITH_BODY!>{
fun foo()
}<!>,
Z <!EXTERNAL_ENUM_ENTRY_WITH_BODY!>{}<!>
}
@@ -0,0 +1,22 @@
package
public external final enum class E : kotlin.Enum<E> {
enum entry X
enum entry Y
enum entry Z
private constructor E()
public final override /*1*/ /*fake_override*/ val name: kotlin.String
public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int
protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: E): kotlin.Int
public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
// Static members
public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): E
public final /*synthesized*/ fun values(): kotlin.Array<E>
}
@@ -0,0 +1 @@
external class C(x: Int, <!EXTERNAL_CLASS_CONSTRUCTOR_PROPERTY_PARAMETER!>val y: String<!>)
@@ -0,0 +1,9 @@
package
public external final class C {
public constructor C(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.String)
public final val y: kotlin.String
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
}
@@ -1,4 +1,4 @@
external annotation class <!WRONG_EXTERNAL_DECLARATION!>A<!>
external annotation class <!WRONG_EXTERNAL_DECLARATION!>A(val x: Int)<!>
val x: Int
<!WRONG_EXTERNAL_DECLARATION!>external get()<!> = noImpl
@@ -16,4 +16,6 @@ class C {
external class D {
val a: Int
<!WRONG_EXTERNAL_DECLARATION!>external get()<!> = noImpl
}
}
external data class <!WRONG_EXTERNAL_DECLARATION!>E(val x: Int)<!>
@@ -4,7 +4,8 @@ public val x: kotlin.Int
public val B.x: kotlin.Int
public external final annotation class A : kotlin.Annotation {
public constructor A()
public constructor A(/*0*/ x: kotlin.Int)
public final val x: kotlin.Int
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
@@ -32,3 +33,13 @@ public external final class D {
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public external final data class E {
public constructor E(/*0*/ x: kotlin.Int)
public final val x: kotlin.Int
public final operator /*synthesized*/ fun component1(): kotlin.Int
public final /*synthesized*/ fun copy(/*0*/ x: kotlin.Int = ...): E
public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String
}
@@ -569,6 +569,12 @@ public class DiagnosticsTestWithJsStdLibGenerated extends AbstractDiagnosticsTes
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/testsWithJsStdLib/native"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("anonymousInitializer.kt")
public void testAnonymousInitializer() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/native/anonymousInitializer.kt");
doTest(fileName);
}
@TestMetadata("body.kt")
public void testBody() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/native/body.kt");
@@ -587,6 +593,12 @@ public class DiagnosticsTestWithJsStdLibGenerated extends AbstractDiagnosticsTes
doTest(fileName);
}
@TestMetadata("enumEntry.kt")
public void testEnumEntry() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/native/enumEntry.kt");
doTest(fileName);
}
@TestMetadata("extensionFunctionAndProperty.kt")
public void testExtensionFunctionAndProperty() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/native/extensionFunctionAndProperty.kt");
@@ -635,6 +647,12 @@ public class DiagnosticsTestWithJsStdLibGenerated extends AbstractDiagnosticsTes
doTest(fileName);
}
@TestMetadata("propertyParameter.kt")
public void testPropertyParameter() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/native/propertyParameter.kt");
doTest(fileName);
}
@TestMetadata("wrongTarget.kt")
public void testWrongTarget() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/native/wrongTarget.kt");
@@ -80,8 +80,11 @@ private val DIAGNOSTIC_FACTORY_TO_RENDERER by lazy {
put(ErrorsJs.WRONG_INITIALIZER_OF_EXTERNAL_DECLARATION, "Wrong initializer of external declaration. Must be ' = noImpl'")
put(ErrorsJs.WRONG_DEFAULT_VALUE_FOR_EXTERNAL_FUN_PARAMETER,
"Wrong default value for parameter of external function. Must be ' = noImpl'")
put(ErrorsJs.EXTERNAL_DELEGATED_CONSTRUCTOR_CALL, "Delegated constructor call in external class")
put(ErrorsJs.EXTERNAL_DELEGATION, "Using delegate on external declaration")
put(ErrorsJs.EXTERNAL_DELEGATED_CONSTRUCTOR_CALL, "Delegated constructor call in external class is not allowed")
put(ErrorsJs.EXTERNAL_DELEGATION, "Can't use delegate on external declaration")
put(ErrorsJs.EXTERNAL_ANONYMOUS_INITIALIZER, "Anonymous initializer is not allowed in external classes")
put(ErrorsJs.EXTERNAL_ENUM_ENTRY_WITH_BODY, "Entry of external enum class can't have body")
put(ErrorsJs.EXTERNAL_CLASS_CONSTRUCTOR_PROPERTY_PARAMETER, "External class constructor cannot have a property parameter")
this
}
@@ -20,10 +20,7 @@ import com.intellij.psi.PsiElement;
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
import org.jetbrains.kotlin.diagnostics.*;
import org.jetbrains.kotlin.psi.KtClassOrObject;
import org.jetbrains.kotlin.psi.KtDeclaration;
import org.jetbrains.kotlin.psi.KtElement;
import org.jetbrains.kotlin.psi.KtExpression;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.types.KotlinType;
import static org.jetbrains.kotlin.diagnostics.PositioningStrategies.*;
@@ -87,6 +84,9 @@ public interface ErrorsJs {
DiagnosticFactory0<KtExpression> WRONG_DEFAULT_VALUE_FOR_EXTERNAL_FUN_PARAMETER = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtElement> EXTERNAL_DELEGATED_CONSTRUCTOR_CALL = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtElement> EXTERNAL_DELEGATION = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtAnonymousInitializer> EXTERNAL_ANONYMOUS_INITIALIZER = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtClassBody> EXTERNAL_ENUM_ENTRY_WITH_BODY = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtParameter> EXTERNAL_CLASS_CONSTRUCTOR_PROPERTY_PARAMETER = DiagnosticFactory0.create(ERROR);
@SuppressWarnings("UnusedDeclaration")
Object _initializer = new Object() {
@@ -51,6 +51,9 @@ object JsExternalChecker : SimpleDeclarationChecker {
if (DescriptorUtils.isAnnotationClass(descriptor)) {
diagnosticHolder.report(ErrorsJs.WRONG_EXTERNAL_DECLARATION.on(declaration, "annotation class"))
}
else if (descriptor is ClassDescriptor && descriptor.isData) {
diagnosticHolder.report(ErrorsJs.WRONG_EXTERNAL_DECLARATION.on(declaration, "data class"))
}
else if (descriptor is PropertyAccessorDescriptor && isDirectlyExternal(declaration, descriptor)) {
diagnosticHolder.report(ErrorsJs.WRONG_EXTERNAL_DECLARATION.on(declaration, "property accessor"))
}
@@ -92,6 +95,9 @@ object JsExternalChecker : SimpleDeclarationChecker {
checkBody(declaration, descriptor, diagnosticHolder, bindingContext)
checkDelegation(declaration, descriptor, diagnosticHolder)
checkAnonymousInitializer(declaration, diagnosticHolder)
checkEnumEntry(declaration, diagnosticHolder)
checkConstructorPropertyParam(declaration, descriptor, diagnosticHolder)
}
private fun checkBody(
@@ -143,6 +149,32 @@ object JsExternalChecker : SimpleDeclarationChecker {
}
}
private fun checkAnonymousInitializer(declaration: KtDeclaration, diagnosticHolder: DiagnosticSink) {
if (declaration !is KtClassOrObject) return
for (anonymousInitializer in declaration.getAnonymousInitializers()) {
diagnosticHolder.report(ErrorsJs.EXTERNAL_ANONYMOUS_INITIALIZER.on(anonymousInitializer))
}
}
private fun checkEnumEntry(declaration: KtDeclaration, diagnosticHolder: DiagnosticSink) {
if (declaration !is KtEnumEntry) return
declaration.getBody()?.let {
diagnosticHolder.report(ErrorsJs.EXTERNAL_ENUM_ENTRY_WITH_BODY.on(it))
}
}
private fun checkConstructorPropertyParam(
declaration: KtDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink
) {
if (descriptor !is PropertyDescriptor || declaration !is KtParameter) return
val containingClass = descriptor.containingDeclaration as ClassDescriptor
if (containingClass.isData || DescriptorUtils.isAnnotationClass(containingClass)) return
diagnosticHolder.report(ErrorsJs.EXTERNAL_CLASS_CONSTRUCTOR_PROPERTY_PARAMETER.on(declaration))
}
private fun isDirectlyExternal(declaration: KtDeclaration, descriptor: DeclarationDescriptor): Boolean {
if (declaration is KtProperty && descriptor is PropertyAccessorDescriptor) return false
+3 -1
View File
@@ -2,7 +2,9 @@
package foo
@JsModule("lib")
external class A(val x: Int = noImpl) {
external class A(x: Int = noImpl) {
val x: Int
fun foo(y: Int): Int = noImpl
}
+3 -1
View File
@@ -2,7 +2,9 @@
@file:JsModule("lib")
package foo
external class A(@native val x: Int = noImpl) {
external class A(@native x: Int = noImpl) {
val x: Int
fun foo(y: Int): Int = noImpl
}
@@ -3,7 +3,9 @@
@file:JsModule("lib")
package foo
external class A(@native val x: Int = noImpl) {
external class A(x: Int = noImpl) {
val x: Int
fun foo(y: Int): Int = noImpl
}
@@ -2,7 +2,9 @@
@file:JsNonModule
package foo
external class A(val x: Int = noImpl) {
external class A(x: Int = noImpl) {
val x: Int
fun foo(y: Int): Int = noImpl
}
@@ -4,7 +4,9 @@
@file:JsNonModule
package foo
external class A(val x: Int = noImpl) {
external class A(x: Int = noImpl) {
val x: Int
fun foo(y: Int): Int = noImpl
}
@@ -3,7 +3,9 @@
package foo
@JsName("A")
external open class B(val foo: String)
external open class B(foo: String) {
val foo: String
}
class C(s: String) : B(s)
@@ -4,7 +4,9 @@
package foo
@JsName("A")
external open class B(val foo: String)
external open class B(foo: String) {
val foo: String
}
// MODULE: main(module1)
// FILE: main.kt
@@ -4,7 +4,9 @@
@file:JsModule("native-lib")
package foo
external class A(val x: Int = noImpl) {
external class A(x: Int = noImpl) {
val x: Int
fun foo(y: Int): Int = noImpl
}
+3 -1
View File
@@ -1,6 +1,8 @@
package foo
external class A(val c: Int) {
external class A(c: Int) {
val c: Int
companion object {
val g: Int
val c: String = noImpl
@@ -1,6 +1,8 @@
package foo
internal external open class A(val a: Int) {
internal external open class A(a: Int) {
val a: Int
fun g(): Int = noImpl
fun m(): Int = noImpl
+8 -4
View File
@@ -87,7 +87,8 @@ external object Object {
fun test(): Int = noImpl
@JsName("AnotherClass")
class Class(val a: String) {
class Class(a: String) {
val a: String
var b: String = noImpl
fun test(): Int = noImpl
@@ -99,7 +100,8 @@ external object Object {
}
}
class Class(val a: String) {
class Class(a: String) {
val a: String
var b: String = noImpl
fun test(): Int = noImpl
@@ -135,7 +137,8 @@ external class Class {
fun test(): Int = noImpl
}
class Class(val a: String) {
class Class(a: String) {
val a: String
var b: String = noImpl
fun test(): Int = noImpl
@@ -174,7 +177,8 @@ external interface Trait {
fun test(): Int = noImpl
}
class Class(val a: String) {
class Class(a: String) {
val a: String
var b: String = noImpl
fun test(): Int = noImpl
@@ -1,6 +1,8 @@
package foo
internal external class A(val v: String)
internal external class A(v: String) {
val v: String
}
internal class B {
fun bar(a: A, extLambda: A.(Int, String) -> String): String = a.extLambda(7, "_rr_")
@@ -1,6 +1,8 @@
package foo
external class A(val v: String)
external class A(v: String) {
val v: String
}
external fun bar(a: A, extLambda: A.(Int, String) -> String): String = noImpl
@@ -1,6 +1,8 @@
package foo
external class A(val v: String) {
external class A(v: String) {
val v: String
fun m(i:Int, s:String): String = noImpl
}
+2 -1
View File
@@ -16,7 +16,8 @@ fun anotherCount(vararg a: Int) = anotherParamCount(*a)
external fun test3(bar: Bar, dummy: Int, vararg args: Int): Boolean = noImpl
external class Bar(val size: Int, order: Int = noImpl) {
external class Bar(size: Int, order: Int = noImpl) {
val size: Int
fun test(order: Int, dummy: Int, vararg args: Int): Boolean = noImpl
companion object {
fun startNewTest(): Boolean = noImpl
+3 -1
View File
@@ -7,7 +7,9 @@ external class A(x: Int) {
fun foo(): Int = noImpl
class B(val value: Int) {
class B(value: Int) {
val value: Int
fun bar(): Int = noImpl
}
}