JS backend: consider functions which renamed by annotations in simple mangling.

This commit is contained in:
Zalim Bashorov
2014-01-31 17:39:05 +04:00
parent 5c0eeb59f6
commit 8a1ffeea70
7 changed files with 132 additions and 31 deletions
@@ -339,12 +339,13 @@ public class BindingContextUtils {
}
@NotNull
public static Set<FunctionDescriptor> getAllOverriddenDeclarations(@NotNull FunctionDescriptor functionDescriptor) {
Set<FunctionDescriptor> result = Sets.newHashSet();
for (FunctionDescriptor overriddenDeclaration : functionDescriptor.getOverriddenDescriptors()) {
public static <T extends CallableMemberDescriptor> Set<T> getAllOverriddenDeclarations(@NotNull T memberDescriptor) {
Set<T> 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;
}
@@ -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;
}
@@ -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<DeclarationDescriptor> descriptors;
if (declarationDescriptor instanceof CallableMemberDescriptor &&
((CallableMemberDescriptor) declarationDescriptor).getKind() != CallableMemberDescriptor.Kind.DECLARATION) {
Set<CallableMemberDescriptor> overriddenDeclarations =
BindingContextUtils.getAllOverriddenDeclarations((CallableMemberDescriptor) declarationDescriptor);
//noinspection unchecked
descriptors = ContainerUtil.<CallableMemberDescriptor, DeclarationDescriptor>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;
}
@@ -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<FunctionDescriptor> functions = jetScope.getFunctions(descriptor.getName());
List<FunctionDescriptor> overloadedFunctions = ContainerUtil.filter(functions, new Condition<FunctionDescriptor>() {
Collection<DeclarationDescriptor> declarations = jetScope.getAllDescriptors();
List<FunctionDescriptor> overloadedFunctions = ContainerUtil.mapNotNull(declarations, new Function<DeclarationDescriptor, FunctionDescriptor>() {
@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<FunctionDescriptor> {
@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<FunctionDescriptor> declarations = BindingContextUtils.getAllOverriddenDeclarations(descriptor);
for (FunctionDescriptor memberDescriptor : declarations) {
if (AnnotationsUtils.isNativeObject(memberDescriptor)) return true;
}
return false;
}
}
}
@@ -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<Int>) = "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<Int>): 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<Int>): 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<Int>): 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<Int>) = "should be ingnored"
public fun mixed_boo(s: String): Int = 3
fun mixed_boo(): Int = 1
@@ -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"
}
@@ -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 + ")";
}