JS: prohibit private members of external classes (see KT-14029)
This commit is contained in:
@@ -0,0 +1,55 @@
|
|||||||
|
// !DIAGNOSTICS: -NOTHING_TO_INLINE
|
||||||
|
// TODO: should we disable NOTHING_TO_INLINE in JS backend?
|
||||||
|
|
||||||
|
external class C {
|
||||||
|
<!EXTERNAL_CLASS_PRIVATE_MEMBER!>private fun a(): Int<!>
|
||||||
|
|
||||||
|
<!EXTERNAL_CLASS_PRIVATE_MEMBER!>private val b: String<!>
|
||||||
|
|
||||||
|
<!EXTERNAL_CLASS_PRIVATE_MEMBER!>private var c: Float<!>
|
||||||
|
|
||||||
|
<!EXTERNAL_CLASS_PRIVATE_MEMBER!>private var d: Float<!>
|
||||||
|
get
|
||||||
|
set
|
||||||
|
|
||||||
|
private inline fun inline_a(): Int = 23
|
||||||
|
|
||||||
|
private inline val inline_prop: Int
|
||||||
|
get() = 42
|
||||||
|
}
|
||||||
|
|
||||||
|
external object O {
|
||||||
|
<!EXTERNAL_CLASS_PRIVATE_MEMBER!>private fun a(): Int<!>
|
||||||
|
|
||||||
|
<!EXTERNAL_CLASS_PRIVATE_MEMBER!>private val b: String<!>
|
||||||
|
|
||||||
|
<!EXTERNAL_CLASS_PRIVATE_MEMBER!>private var c: Float<!>
|
||||||
|
|
||||||
|
<!EXTERNAL_CLASS_PRIVATE_MEMBER!>private var d: Float<!>
|
||||||
|
get
|
||||||
|
set
|
||||||
|
|
||||||
|
private inline fun inline_a(): Int = 23
|
||||||
|
|
||||||
|
private inline val inline_prop: Int
|
||||||
|
get() = 42
|
||||||
|
}
|
||||||
|
|
||||||
|
external class Outer {
|
||||||
|
class Inner {
|
||||||
|
<!EXTERNAL_CLASS_PRIVATE_MEMBER!>private fun a(): Int<!>
|
||||||
|
|
||||||
|
<!EXTERNAL_CLASS_PRIVATE_MEMBER!>private val b: String<!>
|
||||||
|
|
||||||
|
<!EXTERNAL_CLASS_PRIVATE_MEMBER!>private var c: Float<!>
|
||||||
|
|
||||||
|
<!EXTERNAL_CLASS_PRIVATE_MEMBER!>private var d: Float<!>
|
||||||
|
get
|
||||||
|
set
|
||||||
|
|
||||||
|
private inline fun inline_a(): Int = 23
|
||||||
|
|
||||||
|
private inline val inline_prop: Int
|
||||||
|
get() = 42
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public final class C {
|
||||||
|
public constructor C()
|
||||||
|
private final val b: kotlin.String
|
||||||
|
private final var c: kotlin.Float
|
||||||
|
private final var d: kotlin.Float
|
||||||
|
private final val inline_prop: kotlin.Int
|
||||||
|
private final fun a(): 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
|
||||||
|
private final inline fun inline_a(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
public object O {
|
||||||
|
private constructor O()
|
||||||
|
private final val b: kotlin.String
|
||||||
|
private final var c: kotlin.Float
|
||||||
|
private final var d: kotlin.Float
|
||||||
|
private final val inline_prop: kotlin.Int
|
||||||
|
private final fun a(): 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
|
||||||
|
private final inline fun inline_a(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class Outer {
|
||||||
|
public constructor Outer()
|
||||||
|
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
|
||||||
|
|
||||||
|
public final class Inner {
|
||||||
|
public constructor Inner()
|
||||||
|
private final val b: kotlin.String
|
||||||
|
private final var c: kotlin.Float
|
||||||
|
private final var d: kotlin.Float
|
||||||
|
private final val inline_prop: kotlin.Int
|
||||||
|
private final fun a(): 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
|
||||||
|
private final inline fun inline_a(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -539,6 +539,12 @@ public class DiagnosticsTestWithJsStdLibGenerated extends AbstractDiagnosticsTes
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("privateMembers.kt")
|
||||||
|
public void testPrivateMembers() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/native/privateMembers.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("wrongTarget.kt")
|
@TestMetadata("wrongTarget.kt")
|
||||||
public void testWrongTarget() throws Exception {
|
public void testWrongTarget() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/native/wrongTarget.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/native/wrongTarget.kt");
|
||||||
|
|||||||
+1
@@ -38,6 +38,7 @@ private val DIAGNOSTIC_FACTORY_TO_RENDERER by lazy {
|
|||||||
put(ErrorsJs.REFERENCE_TO_BUILTIN_MEMBERS_NOT_SUPPORTED, "Callable references for builtin members are not supported yet: ''{0}''", RenderFirstLineOfElementText)
|
put(ErrorsJs.REFERENCE_TO_BUILTIN_MEMBERS_NOT_SUPPORTED, "Callable references for builtin members are not supported yet: ''{0}''", RenderFirstLineOfElementText)
|
||||||
put(ErrorsJs.JSCODE_NO_JAVASCRIPT_PRODUCED, "Argument must be non-empty JavaScript code")
|
put(ErrorsJs.JSCODE_NO_JAVASCRIPT_PRODUCED, "Argument must be non-empty JavaScript code")
|
||||||
put(ErrorsJs.NESTED_EXTERNAL_DECLARATION, "Non top-level `external` declaration")
|
put(ErrorsJs.NESTED_EXTERNAL_DECLARATION, "Non top-level `external` declaration")
|
||||||
|
put(ErrorsJs.EXTERNAL_CLASS_PRIVATE_MEMBER, "Private non-inline members of external classes are prohibited")
|
||||||
put(ErrorsJs.JS_NAME_CLASH, "JavaScript name ({0}) generated for this declaration clashes with another declaration: {1}",
|
put(ErrorsJs.JS_NAME_CLASH, "JavaScript name ({0}) generated for this declaration clashes with another declaration: {1}",
|
||||||
Renderers.STRING, Renderers.COMPACT)
|
Renderers.STRING, Renderers.COMPACT)
|
||||||
put(ErrorsJs.JS_FAKE_NAME_CLASH, "JavaScript name {0} is generated for different inherited members: {1} and {2}",
|
put(ErrorsJs.JS_FAKE_NAME_CLASH, "JavaScript name {0} is generated for different inherited members: {1} and {2}",
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ public interface ErrorsJs {
|
|||||||
DiagnosticFactory1<KtElement, KtElement> NOT_SUPPORTED = DiagnosticFactory1.create(ERROR, DEFAULT);
|
DiagnosticFactory1<KtElement, KtElement> NOT_SUPPORTED = DiagnosticFactory1.create(ERROR, DEFAULT);
|
||||||
DiagnosticFactory1<KtElement, KtElement> REFERENCE_TO_BUILTIN_MEMBERS_NOT_SUPPORTED = DiagnosticFactory1.create(ERROR, DEFAULT);
|
DiagnosticFactory1<KtElement, KtElement> REFERENCE_TO_BUILTIN_MEMBERS_NOT_SUPPORTED = DiagnosticFactory1.create(ERROR, DEFAULT);
|
||||||
DiagnosticFactory0<KtExpression> JSCODE_NO_JAVASCRIPT_PRODUCED = DiagnosticFactory0.create(ERROR, DEFAULT);
|
DiagnosticFactory0<KtExpression> JSCODE_NO_JAVASCRIPT_PRODUCED = DiagnosticFactory0.create(ERROR, DEFAULT);
|
||||||
|
DiagnosticFactory0<KtDeclaration> EXTERNAL_CLASS_PRIVATE_MEMBER = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE_OR_DEFAULT);
|
||||||
DiagnosticFactory0<KtExpression> NESTED_EXTERNAL_DECLARATION = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE_OR_DEFAULT);
|
DiagnosticFactory0<KtExpression> NESTED_EXTERNAL_DECLARATION = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE_OR_DEFAULT);
|
||||||
DiagnosticFactory2<KtElement, String, DeclarationDescriptor> JS_NAME_CLASH = DiagnosticFactory2.create(
|
DiagnosticFactory2<KtElement, String, DeclarationDescriptor> JS_NAME_CLASH = DiagnosticFactory2.create(
|
||||||
ERROR, DECLARATION_SIGNATURE_OR_DEFAULT);
|
ERROR, DECLARATION_SIGNATURE_OR_DEFAULT);
|
||||||
|
|||||||
+14
-4
@@ -16,10 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.js.resolve.diagnostics
|
package org.jetbrains.kotlin.js.resolve.diagnostics
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors
|
import org.jetbrains.kotlin.diagnostics.Errors
|
||||||
import org.jetbrains.kotlin.js.PredefinedAnnotation
|
import org.jetbrains.kotlin.js.PredefinedAnnotation
|
||||||
@@ -49,6 +46,9 @@ class JsExternalChecker : SimpleDeclarationChecker {
|
|||||||
else if (descriptor is PropertyAccessorDescriptor && isDirectlyExternal(declaration, descriptor)) {
|
else if (descriptor is PropertyAccessorDescriptor && isDirectlyExternal(declaration, descriptor)) {
|
||||||
diagnosticHolder.report(Errors.WRONG_MODIFIER_TARGET.on(declaration, KtTokens.EXTERNAL_KEYWORD, "property accessor"))
|
diagnosticHolder.report(Errors.WRONG_MODIFIER_TARGET.on(declaration, KtTokens.EXTERNAL_KEYWORD, "property accessor"))
|
||||||
}
|
}
|
||||||
|
else if (isPrivateNonInlineMemberOfExternalClass(descriptor)) {
|
||||||
|
diagnosticHolder.report(ErrorsJs.EXTERNAL_CLASS_PRIVATE_MEMBER.on(declaration))
|
||||||
|
}
|
||||||
|
|
||||||
if (descriptor !is PropertyAccessorDescriptor && descriptor.isExtension) {
|
if (descriptor !is PropertyAccessorDescriptor && descriptor.isExtension) {
|
||||||
val target = when (descriptor) {
|
val target = when (descriptor) {
|
||||||
@@ -66,4 +66,14 @@ class JsExternalChecker : SimpleDeclarationChecker {
|
|||||||
return declaration.hasModifier(KtTokens.EXTERNAL_KEYWORD) ||
|
return declaration.hasModifier(KtTokens.EXTERNAL_KEYWORD) ||
|
||||||
AnnotationsUtils.hasAnnotation(descriptor, PredefinedAnnotation.NATIVE)
|
AnnotationsUtils.hasAnnotation(descriptor, PredefinedAnnotation.NATIVE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun isPrivateNonInlineMemberOfExternalClass(descriptor: DeclarationDescriptor): Boolean {
|
||||||
|
if (descriptor is PropertyAccessorDescriptor) return false
|
||||||
|
if (descriptor !is MemberDescriptor || descriptor.visibility != Visibilities.PRIVATE) return false
|
||||||
|
if (descriptor is FunctionDescriptor && descriptor.isInline) return false
|
||||||
|
if (descriptor is PropertyDescriptor && descriptor.accessors.all { it.isInline }) return false
|
||||||
|
|
||||||
|
val containingDeclaration = descriptor.containingDeclaration as? ClassDescriptor ?: return false
|
||||||
|
return AnnotationsUtils.isNativeObject(containingDeclaration)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user