KT-2752: fixes after code review
This commit is contained in:
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.resolve.calls.results.isSignatureNotLessSpecific
|
|||||||
import org.jetbrains.kotlin.resolve.calls.tower.getTypeAliasConstructors
|
import org.jetbrains.kotlin.resolve.calls.tower.getTypeAliasConstructors
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.hasLowPriorityInOverloadResolution
|
import org.jetbrains.kotlin.resolve.descriptorUtil.hasLowPriorityInOverloadResolution
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.varargParameterPosition
|
import org.jetbrains.kotlin.resolve.descriptorUtil.varargParameterPosition
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtensionProperty
|
||||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||||
import org.jetbrains.kotlin.types.ErrorUtils
|
import org.jetbrains.kotlin.types.ErrorUtils
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
@@ -80,14 +81,10 @@ class OverloadChecker(val specificityComparator: TypeSpecificityComparator) {
|
|||||||
EXTENSION_PROPERTY
|
EXTENSION_PROPERTY
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun DeclarationDescriptor.isExtensionProperty() =
|
|
||||||
this is PropertyDescriptor &&
|
|
||||||
extensionReceiverParameter != null
|
|
||||||
|
|
||||||
private fun getDeclarationCategory(a: DeclarationDescriptor): DeclarationCategory =
|
private fun getDeclarationCategory(a: DeclarationDescriptor): DeclarationCategory =
|
||||||
when (a) {
|
when (a) {
|
||||||
is PropertyDescriptor ->
|
is PropertyDescriptor ->
|
||||||
if (a.isExtensionProperty())
|
if (a.isExtensionProperty)
|
||||||
DeclarationCategory.EXTENSION_PROPERTY
|
DeclarationCategory.EXTENSION_PROPERTY
|
||||||
else
|
else
|
||||||
DeclarationCategory.TYPE_OR_VALUE
|
DeclarationCategory.TYPE_OR_VALUE
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
class <!JS_NAME_CLASH!>A(val x: Int)<!>
|
||||||
|
|
||||||
|
<!JS_NAME_CLASH!>fun A()<!> {}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
package foo {
|
||||||
|
public fun A(): kotlin.Unit
|
||||||
|
|
||||||
|
public final class 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
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-2
@@ -12,7 +12,7 @@ class C : A, B {
|
|||||||
<!JS_NAME_CLASH!>override fun g()<!> {}
|
<!JS_NAME_CLASH!>override fun g()<!> {}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class <!JS_NAME_CLASH_SYNTHETIC!>D<!> : A, B
|
abstract class <!JS_FAKE_NAME_CLASH!>D<!> : A, B
|
||||||
|
|
||||||
open class E {
|
open class E {
|
||||||
open fun f() {}
|
open fun f() {}
|
||||||
@@ -20,4 +20,4 @@ open class E {
|
|||||||
open fun g() {}
|
open fun g() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
class <!JS_NAME_CLASH_SYNTHETIC!>F<!> : E(), A, B
|
class <!JS_FAKE_NAME_CLASH!>F<!> : E(), A, B
|
||||||
|
|||||||
+2
-2
@@ -6,8 +6,8 @@ class A {
|
|||||||
set(value) {}
|
set(value) {}
|
||||||
|
|
||||||
<!JS_NAME_IS_NOT_ON_ALL_ACCESSORS!>var y: Int<!>
|
<!JS_NAME_IS_NOT_ON_ALL_ACCESSORS!>var y: Int<!>
|
||||||
@JsName("get_y") get() = 23
|
get() = 23
|
||||||
set(value) {}
|
@JsName("set_y") set(value) {}
|
||||||
|
|
||||||
var z: Int
|
var z: Int
|
||||||
@JsName("get_z") get() = 23
|
@JsName("get_z") get() = 23
|
||||||
|
|||||||
@@ -295,6 +295,12 @@ public class DiagnosticsTestWithJsStdLibGenerated extends AbstractDiagnosticsTes
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/testsWithJsStdLib/name"), Pattern.compile("^(.+)\\.kt$"), true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/testsWithJsStdLib/name"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("classAndFunction.kt")
|
||||||
|
public void testClassAndFunction() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/name/classAndFunction.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("classLevelMethodAndProperty.kt")
|
@TestMetadata("classLevelMethodAndProperty.kt")
|
||||||
public void testClassLevelMethodAndProperty() throws Exception {
|
public void testClassLevelMethodAndProperty() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/name/classLevelMethodAndProperty.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/name/classLevelMethodAndProperty.kt");
|
||||||
|
|||||||
@@ -322,5 +322,16 @@ private fun ClassDescriptor.getAllSuperClassesTypesIncludeItself(): List<KotlinT
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun FunctionDescriptor.isEnumValueOfMethod(): Boolean {
|
||||||
|
val methodTypeParameters = valueParameters
|
||||||
|
val nullableString = TypeUtils.makeNullable(builtIns.stringType)
|
||||||
|
return DescriptorUtils.ENUM_VALUE_OF == name
|
||||||
|
&& methodTypeParameters.size == 1
|
||||||
|
&& KotlinTypeChecker.DEFAULT.isSubtypeOf(methodTypeParameters[0].type, nullableString)
|
||||||
|
}
|
||||||
|
|
||||||
|
val DeclarationDescriptor.isExtensionProperty: Boolean
|
||||||
|
get() = this is PropertyDescriptor && extensionReceiverParameter != null
|
||||||
|
|
||||||
fun ClassDescriptor.getAllSuperclassesWithoutAny() =
|
fun ClassDescriptor.getAllSuperclassesWithoutAny() =
|
||||||
generateSequence(getSuperClassNotAny(), ClassDescriptor::getSuperClassNotAny).toCollection(SmartList<ClassDescriptor>())
|
generateSequence(getSuperClassNotAny(), ClassDescriptor::getSuperClassNotAny).toCollection(SmartList<ClassDescriptor>())
|
||||||
|
|||||||
@@ -189,16 +189,18 @@ class NameSuggestion {
|
|||||||
overriddenDescriptor is CallableDescriptor && stable -> {
|
overriddenDescriptor is CallableDescriptor && stable -> {
|
||||||
getStableMangledName(baseName, getArgumentTypesAsString(overriddenDescriptor))
|
getStableMangledName(baseName, getArgumentTypesAsString(overriddenDescriptor))
|
||||||
}
|
}
|
||||||
shouldMangleUnstable(overriddenDescriptor) -> {
|
shouldMangleUnstable(overriddenDescriptor) -> getPrivateMangledName(baseName, overriddenDescriptor as CallableDescriptor)
|
||||||
val ownerName = descriptor.containingDeclaration!!.fqNameUnsafe.asString()
|
|
||||||
getStableMangledName(baseName, ownerName + ":" + getArgumentTypesAsString(overriddenDescriptor as CallableDescriptor))
|
|
||||||
}
|
|
||||||
else -> baseName
|
else -> baseName
|
||||||
}
|
}
|
||||||
|
|
||||||
return Pair(finalName, stable)
|
return Pair(finalName, stable)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JvmStatic fun getPrivateMangledName(baseName: String, descriptor: CallableDescriptor): String {
|
||||||
|
val ownerName = descriptor.containingDeclaration.fqNameUnsafe.asString()
|
||||||
|
return getStableMangledName(baseName, ownerName + ":" + getArgumentTypesAsString(descriptor))
|
||||||
|
}
|
||||||
|
|
||||||
private fun getArgumentTypesAsString(descriptor: CallableDescriptor): String {
|
private fun getArgumentTypesAsString(descriptor: CallableDescriptor): String {
|
||||||
val argTypes = StringBuilder()
|
val argTypes = StringBuilder()
|
||||||
|
|
||||||
@@ -226,7 +228,7 @@ class NameSuggestion {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getStableMangledName(suggestedName: String, forCalculateId: String): String {
|
@JvmStatic fun getStableMangledName(suggestedName: String, forCalculateId: String): String {
|
||||||
val suffix = if (forCalculateId.isEmpty()) "" else "_${mangledId(forCalculateId)}\$"
|
val suffix = if (forCalculateId.isEmpty()) "" else "_${mangledId(forCalculateId)}\$"
|
||||||
return suggestedName + suffix
|
return suggestedName + suffix
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -39,7 +39,7 @@ private val DIAGNOSTIC_FACTORY_TO_RENDERER by lazy {
|
|||||||
put(ErrorsJs.NATIVE_INNER_CLASS_PROHIBITED, "Native inner classes are prohibited")
|
put(ErrorsJs.NATIVE_INNER_CLASS_PROHIBITED, "Native inner 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_NAME_CLASH_SYNTHETIC, "JavaScript name {0} is generated from two different inherited members: {1} and {2}",
|
put(ErrorsJs.JS_FAKE_NAME_CLASH, "JavaScript name {0} is generated for different inherited members: {1} and {2}",
|
||||||
Renderers.STRING, Renderers.COMPACT, Renderers.COMPACT)
|
Renderers.STRING, Renderers.COMPACT, Renderers.COMPACT)
|
||||||
put(ErrorsJs.JS_NAME_ON_PRIMARY_CONSTRUCTOR_PROHIBITED, "@JsName annotation is prohibited for primary constructors")
|
put(ErrorsJs.JS_NAME_ON_PRIMARY_CONSTRUCTOR_PROHIBITED, "@JsName annotation is prohibited for primary constructors")
|
||||||
put(ErrorsJs.JS_NAME_ON_ACCESSOR_AND_PROPERTY, "@JsName can be either on a property or its accessors, not both of them")
|
put(ErrorsJs.JS_NAME_ON_ACCESSOR_AND_PROPERTY, "@JsName can be either on a property or its accessors, not both of them")
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ public interface ErrorsJs {
|
|||||||
DiagnosticFactory0<KtExpression> NATIVE_INNER_CLASS_PROHIBITED = DiagnosticFactory0.create(ERROR);
|
DiagnosticFactory0<KtExpression> NATIVE_INNER_CLASS_PROHIBITED = DiagnosticFactory0.create(ERROR);
|
||||||
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);
|
||||||
DiagnosticFactory3<KtElement, String, DeclarationDescriptor, DeclarationDescriptor> JS_NAME_CLASH_SYNTHETIC =
|
DiagnosticFactory3<KtElement, String, DeclarationDescriptor, DeclarationDescriptor> JS_FAKE_NAME_CLASH =
|
||||||
DiagnosticFactory3.create(ERROR, DECLARATION_SIGNATURE_OR_DEFAULT);
|
DiagnosticFactory3.create(ERROR, DECLARATION_SIGNATURE_OR_DEFAULT);
|
||||||
DiagnosticFactory0<PsiElement> JS_NAME_ON_PRIMARY_CONSTRUCTOR_PROHIBITED = DiagnosticFactory0.create(ERROR);
|
DiagnosticFactory0<PsiElement> JS_NAME_ON_PRIMARY_CONSTRUCTOR_PROHIBITED = DiagnosticFactory0.create(ERROR);
|
||||||
DiagnosticFactory0<PsiElement> JS_NAME_ON_ACCESSOR_AND_PROPERTY = DiagnosticFactory0.create(ERROR);
|
DiagnosticFactory0<PsiElement> JS_NAME_ON_ACCESSOR_AND_PROPERTY = DiagnosticFactory0.create(ERROR);
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.js.PredefinedAnnotation
|
|||||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
|
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
|
||||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.SimpleDeclarationChecker
|
import org.jetbrains.kotlin.resolve.checkers.SimpleDeclarationChecker
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
||||||
import org.jetbrains.kotlin.resolve.source.getPsi
|
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||||
|
|
||||||
|
|||||||
+23
-23
@@ -21,11 +21,11 @@ import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
|||||||
import org.jetbrains.kotlin.js.naming.NameSuggestion
|
import org.jetbrains.kotlin.js.naming.NameSuggestion
|
||||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
|
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
|
||||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||||
import org.jetbrains.kotlin.psi.KtProperty
|
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.resolve.SimpleDeclarationChecker
|
import org.jetbrains.kotlin.resolve.checkers.SimpleDeclarationChecker
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtensionProperty
|
||||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||||
|
|
||||||
class JsNameClashChecker : SimpleDeclarationChecker {
|
class JsNameClashChecker : SimpleDeclarationChecker {
|
||||||
@@ -40,20 +40,24 @@ class JsNameClashChecker : SimpleDeclarationChecker {
|
|||||||
diagnosticHolder: DiagnosticSink,
|
diagnosticHolder: DiagnosticSink,
|
||||||
bindingContext: BindingContext
|
bindingContext: BindingContext
|
||||||
) {
|
) {
|
||||||
if (declaration !is KtProperty || !descriptor.isExtension) {
|
// We don't generate JS properties for extension properties, we generate methods instead, so in this case
|
||||||
|
// check name clash only for accessors, not properties
|
||||||
|
if (!descriptor.isExtensionProperty) {
|
||||||
checkDescriptor(descriptor, declaration, diagnosticHolder)
|
checkDescriptor(descriptor, declaration, diagnosticHolder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkDescriptor(descriptor: DeclarationDescriptor, declaration: KtDeclaration, diagnosticHolder: DiagnosticSink) {
|
private fun checkDescriptor(descriptor: DeclarationDescriptor, declaration: KtDeclaration, diagnosticHolder: DiagnosticSink) {
|
||||||
|
if (descriptor is ConstructorDescriptor && descriptor.isPrimary) return
|
||||||
|
|
||||||
val suggested = nameSuggestion.suggest(descriptor)!!
|
val suggested = nameSuggestion.suggest(descriptor)!!
|
||||||
if (suggested.stable && suggested.scope is ClassOrPackageFragmentDescriptor && isOpaque(suggested.descriptor)) {
|
if (suggested.stable && suggested.scope is ClassOrPackageFragmentDescriptor && presentsInGeneratedCode(suggested.descriptor)) {
|
||||||
val scope = getScope(suggested.scope)
|
val scope = getScope(suggested.scope)
|
||||||
val name = suggested.names.last()
|
val name = suggested.names.last()
|
||||||
val existing = scope[name]
|
val existing = scope[name]
|
||||||
if (existing != null && existing != suggested.descriptor) {
|
if (existing != null && existing != suggested.descriptor) {
|
||||||
diagnosticHolder.report(ErrorsJs.JS_NAME_CLASH.on(declaration, name, existing))
|
diagnosticHolder.report(ErrorsJs.JS_NAME_CLASH.on(declaration, name, existing))
|
||||||
val existingDeclaration = existing.findPsi() ?: declaration
|
val existingDeclaration = existing.findPsi()
|
||||||
if (clashedDescriptors.add(existing) && existingDeclaration is KtDeclaration && existingDeclaration != declaration) {
|
if (clashedDescriptors.add(existing) && existingDeclaration is KtDeclaration && existingDeclaration != declaration) {
|
||||||
diagnosticHolder.report(ErrorsJs.JS_NAME_CLASH.on(existingDeclaration, name, descriptor))
|
diagnosticHolder.report(ErrorsJs.JS_NAME_CLASH.on(existingDeclaration, name, descriptor))
|
||||||
}
|
}
|
||||||
@@ -71,14 +75,14 @@ class JsNameClashChecker : SimpleDeclarationChecker {
|
|||||||
val name = overrideFqn.names.last()
|
val name = overrideFqn.names.last()
|
||||||
val existing = scope[name]
|
val existing = scope[name]
|
||||||
if (existing != null && existing != overrideFqn.descriptor) {
|
if (existing != null && existing != overrideFqn.descriptor) {
|
||||||
diagnosticHolder.report(ErrorsJs.JS_NAME_CLASH_SYNTHETIC.on(declaration, name, override, existing))
|
diagnosticHolder.report(ErrorsJs.JS_FAKE_NAME_CLASH.on(declaration, name, override, existing))
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
val clashedOverrides = clashedFakeOverrides[override]
|
val clashedOverrides = clashedFakeOverrides[override]
|
||||||
if (clashedOverrides != null) {
|
if (clashedOverrides != null) {
|
||||||
val (firstExample, secondExample) = clashedOverrides
|
val (firstExample, secondExample) = clashedOverrides
|
||||||
diagnosticHolder.report(ErrorsJs.JS_NAME_CLASH_SYNTHETIC.on(declaration, name, firstExample, secondExample))
|
diagnosticHolder.report(ErrorsJs.JS_FAKE_NAME_CLASH.on(declaration, name, firstExample, secondExample))
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -115,33 +119,29 @@ class JsNameClashChecker : SimpleDeclarationChecker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val fqn = nameSuggestion.suggest(descriptor) ?: return
|
val fqn = nameSuggestion.suggest(descriptor) ?: return
|
||||||
if (fqn.stable && isOpaque(fqn.descriptor)) {
|
if (fqn.stable && presentsInGeneratedCode(fqn.descriptor)) {
|
||||||
target[fqn.names.last()] = fqn.descriptor
|
target[fqn.names.last()] = fqn.descriptor
|
||||||
(fqn.descriptor as? CallableMemberDescriptor)?.let { checkOverrideClashes(it, target) }
|
(fqn.descriptor as? CallableMemberDescriptor)?.let { checkOverrideClashes(it, target) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkOverrideClashes(descriptor: CallableMemberDescriptor, target: MutableMap<String, DeclarationDescriptor>) {
|
private fun checkOverrideClashes(descriptor: CallableMemberDescriptor, target: MutableMap<String, DeclarationDescriptor>) {
|
||||||
var overridden = descriptor.overriddenDescriptors
|
for (overriddenDescriptor in DescriptorUtils.getAllOverriddenDeclarations(descriptor)) {
|
||||||
while (overridden.isNotEmpty()) {
|
val overriddenFqn = nameSuggestion.suggest(overriddenDescriptor)!!
|
||||||
for (overridenDescriptor in overridden) {
|
if (overriddenFqn.stable) {
|
||||||
val overriddenFqn = nameSuggestion.suggest(overridenDescriptor)!!
|
val existing = target[overriddenFqn.names.last()]
|
||||||
if (overriddenFqn.stable) {
|
if (existing != null) {
|
||||||
val existing = target[overriddenFqn.names.last()]
|
if (existing != descriptor && descriptor.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
|
||||||
if (existing != null) {
|
clashedFakeOverrides[descriptor] = Pair(existing, overriddenDescriptor)
|
||||||
if (existing != descriptor && descriptor.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
|
|
||||||
clashedFakeOverrides[descriptor] = Pair(existing, overridenDescriptor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
target[overriddenFqn.names.last()] = descriptor
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
target[overriddenFqn.names.last()] = descriptor
|
||||||
|
}
|
||||||
}
|
}
|
||||||
overridden = overridden.flatMap { it.overriddenDescriptors }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isOpaque(descriptor: DeclarationDescriptor) =
|
private fun presentsInGeneratedCode(descriptor: DeclarationDescriptor) =
|
||||||
!AnnotationsUtils.isNativeObject(descriptor) && !AnnotationsUtils.isLibraryObject(descriptor)
|
!AnnotationsUtils.isNativeObject(descriptor) && !AnnotationsUtils.isLibraryObject(descriptor)
|
||||||
}
|
}
|
||||||
@@ -102,7 +102,14 @@ public final class AnnotationsUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isNativeObject(@NotNull DeclarationDescriptor descriptor) {
|
public static boolean isNativeObject(@NotNull DeclarationDescriptor descriptor) {
|
||||||
return hasAnnotationOrInsideAnnotatedClass(descriptor, PredefinedAnnotation.NATIVE);
|
if (hasAnnotationOrInsideAnnotatedClass(descriptor, PredefinedAnnotation.NATIVE)) return true;
|
||||||
|
|
||||||
|
if (descriptor instanceof PropertyAccessorDescriptor) {
|
||||||
|
PropertyAccessorDescriptor accessor = (PropertyAccessorDescriptor) descriptor;
|
||||||
|
return hasAnnotationOrInsideAnnotatedClass(accessor.getCorrespondingProperty(), PredefinedAnnotation.NATIVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isLibraryObject(@NotNull DeclarationDescriptor descriptor) {
|
public static boolean isLibraryObject(@NotNull DeclarationDescriptor descriptor) {
|
||||||
|
|||||||
@@ -0,0 +1,149 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2015 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.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.js.test
|
||||||
|
|
||||||
|
import com.intellij.openapi.util.io.FileUtil
|
||||||
|
import com.intellij.openapi.util.text.StringUtil
|
||||||
|
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||||
|
import org.jetbrains.kotlin.js.config.EcmaVersion
|
||||||
|
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||||
|
import org.jetbrains.kotlin.js.config.JsConfig
|
||||||
|
import org.jetbrains.kotlin.js.facade.MainCallParameters
|
||||||
|
import org.jetbrains.kotlin.js.test.rhino.RhinoFunctionResultChecker
|
||||||
|
import org.jetbrains.kotlin.js.test.utils.JsTestUtils.getAllFilesInDir
|
||||||
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
||||||
|
import org.jetbrains.kotlin.utils.KotlinJavascriptMetadataUtils
|
||||||
|
import java.io.File
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
abstract class MultipleModulesTranslationTest(main: String) : BasicTest(main) {
|
||||||
|
private val MAIN_MODULE_NAME: String = "main"
|
||||||
|
private val OLD_MODULE_SUFFIX = "-old"
|
||||||
|
private var dependencies: Map<String, List<String>>? = null
|
||||||
|
protected var moduleKind = ModuleKind.PLAIN
|
||||||
|
|
||||||
|
override fun checkFooBoxIsOkByPath(filePath: String) {
|
||||||
|
val dirName = getTestName(true)
|
||||||
|
dependencies = readModuleDependencies(filePath)
|
||||||
|
|
||||||
|
// KT-7428: !! is necessary here
|
||||||
|
for ((moduleName, dependencies) in dependencies!!) {
|
||||||
|
translateModule(dirName, filePath, moduleName, dependencies)
|
||||||
|
}
|
||||||
|
|
||||||
|
val filename = getInputFilePath(getModuleDirectoryName(dirName, MAIN_MODULE_NAME) + File.separator + MAIN_MODULE_NAME + ".kt")
|
||||||
|
val packageName = getPackageName(filename)
|
||||||
|
runMultiModuleTest(dirName, packageName, BasicTest.TEST_FUNCTION, "OK")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun runMultiModuleTest(dirName: String, packageName: String, functionName: String, expectedResult: Any) {
|
||||||
|
val moduleDirectoryName = getModuleDirectoryName(dirName, MAIN_MODULE_NAME)
|
||||||
|
val checker = RhinoFunctionResultChecker(MAIN_MODULE_NAME, packageName, functionName, expectedResult)
|
||||||
|
runRhinoTests(moduleDirectoryName, BasicTest.DEFAULT_ECMA_VERSIONS, checker)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun translateModule(dirName: String, pathToDir: String, moduleName: String, dependencies: List<String>) {
|
||||||
|
val moduleDirectoryName = getModuleDirectoryName(dirName, moduleName)
|
||||||
|
val fullFilePaths = getAllFilesInDir(pathToDir + File.separator + moduleName)
|
||||||
|
|
||||||
|
BasicTest.DEFAULT_ECMA_VERSIONS.forEach { version ->
|
||||||
|
val libraries = arrayListOf<String>()
|
||||||
|
for (dependencyName in dependencies) {
|
||||||
|
val moduleDir = getModuleDirectoryName(dirName, dependencyName)
|
||||||
|
libraries.add(getMetaFileOutputPath(moduleDir, version))
|
||||||
|
}
|
||||||
|
generateJavaScriptFiles(fullFilePaths, moduleDirectoryName, MainCallParameters.noCall(), version,
|
||||||
|
moduleName.removeSuffix(OLD_MODULE_SUFFIX), libraries)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getMetaFileOutputPath(moduleDirectoryName: String, version: EcmaVersion) =
|
||||||
|
KotlinJavascriptMetadataUtils.replaceSuffix(getOutputFilePath(moduleDirectoryName, version))
|
||||||
|
|
||||||
|
override fun setupConfig(configuration: CompilerConfiguration) {
|
||||||
|
val method = try {
|
||||||
|
javaClass.getMethod(name)
|
||||||
|
}
|
||||||
|
catch (e: NoSuchMethodException) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
method.getAnnotation(WithModuleKind::class.java)?.let { moduleKind = it.value }
|
||||||
|
configuration.put(JSConfigurationKeys.MODULE_KIND, moduleKind)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun shouldGenerateMetaInfo() = true
|
||||||
|
|
||||||
|
override fun additionalJsFiles(ecmaVersion: EcmaVersion): List<String> {
|
||||||
|
val result = mutableListOf(MODULE_EMULATION_FILE)
|
||||||
|
result += super.additionalJsFiles(ecmaVersion)
|
||||||
|
val dirName = getTestName(true)
|
||||||
|
assert(dependencies != null) { "dependencies should not be null" }
|
||||||
|
|
||||||
|
for (moduleName in dependencies!!.keys.filter { !it.endsWith(OLD_MODULE_SUFFIX) }) {
|
||||||
|
if (moduleName != MAIN_MODULE_NAME && !moduleName.endsWith(OLD_MODULE_SUFFIX)) {
|
||||||
|
result.add(getOutputFilePath(getModuleDirectoryName(dirName, moduleName), ecmaVersion))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun translateFiles(jetFiles: MutableList<KtFile>, outputFile: File, mainCallParameters: MainCallParameters,
|
||||||
|
config: JsConfig) {
|
||||||
|
super.translateFiles(jetFiles, outputFile, mainCallParameters, config)
|
||||||
|
|
||||||
|
if (config.moduleKind == ModuleKind.COMMON_JS) {
|
||||||
|
val content = FileUtil.loadFile(outputFile, true)
|
||||||
|
val wrappedContent = "__beginModule__();\n" +
|
||||||
|
"$content\n" +
|
||||||
|
"__endModule__(\"${StringUtil.escapeStringCharacters(config.moduleId)}\");"
|
||||||
|
FileUtil.writeToFile(outputFile, wrappedContent)
|
||||||
|
// TODO: it would be better to wrap output before JS file is actually written
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun readModuleDependencies(testDataDir: String): Map<String, List<String>> {
|
||||||
|
val dependenciesTxt = upsearchFile(testDataDir, "dependencies.txt")
|
||||||
|
assert(dependenciesTxt.isFile) { "moduleDependencies should not be null" }
|
||||||
|
|
||||||
|
val result = LinkedHashMap<String, List<String>>()
|
||||||
|
for (line in dependenciesTxt.readLines()) {
|
||||||
|
val split = line.split("->")
|
||||||
|
val module = split[0]
|
||||||
|
val dependencies = if (split.size > 1) split[1] else ""
|
||||||
|
val dependencyList = dependencies.split(",").filterNot { it.isEmpty() }
|
||||||
|
|
||||||
|
result[module] = dependencyList
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun upsearchFile(startingDir: String, name: String): File {
|
||||||
|
var dir: File? = File(startingDir)
|
||||||
|
var file = File(dir, name)
|
||||||
|
|
||||||
|
while (dir != null && dir.isDirectory && !file.isFile) {
|
||||||
|
dir = dir.parentFile
|
||||||
|
file = File(dir, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return file
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,22 +25,26 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
|
||||||
|
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor;
|
||||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
|
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
|
||||||
import org.jetbrains.kotlin.idea.KotlinLanguage;
|
import org.jetbrains.kotlin.idea.KotlinLanguage;
|
||||||
|
import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
|
||||||
import org.jetbrains.kotlin.js.naming.NameSuggestion;
|
import org.jetbrains.kotlin.js.naming.NameSuggestion;
|
||||||
|
import org.jetbrains.kotlin.js.naming.SuggestedName;
|
||||||
import org.jetbrains.kotlin.js.resolve.JsPlatform;
|
import org.jetbrains.kotlin.js.resolve.JsPlatform;
|
||||||
import org.jetbrains.kotlin.name.FqName;
|
import org.jetbrains.kotlin.name.FqName;
|
||||||
import org.jetbrains.kotlin.name.FqNameUnsafe;
|
import org.jetbrains.kotlin.name.FqNameUnsafe;
|
||||||
|
import org.jetbrains.kotlin.name.Name;
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static com.google.dart.compiler.backend.js.ast.JsScopesKt.JsObjectScope;
|
import static com.google.dart.compiler.backend.js.ast.JsScopesKt.JsObjectScope;
|
||||||
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn;
|
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn;
|
||||||
import static org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils.getModuleName;
|
import static org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils.getModuleName;
|
||||||
import static org.jetbrains.kotlin.js.translate.utils.ManglingUtils.getStableMangledNameForDescriptor;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encapsulates different types of constants and naming conventions.
|
* Encapsulates different types of constants and naming conventions.
|
||||||
@@ -300,6 +304,17 @@ public final class Namer {
|
|||||||
modulesMap = kotlin("modules");
|
modulesMap = kotlin("modules");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: get rid of this function
|
||||||
|
@NotNull
|
||||||
|
public static String getStableMangledNameForDescriptor(@NotNull ClassDescriptor descriptor, @NotNull String functionName) {
|
||||||
|
Collection<SimpleFunctionDescriptor> functions = descriptor.getDefaultType().getMemberScope().getContributedFunctions(
|
||||||
|
Name.identifier(functionName), NoLookupLocation.FROM_BACKEND);
|
||||||
|
assert functions.size() == 1 : "Can't select a single function: " + functionName + " in " + descriptor;
|
||||||
|
SuggestedName suggested = new NameSuggestion().suggest(functions.iterator().next());
|
||||||
|
assert suggested != null : "Suggested name for class members is always non-null: " + functions.iterator().next();
|
||||||
|
return suggested.getNames().get(0);
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public JsExpression classCreationMethodReference() {
|
public JsExpression classCreationMethodReference() {
|
||||||
return kotlin(className);
|
return kotlin(className);
|
||||||
|
|||||||
@@ -113,8 +113,6 @@ public final class StaticContext {
|
|||||||
@NotNull
|
@NotNull
|
||||||
private final Map<PropertyDescriptor, JsName> backingFieldNameCache = new HashMap<PropertyDescriptor, JsName>();
|
private final Map<PropertyDescriptor, JsName> backingFieldNameCache = new HashMap<PropertyDescriptor, JsName>();
|
||||||
|
|
||||||
private final Map<JsScope, Map<String, JsName>> persistentNames = new HashMap<JsScope, Map<String, JsName>>();
|
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private final Map<DeclarationDescriptor, JsExpression> fqnCache = new HashMap<DeclarationDescriptor, JsExpression>();
|
private final Map<DeclarationDescriptor, JsExpression> fqnCache = new HashMap<DeclarationDescriptor, JsExpression>();
|
||||||
|
|
||||||
@@ -224,13 +222,8 @@ public final class StaticContext {
|
|||||||
SuggestedName suggested = nameSuggestion.suggest(descriptor);
|
SuggestedName suggested = nameSuggestion.suggest(descriptor);
|
||||||
if (suggested == null) {
|
if (suggested == null) {
|
||||||
ModuleDescriptor module = DescriptorUtils.getContainingModule(descriptor);
|
ModuleDescriptor module = DescriptorUtils.getContainingModule(descriptor);
|
||||||
if (currentModule == module) {
|
JsExpression result = getModuleExpressionFor(module);
|
||||||
return pureFqn(Namer.getRootPackageName(), null);
|
return result != null ? result : pureFqn(Namer.getRootPackageName(), null);
|
||||||
}
|
|
||||||
else {
|
|
||||||
JsExpression result = getModuleExpressionFor(module);
|
|
||||||
return result != null ? result : JsAstUtils.pureFqn(rootScope.declareName(Namer.getRootPackageName()), null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JsExpression expression;
|
JsExpression expression;
|
||||||
@@ -239,22 +232,20 @@ public final class StaticContext {
|
|||||||
expression = Namer.kotlinObject();
|
expression = Namer.kotlinObject();
|
||||||
partNames = Collections.singletonList(standardClasses.getStandardObjectName(suggested.getDescriptor()));
|
partNames = Collections.singletonList(standardClasses.getStandardObjectName(suggested.getDescriptor()));
|
||||||
}
|
}
|
||||||
else if (isLibraryObject(suggested.getDescriptor())) {
|
|
||||||
expression = Namer.kotlinObject();
|
|
||||||
partNames = getActualNameFromSuggested(suggested);
|
|
||||||
}
|
|
||||||
else if (isNative(suggested.getDescriptor()) && !isNativeObject(suggested.getScope())) {
|
|
||||||
expression = null;
|
|
||||||
partNames = getActualNameFromSuggested(suggested);
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
if (suggested.getDescriptor() instanceof CallableDescriptor && suggested.getScope() instanceof FunctionDescriptor) {
|
partNames = getActualNameFromSuggested(suggested);
|
||||||
|
if (isLibraryObject(suggested.getDescriptor())) {
|
||||||
|
expression = Namer.kotlinObject();
|
||||||
|
}
|
||||||
|
// Don't generate qualifier for top-level native declarations
|
||||||
|
// Don't generate qualifier for local declarations
|
||||||
|
else if (isNativeObject(suggested.getDescriptor()) && !isNativeObject(suggested.getScope()) ||
|
||||||
|
suggested.getDescriptor() instanceof CallableDescriptor && suggested.getScope() instanceof FunctionDescriptor) {
|
||||||
expression = null;
|
expression = null;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
expression = getQualifiedExpression(suggested.getScope());
|
expression = getQualifiedExpression(suggested.getScope());
|
||||||
}
|
}
|
||||||
partNames = getActualNameFromSuggested(suggested);
|
|
||||||
}
|
}
|
||||||
for (JsName partName : partNames) {
|
for (JsName partName : partNames) {
|
||||||
expression = new JsNameRef(partName, expression);
|
expression = new JsNameRef(partName, expression);
|
||||||
@@ -264,17 +255,6 @@ public final class StaticContext {
|
|||||||
return expression;
|
return expression;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isNative(DeclarationDescriptor descriptor) {
|
|
||||||
if (isNativeObject(descriptor)) return true;
|
|
||||||
|
|
||||||
if (descriptor instanceof PropertyAccessorDescriptor) {
|
|
||||||
PropertyAccessorDescriptor accessor = (PropertyAccessorDescriptor) descriptor;
|
|
||||||
return isNative(accessor.getCorrespondingProperty());
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public JsNameRef getQualifiedReference(@NotNull FqName packageFqName) {
|
public JsNameRef getQualifiedReference(@NotNull FqName packageFqName) {
|
||||||
JsName packageName = getNameForPackage(packageFqName);
|
JsName packageName = getNameForPackage(packageFqName);
|
||||||
@@ -300,11 +280,7 @@ public final class StaticContext {
|
|||||||
assert fqn.getNames().size() == 1 : "Private names must always consist of exactly one name";
|
assert fqn.getNames().size() == 1 : "Private names must always consist of exactly one name";
|
||||||
|
|
||||||
JsScope scope = getScopeForDescriptor(fqn.getScope());
|
JsScope scope = getScopeForDescriptor(fqn.getScope());
|
||||||
|
String baseName = NameSuggestion.getPrivateMangledName(fqn.getNames().get(0), property) + "_0";
|
||||||
if (DynamicCallsKt.isDynamic(property)) {
|
|
||||||
scope = JsDynamicScope.INSTANCE;
|
|
||||||
}
|
|
||||||
String baseName = fqn.getNames().get(0) + "_0";
|
|
||||||
name = scope.declareFreshName(baseName);
|
name = scope.declareFreshName(baseName);
|
||||||
backingFieldNameCache.put(property, name);
|
backingFieldNameCache.put(property, name);
|
||||||
}
|
}
|
||||||
@@ -322,18 +298,9 @@ public final class StaticContext {
|
|||||||
|
|
||||||
List<JsName> names = new ArrayList<JsName>();
|
List<JsName> names = new ArrayList<JsName>();
|
||||||
if (suggested.getStable()) {
|
if (suggested.getStable()) {
|
||||||
Map<String, JsName> scopeNames = persistentNames.get(scope);
|
|
||||||
if (scopeNames == null) {
|
|
||||||
scopeNames = new HashMap<String, JsName>();
|
|
||||||
persistentNames.put(scope, scopeNames);
|
|
||||||
}
|
|
||||||
for (String namePart : suggested.getNames()) {
|
for (String namePart : suggested.getNames()) {
|
||||||
JsName name = scopeNames.get(namePart);
|
names.add(scope.declareName(namePart));
|
||||||
if (name == null) {
|
|
||||||
name = scope.declareName(namePart);
|
|
||||||
scopeNames.put(namePart, name);
|
|
||||||
}
|
|
||||||
names.add(name);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
+1
-1
@@ -63,7 +63,7 @@ class DelegationTranslator(
|
|||||||
else {
|
else {
|
||||||
val classFqName = DescriptorUtils.getFqName(classDescriptor)
|
val classFqName = DescriptorUtils.getFqName(classDescriptor)
|
||||||
val typeFqName = DescriptorUtils.getFqName(descriptor)
|
val typeFqName = DescriptorUtils.getFqName(descriptor)
|
||||||
val idForMangling = "${classFqName.asString()}:${typeFqName.asString()}"
|
val idForMangling = classFqName.asString()
|
||||||
val suggestedName = NameSuggestion.getStableMangledName(Namer.getDelegatePrefix(), idForMangling)
|
val suggestedName = NameSuggestion.getStableMangledName(Namer.getDelegatePrefix(), idForMangling)
|
||||||
val delegateName = context.getScopeForDescriptor(classDescriptor).declareFreshName("${suggestedName}_0")
|
val delegateName = context.getScopeForDescriptor(classDescriptor).declareFreshName("${suggestedName}_0")
|
||||||
fields[specifier] = Field(delegateName, true)
|
fields[specifier] = Field(delegateName, true)
|
||||||
|
|||||||
+1
-1
@@ -53,7 +53,7 @@ import java.util.Map;
|
|||||||
import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.FQ_NAMES;
|
import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.FQ_NAMES;
|
||||||
import static org.jetbrains.kotlin.js.patterns.PatternBuilder.pattern;
|
import static org.jetbrains.kotlin.js.patterns.PatternBuilder.pattern;
|
||||||
import static org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.FunctionIntrinsic.CallParametersAwareFunctionIntrinsic;
|
import static org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.FunctionIntrinsic.CallParametersAwareFunctionIntrinsic;
|
||||||
import static org.jetbrains.kotlin.js.translate.utils.ManglingUtils.getStableMangledNameForDescriptor;
|
import static org.jetbrains.kotlin.js.translate.context.Namer.getStableMangledNameForDescriptor;
|
||||||
|
|
||||||
public final class TopLevelFIF extends CompositeFIF {
|
public final class TopLevelFIF extends CompositeFIF {
|
||||||
public static final DescriptorPredicate EQUALS_IN_ANY = pattern("kotlin", "Any", "equals");
|
public static final DescriptorPredicate EQUALS_IN_ANY = pattern("kotlin", "Any", "equals");
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2015 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.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.jetbrains.kotlin.js.translate.utils;
|
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
|
|
||||||
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor;
|
|
||||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
|
|
||||||
import org.jetbrains.kotlin.js.naming.NameSuggestion;
|
|
||||||
import org.jetbrains.kotlin.js.naming.SuggestedName;
|
|
||||||
import org.jetbrains.kotlin.name.Name;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
public class ManglingUtils {
|
|
||||||
private ManglingUtils() {}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public static String getStableMangledNameForDescriptor(@NotNull ClassDescriptor descriptor, @NotNull String functionName) {
|
|
||||||
Collection<SimpleFunctionDescriptor> functions = descriptor.getDefaultType().getMemberScope().getContributedFunctions(
|
|
||||||
Name.identifier(functionName), NoLookupLocation.FROM_BACKEND);
|
|
||||||
assert functions.size() == 1 : "Can't select a single function: " + functionName + " in " + descriptor;
|
|
||||||
SuggestedName suggested = new NameSuggestion().suggest(functions.iterator().next());
|
|
||||||
assert suggested != null : "Suggested name for class members is always non-null: " + functions.iterator().next();
|
|
||||||
return suggested.getNames().get(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Vendored
+3
-5
@@ -1,15 +1,13 @@
|
|||||||
// KT-2995 creating factory methods to simulate overloaded constructors don't work in JavaScript
|
// KT-2995 creating factory methods to simulate overloaded constructors don't work in JavaScript
|
||||||
// This test is incorrect, since both constructor and function must have the same name.
|
|
||||||
package foo
|
package foo
|
||||||
|
|
||||||
class Foo(val name: String)
|
class Foo(val name: String)
|
||||||
|
|
||||||
//fun Foo() = Foo("<default-name>")
|
fun Foo(x: Int) = Foo("<$x>")
|
||||||
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
// TODO: Don't know another way to suppress the test
|
assertEquals("<123>", Foo(123).name)
|
||||||
/*assertEquals("<default-name>", Foo().name)
|
assertEquals("BarBaz", Foo("BarBaz").name)
|
||||||
assertEquals("BarBaz", Foo("BarBaz").name)*/
|
|
||||||
|
|
||||||
return "OK"
|
return "OK"
|
||||||
}
|
}
|
||||||
+2
-2
@@ -1,11 +1,11 @@
|
|||||||
package foo
|
package foo
|
||||||
|
|
||||||
@JsName("AA") object A {
|
@JsName("AA") object A {
|
||||||
@JsName("foo") fun foo() = "A.foo"
|
@JsName("foo") fun bar() = "A.foo"
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsName("BB") class B {
|
@JsName("BB") class B {
|
||||||
@JsName("foo") fun foo() = "B.foo"
|
@JsName("foo") fun bar() = "B.foo"
|
||||||
}
|
}
|
||||||
|
|
||||||
fun testA() = js("""
|
fun testA() = js("""
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
class A {
|
||||||
|
val x: String
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
val o = "O"
|
||||||
|
fun baz() = o + "K"
|
||||||
|
x = baz()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box() = A().x
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
lib1->
|
||||||
|
lib2->
|
||||||
|
main->lib1,lib2
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
package lib1
|
||||||
|
|
||||||
|
interface A {
|
||||||
|
private fun foo() = "A.foo"
|
||||||
|
|
||||||
|
fun bar() = foo()
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
package lib2
|
||||||
|
|
||||||
|
interface B {
|
||||||
|
private fun foo() = "B.foo"
|
||||||
|
|
||||||
|
fun bar() = foo()
|
||||||
|
}
|
||||||
+32
@@ -0,0 +1,32 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import lib1.A
|
||||||
|
import lib2.B
|
||||||
|
|
||||||
|
class Derived1 : A, B {
|
||||||
|
override fun bar() = super<A>.bar()
|
||||||
|
}
|
||||||
|
|
||||||
|
class Derived2 : A, B {
|
||||||
|
override fun bar() = super<B>.bar()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE. This test is fragile, it may fail due to unexpected (and correct) changes in algorithm that assigns
|
||||||
|
// unique identifiers to non-public declarations. However, we don't see any way of doing such test so that
|
||||||
|
// it won't report false positives eventually. So be patient and just update this test whenever you changed
|
||||||
|
// algorithm of assigning unique identifiers.
|
||||||
|
// Please, check that A.foo and B.foo have different JS names.
|
||||||
|
private fun checkJsNames(o: dynamic): Boolean = "foo_2pru9n\$_0" in o && "foo_2psha1\$_0" in o
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
val a = Derived1()
|
||||||
|
if (a.bar() != "A.foo") return "fail1: ${a.bar()}"
|
||||||
|
|
||||||
|
val b = Derived2()
|
||||||
|
if (b.bar() != "B.foo") return "fail2: ${b.bar()}"
|
||||||
|
|
||||||
|
if (!checkJsNames(a)) return "fail3"
|
||||||
|
if (!checkJsNames(b)) return "fail4"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
lib->
|
||||||
|
lib-old->
|
||||||
|
main->lib-old
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package lib
|
||||||
|
|
||||||
|
open class A {
|
||||||
|
fun foo() = 12
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun check() = true
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package lib
|
||||||
|
|
||||||
|
open class A {
|
||||||
|
private val x = 23
|
||||||
|
|
||||||
|
fun foo() = x
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import lib.A
|
||||||
|
import lib.check
|
||||||
|
|
||||||
|
class B : A() {
|
||||||
|
private var x = 42
|
||||||
|
|
||||||
|
fun bar() = x
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE. This test is fragile, it may fail due to unexpected (and correct) changes in algorithm that assigns
|
||||||
|
// unique identifiers to non-public declarations. However, we don't see any way of doing such test so that
|
||||||
|
// it won't report false positives eventually. So be patient and just update this test whenever you changed
|
||||||
|
// algorithm of assigning unique identifiers.
|
||||||
|
// Please, check that A.x and B.x have different JS names.
|
||||||
|
private fun checkJsNames(o: dynamic): Boolean = "x_i8qwny\$_0" in o && "x_dqqnpp\$_0" in o
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
if (!check()) return "check failed: did not compile agains old library"
|
||||||
|
|
||||||
|
val a = A()
|
||||||
|
if (a.foo() != 23) return "fail1: ${a.foo()}"
|
||||||
|
|
||||||
|
val b = B()
|
||||||
|
if (b.foo() != 23) return "fail2: ${b.foo()}"
|
||||||
|
if (b.bar() != 42) return "fail3: ${b.bar()}"
|
||||||
|
if (!checkJsNames(b)) return "fail4"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user