diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContextUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContextUtils.java index 4aa81ff10a6..1dedc0dee6f 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContextUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContextUtils.java @@ -339,12 +339,13 @@ public class BindingContextUtils { } @NotNull - public static Set getAllOverriddenDeclarations(@NotNull FunctionDescriptor functionDescriptor) { - Set result = Sets.newHashSet(); - for (FunctionDescriptor overriddenDeclaration : functionDescriptor.getOverriddenDescriptors()) { + public static Set getAllOverriddenDeclarations(@NotNull T memberDescriptor) { + Set result = Sets.newHashSet(); + for (CallableMemberDescriptor overriddenDeclaration : memberDescriptor.getOverriddenDescriptors()) { CallableMemberDescriptor.Kind kind = overriddenDeclaration.getKind(); if (kind == DECLARATION) { - result.add(overriddenDeclaration); + //noinspection unchecked + result.add((T) overriddenDeclaration); } else if (kind == DELEGATION || kind == FAKE_OVERRIDE || kind == SYNTHESIZED) { //do nothing @@ -352,7 +353,8 @@ public class BindingContextUtils { else { throw new AssertionError("Unexpected callable kind " + kind); } - result.addAll(getAllOverriddenDeclarations(overriddenDeclaration)); + //noinspection unchecked + result.addAll(getAllOverriddenDeclarations((T) overriddenDeclaration)); } return result; } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/context/StaticContext.java b/js/js.translator/src/org/jetbrains/k2js/translate/context/StaticContext.java index c7cfec7f3aa..f85bd5b7ff3 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/context/StaticContext.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/context/StaticContext.java @@ -37,7 +37,7 @@ import org.jetbrains.k2js.translate.utils.JsAstUtils; import java.util.Map; -import static org.jetbrains.k2js.translate.utils.AnnotationsUtils.getNameForAnnotatedObject; +import static org.jetbrains.k2js.translate.utils.AnnotationsUtils.getNameForAnnotatedObjectWithOverrides; import static org.jetbrains.k2js.translate.utils.AnnotationsUtils.isLibraryObject; import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.*; import static org.jetbrains.k2js.translate.utils.TranslationUtils.getMangledName; @@ -263,7 +263,7 @@ public final class StaticContext { return null; } - String nameFromAnnotation = getNameForAnnotatedObject(propertyDescriptor); + String nameFromAnnotation = getNameForAnnotatedObjectWithOverrides(propertyDescriptor); if (nameFromAnnotation != null) { return declarePropertyOrPropertyAccessorName(descriptor, nameFromAnnotation, false); } @@ -297,7 +297,7 @@ public final class StaticContext { return null; } - String name = getNameForAnnotatedObject(descriptor); + String name = getNameForAnnotatedObjectWithOverrides(descriptor); if (name != null) return getEnclosingScope(descriptor).declareName(name); return null; } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/utils/AnnotationsUtils.java b/js/js.translator/src/org/jetbrains/k2js/translate/utils/AnnotationsUtils.java index fcf87056279..7e356245862 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/utils/AnnotationsUtils.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/utils/AnnotationsUtils.java @@ -16,14 +16,20 @@ package org.jetbrains.k2js.translate.utils; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; +import org.jetbrains.jet.lang.resolve.BindingContextUtils; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.name.FqName; +import java.util.Set; + import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.getContainingClass; public final class AnnotationsUtils { @@ -65,15 +71,30 @@ public final class AnnotationsUtils { } @Nullable - public static String getNameForAnnotatedObject(@NotNull DeclarationDescriptor descriptor) { - for (PredefinedAnnotation annotation : PredefinedAnnotation.values()) { - if (!hasAnnotationOrInsideAnnotatedClass(descriptor, annotation)) { - continue; - } - String name = getNameForAnnotatedObject(descriptor, annotation); - return name != null ? name : descriptor.getName().asString(); + public static String getNameForAnnotatedObjectWithOverrides(@NotNull DeclarationDescriptor declarationDescriptor) { + Set descriptors; + + if (declarationDescriptor instanceof CallableMemberDescriptor && + ((CallableMemberDescriptor) declarationDescriptor).getKind() != CallableMemberDescriptor.Kind.DECLARATION) { + + Set overriddenDeclarations = + BindingContextUtils.getAllOverriddenDeclarations((CallableMemberDescriptor) declarationDescriptor); + //noinspection unchecked + descriptors = ContainerUtil.map2Set(overriddenDeclarations, Function.ID); + } + else { + descriptors = ContainerUtil.newHashSet(declarationDescriptor); } + for (DeclarationDescriptor descriptor : descriptors) { + for (PredefinedAnnotation annotation : PredefinedAnnotation.values()) { + if (!hasAnnotationOrInsideAnnotatedClass(descriptor, annotation)) { + continue; + } + String name = getNameForAnnotatedObject(descriptor, annotation); + return name != null ? name : descriptor.getName().asString(); + } + } return null; } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/utils/TranslationUtils.java b/js/js.translator/src/org/jetbrains/k2js/translate/utils/TranslationUtils.java index 2d8f9e8ce0a..71511c69b5c 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/utils/TranslationUtils.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/utils/TranslationUtils.java @@ -17,7 +17,6 @@ package org.jetbrains.k2js.translate.utils; import com.google.dart.compiler.backend.js.ast.*; -import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.Function; @@ -26,6 +25,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.resolve.BindingContextUtils; import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.k2js.translate.context.TemporaryConstVariable; @@ -179,7 +179,7 @@ public final class TranslationUtils { } @NotNull - private static String getSimpleMangledName(@NotNull FunctionDescriptor descriptor) { + private static String getSimpleMangledName(@NotNull final FunctionDescriptor descriptor) { DeclarationDescriptor declaration = descriptor.getContainingDeclaration(); JetScope jetScope = null; @@ -193,11 +193,24 @@ public final class TranslationUtils { int counter = 0; if (jetScope != null) { - Collection functions = jetScope.getFunctions(descriptor.getName()); - List overloadedFunctions = ContainerUtil.filter(functions, new Condition() { + Collection declarations = jetScope.getAllDescriptors(); + List overloadedFunctions = ContainerUtil.mapNotNull(declarations, new Function() { @Override - public boolean value(FunctionDescriptor descriptor) { - return !needsStableMangling(descriptor) && !AnnotationsUtils.isNativeObject(descriptor); + public FunctionDescriptor fun(DeclarationDescriptor declarationDescriptor) { + if (!(declarationDescriptor instanceof FunctionDescriptor)) return null; + + FunctionDescriptor functionDescriptor = (FunctionDescriptor) declarationDescriptor; + + String name = AnnotationsUtils.getNameForAnnotatedObjectWithOverrides(functionDescriptor); + + if (name == null) { + // when name == null it's mean that it's not native + if (needsStableMangling(functionDescriptor)) return null; + + name = declarationDescriptor.getName().asString(); + } + + return descriptor.getName().asString().equals(name) ? functionDescriptor : null; } }); @@ -369,6 +382,14 @@ public final class TranslationUtils { private static class OverloadedFunctionComparator implements Comparator { @Override public int compare(@NotNull FunctionDescriptor a, @NotNull FunctionDescriptor b) { + // native functions first + if (isNativeOrOverrideNative(a)) { + if (!isNativeOrOverrideNative(b)) return -1; + } + else if (isNativeOrOverrideNative(b)) { + return 1; + } + // be visibility // Actually "internal" > "private", but we want to have less number for "internal", so compare b with a instead of a with b. Integer result = Visibilities.compare(b.getVisibility(), a.getVisibility()); @@ -390,5 +411,13 @@ public final class TranslationUtils { private static int arity(FunctionDescriptor descriptor) { return descriptor.getValueParameters().size() + (descriptor.getReceiverParameter() == null ? 0 : 1); } + + private static boolean isNativeOrOverrideNative(FunctionDescriptor descriptor) { + Set declarations = BindingContextUtils.getAllOverriddenDeclarations(descriptor); + for (FunctionDescriptor memberDescriptor : declarations) { + if (AnnotationsUtils.isNativeObject(memberDescriptor)) return true; + } + return false; + } } } diff --git a/js/js.translator/testFiles/expression/function/cases/mangling.kt b/js/js.translator/testFiles/expression/function/cases/mangling.kt index 15daabf9166..7e88f3c2ae0 100644 --- a/js/js.translator/testFiles/expression/function/cases/mangling.kt +++ b/js/js.translator/testFiles/expression/function/cases/mangling.kt @@ -7,6 +7,7 @@ fun internal_foo(i: Int): Int = 2 fun internal_boo(i: Int): Int = 2 fun internal_boo(s: String): Int = 3 fun internal_boo(): Int = 1 +native fun internal_boo(a: Array) = "should be ingnored" val internal_f = { internal_foo() + internal_foo(1) } val internal_b = { internal_boo() + internal_boo(1) } @@ -19,6 +20,7 @@ public fun public_foo(i: Int): Int = 2 public fun public_boo(i: Int): Int = 2 public fun public_boo(s: String): Int = 3 public fun public_boo(): Int = 1 +native public fun public_boo(a: Array): String = "should be ingnored" val public_f = { public_foo() + public_foo(1) } val public_b = { public_boo() + public_boo(1) } @@ -28,6 +30,7 @@ native private fun private_foo(a: Array): String = "should be ingnored" private fun private_foo(): Int = 1 private fun private_foo(i: Int): Int = 2 +native private fun private_boo(a: Array): String = "should be ingnored" private fun private_boo(i: Int): Int = 2 private fun private_boo(s: String): Int = 3 private fun private_boo(): Int = 1 @@ -44,6 +47,7 @@ fun mixed_foo(i: Int): Int = 2 fun mixed_boo(i: Int): Int = 2 private fun mixed_boo(s: String, i: Int): Int = 4 +native fun mixed_boo(a: Array) = "should be ingnored" public fun mixed_boo(s: String): Int = 3 fun mixed_boo(): Int = 1 diff --git a/js/js.translator/testFiles/native/cases/inheritanceFromNativeClass.kt b/js/js.translator/testFiles/native/cases/inheritanceFromNativeClass.kt index 42c203610ee..c07ebd3e9af 100644 --- a/js/js.translator/testFiles/native/cases/inheritanceFromNativeClass.kt +++ b/js/js.translator/testFiles/native/cases/inheritanceFromNativeClass.kt @@ -1,19 +1,49 @@ package foo native -open class A(b: Int) { +open class A(val a: Int) { fun g(): Int = noImpl fun m(): Int = noImpl + + public open fun foo(i: Int): String = noImpl + public fun boo(i: Int): String = noImpl + native("bar") + open fun baz(i: Int): String = noImpl } -class B(val b: Int) : A(b / 2) +class B(val b: Int) : A(b / 2) { + override fun foo(i: Int): String = "B.foo($i: Int)" + + fun boo(): String = "B.boo()" + fun boo(i: String): String = "B.boo($i: String)" + + fun bar(i: String): String = "B.bar($i: String)" + override fun baz(i: Int): String = "B.baz($i: Int)" + fun bar(): String = "B.bar()" +} fun box(): String { - val b = B(10) + if (b !is A) return "b !is A" if (b.g() != 10) return "b.g() != 10, it: ${b.g()}" if (b.m() != 4) return "b.m() != 4, it: ${b.m()}" + if (b.foo(4) != "B.foo(4: Int)") return "b.foo(4) != \"B.foo(4: Int)\", it: ${b.foo(4)}" + + if (b.boo(434) != "A.boo(434)") return "b.boo(434) != \"A.boo(434)\", it: ${b.boo(434)}" + if (b.boo() != "B.boo()") return "b.boo() != \"B.boo()\", it: ${b.boo()}" + if (b.boo("qlfj") != "B.boo(qlfj: String)") return "b.boo(\"qlfj\") != \"B.boo(qlfj: String)\", it: ${b.boo("qlfj")}" + + if (b.bar("apl") != "B.bar(apl: String)") return "b.bar(\"apl\") != \"B.bar(apl: String)\", it: ${b.bar("apl")}" + if (b.baz(34) != "B.baz(34: Int)") return "b.baz(34) != \"B.baz(34: Int)\", it: ${b.baz(34)}" + if (b.bar() != "B.bar()") return "b.bar() != \"B.bar()\", it: ${b.bar()}" + + val a: A = b + + if (a.foo(4) != "B.foo(4: Int)") return "a.foo(4) != \"B.foo(4: Int)\", it: ${a.foo(4)}" + if (a.boo(434) != "A.boo(434)") return "a.boo(434) != \"A.boo(434)\", it: ${a.boo(434)}" + if (a.baz(34) != "B.baz(34: Int)") return "a.baz(34) != \"B.baz(34: Int)\", it: ${a.baz(34)}" + return "OK" } \ No newline at end of file diff --git a/js/js.translator/testFiles/native/native/inheritanceFromNativeClass.js b/js/js.translator/testFiles/native/native/inheritanceFromNativeClass.js index c8c3052a34e..6eee65e132b 100644 --- a/js/js.translator/testFiles/native/native/inheritanceFromNativeClass.js +++ b/js/js.translator/testFiles/native/native/inheritanceFromNativeClass.js @@ -1,8 +1,23 @@ -function A(b) { - this.g = function() { - return 2 * b; - }; - this.m = function() { - return b - 1; - } +function A(a) { + this.a = a; +} + +A.prototype.g = function() { + return 2 * this.a; +}; + +A.prototype.m = function() { + return this.a - 1; +}; + +A.prototype.foo = function(i) { + return "A.foo(" + i + ")"; +}; + +A.prototype.boo = function(i) { + return "A.boo(" + i + ")"; +}; + +A.prototype.bar = function(i) { + return "A.bar(" + i + ")"; } \ No newline at end of file