JS backend: remake NameGenerator in case Property & PropertyAccessor. Fix overload extension property.

This commit is contained in:
Erokhin Stanislav
2013-09-06 15:22:21 +04:00
parent c5a720164e
commit 12cb774f1c
5 changed files with 59 additions and 37 deletions
@@ -84,6 +84,10 @@ public class RegressionMergeEcmaTest extends SingleFileTranslationTest {
checkFooBoxIsOk(); checkFooBoxIsOk();
} }
public void testBackendField() throws Exception {
checkFooBoxIsOk();
}
public void testExtensionClass() throws Exception { public void testExtensionClass() throws Exception {
checkFooBoxIsOk(); checkFooBoxIsOk();
} }
@@ -35,7 +35,6 @@ import org.jetbrains.k2js.translate.expression.LiteralFunctionTranslator;
import org.jetbrains.k2js.translate.intrinsic.Intrinsics; import org.jetbrains.k2js.translate.intrinsic.Intrinsics;
import org.jetbrains.k2js.translate.utils.AnnotationsUtils; import org.jetbrains.k2js.translate.utils.AnnotationsUtils;
import org.jetbrains.k2js.translate.utils.JsAstUtils; import org.jetbrains.k2js.translate.utils.JsAstUtils;
import org.jetbrains.k2js.translate.utils.JsDescriptorUtils;
import org.jetbrains.k2js.translate.utils.PredefinedAnnotation; import org.jetbrains.k2js.translate.utils.PredefinedAnnotation;
import java.util.Arrays; import java.util.Arrays;
@@ -44,7 +43,6 @@ import java.util.Comparator;
import java.util.Map; import java.util.Map;
import static org.jetbrains.k2js.translate.utils.AnnotationsUtils.*; import static org.jetbrains.k2js.translate.utils.AnnotationsUtils.*;
import static org.jetbrains.k2js.translate.utils.BindingUtils.isObjectDeclaration;
import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.*; import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.*;
/** /**
@@ -199,13 +197,6 @@ public final class StaticContext {
} }
private final class NameGenerator extends Generator<JsName> { private final class NameGenerator extends Generator<JsName> {
private JsName declareName(DeclarationDescriptor descriptor, String name) {
JsScope scope = getEnclosingScope(descriptor);
// ecma 5 property name never declares as obfuscatable:
// 1) property cannot be overloaded, so, name collision is not possible
// 2) main reason: if property doesn't have any custom accessor, value holder will have the same name as accessor, so, the same name will be declared more than once
return isEcma5() ? scope.declareName(name) : scope.declareFreshName(name);
}
public NameGenerator() { public NameGenerator() {
Rule<JsName> namesForStandardClasses = new Rule<JsName>() { Rule<JsName> namesForStandardClasses = new Rule<JsName>() {
@@ -286,23 +277,40 @@ public final class StaticContext {
return getNameForDescriptor(containingClass); return getNameForDescriptor(containingClass);
} }
}; };
Rule<JsName> accessorsHasNamesWithSpecialPrefixes = new Rule<JsName>() {
// ecma 5 property name never declares as obfuscatable:
// 1) property cannot be overloaded, so, name collision is not possible
// 2) main reason: if property doesn't have any custom accessor, value holder will have the same name as accessor, so, the same name will be declared more than once
//
// But extension property may obfuscatable, because transform into function. Example: String.foo = 1, Int.foo = 2
Rule<JsName> propertyOrPropertyAccessor = new Rule<JsName>() {
@Override @Override
public JsName apply(@NotNull DeclarationDescriptor descriptor) { public JsName apply(@NotNull DeclarationDescriptor descriptor) {
if (!(descriptor instanceof PropertyAccessorDescriptor)) { PropertyDescriptor propertyDescriptor;
if (descriptor instanceof PropertyAccessorDescriptor) {
propertyDescriptor = ((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty();
}
else if (descriptor instanceof PropertyDescriptor) {
propertyDescriptor = (PropertyDescriptor) descriptor;
}
else {
return null; return null;
} }
PropertyAccessorDescriptor accessorDescriptor = (PropertyAccessorDescriptor) descriptor; String propertyName = propertyDescriptor.getName().asString();
String propertyName = accessorDescriptor.getCorrespondingProperty().getName().asString();
if (isObjectDeclaration(accessorDescriptor.getCorrespondingProperty())) {
return declareName(descriptor, propertyName);
}
boolean isGetter = descriptor instanceof PropertyGetterDescriptor; if (!isExtension(propertyDescriptor)) {
String accessorName = Namer.getNameForAccessor(propertyName, isGetter, return declarePropertyOrPropertyAccessorName(descriptor, propertyName, false);
accessorDescriptor.getReceiverParameter() == null && isEcma5()); } else {
return declareName(descriptor, accessorName); if (descriptor instanceof PropertyDescriptor) {
return declarePropertyOrPropertyAccessorName(descriptor, propertyName, true);
} else {
String propertyJsName = getNameForDescriptor(propertyDescriptor).getIdent();
boolean isGetter = descriptor instanceof PropertyGetterDescriptor;
String accessorName = Namer.getNameForAccessor(propertyJsName, isGetter, false);
return declarePropertyOrPropertyAccessorName(descriptor, accessorName, false);
}
}
} }
}; };
@@ -320,21 +328,6 @@ public final class StaticContext {
return null; return null;
} }
}; };
Rule<JsName> propertiesCorrespondToSpeciallyTreatedBackingFieldNames = new Rule<JsName>() {
@Override
public JsName apply(@NotNull DeclarationDescriptor descriptor) {
if (!(descriptor instanceof PropertyDescriptor)) {
return null;
}
String name = descriptor.getName().asString();
if (!isEcma5() || !JsDescriptorUtils.isSimpleProperty((PropertyDescriptor) descriptor)) {
name = Namer.getKotlinBackingFieldName(name);
}
return declareName(descriptor, name);
}
};
Rule<JsName> overridingDescriptorsReferToOriginalName = new Rule<JsName>() { Rule<JsName> overridingDescriptorsReferToOriginalName = new Rule<JsName>() {
@Override @Override
public JsName apply(@NotNull DeclarationDescriptor descriptor) { public JsName apply(@NotNull DeclarationDescriptor descriptor) {
@@ -355,15 +348,20 @@ public final class StaticContext {
}; };
addRule(namesForStandardClasses); addRule(namesForStandardClasses);
addRule(constructorHasTheSameNameAsTheClass); addRule(constructorHasTheSameNameAsTheClass);
addRule(propertyOrPropertyAccessor);
addRule(predefinedObjectsHasUnobfuscatableNames); addRule(predefinedObjectsHasUnobfuscatableNames);
addRule(propertiesCorrespondToSpeciallyTreatedBackingFieldNames);
addRule(namespacesShouldBeDefinedInRootScope); addRule(namespacesShouldBeDefinedInRootScope);
addRule(overridingDescriptorsReferToOriginalName); addRule(overridingDescriptorsReferToOriginalName);
addRule(accessorsHasNamesWithSpecialPrefixes);
addRule(memberDeclarationsInsideParentsScope); addRule(memberDeclarationsInsideParentsScope);
} }
} }
@NotNull
public JsName declarePropertyOrPropertyAccessorName(@NotNull DeclarationDescriptor descriptor, @NotNull String name, boolean fresh) {
JsScope scope = getEnclosingScope(descriptor);
return fresh ? scope.declareFreshName(name) : scope.declareName(name);
}
@NotNull @NotNull
private JsScope getEnclosingScope(@NotNull DeclarationDescriptor descriptor) { private JsScope getEnclosingScope(@NotNull DeclarationDescriptor descriptor) {
DeclarationDescriptor containingDeclaration = getContainingDeclaration(descriptor); DeclarationDescriptor containingDeclaration = getContainingDeclaration(descriptor);
@@ -172,6 +172,11 @@ public class TranslationContext {
return staticContext.getNameForDescriptor(descriptor); return staticContext.getNameForDescriptor(descriptor);
} }
@NotNull
public JsName declarePropertyOrPropertyAccessorName(@NotNull DeclarationDescriptor descriptor, @NotNull String name, boolean fresh) {
return staticContext.declarePropertyOrPropertyAccessorName(descriptor, name, fresh);
}
@NotNull @NotNull
public JsStringLiteral nameToLiteral(@NotNull Named named) { public JsStringLiteral nameToLiteral(@NotNull Named named) {
return program().getStringLiteral(named.getName().asString()); return program().getStringLiteral(named.getName().asString());
@@ -34,6 +34,7 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import static com.google.dart.compiler.backend.js.ast.JsBinaryOperator.*; import static com.google.dart.compiler.backend.js.ast.JsBinaryOperator.*;
import static org.jetbrains.k2js.translate.context.Namer.getKotlinBackingFieldName;
import static org.jetbrains.k2js.translate.utils.BindingUtils.getFunctionDescriptorForOperationExpression; import static org.jetbrains.k2js.translate.utils.BindingUtils.getFunctionDescriptorForOperationExpression;
import static org.jetbrains.k2js.translate.utils.JsAstUtils.assignment; import static org.jetbrains.k2js.translate.utils.JsAstUtils.assignment;
import static org.jetbrains.k2js.translate.utils.JsAstUtils.createDataDescriptor; import static org.jetbrains.k2js.translate.utils.JsAstUtils.createDataDescriptor;
@@ -154,6 +155,11 @@ public final class TranslationUtils {
public static JsNameRef backingFieldReference(@NotNull TranslationContext context, public static JsNameRef backingFieldReference(@NotNull TranslationContext context,
@NotNull PropertyDescriptor descriptor) { @NotNull PropertyDescriptor descriptor) {
JsName backingFieldName = context.getNameForDescriptor(descriptor); JsName backingFieldName = context.getNameForDescriptor(descriptor);
if(!JsDescriptorUtils.isSimpleProperty(descriptor)) {
backingFieldName = context.declarePropertyOrPropertyAccessorName(descriptor,
getKotlinBackingFieldName(backingFieldName.getIdent()),
false);
}
return new JsNameRef(backingFieldName, JsLiteral.THIS); return new JsNameRef(backingFieldName, JsLiteral.THIS);
} }
@@ -0,0 +1,9 @@
package foo
val a: Int = 1
get() = $a + 1
fun box(): String {
if (a != 2) return "a != 2, it: $a"
return "OK"
}